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