1 /*
2 * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
3 * Copyright (c) 1996-2005 Michael T Pins. All rights reserved.
4 *
5 * Response handling.
6 */
7
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include "config.h"
13 #include "global.h"
14 #include "answer.h"
15 #include "aux.h"
16 #include "db.h"
17 #include "fullname.h"
18 #include "group.h"
19 #include "hostname.h"
20 #include "init.h"
21 #include "kill.h"
22 #include "match.h"
23 #include "news.h"
24 #include "nn.h"
25 #include "nntp.h"
26 #include "options.h"
27 #include "printconf.h"
28 #include "regexp.h"
29 #include "reroute.h"
30 #include "nn_term.h"
31 #include "variable.h"
32
33 /* answer.c */
34
35 static int subj_line(FILE * t, int re, char *subj, char *prefix);
36 static void ng_line(FILE * t, int use_follow);
37 static void ref_line(FILE * t);
38 static int to_line(FILE * t, char *to);
39 static void alt_to_line(FILE * t, char *to, int mask);
40 static void end_header(FILE * t, register char *extra_headers);
41 static int reply_to(FILE * t, char *address);
42 static char *get_distr(char *orig, char *distr);
43 static char *inet_name(void);
44 static int check_sender(char *sender);
45
46 extern char *temp_file;
47 extern char *news_lib_directory;
48
49 #ifndef DEFAULT_DISTRIB
50 #define DEFAULT_DISTRIB "world"
51 #endif
52
53 char *default_distribution = DEFAULT_DISTRIB;
54 char *distribution_follow = "always same default";
55 char *distribution_post = "ask default";
56 char *extra_mail_headers = NULL;
57 char *extra_news_headers = NULL;
58 char *mail_record = NULL;
59 char *news_record = NULL;
60 char *mail_script = NULL;
61 char *news_script = NULL;
62 char *inews_program = NULL;
63 int inews_pipe_input = 1;
64
65 char *bug_address = BUG_REPORT_ADDRESS;
66
67 int include_art_id = 0;
68 int include_full_header = 0;
69 int orig_to_include_mask = 0x3;
70 int include_mark_blanks = 0;
71
72
73 #ifdef APPEND_SIGNATURE
74 int append_sig_mail = 1; /* mail does not append it */
75 #else
76 int append_sig_mail = 0;
77 #endif
78
79 int append_sig_post = 1; /* we should do this */
80
81
82 #define INCL_MARK_SIZE 10
83
84 char included_mark[INCL_MARK_SIZE + 1] = ">";
85
86 extern char delayed_msg[];
87 extern int auto_select_rw;
88 extern int ignore_fancy_select;
89 extern char *organization;
90
91 extern key_type help_key;
92
93 extern regexp *pg_regexp;
94 extern int pg_new_regexp;
95
96 static int ed_line;
97
98 #ifdef NNTP
99 #include <time.h>
100 #include <pwd.h>
101
102 extern struct tm *gmtime();
103 extern char *asctime();
104 #endif
105
106 static int
checkhold(article_header * ah,int command)107 checkhold(article_header * ah, int command)
108 {
109 int ans;
110
111 if (file_exist(relative(nn_directory, "hold.work"), (char *) NULL)) {
112 prompt("\1An uncompleted reponse exists\1 - complete now? ");
113 if ((ans = yes(1)) < 0)
114 return 0;
115 if (ans) {
116 if (ah && ah->a_group)
117 init_group(ah->a_group);
118 new_temp_file();
119 if (command == K_REPLY)
120 aux_sh(ah, (char *) NULL, "COMPLETE.mail", (char *) NULL,
121 (char *) NULL, "Mail%s sent", 0, 0);
122 else
123 aux_sh(ah, (char *) NULL, "COMPLETE.post", (char *) NULL,
124 (char *) NULL, "Article%s posted", 0, 0);
125 return 1;
126 }
127 prompt("Remove uncompleted reponse? ");
128 if ((ans = yes(1)) < 0)
129 return 0;
130 if (ans) {
131 unlink(relative(nn_directory, "hold.work"));
132 unlink(relative(nn_directory, "hold.param"));
133 }
134 }
135 return 0;
136 }
137
138
139
140 static int
subj_line(FILE * t,int re,char * subj,char * prefix)141 subj_line(FILE * t, int re, char *subj, char *prefix)
142 {
143 if (subj == NULL)
144 return 0;
145
146 fputs("Subject: ", t);
147
148 if (re >= 0)
149 fputs("Re: ", t);
150
151 if (prefix) {
152 fputs(prefix, t);
153 fputc(' ', t);
154 }
155 fputs(subj, t);
156 fputc(NL, t);
157
158 ed_line++;
159 return 1;
160 }
161
162
163 static void
ng_line(FILE * t,int use_follow)164 ng_line(FILE * t, int use_follow)
165 {
166 char *ng;
167
168 ng = use_follow && news.ng_follow ? news.ng_follow : news.ng_groups;
169 if (ng == NULL)
170 return;
171
172 fprintf(t, "Newsgroups: %s\n", ng);
173 ed_line++;
174 }
175
176 static void
ref_line(FILE * t)177 ref_line(FILE * t)
178 {
179 if (news.ng_ref == NULL && news.ng_ident == NULL)
180 return;
181
182 fputs("References:", t);
183
184 /*
185 * Trim References: to less than 1000 bytes. The first References: item
186 * must remain the base article id. Then delete as many as necessary,
187 * then output the tail.
188 */
189 if (news.ng_ref) {
190 int pos = 11; /* output position, currently
191 * strlen("References:") */
192 char *p = news.ng_ref;
193
194 /*
195 * maximum position is 997 and maybe minus news.ng_ident, which if
196 * output is preceded by a space
197 */
198 int maxpos = (news.ng_ident ? 997 - (1 + strlen(news.ng_ident)) : 997);
199 int rlen;
200
201 /* First, output the base article's message id. */
202 /* First output a space between "References:" and the message id. */
203 putc(' ', t);
204 pos++;
205 /* Skip leading white space. */
206 while (*p && isascii(*p) && isspace(*p))
207 p++;
208 /* Output through next white space. */
209 while (*p && !(isascii(*p) && isspace(*p))) {
210 putc(*p++, t);
211 pos++;
212 }
213
214 /*
215 * Now, the rest of the previous article's references, but maybe
216 * leaving some of them out to avoid exceeding 997 bytes.
217 */
218 rlen = strlen(p); /* number of bytes remaining */
219 if (pos + rlen <= maxpos) {
220 fputs(p, t);
221 } else {
222
223 /*
224 * Find message id at which to start. Jump into the middle and
225 * then find a valid starting place.
226 */
227 p += rlen - (maxpos - pos);
228 /* find next '<' */
229 while (*p && *p != '<')
230 p++;
231 if (*p)
232 fputs(p - 1, t);
233
234 /*
235 * go back to include one white space character. This is
236 * guaranteed to stay within the array because maxpos-pos is
237 * strictly less than rlen, therefore rlen - (maxpos - pos) is
238 * positive, therefore p is greater than it was before this
239 * enclosing 'else'.
240 */
241 }
242 }
243 if (news.ng_ident)
244 fprintf(t, " %s", news.ng_ident);
245 putc(NL, t);
246 ed_line++;
247 }
248
249
250 static int
to_line(FILE * t,char * to)251 to_line(FILE * t, char *to)
252 {
253 if (to == NULL)
254 return 0;
255
256 fprintf(t, "To: %s\n", to);
257 ed_line++;
258 return 1;
259 }
260
261 static void
alt_to_line(FILE * t,char * to,int mask)262 alt_to_line(FILE * t, char *to, int mask)
263 {
264 if (to == NULL)
265 return;
266 if (mask && (orig_to_include_mask & mask) == 0)
267 return;
268
269 fprintf(t, "Orig-To: %s\n", to);
270 ed_line++;
271 }
272
273 static void
end_header(FILE * t,register char * extra_headers)274 end_header(FILE * t, register char *extra_headers)
275 {
276 if (extra_headers != NULL && *extra_headers != NUL) {
277 while (*extra_headers != NUL) {
278 if (*extra_headers == ';' || *extra_headers == NL) {
279 if (*++extra_headers == NUL)
280 break;
281 fputc(NL, t);
282 ed_line++;
283 } else {
284 if (*extra_headers == '\\' && *++extra_headers == NUL)
285 break;
286 fputc(*extra_headers++, t);
287 }
288 }
289 fputc(NL, t);
290 ed_line++;
291 }
292 fputc(NL, t);
293 ed_line++;
294 }
295
296
297 static int
reply_to(FILE * t,char * address)298 reply_to(FILE * t, char *address)
299 {
300 char route[512];
301
302 if (address == NULL)
303 return 0;
304
305 if (reroute(route, address)) {
306 to_line(t, route);
307 return 1;
308 }
309 return 0;
310 }
311
312 /*
313 * open_purpose_file(void)
314 *
315 * Open "newsgroups" file once - just rewind() otherwise.
316 * Caller must NOT close it!
317 */
318
319 FILE *
open_purpose_file(void)320 open_purpose_file(void)
321 {
322 static FILE *f = NULL;
323 static int is_open = 0;
324
325 if (is_open) {
326 if (f != NULL)
327 rewind(f);
328 return f;
329 }
330 is_open = 1;
331
332 #ifdef NNTP
333 if (use_nntp) {
334 f = nntp_get_newsgroups();
335 } else
336 #endif
337
338 f = open_file(relative(news_lib_directory, "newsgroups"), OPEN_READ);
339 return f;
340 }
341
342 /*
343 * display list of group purposes
344 */
345
346 static int
display_group_list(int get_regexp)347 display_group_list(int get_regexp)
348 {
349 FILE *f;
350 char line[512];
351 char *expr = NULL;
352
353 if (get_regexp) {
354 prompt("\1/\1");
355 expr = get_s((char *) NULL, (char *) NULL, (char *) NULL, NULL_FCT);
356 if (expr == NULL || *expr == NUL)
357 return 0;
358 }
359 if ((f = open_purpose_file()) == NULL)
360 return 0;
361 if (who_am_i == I_AM_POST) {
362 gotoxy(0, prompt_line + 1);
363 clrpage();
364 pg_init(prompt_line + 1, 1);
365 } else {
366 home();
367 clrdisp();
368 pg_init(0, 1);
369 }
370 if (expr)
371 pg_regexp = regcomp(expr);
372
373 while (fgets(line, 512, f)) {
374 if (pg_regexp && regexec_fold(pg_regexp, line) == 0)
375 continue;
376 if (pg_next() < 0)
377 break;
378 if (pg_new_regexp) {
379 pg_new_regexp = 0; /* pg_next has cleared display */
380 rewind(f);
381 continue;
382 }
383 tprintf("%s", line);
384 }
385 return 1;
386 }
387
388 static char *
get_distr(char * orig,char * distr)389 get_distr(char *orig, char *distr)
390 {
391 flag_type opts;
392 int always, ask, same, dflt;
393 char *str, *dd;
394
395 if ((dd = default_distribution) == NULL)
396 dd = DEFAULT_DISTRIB;
397
398 if (distr == NULL)
399 distr = "default";
400 var_options(&distr, "always\0ask\0same\0default\0", &opts);
401 always = (opts & FLAG(1));
402 ask = (opts & FLAG(2));
403 same = (opts & FLAG(3));
404 dflt = (opts & FLAG(4));
405
406 if (*distr == NUL || dflt)
407 distr = dd;
408
409 if (same && orig != NULL) {
410 distr = orig;
411 if (always)
412 ask = 0;
413 }
414 if (!ask)
415 return distr;
416
417 prompt("Distribution: (default '%s') ", distr);
418 str = get_s(NONE, NONE, NONE, NULL_FCT);
419 if (str == NULL)
420 return NULL;
421 if (*str != NUL)
422 distr = str;
423 return distr;
424 }
425
426 int
answer(article_header * ah,int command,int incl)427 answer(article_header * ah, int command, int incl)
428 /* incl: <0: ask, 0: don't include, >0: include article */
429 {
430 register FILE *t, *art;
431 char *pgm = NULL, *first_action, *record_file;
432 int edit_message, append_sig;
433 char *str, *script;
434 news_header_buffer nhbuf, dhbuf;
435 flag_type nn_st_flag = 0;
436
437 if (checkhold(ah, command))
438 return 1;
439 first_action = "edit";
440 edit_message = 1;
441 append_sig = 0;
442
443 if (incl < 0) {
444 prompt("Include original article? ");
445 if ((incl = yes(0)) < 0)
446 return 0;
447 }
448 art = NULL;
449 if (ah && ah->a_group)
450 init_group(ah->a_group);
451
452 if (incl || (command != K_MAIL_OR_FORWARD && command != K_BUG_REPORT)) {
453 int open_modes;
454
455 open_modes = FILL_NEWS_HEADER | GET_ALL_FIELDS | SKIP_HEADER;
456 if (ah->flag & A_DIGEST)
457 open_modes |= FILL_DIGEST_HEADER;
458
459 art = open_news_article(ah, open_modes, nhbuf, dhbuf);
460 if (art == NULL) {
461 msg("Can't find original article");
462 return 0;
463 }
464 if (ah->flag & A_DIGEST) {
465 if (digest.dg_from) {
466 if (news.ng_reply)
467 news.ng_from = news.ng_reply;
468 news.ng_reply = digest.dg_from;
469 }
470 if (digest.dg_subj)
471 news.ng_subj = digest.dg_subj;
472 }
473 } else
474 ah = NULL;
475
476 /* build header */
477 new_temp_file();
478
479 if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) {
480 msg("Can't create %s", temp_file);
481 return 0;
482 }
483 ed_line = 0;
484
485 follow_to_poster:
486
487 record_file = mail_record;
488 script = mail_script;
489
490 if (command == K_REPLY) {
491 pgm = "reply";
492 append_sig = append_sig_mail;
493
494 nn_st_flag = A_ST_REPLY;
495
496 if (reply_to(t, news.ng_reply) ||
497 reply_to(t, news.ng_from) ||
498 reply_to(t, news.ng_path))
499 goto alt0;
500 if (to_line(t, news.ng_reply))
501 goto alt1;
502 if (to_line(t, news.ng_from))
503 goto alt2;
504 if (to_line(t, news.ng_path))
505 goto alt3;
506 goto err;
507
508 alt0:
509 alt_to_line(t, news.ng_reply, 0x1);
510 alt1:
511 alt_to_line(t, news.ng_from, 0x2);
512 alt2:
513 alt_to_line(t, news.ng_path, 0x4);
514 alt3:
515
516 if (news.ng_subj)
517 subj_line(t, ah->replies, ah->subject, (char *) NULL);
518 else
519 subj_line(t, 0, current_group->group_name, "Your Article in");
520
521 ng_line(t, 0);
522 ref_line(t);
523
524 end_header(t, extra_mail_headers);
525
526 if (incl) {
527 if (current_group->group_flag & G_FOLDER)
528 fprintf(t, "You write:\n");
529 else
530 fprintf(t, "In %s you write:\n", current_group->group_name);
531 ed_line++;
532 }
533 }
534 if (command == K_FOLLOW_UP) {
535 if (news.ng_follow && strcmp(news.ng_follow, "poster") == 0) {
536 command = K_REPLY;
537 msg("Followup by reply to poster");
538 goto follow_to_poster;
539 }
540 pgm = "follow";
541 record_file = news_record;
542 script = news_script;
543 append_sig = append_sig_post;
544
545 nn_st_flag = A_ST_FOLLOW;
546
547 ng_line(t, 1);
548
549 if (news.ng_subj)
550 subj_line(t, ah->replies, ah->subject, (char *) NULL);
551 else if (!subj_line(t, 0, news.ng_from, "Babble from"))
552 if (!subj_line(t, 0, news.ng_ident, "Article")) {
553 prompt("Subject: ");
554 str = get_s(NONE, NONE, NONE, NULL_FCT);
555 if (str == NULL)
556 goto err;
557 subj_line(t, -1, str, (char *) NULL);
558 }
559 if (news.ng_keyw) {
560 fprintf(t, "Keywords: %s\n", news.ng_keyw);
561 ed_line++;
562 }
563 str = get_distr(news.ng_dist, distribution_follow);
564 if (str == NULL)
565 goto close_t;
566 if (strcmp(str, "world")) {
567 fprintf(t, "Distribution: %s\n", str);
568 ed_line++;
569 }
570 ref_line(t);
571
572 end_header(t, extra_news_headers);
573
574 if (incl) {
575 if (news.ng_from) {
576 if (include_art_id && news.ng_ident)
577 fprintf(t, "In%s %s ",
578 ah->flag & A_DIGEST ? " digest" : "",
579 news.ng_ident);
580 fprintf(t, "%s writes:\n", news.ng_from);
581 ed_line++;
582 } else if (news.ng_ident) {
583 fprintf(t, "In %s %s:\n",
584 ah->flag & A_DIGEST ? "digest" : "article",
585 news.ng_ident);
586 ed_line++;
587 }
588 }
589 }
590 if (command == K_MAIL_OR_FORWARD || command == K_BUG_REPORT) {
591 pgm = incl ? "forward" : "mail";
592 append_sig = append_sig_mail;
593
594 m3_again:
595 prompt("To: ");
596 str = get_s(user_name(),
597 command == K_BUG_REPORT ? bug_address : NONE,
598 NONE, NULL_FCT);
599 if (str == NULL)
600 goto close_t;
601
602 if (*str == NUL)
603 str = user_name();
604 if (*str == '?')
605 goto m3_again;
606
607 if (strcmp(str, user_name()) == 0)
608 record_file = NULL; /* we will get this anyway, there is so no
609 * need to save it */
610
611 /* if (reply_to(t, str)) { alt_to_line(t, str, 0); } else */
612 to_line(t, str);
613
614 do {
615 prompt("Subject: ");
616 str = get_s(incl ? ah->subject : NONE,
617 command == K_BUG_REPORT ? "nn bug report" : NONE,
618 NONE, NULL_FCT);
619 if (str == NULL)
620 goto close_t;
621 if (*str == NUL && incl)
622 str = ah->subject;
623 } while (*str == NUL);
624
625 subj_line(t, -1, str, (char *) NULL);
626
627 end_header(t, extra_mail_headers);
628
629 if (incl) {
630 prompt("\1Edit\1 forwarded message? ");
631 if ((edit_message = yes(0)) < 0)
632 goto close_t;
633 if (!edit_message) {
634 first_action = "send";
635 fseek(art, ah->hpos, 0);
636 } else if (include_full_header && command == K_MAIL_OR_FORWARD)
637 fseek(art, ah->hpos, 0);
638 }
639 if (command == K_BUG_REPORT) {
640 fprintf(t, "\n=== configuration ===\n");
641 print_config(t);
642 fprintf(t, "=== variable settings ===\n");
643 print_variable_config(t, 0);
644 fprintf(t, "=== end ===\n");
645 }
646 }
647 prompt("\1WAIT\1");
648
649 if (incl) {
650 register int c, prevnl = 1;
651
652 fputc(NL, t);
653 ed_line++;
654
655 while ((c = getc(art)) != EOF) {
656 if (c == NL) {
657 putc(c, t);
658 if (ftell(art) >= ah->lpos)
659 break;
660 prevnl++;
661 if (!include_mark_blanks)
662 continue;
663 }
664 if (prevnl) {
665 if (command != K_MAIL_OR_FORWARD || ftell(art) < ah->fpos)
666 fputs(included_mark, t);
667 prevnl = 0;
668 if (c == NL)
669 continue;
670 }
671 putc(c, t);
672 }
673 } else {
674 putc(NL, t);
675 ed_line++;
676 }
677
678 fclose(t);
679 if (art)
680 fclose(art);
681
682 if (aux_sh(ah, script, pgm, first_action, record_file,
683 command == K_FOLLOW_UP ? "Article%s posted" : "Mail%s sent",
684 append_sig, ed_line) == 0)
685 if (ah)
686 ah->flag |= nn_st_flag;
687
688 return edit_message;
689
690 err:
691 msg("Can't build header for %s",
692 command != K_FOLLOW_UP ? "letter" : "article");
693
694 close_t:
695 fclose(t);
696 unlink(temp_file);
697 if (art)
698 fclose(art);
699
700 return 0;
701 }
702
703
704 /*
705 * inet_name: return "<user_name()>@<host_name()>"
706 */
707
708 static char *
inet_name(void)709 inet_name(void)
710 {
711 static char *inetname = NULL;
712 char hname[100], *un;
713
714 if (inetname == NULL) {
715 nn_gethostname(hname, 100);
716 un = user_name();
717 inetname = newstr(strlen(hname) + strlen(un) + 2);
718 sprintf(inetname, "%s@%s", un, hname);
719 }
720 return inetname;
721 }
722
723 /*
724 * check_sender: If sender is "root", "news", the full name or the internet
725 * name of the user, return 1 otherwise 0
726 */
727
728 static int
check_sender(char * sender)729 check_sender(char *sender)
730 {
731 return strcmp(user_name(), "root") == 0
732 || strcmp(user_name(), "news") == 0
733 || strmatch(full_name(), sender)
734 || strmatch(inet_name(), sender);
735 }
736
737 int
cancel(article_header * ah)738 cancel(article_header * ah)
739 {
740 news_header_buffer nhbuf;
741 FILE *f;
742
743 if (ah->a_group)
744 init_group(ah->a_group);
745
746 if (ah->flag & A_DIGEST) {
747 tprintf("\rCancel entire digest ? ");
748 clrline();
749 if (yes(1) > 0)
750 ah->flag &= ~A_DIGEST;
751 else {
752 msg("Can only cancel entire digests (yet?)");
753 return 2;
754 }
755 }
756 f = open_news_article(ah, FILL_NEWS_HEADER | GET_ALL_FIELDS, nhbuf, (char *) NULL);
757 if (f == NULL) {
758 msg("Article not found");
759 return 2;
760 }
761 fclose(f);
762
763 if (!check_sender(news.ng_from)) {
764 msg("You can only cancel your own articles!");
765 return 1;
766 }
767 prompt("Confirm cancel: '%s: %.30s'",
768 ah->sender ? ah->sender : "",
769 ah->subject ? ah->subject : "");
770 if (yes(1) <= 0)
771 return 1;
772
773 tprintf("\rCancelling article %s in group %s",
774 news.ng_ident, current_group->group_name);
775 clrline();
776
777 ed_line = -1;
778
779 new_temp_file();
780 if (aux_sh(ah, (char *) NULL, "cancel", news.ng_ident, current_group->group_name,
781 "Article%s cancelled", 0, 0))
782 return -1;
783
784 return 0;
785 }
786
787 static char *post_distribution = NULL;
788 static char *post_subject = NULL;
789 static char *post_summary = NULL;
790 static char *post_keywords = NULL;
791 static char *post_source_file = NULL;
792 static int post_no_edit = 0;
793 static char *post_to_groups = NULL;
794
795 static
Option_Description(post_options)796 Option_Description(post_options)
797 {
798 'd', String_Option(post_distribution),
799 'f', String_Option(post_source_file),
800 'k', String_Option(post_keywords),
801 's', String_Option(post_subject),
802 'y', String_Option(post_summary),
803 'p', Bool_Option(post_no_edit),
804 '\0', 0,
805 };
806
807 void
do_nnpost(int argc,char * argv[])808 do_nnpost(int argc, char *argv[])
809 {
810 int ngroups, i;
811 char newsgroups[FILENAME * 2];
812
813 init_term(0);
814 visit_init_file(0, (char *) NULL);
815 current_group = NULL;
816
817 ngroups =
818 parse_options(argc, argv, (char *) NULL, post_options,
819 " newsgroup...");
820
821 if (post_no_edit && post_source_file == NULL)
822 nn_exitmsg(1, "Must specify a source file with -p\n");
823
824 if (ngroups > 0) {
825 strcpy(newsgroups, argv[1]);
826 for (i = 2; i <= ngroups; i++) {
827 strcat(newsgroups, ",");
828 strcat(newsgroups, argv[i]);
829 }
830 post_to_groups = newsgroups;
831 }
832 if (ngroups > 0 && post_no_edit && post_subject && post_distribution) {
833 if (!post_summary)
834 post_summary = "";
835 if (!post_keywords)
836 post_keywords = "";
837 post_menu();
838 goto no_dialogue;
839 }
840 init_term(1);
841
842 nn_raw();
843 clrdisp();
844 prompt_line = 0;
845 if (post_menu() == 2)
846 clrdisp();
847 tputc(CR);
848 tputc(NL);
849 unset_raw();
850
851 no_dialogue:
852 if (*delayed_msg)
853 nn_exitmsg(0, "%s", delayed_msg);
854 else
855 nn_exit(0);
856 }
857
858 int
post_menu(void)859 post_menu(void)
860 {
861 register FILE *t, *src = NULL;
862 register int c;
863 int must_redraw = 0;
864 char brk_chars[4];
865 char *str, *tail;
866 group_header gh;
867 char group_name[FILENAME], subject[FILENAME], distribution[FILENAME],
868 keywords[FILENAME], summary[FILENAME];
869
870 if (checkhold(NULL, K_POST))
871 return 1;
872 if (post_source_file) {
873 src = open_file(post_source_file, OPEN_READ);
874 if (src == NULL)
875 nn_exitmsg(1, "File %s not found\n", post_source_file);
876 }
877 if (post_to_groups)
878 strcpy(group_name, post_to_groups);
879 else {
880 group_name[0] = NUL;
881
882 again_group:
883
884 prompt(who_am_i == I_AM_POST ? "Newsgroups: " : "\1POST to group\1 ");
885
886 strcpy(brk_chars, " /?");
887 brk_chars[0] = help_key;
888 str = get_s(current_group ? current_group->group_name : NONE,
889 group_name, brk_chars, group_completion);
890 if (str == NULL)
891 goto no_post;
892 if (*str == '?' || (key_type) (*str) == help_key || *str == '/') {
893 if (display_group_list(*str == '/'))
894 must_redraw = 2;
895 else
896 msg("No group list is available");
897 goto again_group;
898 }
899 if (*str == NUL) {
900 if (current_group == NULL || (current_group->group_flag & G_FAKED))
901 goto no_post;
902 str = current_group->group_name;
903 }
904 strcpy(group_name, str);
905
906 for (str = group_name; str; str = tail) {
907 tail = strchr(str, ',');
908 if (tail)
909 *tail = NUL;
910
911 if (lookup(str) == NULL) {
912 msg("unknown group: %s", str);
913 *str = NUL;
914 goto again_group;
915 }
916 if (tail)
917 *tail++ = ',';
918 }
919 if (who_am_i == I_AM_POST) {
920 prompt_line++;
921 if (must_redraw) {
922 gotoxy(0, prompt_line);
923 clrpage();
924 must_redraw = 1;
925 }
926 }
927 }
928
929 if ((str = post_subject) == NULL) {
930 prompt("Subject: ");
931 str = get_s(NONE, NONE, NONE, NULL_FCT);
932 if (str == NULL || *str == NUL)
933 goto no_post;
934 if (who_am_i == I_AM_POST)
935 prompt_line++;
936 }
937 strcpy(subject, str);
938
939 if ((str = post_keywords) == NULL) {
940 prompt("Keywords: ");
941 str = get_s(NONE, NONE, NONE, NULL_FCT);
942 if (str == NULL)
943 goto no_post;
944 if (who_am_i == I_AM_POST)
945 prompt_line++;
946 }
947 strcpy(keywords, str);
948
949 if ((str = post_summary) == NULL) {
950 prompt("Summary: ");
951 str = get_s(NONE, NONE, NONE, NULL_FCT);
952 if (str == NULL)
953 goto no_post;
954 if (who_am_i == I_AM_POST)
955 prompt_line++;
956 }
957 strcpy(summary, str);
958
959 if ((str = post_distribution) == NULL) {
960 str = get_distr(NULL, distribution_post);
961 if (str == NULL)
962 goto no_post;
963 if (who_am_i == I_AM_POST)
964 prompt_line++;
965 }
966 strcpy(distribution, str);
967
968 new_temp_file();
969 if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) {
970 msg("Can't create %s", temp_file);
971 goto no_post;
972 }
973 if (!post_no_edit)
974 prompt("\1WAIT\1");
975
976 ed_line = 3;
977 fprintf(t, "Newsgroups: %s\n", group_name);
978 if (strcmp(distribution, "world")) {
979 fprintf(t, "Distribution: %s\n", distribution);
980 ed_line++;
981 }
982 fprintf(t, "Subject: %s\n", subject);
983 if (organization) {
984 fprintf(t, "Organization: %s\n", organization);
985 ed_line++;
986 }
987 if (*summary) {
988 fprintf(t, "Summary: %s\n", summary);
989 ed_line++;
990 }
991 if (*keywords) {
992 fprintf(t, "Keywords: %s\n", keywords);
993 ed_line++;
994 }
995 end_header(t, extra_news_headers);
996
997 if (post_source_file) {
998 while ((c = getc(src)) != EOF)
999 putc(c, t);
1000 fclose(src);
1001 } else
1002 fputc(NL, t);
1003
1004 fclose(t);
1005
1006 if (auto_select_rw && !ignore_fancy_select) {
1007 tail = strchr(group_name, ',');
1008 if (tail)
1009 *tail = NUL;
1010 gh.group_name = group_name;
1011 enter_kill_file(&gh, subject, 6, 60);
1012 if (tail)
1013 *tail = ',';
1014 }
1015 aux_sh((article_header *) NULL, news_script, "post",
1016 post_no_edit ? "send" : "edit", news_record,
1017 "Article%s posted", append_sig_post, ed_line);
1018 must_redraw = 1;
1019
1020 no_post:
1021 return must_redraw;
1022 }
1023