|
|
1.1 root 1: /*
2: * This software is Copyright (c) 1986 by Rick Adams.
3: *
4: * Permission is hereby granted to copy, reproduce, redistribute or
5: * otherwise use this software as long as: there is no monetary
6: * profit gained specifically from the use or reproduction or this
7: * software, it is not sold, rented, traded or otherwise marketed, and
8: * this copyright notice is included prominently in any copy
9: * made.
10: *
11: * The author make no claims as to the fitness or correctness of
12: * this software for any use whatsoever, and it is provided as is.
13: * Any use of this software is at the user's own risk.
14: *
15: * Postnews: post a news message to Usenet. This C version replaces a shell
16: * script, and does more intelligent prompting and filtering than possible
17: * in a shell script.
18: */
19:
20: #ifdef SCCSID
21: static char *SccsId = "@(#)postnews.c 1.25 3/19/86";
22: #endif /* SCCSID */
23:
24: #include "params.h"
25:
26: #define APPEND 1
27: #define REPLACE 2
28:
29: extern char *MAILPARSER;
30:
31: char tempfname[50]; /* file name used for making article */
32: char original[BUFLEN]; /* file name of original, used in followup */
33: char homedir[BUFLEN]; /* HOME environment setting */
34: char user[SBUFLEN]; /* user name */
35: char ccname[BUFLEN]; /* file name for article copy */
36:
37: /* article header information */
38: char subject[BUFLEN];
39: char distribution[BUFLEN];
40: char references[BUFLEN];
41: char newsgroups[BUFLEN];
42: char moderator[BUFLEN];
43: char isfrom[BUFLEN];
44: char msgid[BUFLEN];
45: char keywords[BUFLEN];
46: char summary[BUFLEN];
47: int uid;
48:
49: char ngsep[] = { NGDELIM, '\0' }; /* == "," */
50:
51: char *Progname = "postnews"; /* for xerror */
52:
53: time_t fmodtime;
54: int ismod = 0;
55: char buf[BUFLEN];
56:
57: struct distr {
58: char abbr[24];
59: char descr[128];
60: } distr[16];
61:
62: FILE *xfopen();
63:
64: main(argc, argv)
65: char *argv[];
66: {
67: register int c;
68:
69: init();
70:
71: if (argc == 2) {
72: if (!prefix(argv[1], SPOOL))
73: xerror("Can only followup to articles in %s", SPOOL);
74: followup(argv[1]);
75: (void) strcpy(original, argv[1]);
76: } else
77: if (askyes("Is this message in response to some other message? ","no")) {
78: char ng[BUFLEN], num[BUFLEN];
79: long i, j, lastnum;
80: register char *p;
81: int fd, dir;
82: char canpost;
83:
84: getpr("In what newsgroup was the article posted? ",ng);
85: if (!valid_ng(ng, &i, &j, &canpost))
86: if (canpost != 'n' )
87: byebye("There is no such newsgroup.");
88: else
89: byebye("You are not allowed to post to that group.");
90:
91: printf("Valid article numbers are from %ld to %ld\n", j, i);
92: lastnum = i + 1;
93: dir = -1;
94:
95: for(;;) {
96: getpr("\nWhat was the article number? ", num);
97: switch(num[0]) {
98: case '+':
99: dir = 1;
100: sprintf(num, "%ld", lastnum + 1);
101: break;
102: case '-':
103: dir = -1;
104: /* no break */
105: case '\0':
106: sprintf(num, "%ld", lastnum + dir);
107: break;
108: }
109: (void) sprintf(original, "%s/%s", SPOOL, ng);
110: for (p=original+strlen(SPOOL)+1; *p ;++p)
111: if (*p == '.')
112: *p = '/';
113: (void) strcat(original, "/");
114: (void) strcat(original, num);
115:
116: if ((fd=open(original,0)) >= 0) {
117: (void) close(fd);
118: printf("\narticle %s\n", original);
119: if (article_line(original, "From: ", buf))
120: printf("%s\n", buf);
121: if (article_line(original, "Subject: ", buf))
122: printf("%s\n", buf);
123: if (askyes("Is this the one you want? ", "n"))
124: break;
125: } else
126: printf("I can't find that article.\n");
127: lastnum = atol(num);
128: }
129:
130: followup(original);
131: } else {
132: do {
133: getpr("Subject: ", subject);
134: if (*subject == '?') {
135: printf("People read the subject line to learn what your article is about.\n");
136: printf("You want it to do the same job as a newspaper headline.\n");
137: printf("So type in something both brief and descriptive.\n");
138: *subject = '\0';
139: }
140: } while (*subject == '\0');
141: getpr("Keywords: ", keywords);
142:
143: while (!get_newsgroup())
144: ;
145: check_mod();
146: get_distribution((char *)0);
147: }
148:
149: if (pre_checks())
150: exit(1);
151:
152: prep_article();
153: c = 'e';
154: for (;;) {
155: if (c == 'e') {
156: edit_article();
157: post_checks();
158: }
159: do {
160: do {
161: getpr("\nWhat now? [send, edit, list, quit, write] ", buf);
162: c = buf[0];
163: } while (c == '\0');
164: if (isupper(c))
165: c = tolower(c);
166: if (c == 'q') {
167: (void) UNLINK(tempfname);
168: exit(1);
169: }
170: if (c == 'l') {
171: char *pager = getenv("PAGER");
172: char lbuf[BUFLEN];
173: if (pager == NULL || *pager == '\0') {
174: #ifdef PAGE
175: # ifdef IHCC
176: (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE);
177: # else /* !IHCC */
178: (void) strcpy(lbuf, PAGE);
179: # endif /* !IHCC */
180: pager = lbuf;
181: #else /* !PAGE */
182: pager = "cat";
183: #endif /* !PAGE */
184: }
185: sprintf(buf, "exec %s %s", pager, tempfname);
186: (void) system(buf);
187: }
188: if (c == 'w') {
189: register int ifd, ofd, nbytes;
190: char iobuf[BUFSIZ];
191: char fname[BUFLEN];
192: getpr("Filename? ", fname);
193: if (fname[0] == '\0')
194: continue;
195: ofd = creat(fname, 0666);
196: if (ofd < 0)
197: perror(fname);
198: else {
199: ifd = open(tempfname, 0);
200: if (ifd < 0)
201: xerror("Can't reopen %s\n", tempfname);
202: while ((nbytes = read(ifd, iobuf, BUFSIZ)) > 0 )
203: write(ofd, iobuf, nbytes);
204: close(ofd);
205: close(ifd);
206: }
207: }
208: } while (!index("eps", c));
209: if (c != 'e')
210: post_article(); /* will exit if posted successfully */
211: };
212: }
213:
214: /*
215: * Find out the topic of interest.
216: */
217: get_newsgroup()
218: {
219: int n;
220: long i;
221: char canpost;
222: static int first = 1;
223:
224: printf("Newsgroups (enter one at a time, end with a blank line):\n");
225: if (first) {
226: printf("\nThe most relevant newsgroup should be the first, you should\n");
227: printf("add others only if your article really MUST be read by people\n");
228: printf("who choose not to read the appropriate group for your article.\n");
229: printf("But DO use multiple newsgroups rather than posting many times.\n\n");
230: first = 0;
231: }
232: printf("For a list of newsgroups, type ?\n");
233: n = 0;
234: newsgroups[0] = '\0';
235:
236: for(;;) {
237: getpr("> ", buf);
238: if (buf[0] == '\0')
239: if (n == 0)
240: return FALSE;
241: else
242: return TRUE;
243: if (buf[0] == '?'){
244: char *pager = getenv("PAGER");
245: char lbuf[BUFLEN];
246: if (pager == NULL) {
247: #ifdef PAGE
248: # ifdef IHCC
249: (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE);
250: # else /* !IHCC */
251: (void) strcpy(lbuf, PAGE);
252: # endif /* !IHCC */
253: pager = lbuf;
254: #else /* !PAGE */
255: pager = "cat";
256: #endif /* !PAGE */
257: }
258: printf("These are the currently active groups:\n");
259: sprintf(buf, "exec %s %s/newsgroups", pager, LIB);
260: (void) system(buf);
261: continue;
262: }
263: if (valid_ng(buf, &i, &i, &canpost)) {
264: if (n++ != 0)
265: (void) strcat(newsgroups, ngsep);
266: (void) strcat(newsgroups, buf);
267: } else {
268: if (canpost == 'n')
269: printf("You are not allowed to post to %s\n",
270: buf);
271: else
272: printf("%s is not a valid newsgroup.\n", buf);
273: }
274: }
275: }
276:
277: /*
278: * Find out how widely the author wants the message distributed.
279: */
280: get_distribution(deflt)
281: char *deflt;
282: {
283: register int i;
284: register char *r;
285: char def[BUFLEN];
286: char *lastgroup;
287:
288: lastgroup = newsgroups;
289: (void) strcpy(def, newsgroups);
290: r = index(def, NGDELIM);
291: if (r)
292: *r = '\0';
293: r = index(def, '.');
294: if (r) {
295: *r = '\0';
296: if (strcmp(def, "net") == 0)
297: (void) strcpy(def, "world");
298: } else {
299: distribution[0] = '\0';
300: return;
301: }
302:
303: if (strcmp(def, "to") == 0) {
304: /*
305: * This only works if "to.xx" is the first (or only)
306: * newsgroup, but it usually is ..
307: * Perhaps we should make the distribution be "to.xxx" ??
308: */
309: distribution[0] = '\0';
310: return; /* He's probably testing something */
311: }
312: if (deflt != (char *)0)
313: (void) strcpy(def, deflt);
314: if (ngmatch("net.test", newsgroups))
315: (void) strcpy(def, "local");
316: for(;;) {
317: do {
318: (void) sprintf(buf, "Distribution (default='%s', '?' for help) : ", def);
319: getpr(buf, distribution);
320: if (distribution[0] == '\0') {
321: if (strcmp(def, "*None*") == 0)
322: printf("You must enter a distribution, '?' for help.\n");
323: (void) strcpy(distribution, def);
324: }
325: } while (strcmp(distribution, "*None*") == 0);
326:
327: /* Did the user ask for help? */
328: if (distribution[0] == '?') {
329: printf("How widely should your article be distributed?\n\n");
330: for (i=0; distr[i].abbr[0]; i++)
331: printf("%s\t%s\n", distr[i].abbr, distr[i].descr);
332: printf("\nEnter the word that specifies the distribution that you require.\n");
333: continue;
334: }
335:
336: /* Check that it's a proper distribution */
337: for (i=0; distr[i].abbr[0]; i++) {
338: if (strncmp(distr[i].abbr, distribution, sizeof(distr[0].abbr)) == 0) {
339: register int n;
340: /* Found a match. Do any special rewriting. */
341: if (strcmp(distribution, "world") == 0)
342: strcpy(distribution, "net");
343: r = newsgroups;
344: n = strlen(distribution);
345: /*
346: * A distribution of foo is useless
347: * if all the newsgroups are in foo.all
348: */
349: for (;;) {
350: if (strncmp(r, distribution, n))
351: return;
352: if ((r = index(r, NGDELIM)) == NULL)
353: break;
354: ++r;
355: }
356: distribution[0] = '\0';
357: return;
358: }
359: }
360: if (strcmp(distribution, def) != 0)
361: printf("Type ? for help.\n");
362: else {
363: int once = TRUE;
364:
365: do {
366: r = lastgroup;
367: while (r = index(r, NGDELIM))
368: if (!prefix(++r, def))
369: break;
370: if (r == NULL) {
371: /*
372: * no newsgroups are distribution
373: * names, and user simply will
374: * not type a valid distribution,
375: * assume that the default is OK.
376: */
377: distribution[0] = '\0';
378: return;
379: }
380: lastgroup = r;
381: if (once)
382: printf("Sorry, '%s' is an unknown distribution. Type ? for help.\n", def);
383: once = FALSE;
384: strcpy(def, r);
385: r = index(def, NGDELIM);
386: if (r)
387: *r = '\0';
388: r = index(def, '.');
389: } while (r == NULL);
390: *r = '\0';
391: if (strcmp(def, "net") == 0)
392: strcpy(def, "world");
393: }
394: }
395: }
396:
397: /*
398: * Do sanity checks before the author types in the message.
399: */
400: pre_checks()
401: {
402: if (recording(newsgroups))
403: return 1;
404: return 0;
405: }
406:
407: /*
408: * Check to see if the newsgroup is moderated.
409: */
410: check_mod()
411: {
412: register FILE *fd;
413: char ng[BUFLEN], mod[BUFLEN];
414:
415: ismod = 0;
416: (void) sprintf(buf, "%s/%s", LIB, "moderators");
417: fd = xfopen(buf, "r");
418:
419: while (fgets(buf, sizeof buf, fd) != NULL) {
420: twosplit(buf, ng, mod);
421: if (ngmatch(newsgroups, ng)) {
422: (void) strcpy(moderator, mod);
423: ismod = 1;
424: }
425: }
426: (void) fclose(fd);
427: }
428:
429: /*
430: * Set up the temp file with headers.
431: */
432: prep_article()
433: {
434: FILE *tf, *of;
435: struct stat stbuf;
436:
437: (void) strcpy(tempfname, "/tmp/postXXXXXX");
438: (void) mktemp(tempfname);
439:
440: /* insert a header */
441: tf = xfopen(tempfname, "w");
442: fprintf(tf, "Subject: %s\n", subject);
443: fprintf(tf, "Newsgroups: %s\n", newsgroups);
444: if (distribution[0] != '\0')
445: fprintf(tf, "Distribution: %s\n", distribution);
446: if (ismod)
447: fprintf(tf, "To: %s\n", moderator);
448:
449: if (keywords[0] != '\0')
450: fprintf(tf, "Keywords: %s\n", keywords);
451: if (summary[0] != '\0')
452: fprintf(tf, "Summary: %s\n", summary);
453:
454: if (references[0] != '\0') {
455: fprintf(tf, "References: %s\n\n", references);
456:
457: if (askyes("Do you want to include a copy of the article? ", "no")){
458: of = xfopen(original, "r");
459: while (fgets(buf, BUFSIZ, of) != NULL)
460: if (buf[0] == '\n') /* skip headers */
461: break;
462: fprintf(tf, "In article %s, %s writes:\n", msgid, isfrom);
463: while (fgets(buf, BUFSIZ, of) != NULL)
464: fprintf(tf, "> %s", buf);
465: (void) fclose(of);
466: printf("OK, but please edit it to suppress unnecessary verbiage, signatures, etc.\n");
467: }
468: }
469:
470: fprintf(tf, "\n\n");
471: (void) fflush(tf);
472: (void) fstat(fileno(tf), &stbuf);
473: fmodtime = stbuf.st_mtime;
474: (void) fclose(tf);
475: }
476:
477: edit_article()
478: {
479: register char *p;
480: char *editor;
481: char *endflag = "";
482: char *getenv();
483:
484: /* edit the file */
485: editor = getenv("EDITOR");
486: if (editor == NULL)
487: editor = DFTEDITOR;
488:
489: p = editor + strlen(editor) - 2;
490: if (strcmp(p, "vi") == 0)
491: endflag = "+";
492:
493: (void) sprintf(buf, "A=%s;export A;exec %s %s %s",
494: original, editor, endflag, tempfname);
495:
496: (void) system(buf);
497: }
498:
499: /*
500: * Do sanity checks after the author has typed in the message.
501: */
502: post_checks()
503: {
504: char group[BUFLEN];
505: register char *c, *p;
506: struct stat stbuf;
507:
508: if (stat(tempfname, &stbuf) < 0) {
509: printf("File deleted - no message posted.\n");
510: (void) UNLINK(tempfname);
511: exit(1);
512: }
513:
514: if (stbuf.st_mtime == fmodtime || stbuf.st_size < 5) {
515: printf("File not modified - no message posted.\n");
516: (void) UNLINK(tempfname);
517: exit(1);
518: }
519:
520: /*
521: * Is this the right number? Most of the headers are yet to be added
522: */
523: if (stbuf.st_size > 65000) {
524: printf("\nYour message will probably be truncated when it\n");
525: printf("passes through a notesfile site, since it is\n");
526: printf("greater than 65000 characters.\n\n");
527: if (!askyes("Do you still want to post it? ","")) {
528: sprintf(ccname, "%s/dead.article", homedir);
529: save_article();
530: (void) UNLINK(tempfname);
531: exit(1);
532: }
533: }
534:
535: /*
536: * get the newsgroups from the edited article, in
537: * case they were altered in the editor
538: */
539: if (!article_line(tempfname, "Newsgroups: ", group)) {
540: nogroups:
541: printf("Not sending to any newsgroups - no message posted\n");
542: (void) UNLINK(tempfname);
543: exit(1);
544: }
545: c = &group[11];
546: while (*c == ' ' || *c == '\t')
547: c++;
548: if (*c == '\0')
549: goto nogroups;
550: for (p = newsgroups; *c; c++) /* copy to newsgroups, w/o blanks */
551: if (*c != ' ' && *c != '\t')
552: *p++ = *c;
553: *p = '\0';
554:
555: /* Sanity checks for certain newsgroups */
556: if (ngmatch(newsgroups, "all.wanted") && ngmatch(distribution,"net,na,usa,att,btl,eunet,aus")) {
557: printf("Is your message something that might go in your local\n");
558: printf("newspaper, for example a used car ad, or an apartment\n");
559: printf("for rent? ");
560: if (askyes("","")) {
561: printf("It's pointless to distribute your article widely, since\n");
562: printf("people more than a hundred miles away won't be interested.\n");
563: printf("Please use a more restricted distribution.\n");
564: get_distribution("*None*");
565: modify_article(tempfname, "Distribution: ", distribution,REPLACE);
566: }
567: }
568:
569: if (ngmatch(newsgroups, "all.jokes")) {
570: if (askyes("Could this be offensive to anyone? ","")) {
571: getpr("Whom might it offend? ", group);
572: (void) sprintf(buf," - offensive to %s (rot 13)",group);
573: modify_article(tempfname, "Subject: ", buf, APPEND);
574: encode(tempfname);
575: }
576: }
577:
578: if (ngmatch(newsgroups, "net.general")) {
579: if (index(newsgroups, NGDELIM)) {
580: printf("Everybody in the world reads net.general, so it doesn't make\n");
581: printf("sense to post to newsgroups in addition to net.general. If your\n");
582: printf("article belongs in one of these other newsgroups, then you\n");
583: printf("should not post to net.general. If it is important enough\n");
584: printf("for net.general, then you shouldn't post it in other places\n");
585: printf("as well. Please reenter the newsgroups.\n");
586: while (!get_newsgroup())
587: ;
588: modify_article(tempfname, "Newsgroups: ", newsgroups,REPLACE);
589: }
590: if (ngmatch(newsgroups, "net.general")) {
591: printf("net.general is for important announcements.\n");
592: printf("It is not for items for which you couldn't think\n");
593: printf("of a better place - those belong in net.misc.\n");
594: if (!askyes("Are you sure your message belongs in net.general? ","")) {
595: while (!get_newsgroup())
596: ;
597: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE);
598: }
599: }
600: }
601:
602: if (ngmatch(newsgroups, "net.sources,!net.sources.all")) {
603: if (!article_line(tempfname, "Subject: ", group)) {
604: nosubj:
605: printf("There seems to be no subject for this article.\n");
606: getpr("Subject: ", subject);
607: modify_article(tempfname, "Subject: ", subject, REPLACE);
608: } else {
609: c = &group[8];
610: while (*c == ' ' || *c == '\t')
611: c++;
612: if (*c == '\0')
613: goto nosubj;
614: strcpy(subject, c);
615: }
616: if (ngmatch(newsgroups, "all.wanted") || iswanted(subject)) {
617: printf("Requests for sources should not be posted to any of\n");
618: printf("the net.sources newsgroups, please post such requests\n");
619: printf("to net.wanted.sources only. Please reenter the newsgroups.\n\n");
620: while (!get_newsgroup())
621: ;
622: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE);
623: }
624: if (ngmatch(newsgroups, "net.sources")) {
625: if (!ngmatch(newsgroups, "net.sources.all") &&
626: stbuf.st_size < (4*1024)) {
627: printf("Your article seems rather small to be a source distribution.\n");
628: if (!askyes("Are you certain that this is really source? ", "")) {
629:
630: while (!get_newsgroup())
631: ;
632: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE);
633: }
634: }
635: if (index(newsgroups, NGDELIM)) {
636: printf("Sources should be posted to one newsgroup only.\n");
637: printf("Please pick the most appropriate group for your article.\n\n");
638: while (!get_newsgroup())
639: ;
640: modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE);
641: }
642: }
643: }
644: check_mod();
645: }
646:
647: iswanted(str)
648: register char *str;
649: {
650: while (*str == ' ')
651: str++;
652:
653: if (prefix(str, "Re:"))
654: return (FALSE);
655:
656: if (isin(str, " wanted ") || isin(str, " can any") ||
657: isin(str, " need ") || isin(str, " please ") || isin(str, " help ")
658: || isin(str, " looking ") || index(str, '?'))
659: return (TRUE);
660:
661: return (FALSE);
662: }
663:
664: isin(str, words)
665: register char *str, *words;
666: {
667: register char *p;
668: register sc, wc;
669:
670: p = words;
671: while (sc = *str++) {
672: if ((wc = *p++) == '\0')
673: return (TRUE);
674: if (wc == ' ') {
675: if (index(".,!?-; \t\n", sc))
676: continue;
677: } else {
678: if (isupper(wc))
679: wc = tolower(wc);
680: if (isupper(sc))
681: sc = tolower(sc);
682: if (wc == sc)
683: continue;
684: }
685: str -= p - words - 1;
686: p = words;
687: }
688: if (*p == '\0')
689: return (TRUE);
690: return (FALSE);
691: }
692:
693: /*
694: * Save a copy of the article in the users NEWSARCHIVE directory.
695: */
696: save_article()
697: {
698: FILE *in, *out;
699: int c;
700: time_t timenow, time();
701: char *today, *ctime();
702: struct stat stbuf;
703: char filename[BUFLEN];
704:
705: if (stat(ccname, &stbuf) == 0 && (stbuf.st_mode&S_IFMT) == S_IFDIR) {
706: /*
707: * It would be much nicer here to write articles
708: * in MH format (numbered files, in rfc822 format)
709: *
710: * one day ..
711: */
712: (void) sprintf(filename, "%s/author_copy", ccname);
713: (void) strcpy(ccname, filename);
714: }
715: in = xfopen(tempfname, "r");
716: out = xfopen(ccname, "a");
717: timenow = time((time_t)0);
718: today = ctime(&timenow);
719: fprintf(out,"From postnews %s",today);
720: while ((c=getc(in)) != EOF)
721: putc(c, out);
722: putc('\n', out);
723: (void) fclose(in);
724: (void) fclose(out);
725: }
726:
727: /*
728: * Post the article to the net.
729: */
730: post_article()
731: {
732: int status;
733:
734: printf("%s article...\n", ismod ? "Mailing" : "Posting" );
735: fflush(stdout);
736: if (ismod)
737: (void) sprintf(buf, "exec %s -t < %s", MAILPARSER, tempfname);
738: else
739: (void) sprintf(buf, "exec %s/%s -h < %s", LIB, "inews", tempfname);
740: status = system(buf);
741:
742: if (status) {
743: printf("Article not %s - exit status %d\n", ismod ? "mailed" : "posted", status);
744: return;
745: } else
746: printf("Article %s successfully.\n", ismod ? "mailed" : "posted" );
747:
748: if (ccname[0]) {
749: printf("A copy has been saved in %s\n", ccname);
750: save_article();
751: }
752:
753: (void) UNLINK(tempfname);
754: exit(0);
755: }
756:
757: /*
758: * Initialization.
759: */
760: init()
761: {
762: FILE *fd;
763: register char *p;
764: int i;
765: char *getenv();
766: struct passwd *pw;
767:
768: references[0] = '\0';
769: distribution[0] = '\0';
770:
771: uid = getuid();
772: pw = getpwuid(uid);
773: if (pw == NULL) {
774: fprintf(stderr,"You're not in /etc/passwd\n");
775: exit(1);
776: }
777: p = getenv("HOME");
778: if (p == NULL) {
779: p = getenv("LOGDIR");
780: if (p == NULL)
781: p = pw->pw_dir;
782: }
783: (void) strncpy(user, pw->pw_name, SBUFLEN);
784: (void) strcpy(homedir, p);
785:
786: p = getenv("NEWSARCHIVE");
787: if (p != NULL) {
788: if (*p == '\0')
789: sprintf(ccname, "%s/author_copy", homedir);
790: else
791: strcpy(ccname, p);
792: }
793:
794: pathinit();
795: (void) sprintf(buf, "%s/%s", LIB, "distributions");
796: fd = xfopen(buf, "r");
797: for (i=0; !feof(fd); i++) {
798: if (fgets(buf, sizeof buf, fd) == NULL)
799: break;
800: twosplit(buf, distr[i].abbr,distr[i].descr);
801: }
802: (void) fclose(fd);
803: }
804:
805: /*
806: * Split a line of the form
807: * text whitespace text
808: * into two strings. Also trim off any trailing newline.
809: * This is destructive on src.
810: */
811: twosplit(src, dest1, dest2)
812: char *src, *dest1, *dest2;
813: {
814: register char *p;
815:
816: (void) nstrip(src);
817: for (p=src; isalnum(*p) || ispunct(*p); p++)
818: ;
819: *p++ = 0;
820: for ( ; isspace(*p); p++)
821: ;
822: (void) strcpy(dest1, src);
823: (void) strcpy(dest2, p);
824: }
825:
826: /*
827: * Get a yes or no answer to a question. A default may be used.
828: */
829: askyes(msg, def)
830: char *msg, *def;
831: {
832: for(;;) {
833: printf("%s", msg);
834: buf[0] = 0;
835: (void) gets(buf);
836: switch(buf[0]) {
837: case 'y':
838: case 'Y':
839: return TRUE;
840: case 'n':
841: case 'N':
842: return FALSE;
843: case '\0':
844: switch(*def) {
845: case 'y':
846: case 'Y':
847: return TRUE;
848: case 'n':
849: case 'N':
850: return FALSE;
851: }
852: default:
853: printf("Please answer yes or no.\n");
854: }
855: }
856: }
857:
858: /*
859: * Get a character string into buf, using prompt msg.
860: */
861: getpr(msg, bptr)
862: char *msg, *bptr;
863: {
864: static int numeof = 0;
865: printf("%s", msg);
866: (void) gets(bptr);
867: (void) nstrip(bptr);
868: if (feof(stdin)) {
869: if (numeof++ > 3) {
870: fprintf(stderr,"Too many EOFs\n");
871: exit(1);
872: }
873: clearerr(stdin);
874: }
875: }
876:
877: byebye(mesg)
878: char *mesg;
879: {
880: printf("%s\n", mesg);
881: exit(1);
882: }
883:
884: /*
885: * make a modification to the header of an article
886: *
887: * fname -- name of article
888: * field -- header field to modify
889: * line -- modification line
890: * how -- APPEND or REPLACE
891: *
892: * example:
893: * modify_article("/tmp/article" , "Subject:" , "new subject" , REPLACE);
894: *
895: *
896: */
897: modify_article(fname, field, line, how)
898: char *fname, *field, *line;
899: {
900: FILE *fpart, *fptmp;
901: char *temp2fname = "/tmp/postXXXXXX";
902: char lbfr[BUFLEN];
903: register found = FALSE;
904:
905: mktemp(temp2fname);
906:
907: fptmp = xfopen(temp2fname, "w");
908: fpart = xfopen(fname, "r");
909:
910: while (fgets(lbfr, BUFLEN, fpart) != NULL) {
911: if (prefix(lbfr, field)) {
912: found = TRUE;
913: (void) nstrip(lbfr);
914: if (how == APPEND) {
915: /* append to current field */
916: (void) strcat(lbfr, line);
917: (void) strcat(lbfr, "\n");
918: } else
919: /* replace current field */
920: (void) sprintf(lbfr, "%s%s\n", field, line);
921: }
922: (void) fputs(lbfr, fptmp);
923: }
924:
925: fclose(fpart);
926: fclose(fptmp);
927:
928: fptmp = xfopen(temp2fname, "r");
929: fpart = xfopen(fname, "w");
930:
931: if (!found)
932: fprintf(fpart, "%s%s\n", field, line);
933: while (fgets(buf,BUFLEN,fptmp) != NULL)
934: (void) fputs(buf, fpart);
935:
936: (void) fclose(fpart);
937: (void) fclose(fptmp);
938: (void) UNLINK(temp2fname);
939: }
940:
941:
942: /* verify that newsgroup exists, and get number of entries */
943: valid_ng(ng, maxart, minart, canpost)
944: char *ng;
945: long *maxart, *minart;
946: char *canpost;
947: {
948: char ng_check[BUFLEN], ng_read[BUFLEN];
949: FILE *fp;
950:
951: fp = xfopen(ACTIVE, "r");
952: while (fgets(ng_read, BUFLEN, fp) != NULL) {
953: switch (sscanf(ng_read, "%s %ld %ld %c", ng_check, maxart, minart, canpost)) {
954: case 2:
955: *minart = 1;
956: /* fall through */
957: case 3:
958: *canpost = 'y';
959: /* fall through */
960: case 4:
961: break;
962:
963: default:
964: printf("Active file (%s) corrupted. ", ACTIVE);
965: byebye("Seek help!");
966: }
967:
968: if (strcmp(ng_check, ng) == 0) {
969: (void) fclose(fp);
970: if (*canpost == 'y') {
971: #ifdef FASCIST
972: if (uid && uid != ROOTID && fascist(user, ng)) {
973: *canpost = 'n';
974: return FALSE;
975: }
976: #endif FASCIST
977: return TRUE;
978: } else
979: return FALSE;
980: }
981: }
982: *canpost = 'i';
983: *maxart = 0;
984: *minart = 0;
985: (void) fclose(fp);
986: return FALSE;
987: }
988:
989: /* get the line specified by field from an article */
990: article_line(article, field, line)
991: char *article, *field, *line;
992: {
993: FILE *fp;
994: char *c;
995:
996: fp = xfopen(article,"r");
997: while ((c=fgets(line,BUFLEN,fp)) != NULL && !prefix(line, field))
998: if (line[0] == '\n') {
999: c = NULL;
1000: break;
1001: }
1002: (void) fclose(fp);
1003: if (c != NULL) {
1004: (void) nstrip(line);
1005: return TRUE;
1006: } else {
1007: line[0] = '\0';
1008: return FALSE;
1009: }
1010: }
1011:
1012: /* get the header information for a followup article */
1013: followup(baseart)
1014: register char *baseart;
1015: {
1016: register char *p;
1017:
1018: /* subject */
1019: if (article_line(baseart, "Subject: ", buf)) {
1020: p = buf+9;
1021: for ( ; ; ) {
1022: while (*p == ' ' || *p == '\t')
1023: ++p;
1024: if ((*p != 'r' && *p != 'R') ||
1025: (p[1] != 'e' && p[1] != 'E') ||
1026: (p[2] != ':' && p[2] != ' '))
1027: break;
1028: p += 3;
1029: }
1030: (void) sprintf(subject, "Re: %s", p);
1031: } else {
1032: if (article_line(baseart, "From: ", buf))
1033: (void) sprintf(subject, "Re: orphan response from %s", buf);
1034: else
1035: (void) strcpy(subject, "Re: orphan response");
1036: }
1037:
1038: /* newsgroup */
1039: if (article_line(baseart, "Newsgroups: ", buf))
1040: (void) strcpy(newsgroups, buf+12);
1041: if (ngmatch(newsgroups, "net.general"))
1042: (void) strcpy(newsgroups,"net.followup");
1043: if (ngmatch(newsgroups, "net.sources,!net.sources.all"))
1044: (void) strcpy(newsgroups,"net.sources.d");
1045: if (ngmatch(newsgroups, "net.jobs")) {
1046: printf("net.jobs is for the direct posting of job announcements and requests.\n");
1047: printf("it is not for discussion. You followup has been directed to net.misc\n");
1048: (void) strcpy(newsgroups,"net.misc");
1049: }
1050:
1051: /* moderator */
1052: check_mod();
1053:
1054: /* distribution */
1055: if (article_line(baseart, "Distribution: ", buf))
1056: (void) strcpy(distribution, buf+14);
1057:
1058: /* references */
1059: if (article_line(baseart, "References: ", buf)) {
1060: register char *rcp;
1061: (void) strcpy(references, buf+12);
1062: (void) strcat(references, " ");
1063: /* keep the number of references to a reasonable number */
1064: rcp = rindex(references, ' '); /* Can not fail */
1065: while ((int)(rcp - references) > 70) {
1066: while (*--rcp != ' ')
1067: ;
1068: rcp[1] = '\0';
1069: }
1070: }
1071: if (article_line(baseart, "Message-ID: ", buf)) {
1072: (void) strcat(references, buf+12);
1073: (void) strcpy(msgid, buf+12);
1074: }
1075:
1076: if (article_line(baseart, "From: ", buf))
1077: (void) strcpy(isfrom, buf+6);
1078:
1079: if (article_line(baseart, "Keywords: ", buf))
1080: (void) strcpy(keywords, buf+10);
1081:
1082: if (article_line(baseart, "Followup-To: ", buf)) {
1083: (void) strcpy(newsgroups, buf+13);
1084: if (strcmp(newsgroups, "poster") == 0)
1085: byebye("Mail followups directly to poster.");
1086: }
1087:
1088: get_summary();
1089: }
1090:
1091: get_summary()
1092: {
1093: register char *p;
1094: register i;
1095:
1096: printf("Please enter a short summary of your contribution to the discussion\n");
1097: printf("Just one or two lines ... (end with a blank line)\n");
1098: p = summary;
1099: for (i = 0; i < 3; i++) { /* 3 * 80 < 256, should be safe .. */
1100: getpr(">\t", p);
1101: if (*p == '\0')
1102: break;
1103: p = index(p, '\0');
1104: (void) strcpy(p, "\n\t ");
1105: p += 3;
1106: }
1107: if (p > summary)
1108: p[-3] = '\0';
1109: }
1110:
1111: encode(article)
1112: char *article;
1113: {
1114: FILE *fpart, *fphead, *fpcoded;
1115: char *headerfile = "/tmp/pheadXXXXXX";
1116: char *codedfile = "/tmp/pcodeXXXXXX";
1117:
1118: (void) mktemp(headerfile);
1119: (void) mktemp(codedfile);
1120:
1121: fpart = xfopen(article, "r");
1122:
1123: /* place article header in "headerfile" file */
1124: fphead = xfopen(headerfile, "w");
1125: while (fgets(buf, BUFLEN, fpart) != NULL) {
1126: (void) fputs(buf, fphead);
1127: if (buf[0] == '\n')
1128: break;
1129: }
1130: (void) fclose(fphead);
1131:
1132: /* place article body in "codedfile" file */
1133: fpcoded = xfopen(codedfile, "w");
1134: while (fgets(buf, BUFLEN, fpart) != NULL)
1135: (void) fputs(buf, fpcoded);
1136: (void) fclose(fpcoded);
1137: (void) fclose(fpart);
1138:
1139: /* encode body and put back together with header */
1140: (void) rename(headerfile, article);
1141:
1142: (void) sprintf(buf,"exec %s/%s 13 < %s >> %s\n", LIB, "caesar", codedfile, article);
1143: printf("Encoding article -- please stand by\n");
1144: if (system(buf)) {
1145: printf("encoding failed");
1146: exit(2);
1147: }
1148: (void) UNLINK(codedfile);
1149: }
1150:
1151:
1152: /*
1153: * Print a recorded message warning the poor luser what he is doing
1154: * and demand that he understands it before proceeding. Only do
1155: * this for newsgroups listed in LIBDIR/recording.
1156: */
1157: recording(ngrps)
1158: char *ngrps;
1159: {
1160: char recbuf[BUFLEN];
1161: FILE *fd;
1162: char nglist[BUFLEN], fname[BUFLEN];
1163: int c, n, yes, retval = 0;
1164:
1165: (void) sprintf(recbuf, "%s/%s", LIB, "recording");
1166: fd = fopen(recbuf, "r");
1167: if (fd == NULL)
1168: return 0;
1169: while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) {
1170: (void) sscanf(recbuf, "%s %s", nglist, fname);
1171: if (ngmatch(ngrps, nglist)) {
1172: (void) fclose(fd);
1173: if (fname[0] == '/')
1174: (void) strcpy(recbuf, fname);
1175: else
1176: (void) sprintf(recbuf, "%s/%s", LIB, fname);
1177: fd = fopen(recbuf, "r");
1178: if (fd == NULL)
1179: return 0;
1180: while ((c = getc(fd)) != EOF)
1181: putc(c, stderr);
1182: fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: ");
1183: n = read(2, recbuf, 100);
1184: c = recbuf[0];
1185: yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0);
1186: if (n <= 0 || !yes)
1187: retval = -1;
1188: }
1189: }
1190: return retval;
1191: }
1192:
1193: xxit(i)
1194: {
1195: exit(i);
1196: }
1197:
1198: #if !defined(BSD4_2) && !defined(BSD4_1C)
1199: rename(from,to)
1200: register char *from, *to;
1201: {
1202: (void) unlink(to);
1203: if (link(from, to) < 0)
1204: return -1;
1205:
1206: (void) unlink(from);
1207: return 0;
1208: }
1209: #endif /* !BSD4_2 && ! BSD4_1C */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.