1 /*
2  * $LynxId: LYMail.c,v 1.100 2020/01/21 21:33:27 tom Exp $
3  */
4 #include <HTUtils.h>
5 #include <HTParse.h>
6 #include <LYGlobalDefs.h>
7 #include <HTAlert.h>
8 #include <LYCurses.h>
9 #include <LYSignal.h>
10 #include <LYUtils.h>
11 #include <LYClean.h>
12 #include <LYStrings.h>
13 #include <GridText.h>
14 #include <LYMail.h>
15 #include <LYEdit.h>
16 #include <LYCharSets.h>		/* to get current charset for mail header */
17 
18 #include <LYLeaks.h>
19 
20 #define MAX_SUBJECT 70
21 
22 BOOLEAN term_letter;		/* Global variable for async i/o. */
23 
terminate_letter(int sig GCC_UNUSED)24 static void terminate_letter(int sig GCC_UNUSED)
25 {
26     term_letter = TRUE;
27     /* Reassert the AST */
28     signal(SIGINT, terminate_letter);
29 #if USE_VMS_MAILER || defined(PDCURSES)
30     /*
31      * Refresh the screen to get rid of the "interrupt" message.
32      */
33     if (!dump_output_immediately) {
34 	lynx_force_repaint();
35 	LYrefresh();
36     }
37 #endif /* VMS */
38 }
39 
40 /* HTUnEscape with control-code nuking */
SafeHTUnEscape(char * string)41 static void SafeHTUnEscape(char *string)
42 {
43     int i;
44     int flg = FALSE;
45 
46     HTUnEscape(string);
47     for (i = 0; string[i] != '\0'; i++) {
48 	/* FIXME: this is no longer explicitly 7-bit ASCII,
49 	   but are there portability problems? */
50 	if ((!LYIsASCII(string[i])) || !isprint(UCH(string[i]))) {
51 	    string[i] = '?';
52 	    flg = TRUE;
53 	}
54     }
55     if (flg)
56 	HTAlert(MAILTO_SQUASH_CTL);
57 }
58 
remove_tildes(char * string)59 static void remove_tildes(char *string)
60 {
61     /*
62      * Change the first character to a space if it is a '~'.
63      */
64     if (*string == '~')
65 	*string = ' ';
66 }
67 
comma_append(char ** dst,char * src)68 static void comma_append(char **dst,
69 			 char *src)
70 {
71     if (*src) {
72 	while (*src == ',' || isspace(UCH(*src)))
73 	    src++;
74 	if (*src) {
75 	    if (isEmpty(*dst)) {
76 		StrAllocCopy(*dst, src);
77 	    } else {
78 		StrAllocCat(*dst, ",");
79 		StrAllocCat(*dst, src);
80 	    }
81 	}
82     }
83 }
84 
extract_field(char ** dst,char * src,const char * keyword)85 static void extract_field(char **dst,
86 			  char *src,
87 			  const char *keyword)
88 {
89     int len = (int) strlen(keyword);
90     char *cp, *cp1;
91 
92     cp = (src + 1);
93     while (*cp != '\0') {
94 	if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
95 	    !strncasecomp(cp, keyword, len)) {
96 	    cp += len;
97 	    if ((cp1 = StrChr(cp, '&')) != NULL) {
98 		*cp1 = '\0';
99 	    }
100 	    comma_append(dst, cp);
101 	    if (cp1) {
102 		*cp1 = '&';
103 		cp = cp1;
104 		cp1 = NULL;
105 	    } else {
106 		break;
107 	    }
108 	}
109 	cp++;
110     }
111     CTRACE((tfp, "extract_field(%s) = '%s'\n", keyword, *dst));
112 }
113 
114 /*
115  * Seek and handle a subject=foo.  - FM
116  */
extract_subject(char * dst,char * src)117 static void extract_subject(char *dst,
118 			    char *src)
119 {
120     const char *keyword = "subject=";
121     int len = (int) strlen(keyword);
122     char *cp, *cp1;
123 
124     cp = (src + 1);
125     while (*cp != '\0') {
126 	if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
127 	    !strncasecomp(cp, keyword, len))
128 	    break;
129 	cp++;
130     }
131     if (*cp) {
132 	cp += len;
133 	if ((cp1 = StrChr(cp, '&')) != NULL) {
134 	    *cp1 = '\0';
135 	}
136 	if (*cp) {
137 	    LYStrNCpy(dst, cp, MAX_SUBJECT);
138 	    SafeHTUnEscape(dst);
139 	}
140 	if (cp1) {
141 	    *cp1 = '&';
142 	    cp1 = NULL;
143 	}
144     }
145     CTRACE((tfp, "extract_subject(%s) = '%s'\n", keyword, NONNULL(dst)));
146 }
147 
148 /*
149  * Seek and handle body=foo fields.  - FM
150  */
extract_body(char ** dst,char * src)151 static void extract_body(char **dst,
152 			 char *src)
153 {
154     const char *keyword = "body=";
155     int len = (int) strlen(keyword);
156     int i;
157     char *cp, *cp0, *cp1, *temp = 0;
158 
159     cp = (src + 1);
160     while (*cp != '\0') {
161 	if ((*(cp - 1) == '?' || *(cp - 1) == '&') &&
162 	    !strncasecomp(cp, keyword, len)) {
163 	    cp += len;
164 	    if ((cp1 = StrChr(cp, '&')) != NULL) {
165 		*cp1 = '\0';
166 	    }
167 	    if (*cp) {
168 		/*
169 		 * Break up the value into lines with a maximum length of 78.
170 		 * - FM
171 		 */
172 		StrAllocCopy(temp, cp);
173 		HTUnEscape(temp);
174 		cp0 = temp;
175 		while ((cp = StrChr(cp0, '\n')) != NULL) {
176 		    *cp = '\0';
177 		    if (cp > cp0) {
178 			if (*(cp - 1) == '\r') {
179 			    *(cp - 1) = '\0';
180 			}
181 		    }
182 		    i = 0;
183 		    len = (int) strlen(cp0);
184 		    while (len > 78) {
185 			HTSprintf(dst, "%.78s\n", &cp0[i]);
186 			i += 78;
187 			len = (int) strlen(&cp0[i]);
188 		    }
189 		    HTSprintf(dst, "%s\n", &cp0[i]);
190 		    cp0 = (cp + 1);
191 		}
192 		i = 0;
193 		len = (int) strlen(cp0);
194 		while (len > 78) {
195 		    HTSprintf(dst, "%.78s\n", &cp0[i]);
196 		    i += 78;
197 		    len = (int) strlen(&cp0[i]);
198 		}
199 		if (len) {
200 		    HTSprintf(dst, "%s\n", &cp0[i]);
201 		}
202 		FREE(temp);
203 	    }
204 	    if (cp1) {
205 		*cp1 = '&';
206 		cp = cp1;
207 		cp1 = NULL;
208 	    } else {
209 		break;
210 	    }
211 	}
212 	cp++;
213     }
214     CTRACE((tfp, "extract_body(%s) = '%s'\n", keyword, NONNULL(*dst)));
215 }
216 
217 /*
218  * Convert any Explorer semi-colon Internet address separators to commas - FM
219  */
trim_comma(char * address)220 static BOOLEAN trim_comma(char *address)
221 {
222     if (address[(strlen(address) - 1)] == ',')
223 	address[(strlen(address) - 1)] = '\0';
224     return (BOOL) (*address == '\0');
225 }
226 
227 /*
228  * Convert any Explorer semi-colon Internet address separators to commas - FM
229  */
convert_explorer(char * address)230 static BOOLEAN convert_explorer(char *address)
231 {
232     char *cp = address;
233     char *cp0;
234     char *cp1;
235 
236     while ((cp1 = StrChr(cp, '@')) != NULL) {
237 	cp1++;
238 	if ((cp0 = StrChr(cp1, ';')) != NULL) {
239 	    *cp0 = ',';
240 	    cp1 = cp0 + 1;
241 	}
242 	cp = cp1;
243     }
244     return trim_comma(address);
245 }
246 
247 /*
248  * reply_by_mail() prompts line-by-line for header information, allowing
249  * scrolling of the screen.
250  */
header_prompt(const char * label,char ** result,unsigned limit)251 static int header_prompt(const char *label,
252 			 char **result,
253 			 unsigned limit)
254 {
255     char buffer[LINESIZE];
256     int ok;
257 
258     if (*result != 0) {
259 	LYaddstr(CTRL_U_TO_ERASE);
260 	LYStrNCpy(buffer, *result, sizeof(buffer) - 1);
261     } else
262 	*buffer = 0;
263 
264     if (limit > sizeof(buffer))
265 	limit = sizeof(buffer);
266 
267     LYaddstr(gettext(label));
268     LYaddstr(": ");
269     ok = (LYGetStr(buffer, FALSE, limit, NORECALL) >= 0
270 	  && !term_letter);
271     LYaddstr("\n");
272 
273     if (ok) {
274 	remove_tildes(buffer);
275 	StrAllocCopy(*result, buffer);
276     }
277     term_letter = FALSE;
278     return ok;
279 }
280 
show_addresses(char * addresses)281 static void show_addresses(char *addresses)
282 {
283     char *cp = addresses;
284     char *cp1;
285 
286     while ((cp1 = StrChr(cp, ',')) != NULL) {
287 	*cp1 = '\0';
288 	while (*cp == ' ')
289 	    cp++;
290 	if (*cp) {
291 	    LYaddstr(cp);
292 	    LYaddstr(",\n  ");
293 	}
294 	*cp1 = ',';
295 	cp = (cp1 + 1);
296     }
297     if (*cp) {
298 	LYaddstr(cp);
299     }
300 }
301 
302 #if USE_BLAT_MAILER
303 
304 /*
305  * blat's options-file parser (see makeargv.cpp) treats backslash and double
306  * quote characters specially.  lynx doesn't.  Do a conversion as we write the
307  * option.
308  *
309  * Other quirks (reading blat 3.06):
310  * + Whitespace not in quotes terminates a line.
311  * + Blat allows a comment-character to terminate a line.  By default, that
312  *   is a semicolon.
313  *
314  * Given that, the simplest thing to do is to always quote the string, using
315  * escaping to handle special cases.
316  */
blat_option(FILE * fp,const char * option,const char * value)317 static void blat_option(FILE *fp, const char *option, const char *value)
318 {
319     if (non_empty(value)) {
320 	char *result = malloc(strlen(option) + 4 + 4 * strlen(value));
321 	char *working = result;
322 
323 	CTRACE((tfp, "blat_option(opt=\"%s\", value=\"%s\")\n", option, value));
324 	sprintf(working, "%s \"", option);
325 	working += strlen(working);
326 
327 	while (*value != '\0') {
328 	    unsigned ch = UCH(*value);
329 
330 	    switch (ch) {
331 	    case '\\':
332 		*working++ = '\\';
333 		*working++ = '\\';
334 		break;
335 	    case '"':
336 		*working++ = '\\';
337 		*working++ = '"';
338 		break;
339 	    default:
340 		if (ch < ' ' || ch > '~') {
341 		    sprintf(working, "\\%03o", ch);
342 		} else {
343 		    *working++ = ch;
344 		}
345 		break;
346 	    }
347 	    ++value;
348 	}
349 	*working++ = '"';
350 	*working++ = '\n';
351 	*working = 0;
352 
353 	CTRACE((tfp, "->%s", result));
354 	fputs(result, fp);
355 	FREE(result);
356     }
357 }
358 
359 /*
360 syntax for blat 2.6.2:
361 Blat <filename> -t <recipient> [optional switches (see below)]
362 
363 -bodyF <filename> : file with the message body
364 -t <recipient>    : recipient list (comma separated)
365 -s <subj>         : subject line
366 -f <sender>       : overrides the default sender address (must be known to server)
367 -i <addr>         : a 'From:' address, not necessarily known to the SMTP server.
368 -c <recipient>    : carbon copy recipient list (comma separated)
369 -b <recipient>    : blind carbon copy recipient list (comma separated)
370 -help             : displays the help message.
371 -mime             : MIME Quoted-Printable Content-Transfer-Encoding.
372 -q                : suppresses *all* output.
373 -server <addr>    : overrides the default SMTP server to be used.
374 
375 */
376 
blat_cmd(char * filename,char * address,char * subject,char * ccaddr,char * mail_addr)377 static char *blat_cmd(char *filename,
378 		      char *address,
379 		      char *subject,
380 		      char *ccaddr,
381 		      char *mail_addr)
382 {
383     char *b_cmd = NULL;
384 
385     if (mail_is_altblat) {
386 	const char *format = "%s %s -t %s -s %s %s%s%s";
387 
388 	HTAddParam(&b_cmd, format, 1, ALTBLAT_MAIL);
389 	HTAddParam(&b_cmd, format, 2, filename);
390 	HTAddParam(&b_cmd, format, 3, address);
391 	HTAddParam(&b_cmd, format, 4, subject);
392 	HTAddToCmd(&b_cmd, format, 5, ALTBLAT_MAIL_FLAGS);
393 	if (non_empty(ccaddr)) {
394 	    HTAddToCmd(&b_cmd, format, 6, " -c ");
395 	    HTAddParam(&b_cmd, format, 7, NonNull(ccaddr));
396 	}
397 	HTEndParam(&b_cmd, format, 8);
398 
399     } else {
400 
401 	const char *format = "%s -of %s";
402 	char bl_cmd_file[LY_MAXPATH];
403 	FILE *fp;
404 
405 #ifdef __CYGWIN__
406 	char dosname[LY_MAXPATH];
407 
408 #else
409 	char *dosname;
410 #endif
411 
412 	bl_cmd_file[0] = '\0';
413 	if ((fp = LYOpenTemp(bl_cmd_file, ".blt", "w")) == NULL) {
414 	    HTAlert(FORM_MAILTO_FAILED);
415 	    return NULL;
416 	}
417 
418 	HTAddParam(&b_cmd, format, 1, BLAT_MAIL);
419 
420 	ConvertToWin32Path(filename, dosname);
421 	blat_option(fp, "-bodyF", dosname);
422 	blat_option(fp, "-t", address);
423 	blat_option(fp, "-s", subject);
424 	blat_option(fp, "-f", mail_addr);
425 	blat_option(fp, "-c", ccaddr);
426 	LYCloseOutput(fp);
427 
428 	ConvertToWin32Path(bl_cmd_file, dosname);
429 
430 	HTAddParam(&b_cmd, format, 2, dosname);
431 	HTEndParam(&b_cmd, format, 3);
432 
433     }
434 
435     return b_cmd;
436 }
437 
438 #endif /* USE_BLAT_MAILER */
439 
440 #if USE_VMS_MAILER
LYMailPMDF(void)441 BOOLEAN LYMailPMDF(void)
442 {
443     return (system_mail != 0)
444 	? !strncasecomp(system_mail, "PMDF SEND", 9)
445 	: FALSE;
446 }
447 
448 /*
449  * Add all of the people in the address field to the command
450  */
vms_append_addrs(char ** cmd,char * address,char * option)451 static void vms_append_addrs(char **cmd, char *address, char *option)
452 {
453     BOOLEAN first = TRUE;
454     char *cp;
455     char *address_ptr1;
456     char *address_ptr2;
457 
458     address_ptr1 = address;
459     do {
460 	if ((cp = StrChr(address_ptr1, ',')) != NULL) {
461 	    address_ptr2 = (cp + 1);
462 	    *cp = '\0';
463 	} else {
464 	    address_ptr2 = NULL;
465 	}
466 
467 	/*
468 	 * 4 letters is arbitrarily the smallest possible mail address, at
469 	 * least for lynx.  That way extra spaces won't confuse the mailer and
470 	 * give a blank address.
471 	 */
472 	if (strlen(address_ptr1) > 3) {
473 	    if (!first) {
474 		StrAllocCat(*cmd, ",");
475 	    }
476 	    HTSprintf(cmd, mail_adrs, address_ptr1);
477 	    if (*option && LYMailPMDF())
478 		StrAllocCat(*cmd, option);
479 	    first = FALSE;
480 	}
481 	address_ptr1 = address_ptr2;
482     } while (address_ptr1 != NULL);
483 }
484 
remove_quotes(char * string)485 static void remove_quotes(char *string)
486 {
487     while (*string != 0) {
488 	if (StrChr("\"&|", *string) != 0)
489 	    *string = ' ';
490 	string++;
491     }
492 }
493 #else
494 #if CAN_PIPE_TO_MAILER
495 
496 /*
497  * Open a pipe to the mailer
498  */
LYPipeToMailer(void)499 FILE *LYPipeToMailer(void)
500 {
501     char *buffer = NULL;
502     FILE *fp = NULL;
503 
504     if (LYSystemMail()) {
505 	HTSprintf0(&buffer, "%s %s", system_mail, system_mail_flags);
506 	fp = popen(buffer, "w");
507 	CTRACE((tfp, "popen(%s) %s\n", buffer, fp != 0 ? "OK" : "FAIL"));
508 	FREE(buffer);
509     }
510     return fp;
511 }
512 #else /* DOS, Win32, etc. */
513 
LYSendMailFile(char * the_address,char * the_filename,char * the_subject GCC_UNUSED,char * the_ccaddr GCC_UNUSED,char * message)514 int LYSendMailFile(char *the_address,
515 		   char *the_filename,
516 		   char *the_subject GCC_UNUSED,
517 		   char *the_ccaddr GCC_UNUSED,
518 		   char *message)
519 {
520     char *cmd = NULL;
521     int code;
522 
523     if (!LYSystemMail())
524 	return 0;
525 
526 #if USE_BLAT_MAILER
527     if (mail_is_blat) {
528 	cmd = blat_cmd(the_filename,
529 		       the_address,
530 		       the_subject,
531 		       the_ccaddr,
532 		       personal_mail_address);
533     } else
534 #endif
535 #ifdef __DJGPP__
536     if (LYGetEnv("SHELL")) {
537 	extern char *shell;
538 	const char *c_option;
539 	const char *format = "%s %s %s -t %s -F %s";
540 
541 	if (dj_is_bash) {
542 	    c_option = "-c";
543 	} else {
544 	    c_option = "/c";
545 	}
546 	HTAddParam(&cmd, format, 1, shell);
547 	HTAddParam(&cmd, format, 2, c_option);
548 	HTAddParam(&cmd, format, 3, system_mail);
549 	HTAddParam(&cmd, format, 4, the_address);
550 	HTAddParam(&cmd, format, 5, the_filename);
551 	HTEndParam(&cmd, format, 6);
552     } else
553 #endif /* __DJGPP__ */
554     {
555 	const char *format = "%s -t %s -F %s";
556 
557 	HTAddParam(&cmd, format, 1, system_mail);
558 	HTAddParam(&cmd, format, 2, the_address);
559 	HTAddParam(&cmd, format, 3, the_filename);
560 	HTEndParam(&cmd, format, 4);
561     }
562 
563     stop_curses();
564     SetOutputMode(O_TEXT);
565     printf("%s\n\n$ %s\n\n%s",
566 	   *message ? message : gettext("Sending"),
567 	   cmd, PLEASE_WAIT);
568     code = LYSystem(cmd);
569     LYSleepMsg();
570     start_curses();
571     SetOutputMode(O_BINARY);
572 
573     FREE(cmd);
574 
575     return code;
576 }
577 #endif /* CAN_PIPE_TO_FILE */
578 #endif /* USE_VMS_MAILER */
579 
580 /*
581  *  mailform() sends form content to the mailto address(es). - FM
582  */
mailform(const char * mailto_address,const char * mailto_subject,const char * mailto_content,const char * mailto_type)583 void mailform(const char *mailto_address,
584 	      const char *mailto_subject,
585 	      const char *mailto_content,
586 	      const char *mailto_type)
587 {
588     FILE *fd;
589     char *address = NULL;
590     char *ccaddr = NULL;
591     char *keywords = NULL;
592     char *cp = NULL;
593     char self[MAX_SUBJECT + 10];
594     char subject[MAX_SUBJECT + 10];
595     char *searchpart = NULL;
596     char buf[512];
597     int len, i;
598 
599 #if USE_VMS_MAILER
600     static char *cmd;
601     char *command = NULL;
602     BOOLEAN isPMDF = LYMailPMDF();
603     char hdrfile[LY_MAXPATH];
604 #endif
605 #if !CAN_PIPE_TO_MAILER
606     char my_tmpfile[LY_MAXPATH];
607 #endif
608 
609     CTRACE((tfp, "mailto_address: \"%s\"\n", NONNULL(mailto_address)));
610     CTRACE((tfp, "mailto_subject: \"%s\"\n", NONNULL(mailto_subject)));
611     CTRACE((tfp, "mailto_content: \"%s\"\n", NONNULL(mailto_content)));
612     CTRACE((tfp, "mailto_type:    \"%s\"\n", NONNULL(mailto_type)));
613 
614     if (!LYSystemMail())
615 	return;
616 
617     if (!mailto_address || !mailto_content) {
618 	HTAlert(BAD_FORM_MAILTO);
619 	return;
620     }
621     subject[0] = '\0';
622     self[0] = '\0';
623 
624     if ((cp = StrChr(mailto_address, '\n')) != NULL)
625 	*cp = '\0';
626     StrAllocCopy(address, mailto_address);
627 
628     /*
629      * Check for a ?searchpart.  - FM
630      */
631     if ((cp = StrChr(address, '?')) != NULL) {
632 	StrAllocCopy(searchpart, cp);
633 	*cp = '\0';
634 	cp = (searchpart + 1);
635 	if (*cp != '\0') {
636 	    /*
637 	     * Seek and handle a subject=foo.  - FM
638 	     */
639 	    extract_subject(subject, searchpart);
640 
641 	    /*
642 	     * Seek and handle to=address(es) fields.  Appends to address.  -
643 	     * FM
644 	     */
645 	    extract_field(&address, searchpart, "to=");
646 
647 	    /*
648 	     * Seek and handle cc=address(es) fields.  Excludes Bcc=address(es)
649 	     * as unsafe.  We may append our own cc (below) as a list for the
650 	     * actual mailing.  - FM
651 	     */
652 	    extract_field(&ccaddr, searchpart, "cc=");
653 
654 	    /*
655 	     * Seek and handle keywords=term(s) fields.  - FM
656 	     */
657 	    extract_field(&keywords, searchpart, "keywords=");
658 
659 	    if (keywords != NULL) {
660 		if (*keywords != '\0') {
661 		    SafeHTUnEscape(keywords);
662 		} else {
663 		    FREE(keywords);
664 		}
665 	    }
666 
667 	    FREE(searchpart);
668 	}
669     }
670 
671     if (convert_explorer(address)) {
672 	HTAlert(BAD_FORM_MAILTO);
673 	goto cleanup;
674     }
675     if (ccaddr != NULL) {
676 	if (convert_explorer(ccaddr)) {
677 	    FREE(ccaddr);
678 	}
679     }
680 
681     /*
682      * Unescape the address and ccaddr fields.  - FM
683      */
684     SafeHTUnEscape(address);
685     if (ccaddr != NULL) {
686 	SafeHTUnEscape(ccaddr);
687     }
688 
689     /*
690      * Allow user to edit the default Subject - FM
691      */
692     if (subject[0] == '\0') {
693 	if (non_empty(mailto_subject)) {
694 	    LYStrNCpy(subject, mailto_subject, MAX_SUBJECT);
695 	} else {
696 	    sprintf(subject, "mailto:%.63s", address);
697 	}
698     }
699     _statusline(SUBJECT_PROMPT);
700     if (LYGetStr(subject, FALSE, MAX_SUBJECT, NORECALL) < 0) {
701 	/*
702 	 * User cancelled via ^G. - FM
703 	 */
704 	HTInfoMsg(FORM_MAILTO_CANCELLED);
705 	goto cleanup;
706     }
707 
708     /*
709      * Allow user to specify a self copy via a CC:  entry, if permitted.  - FM
710      */
711     if (!LYNoCc) {
712 	sprintf(self, "%.*s", MAX_SUBJECT,
713 		isEmpty(personal_mail_address) ? "" : personal_mail_address);
714 	_statusline("Cc: ");
715 	if (LYGetStr(self, FALSE, MAX_SUBJECT, NORECALL) < 0) {
716 	    /*
717 	     * User cancelled via ^G. - FM
718 	     */
719 	    HTInfoMsg(FORM_MAILTO_CANCELLED);
720 	    goto cleanup;
721 	}
722 	remove_tildes(self);
723 	if (ccaddr == NULL) {
724 	    StrAllocCopy(ccaddr, self);
725 	} else {
726 	    StrAllocCat(ccaddr, ",");
727 	    StrAllocCat(ccaddr, self);
728 	}
729     }
730 #if CAN_PIPE_TO_MAILER
731     if ((fd = LYPipeToMailer()) == 0) {
732 	HTAlert(FORM_MAILTO_FAILED);
733 	goto cleanup;
734     }
735 
736     if (non_empty(mailto_type)) {
737 	fprintf(fd, "Mime-Version: 1.0\n");
738 	fprintf(fd, "Content-Type: %s\n", mailto_type);
739     }
740     fprintf(fd, "To: %s\n", address);
741     if (non_empty(personal_mail_address))
742 	fprintf(fd, "From: %s\n", personal_mail_address);
743     if (non_empty(ccaddr))
744 	fprintf(fd, "Cc: %s\n", ccaddr);
745     fprintf(fd, "Subject: %s\n\n", subject);
746     if (non_empty(keywords))
747 	fprintf(fd, "Keywords: %s\n", keywords);
748     _statusline(SENDING_FORM_CONTENT);
749 #else /* e.g., VMS, DOS */
750     if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) {
751 	HTAlert(FORM_MAILTO_FAILED);
752 	goto cleanup;
753     }
754 #if USE_VMS_MAILER
755     if (isPMDF) {
756 	FILE *hfd;
757 
758 	if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) {
759 	    HTAlert(FORM_MAILTO_FAILED);
760 	    LYCloseTempFP(fd);
761 	    goto cleanup;
762 	}
763 	if (non_empty(mailto_type)) {
764 	    fprintf(hfd, "Mime-Version: 1.0\n");
765 	    fprintf(hfd, "Content-Type: %s\n", mailto_type);
766 	    if (non_empty(personal_mail_address))
767 		fprintf(hfd, "From: %s\n", personal_mail_address);
768 	}
769 	/*
770 	 * For PMDF, put any keywords and the subject in the header file and
771 	 * close it.  - FM
772 	 */
773 	if (non_empty(keywords)) {
774 	    fprintf(hfd, "Keywords: %s\n", keywords);
775 	}
776 	fprintf(hfd, "Subject: %s\n\n", subject);
777 	LYCloseTempFP(hfd);
778     } else if (mailto_type &&
779 	       !strncasecomp(mailto_type, "multipart/form-data", 19)) {
780 	/*
781 	 * Ugh!  There's no good way to include headers while we're still using
782 	 * "generic" VMS MAIL, so we'll put this in the body of the message.  -
783 	 * FM
784 	 */
785 	fprintf(fd, "X-Content-Type: %s\n\n", mailto_type);
786     }
787 #else /* !VMS (DOS) */
788 #if USE_BLAT_MAILER
789     if (mail_is_blat) {
790 	if (strlen(subject) > MAX_SUBJECT)
791 	    subject[MAX_SUBJECT] = '\0';
792     } else
793 #endif
794     {
795 	if (non_empty(mailto_type)) {
796 	    fprintf(fd, "Mime-Version: 1.0\n");
797 	    fprintf(fd, "Content-Type: %s\n", mailto_type);
798 	}
799 	fprintf(fd, "To: %s\n", address);
800 	if (non_empty(personal_mail_address))
801 	    fprintf(fd, "From: %s\n", personal_mail_address);
802 	fprintf(fd, "Subject: %.70s\n\n", subject);
803     }
804 #endif /* VMS */
805 #endif /* CAN_PIPE_TO_MAILER */
806 
807     /*
808      * Break up the content into lines with a maximum length of 78.  If the
809      * ENCTYPE was text/plain, we have physical newlines and should take them
810      * into account.  Otherwise, the actual newline characters in the content
811      * are hex escaped.  - FM
812      */
813     while ((cp = StrChr(mailto_content, '\n')) != NULL) {
814 	*cp = '\0';
815 	i = 0;
816 	len = (int) strlen(mailto_content);
817 	while (len > 78) {
818 	    LYStrNCpy(buf, &mailto_content[i], 78);
819 	    fprintf(fd, "%s\n", buf);
820 	    i += 78;
821 	    len = (int) strlen(&mailto_content[i]);
822 	}
823 	fprintf(fd, "%s\n", &mailto_content[i]);
824 	mailto_content = (cp + 1);
825     }
826     i = 0;
827     len = (int) strlen(mailto_content);
828     while (len > 78) {
829 	LYStrNCpy(buf, &mailto_content[i], 78);
830 	fprintf(fd, "%s\n", buf);
831 	i += 78;
832 	len = (int) strlen(&mailto_content[i]);
833     }
834     if (len)
835 	fprintf(fd, "%s\n", &mailto_content[i]);
836 
837 #if CAN_PIPE_TO_MAILER
838     pclose(fd);
839     LYSleepMsg();
840 #else
841     LYCloseTempFP(fd);
842 #if USE_VMS_MAILER
843     /*
844      * Set the mail command.  - FM
845      */
846     if (isPMDF) {
847 	/*
848 	 * Now set up the command.  - FM
849 	 */
850 	HTSprintf0(&cmd,
851 		   "%s %s %s,%s ",
852 		   system_mail,
853 		   system_mail_flags,
854 		   hdrfile,
855 		   my_tmpfile);
856     } else {
857 	/*
858 	 * For "generic" VMS MAIL, include the subject in the command, and
859 	 * ignore any keywords to minimize risk of them making the line too
860 	 * long or having problem characters.  - FM
861 	 */
862 	HTSprintf0(&cmd,
863 		   "%s %s%s/subject=\"%s\" %s ",
864 		   system_mail,
865 		   system_mail_flags,
866 		   (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
867 		   subject,
868 		   my_tmpfile);
869     }
870     StrAllocCopy(command, cmd);
871 
872     vms_append_addrs(&command, address, "");
873     if (non_empty(ccaddr)) {
874 	vms_append_addrs(&command, ccaddr, "/CC");
875     }
876 
877     stop_curses();
878     printf("%s\n\n$ %s\n\n%s", SENDING_FORM_CONTENT, command, PLEASE_WAIT);
879     LYSystem(command);		/* Mail (VMS) */
880     FREE(command);
881     LYSleepAlert();
882     start_curses();
883     (void) LYRemoveTemp(my_tmpfile);
884     if (isPMDF)
885 	(void) LYRemoveTemp(hdrfile);
886 #else /* DOS */
887     LYSendMailFile(address,
888 		   my_tmpfile,
889 		   subject,
890 		   ccaddr,
891 		   SENDING_FORM_CONTENT);
892     (void) LYRemoveTemp(my_tmpfile);
893 #endif /* USE_VMS_MAILER */
894 #endif /* CAN_PIPE_TO_MAILER */
895 
896   cleanup:
897     FREE(address);
898     FREE(ccaddr);
899     FREE(keywords);
900     return;
901 }
902 
903 /*
904  *  mailmsg() sends a message to the owner of the file, if one is defined,
905  *  telling of errors (i.e., link not available).
906  */
mailmsg(int cur,char * owner_address,char * filename,char * linkname)907 void mailmsg(int cur,
908 	     char *owner_address,
909 	     char *filename,
910 	     char *linkname)
911 {
912     FILE *fd, *fp;
913     char *address = NULL;
914     char *searchpart = NULL;
915     char *cmd = NULL, *cp;
916 
917 #ifdef ALERTMAIL
918     BOOLEAN skip_parsing = FALSE;
919 #endif
920 #if !CAN_PIPE_TO_MAILER
921     char *ccaddr;
922     char subject[128];
923     char my_tmpfile[LY_MAXPATH];
924 #endif
925 #if USE_VMS_MAILER
926     BOOLEAN isPMDF = LYMailPMDF();
927     char hdrfile[LY_MAXPATH];
928     char *command = NULL;
929 
930     CTRACE((tfp, "mailmsg(%d, \"%s\", \"%s\", \"%s\")\n", cur,
931 	    NONNULL(owner_address),
932 	    NONNULL(filename),
933 	    NONNULL(linkname)));
934 
935 #endif /* VMS */
936 
937     if (!LYSystemMail())
938 	return;
939 
940 #ifdef ALERTMAIL
941     if (owner_address == NULL) {
942 	owner_address = ALERTMAIL;
943 	skip_parsing = TRUE;
944     }
945 #endif
946 
947     if (isEmpty(owner_address))
948 	return;
949     if ((cp = StrChr(owner_address, '\n')) != NULL) {
950 #ifdef ALERTMAIL
951 	if (skip_parsing)
952 	    return;		/* invalidly defined - ignore - kw */
953 #else
954 	*cp = '\0';
955 #endif
956     }
957     if (!strncasecomp(owner_address, "lynx-dev@", 9)) {
958 	/*
959 	 * Silently refuse sending bad link messages to lynx-dev.
960 	 */
961 	return;
962     }
963     StrAllocCopy(address, owner_address);
964 
965 #ifdef ALERTMAIL
966     /*
967      * If we are using a fixed address given by ALERTMAIL, it is supposed to
968      * already be in usable form, without URL-isms like ?-searchpart and
969      * URL-escaping.  So skip some code.  - kw
970      */
971     if (!skip_parsing)
972 #endif
973     {
974 	/*
975 	 * Check for a ?searchpart.  - FM
976 	 */
977 	if ((cp = StrChr(address, '?')) != NULL) {
978 	    StrAllocCopy(searchpart, cp);
979 	    *cp = '\0';
980 	    cp = (searchpart + 1);
981 	    if (*cp != '\0') {
982 		/*
983 		 * Seek and handle to=address(es) fields.
984 		 * Appends to address.  We ignore any other
985 		 * headers in the ?searchpart.  - FM
986 		 */
987 		extract_field(&address, searchpart, "to=");
988 	    }
989 	}
990 
991 	(void) convert_explorer(address);
992 
993 	/*
994 	 * Unescape the address field.  - FM
995 	 */
996 	SafeHTUnEscape(address);
997     }
998 
999     if (trim_comma(address)) {
1000 	FREE(address);
1001 	CTRACE((tfp, "mailmsg: No address in '%s'.\n", owner_address));
1002 	return;
1003     }
1004 #if CAN_PIPE_TO_MAILER
1005     if ((fd = LYPipeToMailer()) == 0) {
1006 	FREE(address);
1007 	CTRACE((tfp, "mailmsg: '%s' failed.\n", cmd));
1008 	return;
1009     }
1010 
1011     fprintf(fd, "To: %s\n", address);
1012     fprintf(fd, "Subject: Lynx Error in %s\n", filename);
1013     if (non_empty(personal_mail_address)) {
1014 	fprintf(fd, "Cc: %s\n", personal_mail_address);
1015     }
1016     fprintf(fd, "X-URL: %s\n", filename);
1017     fprintf(fd, "X-Mailer: %s, Version %s\n\n", LYNX_NAME, LYNX_VERSION);
1018 #else
1019     if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) {
1020 	CTRACE((tfp, "mailmsg: Could not fopen '%s'.\n", my_tmpfile));
1021 	FREE(address);
1022 	return;
1023     }
1024     sprintf(subject, "Lynx Error in %.56s", filename);
1025     ccaddr = personal_mail_address;
1026 #if USE_VMS_MAILER
1027     if (isPMDF) {
1028 	FILE *hfd;
1029 
1030 	if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) {
1031 	    CTRACE((tfp, "mailmsg: Could not fopen '%s'.\n", hdrfile));
1032 	    FREE(address);
1033 	    return;
1034 	}
1035 
1036 	if (non_empty(personal_mail_address)) {
1037 	    fprintf(fd, "Cc: %s\n", personal_mail_address);
1038 	}
1039 	fprintf(fd, "X-URL: %s\n", filename);
1040 	fprintf(fd, "X-Mailer: %s, Version %s\n\n", LYNX_NAME, LYNX_VERSION);
1041 	/*
1042 	 * For PMDF, put the subject in the header file and close it.  - FM
1043 	 */
1044 	fprintf(hfd, "Subject: Lynx Error in %.56s\n\n", filename);
1045 	LYCloseTempFP(hfd);
1046     }
1047 #endif /* USE_VMS_MAILER */
1048 #endif /* CAN_PIPE_TO_MAILER */
1049 
1050     fprintf(fd, gettext("The link   %s :?: %s \n"),
1051 	    links[cur].lname, links[cur].target);
1052     fprintf(fd, gettext("called \"%s\"\n"), LYGetHiliteStr(cur, 0));
1053     fprintf(fd, gettext("in the file \"%s\" called \"%s\"\n"), filename, linkname);
1054     fprintf(fd, "%s\n\n", gettext("was requested but was not available."));
1055     fprintf(fd, "%s\n\n", gettext("Thought you might want to know."));
1056 
1057     fprintf(fd, "%s\n", gettext("This message was automatically generated by"));
1058     fprintf(fd, "%s %s", LYNX_NAME, LYNX_VERSION);
1059     if ((LynxSigFile != NULL) &&
1060 	(fp = fopen(LynxSigFile, TXT_R)) != NULL) {
1061 	fputs("-- \n", fd);
1062 	while (LYSafeGets(&cmd, fp) != NULL)
1063 	    fputs(cmd, fd);
1064 	LYCloseInput(fp);
1065     }
1066 #if CAN_PIPE_TO_MAILER
1067     pclose(fd);
1068 #else
1069     LYCloseTempFP(fd);
1070 #if USE_VMS_MAILER
1071     if (isPMDF) {
1072 	/*
1073 	 * Now set up the command.  - FM
1074 	 */
1075 	HTSprintf0(&command,
1076 		   "%s %s %s,%s ",
1077 		   system_mail,
1078 		   system_mail_flags,
1079 		   hdrfile,
1080 		   my_tmpfile);
1081     } else {
1082 	/*
1083 	 * For "generic" VMS MAIL, include the subject in the command.  - FM
1084 	 */
1085 	HTSprintf0(&command,
1086 		   "%s %s/self/subject=\"Lynx Error in %.56s\" %s ",
1087 		   system_mail,
1088 		   system_mail_flags,
1089 		   filename,
1090 		   my_tmpfile);
1091     }
1092     vms_append_addrs(&command, address, "");
1093 
1094     LYSystem(command);		/* VMS */
1095     FREE(command);
1096     FREE(cmd);
1097     (void) LYRemoveTemp(my_tmpfile);
1098     if (isPMDF) {
1099 	(void) LYRemoveTemp(hdrfile);
1100     }
1101 #else /* DOS */
1102     LYSendMailFile(address,
1103 		   my_tmpfile,
1104 		   subject,
1105 		   ccaddr,
1106 		   "");
1107     (void) LYRemoveTemp(my_tmpfile);
1108 #endif /* USE_VMS_MAILER */
1109 #endif /* CAN_PIPE_TO_MAILER */
1110 
1111     if (traversal) {
1112 	FILE *ofp;
1113 
1114 	if ((ofp = LYAppendToTxtFile(TRAVERSE_ERRORS)) == NULL) {
1115 	    if ((ofp = LYNewTxtFile(TRAVERSE_ERRORS)) == NULL) {
1116 		perror(NOOPEN_TRAV_ERR_FILE);
1117 		exit_immediately(EXIT_FAILURE);
1118 	    }
1119 	}
1120 
1121 	fprintf(ofp, "%s\t%s \tin %s\n",
1122 		links[cur].lname, links[cur].target, filename);
1123 	LYCloseOutput(ofp);
1124     }
1125 
1126     FREE(address);
1127     return;
1128 }
1129 
1130 /*
1131  *  reply_by_mail() invokes sendmail on Unix or mail on VMS to send
1132  *  a comment from the users to the owner
1133  */
reply_by_mail(char * mail_address,char * filename,const char * title,const char * refid)1134 void reply_by_mail(char *mail_address,
1135 		   char *filename,
1136 		   const char *title,
1137 		   const char *refid)
1138 {
1139     char user_input[LINESIZE];
1140     FILE *fd, *fp;
1141     const char *label = NULL;
1142     char *from_address = NULL;
1143     char *cc_address = NULL;
1144     char *to_address = NULL;
1145     char *the_subject = NULL;
1146     char *ccaddr = NULL;
1147     char *keywords = NULL;
1148     char *searchpart = NULL;
1149     char *body = NULL;
1150     char *cp = NULL, *cp1 = NULL;
1151     int i;
1152     int c = 0;			/* user input */
1153     char my_tmpfile[LY_MAXPATH];
1154     char default_subject[MAX_SUBJECT + 10];
1155 
1156 #if USE_VMS_MAILER
1157     char *command = NULL;
1158     BOOLEAN isPMDF = LYMailPMDF();
1159     char hdrfile[LY_MAXPATH];
1160     FILE *hfd = 0;
1161 
1162 #else
1163 #if !CAN_PIPE_TO_MAILER
1164     char tmpfile2[LY_MAXPATH];
1165 #endif
1166     char buf[4096];		/* 512 */
1167     char *header = NULL;
1168     size_t nbytes;
1169 #endif /* USE_VMS_MAILER */
1170 
1171     CTRACE((tfp, "reply_by_mail(\"%s\", \"%s\", \"%s\", \"%s\")\n",
1172 	    NONNULL(mail_address),
1173 	    NONNULL(filename),
1174 	    NONNULL(title),
1175 	    NONNULL(refid)));
1176 
1177     term_letter = FALSE;
1178 
1179     if (!LYSystemMail())
1180 	return;
1181 
1182     if (isEmpty(mail_address)) {
1183 	HTAlert(NO_ADDRESS_IN_MAILTO_URL);
1184 	return;
1185     }
1186     StrAllocCopy(to_address, mail_address);
1187 
1188     if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) {
1189 	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
1190 	return;
1191     }
1192 #if USE_VMS_MAILER
1193     if (isPMDF) {
1194 	if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) {
1195 	    HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
1196 	    return;
1197 	}
1198     }
1199 #endif /* VMS */
1200     default_subject[0] = '\0';
1201 
1202     /*
1203      * Check for a ?searchpart.  - FM
1204      */
1205     if ((cp = StrChr(to_address, '?')) != NULL) {
1206 	StrAllocCopy(searchpart, cp);
1207 	*cp = '\0';
1208 	cp = (searchpart + 1);
1209 	if (*cp != '\0') {
1210 	    /*
1211 	     * Seek and handle a subject=foo.  - FM
1212 	     */
1213 	    extract_subject(default_subject, searchpart);
1214 
1215 	    /*
1216 	     * Seek and handle to=address(es) fields.  Appends to address.  -
1217 	     * FM
1218 	     */
1219 	    extract_field(&to_address, searchpart, "to=");
1220 
1221 	    /*
1222 	     * Seek and handle cc=address(es) fields.  Excludes Bcc=address(es)
1223 	     * as unsafe.  We may append our own cc (below) as a list for the
1224 	     * actual mailing.  - FM
1225 	     */
1226 	    extract_field(&ccaddr, searchpart, "cc=");
1227 
1228 	    /*
1229 	     * Seek and handle keywords=term(s) fields.  - FM
1230 	     */
1231 	    extract_field(&keywords, searchpart, "keywords=");
1232 
1233 	    if (keywords != NULL) {
1234 		if (*keywords != '\0') {
1235 		    SafeHTUnEscape(keywords);
1236 		} else {
1237 		    FREE(keywords);
1238 		}
1239 	    }
1240 
1241 	    /*
1242 	     * Seek and handle body=foo fields.  - FM
1243 	     */
1244 	    extract_body(&body, searchpart);
1245 
1246 	    FREE(searchpart);
1247 	}
1248     }
1249 
1250     if (convert_explorer(to_address)) {
1251 	HTAlert(NO_ADDRESS_IN_MAILTO_URL);
1252 	goto cancelled;
1253     }
1254     if (ccaddr != NULL) {
1255 	if (convert_explorer(ccaddr)) {
1256 	    FREE(ccaddr);
1257 	}
1258     }
1259 
1260     /*
1261      * Unescape the address and ccaddr fields.  - FM
1262      */
1263     SafeHTUnEscape(to_address);
1264     if (ccaddr != NULL) {
1265 	SafeHTUnEscape(ccaddr);
1266     }
1267 
1268     /*
1269      * Set the default subject.  - FM
1270      */
1271     if ((default_subject[0] == '\0') && non_empty(title)) {
1272 	LYStrNCpy(default_subject, title, MAX_SUBJECT);
1273     }
1274 
1275     /*
1276      * Use ^G to cancel mailing of comment and don't let SIGINTs exit lynx.
1277      */
1278     signal(SIGINT, terminate_letter);
1279 
1280 #if USE_VMS_MAILER
1281     if (isPMDF || !body) {
1282 	/*
1283 	 * Put the X-URL and X-Mailer lines in the hdrfile for PMDF or
1284 	 * my_tmpfile for VMS MAIL.  - FM
1285 	 */
1286 	fprintf((isPMDF ? hfd : fd),
1287 		"X-URL: %s%s\n",
1288 		isEmpty(filename) ? STR_MAILTO_URL : filename,
1289 		isEmpty(filename) ? to_address : "");
1290 	fprintf((isPMDF ? hfd : fd),
1291 		"X-Mailer: %s, Version %s\n", LYNX_NAME, LYNX_VERSION);
1292 #ifdef NO_ANONYMOUS_EMAIL
1293 	if (!isPMDF) {
1294 	    fprintf(fd, "\n");
1295 	}
1296 #endif /* NO_ANONYMOUS_EMAIL */
1297     }
1298 #else /* Unix/DOS/Windows */
1299     /*
1300      * Put the To:  line in the header.
1301      */
1302 #ifndef DOSPATH
1303     HTSprintf(&header, "To: %s\n", to_address);
1304 #endif
1305 
1306     /*
1307      * Put the Mime-Version, Content-Type and Content-Transfer-Encoding in the
1308      * header.  This assumes that the same character set is used for composing
1309      * the mail which is currently selected as display character set...  Don't
1310      * send a charset if we have a CJK character set selected, since it may not
1311      * be appropriate for mail...  Also don't use an unofficial "x-" charset.
1312      * Also if the charset would be "us-ascii" (7-bit replacements selected,
1313      * don't send any MIME headers.  - kw
1314      */
1315     if (strncasecomp(LYCharSet_UC[current_char_set].MIMEname,
1316 		     "us-ascii", 8) != 0) {
1317 	StrAllocCat(header, "Mime-Version: 1.0\n");
1318 	if (!LYHaveCJKCharacterSet &&
1319 	    strncasecomp(LYCharSet_UC[current_char_set].MIMEname, "x-", 2)
1320 	    != 0) {
1321 	    HTSprintf(&header, "Content-Type: " STR_PLAINTEXT "; charset=%s\n",
1322 		      LYCharSet_UC[current_char_set].MIMEname);
1323 	}
1324 	StrAllocCat(header, "Content-Transfer-Encoding: 8bit\n");
1325     }
1326     /*
1327      * Put the X-URL and X-Mailer lines in the header.
1328      */
1329     if (non_empty(filename)) {
1330 	HTSprintf(&header, "X-URL: %s\n", filename);
1331     } else {
1332 	HTSprintf(&header, "X-URL: mailto:%s\n", to_address);
1333     }
1334     HTSprintf(&header, "X-Mailer: %s, Version %s\n", LYNX_NAME, LYNX_VERSION);
1335 
1336     if (non_empty(refid)) {
1337 	HTSprintf(&header, "In-Reply-To: <%s>\n", refid);
1338     }
1339 #endif /* VMS */
1340 
1341     /*
1342      * Clear the screen and inform the user.
1343      */
1344     LYclear();
1345     LYmove(2, 0);
1346     scrollok(LYwin, TRUE);	/* Enable scrolling. */
1347     if (body)
1348 	LYaddstr(SENDING_MESSAGE_WITH_BODY_TO);
1349     else
1350 	LYaddstr(SENDING_COMMENT_TO);
1351     show_addresses(to_address);
1352     if (
1353 #if USE_VMS_MAILER
1354 	   (isPMDF == TRUE) &&
1355 #endif /* VMS */
1356 	   (cp = ccaddr) != NULL) {
1357 	if (StrChr(cp, ',') != NULL) {
1358 	    LYaddstr(WITH_COPIES_TO);
1359 	} else {
1360 	    LYaddstr(WITH_COPY_TO);
1361 	}
1362 	show_addresses(ccaddr);
1363     }
1364     LYaddstr(CTRL_G_TO_CANCEL_SEND);
1365 
1366 #if USE_VMS_MAILER
1367     if (isPMDF || !body) {
1368 #endif /* USE_VMS_MAILER */
1369 #ifndef NO_ANONYMOUS_EMAIL
1370 	/*
1371 	 * Get the user's personal name.
1372 	 */
1373 	LYaddstr(ENTER_NAME_OR_BLANK);
1374 #if USE_VMS_MAILER
1375 	if (isPMDF) {
1376 	    label = "Personal_name";
1377 	} else {
1378 	    label = "X-Personal_name";
1379 	}
1380 #else
1381 	label = "X-Personal_Name";
1382 #endif /* USE_VMS_MAILER */
1383 	if (!header_prompt(label, &personal_mail_name, LINESIZE)) {
1384 	    goto cancelled;
1385 	}
1386 	if (*personal_mail_name) {
1387 #if USE_VMS_MAILER
1388 	    fprintf((isPMDF ? hfd : fd), "%s: %s\n", label, personal_mail_name);
1389 #else
1390 	    HTSprintf(&header, "%s: %s\n", label, personal_mail_name);
1391 #endif /* VMS */
1392 	}
1393 
1394 	/*
1395 	 * Get the user's return address.
1396 	 */
1397 	LYaddstr(ENTER_MAIL_ADDRESS_OR_OTHER);
1398 	LYaddstr(MEANS_TO_CONTACT_FOR_RESPONSE);
1399 #if USE_VMS_MAILER
1400 	if (isPMDF) {
1401 	    label = "From";
1402 	} else {
1403 	    label = "X-From";
1404 	}
1405 #else
1406 	label = "From";
1407 #endif /* VMS */
1408 	/* Add the personal mail address if there is one. */
1409 	if (non_empty(personal_mail_address))
1410 	    StrAllocCopy(from_address, personal_mail_address);
1411 	if (!header_prompt(label, &from_address, LINESIZE)) {
1412 	    goto cancelled;
1413 	}
1414 #if USE_VMS_MAILER
1415 	if (*from_address) {
1416 	    fprintf(isPMDF ? hfd : fd, "%s: %s\n", label, from_address);
1417 	}
1418 	if (!isPMDF) {
1419 	    fprintf(fd, "\n");
1420 	}
1421 #else
1422 	HTSprintf(&header, "%s: %s\n", label, from_address);
1423 #endif /* USE_VMS_MAILER */
1424 #endif /* !NO_ANONYMOUS_EMAIL */
1425 #if USE_VMS_MAILER
1426     }
1427 #endif /* USE_VMS_MAILER */
1428 
1429     /*
1430      * Get the subject line.
1431      */
1432     LYaddstr(ENTER_SUBJECT_LINE);
1433     label = "Subject";
1434     if (*default_subject) {
1435 	StrAllocCopy(the_subject, default_subject);
1436     } else if (non_empty(filename)) {
1437 	HTSprintf(&the_subject, "%s", filename);
1438     } else {
1439 	HTSprintf(&the_subject, "mailto:%s", to_address);
1440     }
1441     if (!header_prompt(label, &the_subject, MAX_SUBJECT)) {
1442 	goto cancelled;
1443     }
1444 
1445     /*
1446      * Offer a CC line, if permitted.  - FM
1447      */
1448     if (!LYNoCc) {
1449 	LYaddstr(ENTER_ADDRESS_FOR_CC);
1450 	LYaddstr(BLANK_FOR_NO_COPY);
1451 	if (non_empty(personal_mail_address))
1452 	    StrAllocCopy(cc_address, personal_mail_address);
1453 	if (!header_prompt("Cc", &cc_address, LINESIZE)) {
1454 	    goto cancelled;
1455 	}
1456 	comma_append(&ccaddr, cc_address);
1457     }
1458 #if !USE_VMS_MAILER
1459     HTSprintf(&header, "%s: %s\n", label, the_subject);
1460 #if !CAN_PIPE_TO_MAILER
1461     if (*to_address) {
1462 	HTSprintf(&header, "To: %s\n", to_address);
1463     }
1464 #endif
1465 
1466     /*
1467      * Add the Cc:  header.  - FM
1468      */
1469     if (non_empty(ccaddr)) {
1470 	HTSprintf(&header, "Cc: %s\n", ccaddr);
1471     }
1472 
1473     /*
1474      * Add the Keywords:  header.  - FM
1475      */
1476     if (non_empty(keywords)) {
1477 	HTSprintf(&header, "Keywords: %s\n", keywords);
1478     }
1479 
1480     /*
1481      * Terminate the header.
1482      */
1483     StrAllocCat(header, "\n");
1484     CTRACE((tfp, "**header==\n%s", header));
1485 #endif /* !VMS */
1486 
1487     if (!no_editor && non_empty(editor)) {
1488 
1489 	if (body) {
1490 	    cp1 = body;
1491 	    while ((cp = StrChr(cp1, '\n')) != NULL) {
1492 		*cp++ = '\0';
1493 		fprintf(fd, "%s\n", cp1);
1494 		cp1 = cp;
1495 	    }
1496 	} else if (strcmp(HTLoadedDocumentURL(), "")) {
1497 	    /*
1498 	     * Ask if the user wants to include the original message.
1499 	     */
1500 	    BOOLEAN is_preparsed = (BOOL) (LYPreparsedSource &&
1501 					   HTisDocumentSource());
1502 
1503 	    if (HTConfirm(is_preparsed
1504 			  ? INC_PREPARSED_MSG_PROMPT
1505 			  : INC_ORIG_MSG_PROMPT) == YES) {
1506 		print_wwwfile_to_fd(fd, TRUE, (BOOL) !is_preparsed);
1507 	    }
1508 	}
1509 	LYCloseTempFP(fd);	/* Close the tmpfile. */
1510 	scrollok(LYwin, FALSE);	/* Stop scrolling.    */
1511 
1512 	if (term_letter || LYCharIsINTERRUPT(c))
1513 	    goto cleanup;
1514 
1515 	/*
1516 	 * Spawn the users editor on the mail file
1517 	 */
1518 	edit_temporary_file(my_tmpfile, "", SPAWNING_EDITOR_FOR_MAIL);
1519 
1520     } else if (body) {
1521 	/*
1522 	 * Let user review the body.  - FM
1523 	 */
1524 	LYclear();
1525 	LYmove(0, 0);
1526 	LYaddstr(REVIEW_MESSAGE_BODY);
1527 	LYrefresh();
1528 	cp1 = body;
1529 	i = (LYlines - 5);
1530 	while ((cp = StrChr(cp1, '\n')) != NULL) {
1531 	    if (i <= 0) {
1532 		LYaddstr(RETURN_TO_CONTINUE);
1533 		LYrefresh();
1534 		c = LYgetch();
1535 		LYaddstr("\n");
1536 		if (term_letter || LYCharIsINTERRUPT(c)) {
1537 		    goto cancelled;
1538 		}
1539 		i = (LYlines - 2);
1540 	    }
1541 	    *cp++ = '\0';
1542 	    fprintf(fd, "%s\n", cp1);
1543 	    LYaddstr(cp1);
1544 	    LYaddstr("\n");
1545 	    cp1 = cp;
1546 	    i--;
1547 	}
1548 	while (i >= 0) {
1549 	    LYaddstr("\n");
1550 	    i--;
1551 	}
1552 	LYrefresh();
1553 	LYCloseTempFP(fd);	/* Close the tmpfile.     */
1554 	scrollok(LYwin, FALSE);	/* Stop scrolling.        */
1555 
1556     } else {
1557 	/*
1558 	 * Use the internal line editor for the message.
1559 	 */
1560 	LYaddstr(ENTER_MESSAGE_BELOW);
1561 	LYaddstr(ENTER_PERIOD_WHEN_DONE_A);
1562 	LYaddstr(ENTER_PERIOD_WHEN_DONE_B);
1563 	LYaddstr(CTRL_G_TO_CANCEL_SEND);
1564 	LYaddstr("\n\n");
1565 	LYrefresh();
1566 	*user_input = '\0';
1567 	if (LYGetStr(user_input, FALSE, sizeof(user_input), NORECALL) < 0 ||
1568 	    term_letter || STREQ(user_input, ".")) {
1569 	    goto cancelled;
1570 	}
1571 
1572 	while (!STREQ(user_input, ".") && !term_letter) {
1573 	    LYaddstr("\n");
1574 	    remove_tildes(user_input);
1575 	    fprintf(fd, "%s\n", user_input);
1576 	    *user_input = '\0';
1577 	    if (LYGetStr(user_input, FALSE,
1578 			 sizeof(user_input), NORECALL) < 0) {
1579 		goto cancelled;
1580 	    }
1581 	}
1582 
1583 	fprintf(fd, "\n");	/* Terminate the message. */
1584 	LYCloseTempFP(fd);	/* Close the tmpfile.     */
1585 	scrollok(LYwin, FALSE);	/* Stop scrolling.        */
1586     }
1587 
1588 #if !USE_VMS_MAILER
1589     /*
1590      * Ignore CTRL-C on this last question.
1591      */
1592     signal(SIGINT, SIG_IGN);
1593 #endif /* !VMS */
1594     LYStatusLine = (LYlines - 1);
1595     c = HTConfirm(body ? SEND_MESSAGE_PROMPT : SEND_COMMENT_PROMPT);
1596     LYStatusLine = -1;
1597     if (c != YES) {
1598 	LYclear();		/* clear the screen */
1599 	goto cleanup;
1600     }
1601     if ((body == NULL && non_empty(LynxSigFile)) &&
1602 	(fp = fopen(LynxSigFile, TXT_R)) != NULL) {
1603 	LYStatusLine = (LYlines - 1);
1604 	if (term_letter) {
1605 	    _user_message(APPEND_SIG_FILE, LynxSigFile);
1606 	    c = 0;
1607 	} else {
1608 	    char *msg = NULL;
1609 
1610 	    HTSprintf0(&msg, APPEND_SIG_FILE, LynxSigFile);
1611 	    c = HTConfirm(msg);
1612 	    FREE(msg);
1613 	}
1614 	LYStatusLine = -1;
1615 	if (c == YES) {
1616 	    if ((fd = fopen(my_tmpfile, TXT_A)) != NULL) {
1617 		char *buffer = NULL;
1618 
1619 		fputs("-- \n", fd);
1620 		while (LYSafeGets(&buffer, fp) != NULL) {
1621 		    fputs(buffer, fd);
1622 		}
1623 		LYCloseOutput(fd);
1624 		FREE(buffer);
1625 	    }
1626 	}
1627 	LYCloseInput(fp);
1628     }
1629     LYclear();			/* Clear the screen. */
1630 
1631     /*
1632      * Send the message.
1633      */
1634 #if USE_VMS_MAILER
1635     /*
1636      * Set the mail command.  - FM
1637      */
1638     if (isPMDF) {
1639 	/*
1640 	 * For PMDF, put any keywords and the subject in the header file and
1641 	 * close it.  - FM
1642 	 */
1643 	if (non_empty(keywords)) {
1644 	    fprintf(hfd, "Keywords: %s\n", keywords);
1645 	}
1646 	fprintf(hfd, "Subject: %s\n\n", the_subject);
1647 	LYCloseTempFP(hfd);
1648 	/*
1649 	 * Now set up the command.  - FM
1650 	 */
1651 	HTSprintf0(&command, "%s %s %s,%s ",
1652 		   system_mail,
1653 		   system_mail_flags,
1654 		   hdrfile,
1655 		   my_tmpfile);
1656     } else {
1657 	/*
1658 	 * For "generic" VMS MAIL, include the subject in the command, and
1659 	 * ignore any keywords to minimize risk of them making the line too
1660 	 * long or having problem characters.  - FM
1661 	 */
1662 	HTSprintf0(&command, "%s %s%s/subject=\"%s\" %s ",
1663 		   system_mail,
1664 		   system_mail_flags,
1665 		   (strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
1666 		   the_subject,
1667 		   my_tmpfile);
1668     }
1669 
1670     vms_append_addrs(&command, to_address, "");
1671     if (non_empty(ccaddr)) {
1672 	vms_append_addrs(&command, ccaddr, "/CC");
1673     }
1674 
1675     stop_curses();
1676     printf("%s\n\n$ %s\n\n%s", SENDING_COMMENT, command, PLEASE_WAIT);
1677     LYSystem(command);		/* SENDING COMMENT (VMS) */
1678     FREE(command);
1679     LYSleepAlert();
1680     start_curses();
1681 #else /* Unix/DOS/Windows */
1682     /*
1683      * Send the tmpfile into sendmail.
1684      */
1685     _statusline(SENDING_YOUR_MSG);
1686 #if CAN_PIPE_TO_MAILER
1687     signal(SIGINT, SIG_IGN);
1688     if ((fp = LYPipeToMailer()) == 0) {
1689 	HTInfoMsg(CANCELLED);
1690     }
1691 #else
1692     if ((fp = LYOpenTemp(tmpfile2, ".txt", "w")) == NULL) {
1693 	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
1694     }
1695 #endif /* CAN_PIPE_TO_MAILER */
1696     if (fp != 0) {
1697 	fd = fopen(my_tmpfile, TXT_R);
1698 	if (fd == NULL) {
1699 	    HTInfoMsg(CANCELLED);
1700 #if CAN_PIPE_TO_MAILER
1701 	    pclose(fp);
1702 #else
1703 	    LYCloseTempFP(fp);
1704 #endif /* CAN_PIPE_TO_MAILER */
1705 	} else {
1706 #if USE_BLAT_MAILER
1707 	    if (!mail_is_blat)
1708 		fputs(header, fp);
1709 #else
1710 	    fputs(header, fp);
1711 #endif
1712 	    while ((nbytes = fread(buf, (size_t) 1, sizeof(buf), fd)) != 0) {
1713 		if (fwrite(buf, (size_t) 1, (size_t) nbytes, fp) < nbytes)
1714 		    break;
1715 	    }
1716 #if CAN_PIPE_TO_MAILER
1717 	    pclose(fp);
1718 #else
1719 	    LYCloseTempFP(fp);	/* Close the tmpfile. */
1720 	    LYSendMailFile(to_address,
1721 			   tmpfile2,
1722 			   the_subject,
1723 			   ccaddr,
1724 			   SENDING_COMMENT);
1725 	    (void) LYRemoveTemp(tmpfile2);	/* Delete the tmpfile. */
1726 #endif /* CAN_PIPE_TO_MAILER */
1727 	    LYCloseInput(fd);	/* Close the tmpfile. */
1728 	}
1729     }
1730 #endif /* USE_VMS_MAILER */
1731     goto cleanup;
1732 
1733     /*
1734      * Come here to cleanup and exit.
1735      */
1736   cancelled:
1737     HTInfoMsg(CANCELLED);
1738     LYCloseTempFP(fd);		/* Close the tmpfile.   */
1739     scrollok(LYwin, FALSE);	/* Stop scrolling.      */
1740   cleanup:
1741     signal(SIGINT, cleanup_sig);
1742     term_letter = FALSE;
1743 
1744 #if USE_VMS_MAILER
1745     while (LYRemoveTemp(my_tmpfile) == 0) ;	/* Delete the tmpfile(s). */
1746     if (isPMDF) {
1747 	(void) LYRemoveTemp(hdrfile);	/* Delete the hdrfile. */
1748     }
1749 #else
1750     FREE(header);
1751     (void) LYRemoveTemp(my_tmpfile);	/* Delete the tmpfile. */
1752 #endif /* VMS */
1753 
1754     FREE(from_address);
1755     FREE(the_subject);
1756     FREE(cc_address);
1757     FREE(to_address);
1758     FREE(ccaddr);
1759     FREE(keywords);
1760     FREE(body);
1761     return;
1762 }
1763 
1764 /*
1765  * Check that we have configured values for system mailer.
1766  */
LYSystemMail(void)1767 BOOLEAN LYSystemMail(void)
1768 {
1769     if (isEmpty(system_mail) || !strcmp(system_mail, "unknown")) {
1770 	HTAlert(gettext("No system mailer configured"));
1771 	return FALSE;
1772     }
1773     return TRUE;
1774 }
1775