|
|
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: * inews - insert, receive, and transmit news articles.
16: *
17: */
18:
19: #ifdef SCCSID
20: static char *SccsId = "@(#)inews.c 2.61 3/19/86";
21: #endif /* SCCSID */
22:
23: #include "iparams.h"
24: #include <errno.h>
25:
26: /* local defines for inews */
27:
28: #define OPTION 0 /* pick up an option string */
29: #define STRING 1 /* pick up a string of arguments */
30:
31: #define UNKNOWN 0001 /* possible modes for news program */
32: #define UNPROC 0002 /* Unprocessed input */
33: #define PROC 0004 /* Processed input */
34: #define CANCEL 0010 /* Cancel an article */
35: #define CREATENG 0020 /* Create a new newsgroup */
36:
37: char forgedname[NAMELEN]; /* A user specified -f option. */
38: extern char histline[];
39: /* Fake sys line in case they forget their own system */
40: struct srec dummy_srec = { "MEMEME", "", "all", "", "" };
41:
42: char *Progname = "inews"; /* used by xerror to identify failing program */
43:
44: struct { /* options table. */
45: char optlet; /* option character. */
46: char filchar; /* if to pickup string, fill character. */
47: int flag; /* TRUE if have seen this opt. */
48: int oldmode; /* OR of legal input modes. */
49: int newmode; /* output mode. */
50: char *buf; /* string buffer */
51: } *optpt, options[] = { /*
52: optlet filchar flag oldmode newmode buf */
53: 't', ' ', FALSE, UNPROC, UNKNOWN, header.title,
54: 'n', NGDELIM, FALSE, UNPROC, UNKNOWN, header.nbuf,
55: 'd', '\0', FALSE, UNPROC, UNKNOWN, header.distribution,
56: 'e', ' ', FALSE, UNPROC, UNKNOWN, header.expdate,
57: 'p', '\0', FALSE, UNKNOWN,PROC, filename,
58: 'f', '\0', FALSE, UNPROC, UNKNOWN, forgedname,
59: 'F', ' ', FALSE, UNPROC, UNKNOWN, header.followid,
60: 'c', '\0', FALSE, UNKNOWN,CANCEL, filename,
61: 'C', '\0', FALSE, UNKNOWN,CREATENG, header.nbuf,
62: #define hflag options[9].flag
63: 'h', '\0', FALSE, UNPROC, UNKNOWN, filename,
64: #define oflag options[10].flag
65: 'o', '\0', FALSE, UNPROC, UNKNOWN, header.organization,
66: #define Mflag options[11].flag
67: 'M', '\0', FALSE, UNPROC, UNKNOWN, filename,
68: 'a', '\0', FALSE, UNPROC, UNKNOWN, header.approved,
69: '\0', '\0', 0, 0, 0, (char *)NULL
70: };
71:
72: FILE *mailhdr();
73: char *genversion();
74: extern int errno;
75:
76: /*
77: * Authors:
78: * Matt Glickman [email protected]
79: * Mark Horton [email protected]
80: * Stephen Daniels [email protected]
81: * Tom Truscott [email protected]
82: * IHCC version adapted by:
83: * Larry Marek [email protected]
84: */
85: main(argc, argv)
86: int argc;
87: register char **argv;
88: {
89: int state; /* which type of argument to pick up */
90: int tlen, len; /* temps for string processing routine */
91: register char *ptr; /* pointer to rest of buffer */
92: int filchar; /* fill character (state = STRING) */
93: char *user = NULL, *home = NULL; /* environment temps */
94: struct passwd *pw; /* struct for pw lookup */
95: struct group *gp; /* struct for group lookup */
96: register int i;
97: FILE *mfd; /* mail file file-descriptor */
98: char cbuf[BUFLEN]; /* command buffer */
99:
100: /* uuxqt doesn't close all it's files */
101: for (i = 3; !close(i); i++)
102: ;
103: /* set up defaults and initialize. */
104: mode = UNKNOWN;
105: pathinit();
106: ptr = rindex(*argv, '/');
107: if (!ptr)
108: ptr = *argv - 1;
109: if (!strncmp(ptr+1, "rnews", 5)) {
110: mode = PROC;
111: #ifdef NICENESS
112: nice(NICENESS);
113: #endif /* NICENESS */
114: } else if (argc < 2)
115: goto usage;
116:
117: state = OPTION;
118: header.title[0] = header.nbuf[0] = filename[0] = '\0';
119:
120: /* check for existence of special files */
121: if (!rwaccess(ARTFILE)) {
122: mfd = mailhdr((struct hbuf *)NULL, exists(ARTFILE) ? "Unwritable files!" : "Missing files!");
123: if (mfd != NULL) {
124: #ifdef HIDDENNET
125: fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE);
126: #else /* !HIDDENNET */
127: fprintf(mfd,"System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ARTFILE);
128: #endif /* !HIDDENNET */
129: (void) sprintf(cbuf, "touch %s;chmod 666 %s", ARTFILE, ARTFILE);
130: (void) system(cbuf);
131: if (rwaccess(ARTFILE))
132: fprintf(mfd, "The problem has been taken care of.\n");
133: else
134: fprintf(mfd, "Corrective action failed - check suid bits.\n");
135: (void) mclose(mfd);
136: }
137: }
138: if (!rwaccess(ACTIVE)) {
139: mfd = mailhdr((struct hbuf *)NULL, exists(ACTIVE) ? "Unwritable files!" : "Missing files!");
140: if (mfd != NULL) {
141: #ifdef HIDDENNET
142: fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE);
143: #else /* !HIDDENNET */
144: fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ACTIVE);
145: #endif /* !HIDDENNET */
146: (void) sprintf(cbuf, "touch %s;chmod 666 %s", ACTIVE, ACTIVE);
147: (void) system(cbuf);
148: if (rwaccess(ACTIVE))
149: fprintf(mfd, "The problem has been taken care of.\n");
150: else
151: fprintf(mfd, "Corrective action failed - check suid bits.\n");
152: (void) mclose(mfd);
153: }
154: }
155: SigTrap = FALSE; /* true if a signal has been caught */
156: if (mode != PROC) {
157: (void) signal(SIGHUP, onsig);
158: (void) signal(SIGINT, onsig);
159: }
160: savmask = umask(N_UMASK); /* set up mask */
161: uid = getuid();
162: gid = getgid();
163: duid = geteuid();
164: dgid = getegid();
165: if (uid == 0 && duid == 0) {
166: /*
167: * Must go through with this kludge since
168: * some systems do not honor the setuid bit
169: * when root invokes a setuid program.
170: */
171: if ((pw = getpwnam(NEWSUSR)) == NULL)
172: xerror("Cannot get NEWSU pw entry");
173:
174: duid = pw->pw_uid;
175: if ((gp = getgrnam(NEWSGRP)) == NULL)
176: xerror("Cannot get NEWSG gr entry");
177: dgid = gp->gr_gid;
178: (void) setgid(dgid);
179: (void) setuid(duid);
180: }
181:
182: #ifndef IHCC
183: /*
184: * We force the use of 'getuser()' to prevent forgery of articles
185: * by just changing $LOGNAME
186: */
187: if (isatty(fileno(stderr))) {
188: if ((user = getenv("USER")) == NULL)
189: user = getenv("LOGNAME");
190: if ((home = getenv("HOME")) == NULL)
191: home = getenv("LOGDIR");
192: }
193: #endif
194: if (user == NULL || home == NULL)
195: getuser();
196: else {
197: if (username == NULL || username[0] == 0) {
198: username = AllocCpy(user);
199: }
200: userhome = AllocCpy(home);
201: }
202: getuser();
203:
204: /* loop once per arg. */
205:
206: ++argv; /* skip first arg, which is prog name. */
207:
208: while (--argc) {
209: if (state == OPTION) {
210: if (**argv != '-') {
211: xerror("Bad option string \"%s\"", *argv);
212: }
213: while (*++*argv != '\0') {
214: for (optpt = options; optpt->optlet != '\0'; ++optpt) {
215: if (optpt->optlet == **argv)
216: goto found;
217: }
218: /* unknown option letter */
219: usage:
220: fprintf(stderr, "usage: inews -t title");
221: fprintf(stderr, " [ -n newsgroups ]");
222: fprintf(stderr, " [ -e expiration date ]\n");
223: fprintf(stderr, "\t[ -f sender]\n\n");
224: xxit(1);
225:
226: found:;
227: if (optpt->flag == TRUE || (mode != UNKNOWN &&
228: (mode&optpt->oldmode) == 0)) {
229: xerror("Bad %c option", **argv);
230: }
231: if (mode == UNKNOWN)
232: mode = optpt->newmode;
233: filchar = optpt->filchar;
234: optpt->flag = TRUE;
235: state = STRING;
236: ptr = optpt->buf;
237: len = BUFLEN;
238: }
239:
240: argv++; /* done with this option arg. */
241:
242: } else {
243:
244: /*
245: * Pick up a piece of a string and put it into
246: * the appropriate buffer.
247: */
248: if (**argv == '-') {
249: state = OPTION;
250: argc++; /* uncount this arg. */
251: continue;
252: }
253:
254: if ((tlen = strlen(*argv)) >= len)
255: xerror("Argument string too long");
256: (void) strcpy(ptr, *argv++);
257: ptr += tlen;
258: if (*(ptr-1) != filchar)
259: *ptr++ = filchar;
260: len -= tlen + 1;
261: *ptr = '\0';
262: }
263: }
264:
265: /*
266: * ALL of the command line has now been processed. (!)
267: */
268:
269: tty = isatty(fileno(stdin));
270:
271: /* This code is really intended to be replaced by the control message. */
272: if (mode == CANCEL) {
273: char *p; FILE *f;
274: f = xfopen(filename, "r");
275: (void) hread(&header, f, TRUE);
276: p = index(header.path, ' ');
277: if (p != NULL)
278: *p = 0;
279: p = header.path;
280: if (strncmp(username, p, strlen(username))
281: && uid != ROOTID && uid != geteuid() && uid)
282: xerror("Not contributor");
283: cancel();
284: xxit(0);
285: }
286:
287: if (*header.nbuf) {
288: lcase(header.nbuf);
289: ptr = index(header.nbuf, '\0');
290: if (ptr[-1] == NGDELIM)
291: *--ptr = '\0';
292: }
293: (void) nstrip(header.title);
294: (void) nstrip(header.expdate);
295: (void) nstrip(header.followid);
296: if (mode != PROC) {
297: getident(&header);
298: if (hflag) {
299: header.path[0] = '\0';
300: (void) hread(&header, stdin, FALSE);
301: /* there are certain fields we won't let him specify. */
302: if (header.from[0])
303: (void) strcpy(forgedname, header.from);
304: if (!header.approved[0])
305: Mflag = FALSE;
306: header.from[0] = '\0';
307: header.subdate[0] = '\0';
308: header.sender[0] = '\0';
309: }
310: #ifdef MYORG
311: if (header.organization[0] == '\0' && !Mflag) {
312: strncpy(header.organization, MYORG, BUFLEN);
313: if (strncmp(header.organization, "Frobozz", 7) == 0)
314: header.organization[0] = '\0';
315: if (ptr = getenv("ORGANIZATION"))
316: strncpy(header.organization, ptr, BUFLEN);
317: /*
318: * Note that the organization can also be turned off by
319: * setting it to the null string, either in MYORG or
320: * $ORGANIZATION in the environment.
321: */
322: if (header.organization[0] == '/') {
323: mfd = fopen(header.organization, "r");
324: if (mfd) {
325: (void) fgets(header.organization, sizeof header.organization, mfd);
326: (void) fclose(mfd);
327: } else {
328: header.organization[0] = '\0';
329: logerr("Couldn't open %s",
330: header.organization);
331: }
332: ptr = index(header.organization, '\n');
333: if (ptr)
334: *ptr = '\0';
335: }
336: }
337: #endif /* MYORG */
338: if (forgedname[0]) {
339: register char *p1;
340: if (Mflag)
341: sprintf(header.path, "%s!%s",
342: FULLSYSNAME, username);
343: else if (!header.path[0]) {
344: (void) strcpy(header.path, forgedname);
345:
346: if ((p1 = strpbrk(header.path, "@ (<")) != NULL)
347: *p1 = '\0';
348: }
349: if (!Mflag && !strpbrk(forgedname, "@ (<"))
350: (void) sprintf(header.from,"%s@%s%s",
351: forgedname, FULLSYSNAME, MYDOMAIN);
352: else
353: (void) strncpy(header.from, forgedname, BUFLEN);
354:
355: (void) sprintf(header.sender, "%s@%s%s",
356: username, FULLSYSNAME, MYDOMAIN);
357: } else {
358: gensender(&header, username);
359: }
360: }
361:
362: /* Authorize newsgroups. */
363: if (mode == PROC) {
364: #ifdef BATCH
365: checkbatch();
366: #endif /* BATCH */
367: (void) signal(SIGHUP, SIG_IGN);
368: (void) signal(SIGINT, SIG_IGN);
369: (void) signal(SIGQUIT, SIG_IGN);
370: header.ident[0] = '\0';
371: if (hread(&header, stdin, TRUE) == NULL)
372: xerror("Inbound news is garbled");
373: input();
374: if (history(&header)) {
375: log("Duplicate article %s rejected. Path: %s",
376: header.ident, header.path);
377: xxit(0);
378: }
379: }
380:
381: /* Easy way to make control messages, since all.all.ctl is unblessed */
382: if (mode != PROC && prefix(header.title, "cmsg ") && header.ctlmsg[0] == 0)
383: (void) strcpy(header.ctlmsg, &header.title[5]);
384: is_ctl = mode != CREATENG &&
385: (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]);
386: #ifdef DEBUG
387: fprintf(stderr,"is_ctl set to %d\n", is_ctl);
388: #endif
389:
390: /* Must end in comma (NGDELIM) */
391: #define MODGROUPS "mod.all,all.mod,all.announce,"
392: if (ngmatch(header.nbuf, MODGROUPS) && !header.approved[0]) {
393: mfd = mailhdr(&header, "Moderated newsgroup");
394: if (mfd) {
395: fprintf(mfd, "This newsgroup is moderated, and cannot be posted to directly.\n");
396: fprintf(mfd, "Please mail your article to the moderator for posting.\n");
397: hwrite(&header, mfd);
398: if (infp)
399: while ((i = getc(infp)) != EOF)
400: putc(i, mfd);
401: (void) mclose(mfd);
402: }
403: xerror("Unapproved moderated newsgroup.");
404: }
405:
406: if (mode != CREATENG) {
407: if (!*header.title)
408: xerror("No title, ng %s from %s", header.nbuf,
409: header.from);
410: if (!*header.nbuf)
411: (void) strcpy(header.nbuf, DFLTNG);
412: }
413:
414: if (mode <= UNPROC) {
415: #ifdef FASCIST
416: if (uid && uid != ROOTID && fascist(user, header.nbuf))
417: xerror("User %s is not authorized to post to newsgroup %s", user, header.nbuf);
418: #endif /* FASCIST */
419: ctlcheck();
420: }
421:
422: if (mode == CREATENG)
423: createng();
424: /* Determine input. */
425: if (mode != PROC)
426: input();
427:
428: /* Do the actual insertion. */
429: insert();
430: }
431:
432: /*
433: * Create a newsgroup
434: */
435: createng()
436: {
437:
438: /*
439: * Only certain users are allowed to create newsgroups
440: */
441: if (uid != ROOTID && uid != geteuid() && uid) {
442: fprintf(stderr, "Please contact one of the local netnews people\n\tto create this group for you");
443: xxit(1);
444: }
445:
446: (void) sprintf(bfr, "%s/inews -n %s.ctl -t cmsg newgroup %s -d local",
447: LIB, header.nbuf, header.nbuf);
448: printf("Please type in a paragraph describing the new newsgroup.\n");
449: printf("End with control D as usual.\n");
450: printf("%s\n", bfr);
451: (void) fflush(stdout);
452: (void) system(bfr);
453: exit(0);
454: /*NOTREACHED*/
455: }
456:
457: char firstbufname[BUFLEN];
458: /*
459: * Link ARTICLE into dir for ngname and update active file.
460: */
461: long
462: localize(ngname)
463: char *ngname;
464: {
465: char afline[BUFLEN];
466: long ngsize;
467: long fpos;
468: int e;
469: char *cp;
470:
471: lock();
472: actfp = xfopen(ACTIVE, "r+");
473:
474: for(;;) {
475: fpos = ftell(actfp);
476: if (fgets(afline, sizeof afline, actfp) == NULL) {
477: unlock();
478: (void) fclose(actfp);
479: logerr("Can't fine \"%s\" in active file", ngname);
480: return FALSE; /* No such newsgroup locally */
481: }
482: if (prefix(afline, ngname)) {
483: (void) sscanf(afline, "%s %ld", bfr, &ngsize);
484: if (strcmp(bfr, ngname) == 0) {
485: if (ngsize < 0 || ngsize > 99998) {
486: logerr("found bad ngsize %ld ng %s, setting to 1", ngsize, bfr);
487: ngsize = 1;
488: }
489: break;
490: }
491: }
492: }
493: for (;;) {
494: cp = dirname(ngname);
495: if (!exists(cp))
496: mknewsg(cp, ngname);
497:
498: (void) sprintf(bfr, "%s/%ld", cp, ngsize+1);
499: #ifdef VMS
500: if (vmslink(ARTICLE, bfr) == 0)
501: break;
502: #else /* !VMS */
503: if (link(ARTICLE, bfr) == 0)
504: break;
505: #endif /* !VMS */
506: e = errno; /* keep log from clobbering it */
507: log("Cannot install article as %s: %s", bfr, errmsg(errno));
508: if (e != EEXIST) {
509: logerr("Link into %s failed (%s); check dir permissions.",
510: bfr, errmsg(e));
511: unlock();
512: (void) fclose(actfp);
513: return FALSE;
514: }
515: ngsize++;
516: }
517:
518: (void) fflush(actfp);
519: #ifdef VMS
520: (void) fclose(actfp);
521: vmstounix(ACTIVE);
522: actfp = fopen(ACTIVE, "r+");
523: #endif /* VMS */
524:
525: /*
526: * This works around a bug in the 4.1bsd stdio
527: * on fseeks to non even offsets in r+w files
528: */
529: if (fpos&1)
530: (void) rewind(actfp);
531:
532: (void) fseek(actfp, fpos, 0);
533: /* Has to be same size as old because of %05d.
534: * This will overflow with 99999 articles.
535: */
536: fprintf(actfp, "%s %05ld", ngname, ngsize+1);
537: if (ferror(actfp))
538: xerror("Active file write failed");
539: (void) fclose(actfp);
540: #ifdef VMS
541: unixtovms(ACTIVE);
542: #endif /* VMS */
543: unlock();
544: if (firstbufname[0] == '\0')
545: (void) strcpy(firstbufname, bfr);
546: (void) sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
547: addhist(bfr);
548: return ngsize+1;
549: }
550:
551: /*
552: * Localize for each newsgroup and broadcast.
553: */
554: insert()
555: {
556: register char *ptr;
557: register FILE *tfp;
558: register int c;
559: struct srec srec; /* struct for sys file lookup */
560: struct tm *tm;
561: int is_invalid = FALSE;
562: int exitcode = 0;
563: long now;
564: #ifdef DOXREFS
565: register char *nextref = header.xref;
566: #endif /* DOXREFS */
567:
568: /* Fill up the rest of header. */
569: if (mode != PROC) {
570: history(&header);
571: }
572: dates(&header);
573: (void) time(&now);
574: tm = localtime(&now);
575: if (header.expdate[0])
576: addhist(" ");
577: #ifdef USG
578: sprintf(bfr,"%2.2d/%2.2d/%d %2.2d:%2.2d\t",
579: #else /* !USG */
580: sprintf(bfr,"%02d/%02d/%d %02d:%02d\t",
581: #endif /* !USG */
582: tm->tm_mon+1, tm->tm_mday, tm->tm_year,tm->tm_hour, tm->tm_min);
583: addhist(bfr);
584: log("%s %s ng %s subj '%s' from %s",
585: mode==PROC ? "received" : "posted",
586: header.ident, header.nbuf, header.title, header.from);
587:
588: /* Clean up Newsgroups: line */
589: if (!is_ctl && mode != CREATENG)
590: is_invalid = ngfcheck(mode == PROC);
591:
592: /* Write article to temp file. */
593: tfp = xfopen(mktemp(ARTICLE), "w");
594:
595: if (is_invalid) {
596: logerr("No valid newsgroups found, moved to junk");
597: if (localize("junk"))
598: savehist(histline);
599: exitcode = 1;
600: goto writeout;
601: }
602:
603: if (time((time_t *)0) > (cgtdate(header.subdate) + HISTEXP) ){
604: logerr("Article too old, moved to junk");
605: if (localize("junk"))
606: savehist(histline);
607: exitcode = 1;
608: goto writeout;
609: }
610:
611: if (is_ctl) {
612: exitcode = control(&header);
613: if (localize("control") && exitcode != 0)
614: savehist(histline);
615: } else {
616: if (s_find(&srec, FULLSYSNAME) == FALSE) {
617: logerr("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE);
618: srec = dummy_srec;
619: }
620: #ifdef DOXREFS
621: (void) strncpy(nextref, FULLSYSNAME, BUFLEN);
622: #endif /* DOXREFS */
623: for (ptr = nbuf; *ptr;) {
624: if (ngmatch(ptr,srec.s_nbuf) || index(ptr,'.') == NULL){
625: #ifdef DOXREFS
626: while (*nextref++)
627: ;
628: (void) sprintf(--nextref, " %s:%ld", ptr, localize(ptr));
629: #else /* !DOXREFS */
630: (void) localize(ptr);
631: #endif /* !DOXREFS */
632: }
633: while (*ptr++)
634: ;
635: }
636: if (firstbufname[0] == '\0') {
637: logerr("Newsgroups in active, but not sys");
638: (void) localize("junk");
639: }
640: }
641: #ifdef DOXREFS
642: if (index(header.nbuf, NGDELIM) == NULL)
643: header.xref[0] = '\0';
644: #endif /* DOXREFS */
645:
646: writeout:
647: /* Part 1 of kludge to get around article truncation problem */
648: if ( (c=getc(infp)) != EOF) {
649: ungetc(c, infp);
650: if (c == ' ' || c == '\t') {
651: header.intnumlines++;
652: (void) sprintf(header.numlines, "%d",
653: header.intnumlines);
654: }
655: }
656: /* End of part 1 */
657: lhwrite(&header, tfp);
658: if ((c = getc(infp)) != EOF) {
659: /* Part 2 of kludge to get around article truncation problem */
660: if (c == ' ' || c == '\t' )
661: putc('\n', tfp);
662: /* End of part 2 */
663: ungetc(c, infp);
664: while (fgets(bfr, BUFLEN, infp) != NULL)
665: fputs(bfr, tfp);
666: if (bfr[strlen(bfr)-1] != '\n')
667: putc('\n',tfp);
668: }
669: if (ferror(tfp))
670: xerror("Write failed for temp file");
671: (void) fclose(tfp);
672: (void) fclose(infp);
673:
674: if(exitcode == 0) {
675: int pid;
676: /* article has passed all the checks, so work in background */
677: if (mode != PROC)
678: if ((pid=fork()) < 0)
679: xerror("Can't fork");
680: else if (pid > 0)
681: exit(0);
682: #ifdef SIGTTOU
683: signal(SIGTTOU, SIG_IGN);
684: #endif /* SIGTTOU */
685: savehist(histline);
686: broadcast();
687: }
688: xxit(mode == PROC ? 0 : exitcode);
689: }
690:
691: input()
692: {
693: register char *cp;
694: register int c;
695: register int empty = TRUE;
696: FILE *tmpfp;
697: int consec_newlines = 0;
698: int linecount = 0;
699: int linserted = 0;
700:
701: tmpfp = xfopen(mktemp(INFILE), "w");
702: if (*filename) {
703: tty = FALSE;
704: infp = xfopen(filename, "r");
705: } else {
706: infp = stdin;
707: }
708: while (!SigTrap && fgets(bfr, BUFLEN, stdin) != NULL) {
709: if (mode == PROC) { /* zap trailing empty lines */
710: #ifdef ZAPNOTES
711: if (empty && bfr[0] == '#' && bfr[2] == ':'
712: && header.nf_id[0] == '\0'
713: && header.nf_from[0] == '\0' ) {
714: (void) strcpy(header.nf_id, bfr);
715: (void) nstrip(header.nf_id);
716: (void) fgets(bfr, BUFLEN, stdin);
717: (void) strcpy(header.nf_from, bfr);
718: (void) nstrip(header.nf_from);
719: (void) fgets(bfr, BUFLEN, stdin);
720:
721: if (header.numlines[0]) {
722: header.intnumlines -= 2;
723: (void) sprintf(header.numlines, "%d", header.intnumlines);
724: }
725:
726: /* Strip trailing " - (nf)" */
727: if ((cp = rindex(header.title, '-')) != NULL
728: && !strcmp(--cp, " - (nf)"))
729: *cp = '\0';
730: log("Stripped notes header on %s", header.ident);
731: continue;
732: }
733: #endif /* ZAPNOTES */
734: if (bfr[0] == '\n' ||
735: /* Bandage for older versions of inews */
736: bfr[1] == '\n' && !isascii(bfr[0])) {
737: consec_newlines++; /* count it, in case */
738: continue; /* but don't write it*/
739: }
740: /* foo! a non-empty line. write out all saved lines. */
741: while (consec_newlines > 0) {
742: putc('\n', tmpfp);
743: consec_newlines--;
744: linecount++;
745: }
746: }
747: if (mode != PROC && tty && strcmp(bfr, ".\n") == 0)
748: break;
749: for (cp = bfr; c = toascii(*cp); cp++) {
750: if (isprint(c) || isspace(c) || c == '\b')
751: putc(c, tmpfp);
752: if (c == '\n')
753: linecount++;
754: }
755: if (bfr[0] == '>')
756: linserted++;
757: empty = FALSE;
758: }
759: if (*filename)
760: (void) fclose(infp);
761: if (mode != PROC && linserted > (linecount-linserted))
762: xerror("Article rejected: More included text than new text");
763:
764: if (mode != PROC && !is_ctl && header.sender[0] == '\0') {
765: int siglines = 0;
766: char sbuf[BUFLEN];
767: (void) sprintf(bfr, "%s/%s", userhome, ".signature");
768: if (access(bfr, 4) == 0) {
769: if ((infp = fopen(bfr, "r")) == NULL) {
770: (void) fprintf(stderr,
771: "inews: \"%s\" left off (must be readable by \"inews\" owner)\n", bfr);
772: goto finish;
773: }
774:
775: while (fgets(sbuf, sizeof sbuf, infp) != NULL)
776: if (++siglines > 4)
777: break;
778: if (siglines > 4)
779: fprintf(stderr,".signature not included (> 4 lines)\n");
780: else {
781: rewind(infp);
782: fprintf(tmpfp, "-- \n"); /* To separate */
783: linecount++;
784: while ((c = getc(infp)) != EOF) {
785: putc(c, tmpfp);
786: if (c == '\n')
787: linecount++;
788: }
789: }
790: (void) fclose(infp);
791: }
792: }
793:
794: finish:
795: if (ferror(tmpfp))
796: xerror("write failed to temp file");
797: (void) fclose(tmpfp);
798: if (SigTrap) {
799: if (tty)
800: fprintf(stderr, "Interrupt\n");
801: if (tty && !empty)
802: fwait(fsubr(newssave, (char *) NULL, (char *) NULL));
803: if (!tty)
804: log("Blown away by an interrupt %d", SigTrap);
805: xxit(1);
806: }
807: if (tty)
808: fprintf(stderr, "EOT\n");
809: fflush(stdout);
810: infp = fopen(INFILE, "r");
811: if (header.numlines[0]) {
812: /*
813: * Check line count if there's already one attached to
814: * the article. Could make this a fatal error -
815: * throwing it away if it got chopped, in hopes that
816: * another copy will come in later with a correct
817: * line count. But that seems a bit much for now.
818: */
819: if (linecount != header.intnumlines) {
820: if (linecount == 0)
821: xerror("%s rejected. linecount expected %d, got 0", header.ident, header.intnumlines);
822: if (linecount > header.intnumlines ||
823: linecount+consec_newlines < header.intnumlines)
824: log("linecount expected %d, got %d", header.intnumlines, linecount+consec_newlines);
825: }
826: /* adjust count for blank lines we stripped off */
827: if (consec_newlines) {
828: header.intnumlines -= consec_newlines;
829: if (header.intnumlines < 0 )
830: header.intnumlines = 0; /* paranoia */
831: (void) sprintf(header.numlines, "%d", header.intnumlines);
832: }
833:
834: } else {
835: /* Attach a line count to the article. */
836: header.intnumlines = linecount;
837: (void) sprintf(header.numlines, "%d", linecount);
838: }
839: }
840:
841: /*
842: * Make the directory for a new newsgroup. ngname should be the
843: * full pathname of the directory. Do the other stuff too.
844: * The various games with setuid and chown are to try to make sure
845: * the directory is owned by NEWSUSR and NEWSGRP, which is tough to
846: * do if you aren't root. This will work on a UCB system (which allows
847: * setuid(geteuid()) or a USG system (which allows you to give away files
848: * you own with chown), otherwise you have to change your kernel to allow
849: * one of these things or run with your dirs 777 so that it doesn't matter
850: * who owns them.
851: */
852: mknewsg(fulldir, ngname)
853: char *fulldir;
854: char *ngname;
855: {
856: #ifdef USG
857: register char *p;
858: char parent[200];
859: char sysbuf[200];
860: struct stat sbuf;
861: #endif /* USG */
862:
863: if (ngname == NULL || !isalpha(ngname[0]))
864: xerror("Tried to make illegal newsgroup %s", ngname);
865:
866: #ifdef USG
867: /*
868: * If the parent is 755 the setuid(getuid)
869: * will fail, and since mkdir is suid, and our real uid is random,
870: * the mkdir will fail. So we have to temporarily chmod it to 777.
871: */
872: (void) strcpy(parent, fulldir);
873: while (p = rindex(parent, '/')) {
874: *p = '\0';
875: if (stat(parent, &sbuf) == 0) {
876: (void) chmod(parent, 0777);
877: break;
878: }
879: }
880: #endif /* USG */
881:
882: /* Create the directory */
883: mkparents(fulldir);
884: if (mkdir(fulldir, 0777) < 0)
885: xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno));
886:
887: #ifdef USG
888: (void) chmod(parent, (int)sbuf.st_mode); /* put it back */
889: /*
890: * Give away the directories we just created which were assigned
891: * our real uid.
892: */
893: (void) setuid(uid);
894: (void) chown(fulldir, duid, dgid);
895: (void) strcpy(sysbuf, fulldir);
896: while (p = rindex(sysbuf, '/')) {
897: *p = '\0';
898: /* stop when get to last known good parent */
899: if (strcmp(sysbuf, parent) == 0)
900: break;
901: (void) chown(sysbuf, duid, dgid);
902: }
903: (void) setuid(duid);
904: #endif /* USG */
905:
906: log("make newsgroup %s in dir %s", ngname, fulldir);
907: }
908:
909: /*
910: * If any parent directories of this dir don't exist, create them.
911: */
912: mkparents(dname)
913: char *dname;
914: {
915: char buf[200];
916: register char *p;
917:
918: (void) strcpy(buf, dname);
919: p = rindex(buf, '/');
920: if (p)
921: *p = '\0';
922: if (exists(buf))
923: return;
924: mkparents(buf);
925: if (mkdir(buf, 0777) < 0)
926: xerror("Can not mkdir %s: %s", buf, errmsg(errno));
927: }
928:
929: cancel()
930: {
931: register FILE *fp;
932:
933: log("cancel article %s", filename);
934: fp = fopen(filename, "r");
935: if (fp == NULL) {
936: log("article %s not found", filename);
937: return;
938: }
939: if (hread(&header, fp, TRUE) == NULL)
940: xerror("Article is garbled.");
941: (void) fclose(fp);
942: (void) unlink(filename);
943: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.