sources-request@mirror.UUCP (11/06/86)
Submitted by: seismo!rick (Rick Adams) Mod.sources: Volume 7, Issue 53 Archive-name: 2.11news/Part14 # To extract, sh this file # # news 2.11 source part 4 of 9 # if test ! -d src then mkdir src fi echo x - src/postnews.c 1>&2 sed 's/.//' >src/postnews.c <<'*-*-END-of-src/postnews.c-*-*' -/* - * This software is Copyright (c) 1986 by Rick Adams. - * - * Permission is hereby granted to copy, reproduce, redistribute or - * otherwise use this software as long as: there is no monetary - * profit gained specifically from the use or reproduction or this - * software, it is not sold, rented, traded or otherwise marketed, and - * this copyright notice is included prominently in any copy - * made. - * - * The author make no claims as to the fitness or correctness of - * this software for any use whatsoever, and it is provided as is. - * Any use of this software is at the user's own risk. - * - * Postnews: post a news message to Usenet. This C version replaces a shell - * script, and does more intelligent prompting and filtering than possible - * in a shell script. - */ - -#ifdef SCCSID -static char *SccsId = "@(#)postnews.c 1.28 10/23/86"; -#endif /* SCCSID */ - -#include "params.h" - -#define APPEND 1 -#define REPLACE 2 - -extern char *MAILPARSER; - -char tempfname[50]; /* file name used for making article */ -char original[BUFLEN]; /* file name of original, used in followup */ -char homedir[BUFLEN]; /* HOME environment setting */ -char user[SBUFLEN]; /* user name */ -char ccname[BUFLEN]; /* file name for article copy */ - -/* article header information */ -char subject[BUFLEN]; -char distribution[BUFLEN]; -char references[BUFLEN]; -char newsgroups[BUFLEN]; -char isfrom[BUFLEN]; -char msgid[BUFLEN]; -char keywords[BUFLEN]; -char summary[BUFLEN]; - -char ngsep[] = { NGDELIM, '\0' }; /* == "," */ - -char *Progname = "postnews"; /* for xerror */ - -time_t fmodtime; -char buf[BUFLEN]; - -#define MAXDISTR 16 -struct distr { - char abbr[24]; - char descr[128]; -} distr[MAXDISTR]; - -FILE *xfopen(); - -main(argc, argv) -char *argv[]; -{ - register int c; - - init(); - - if (argc == 2) { - if (!prefix(argv[1], SPOOL)) - xerror("Can only followup to articles in %s", SPOOL); - followup(argv[1]); - (void) strcpy(original, argv[1]); - } else - if (askyes("Is this message in response to some other message? ","no")) { - char ng[BUFLEN], num[BUFLEN]; - long i, j, lastnum; - register char *p; - int fd, dir; - char canpost; - - getpr("In what newsgroup was the article posted? ",ng); - if (!valid_ng(ng, &i, &j, &canpost)) - if (canpost == 'i' ) - byebye("There is no such newsgroup."); - else if (canpost == 'n') - byebye("You are not allowed to post to that group."); - - printf("Valid article numbers are from %ld to %ld\n", j, i); - lastnum = i + 1; - dir = -1; - - for(;;) { - getpr("\nWhat was the article number? ", num); - switch(num[0]) { - case '+': - dir = 1; - sprintf(num, "%ld", lastnum + 1); - break; - case '-': - dir = -1; - /* no break */ - case '\0': - sprintf(num, "%ld", lastnum + dir); - break; - } - (void) sprintf(original, "%s/%s", SPOOL, ng); - for (p=original+strlen(SPOOL)+1; *p ;++p) - if (*p == '.') - *p = '/'; - (void) strcat(original, "/"); - (void) strcat(original, num); - - if ((fd=open(original,0)) >= 0) { - (void) close(fd); - printf("\narticle %s\n", original); - if (article_line(original, "From: ", buf)) - printf("%s\n", buf); - if (article_line(original, "Subject: ", buf)) - printf("%s\n", buf); - if (askyes("Is this the one you want? ", "n")) - break; - } else - printf("I can't find that article.\n"); - lastnum = atol(num); - } - - followup(original); - } else { - do { - getpr("Subject: ", subject); - if (*subject == '?') { -printf("People read the subject line to learn what your article is about.\n"); -printf("You want it to do the same job as a newspaper headline.\n"); -printf("So type in something both brief and descriptive.\n"); - *subject = '\0'; - } - } while (*subject == '\0'); - getpr("Keywords: ", keywords); - - while (!get_newsgroup()) - ; - get_distribution((char *)0); - } - - if (pre_checks()) - exit(1); - - prep_article(); - c = 'e'; - for (;;) { - if (c == 'e') { - edit_article(); - post_checks(); - } - do { - do { - getpr("\nWhat now? [send, edit, list, quit, write] ", buf); - c = buf[0]; - } while (c == '\0'); - if (isupper(c)) - c = tolower(c); - if (c == 'q') { - (void) UNLINK(tempfname); - exit(1); - } - if (c == 'l') { - char *pager = getenv("PAGER"); - char lbuf[BUFLEN]; - if (pager == NULL || *pager == '\0') { -#ifdef PAGE -# ifdef IHCC - (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE); -# else /* !IHCC */ - (void) strcpy(lbuf, PAGE); -# endif /* !IHCC */ - pager = lbuf; -#else /* !PAGE */ - pager = "cat"; -#endif /* !PAGE */ - } - sprintf(buf, "exec %s %s", pager, tempfname); - (void) system(buf); - } - if (c == 'w') { - register int ifd, ofd, nbytes; - char iobuf[BUFSIZ]; - char fname[BUFLEN]; - getpr("Filename? ", fname); - if (fname[0] == '\0') - continue; - ofd = creat(fname, 0666); - if (ofd < 0) - perror(fname); - else { - ifd = open(tempfname, 0); - if (ifd < 0) - xerror("Can't reopen %s\n", tempfname); - while ((nbytes = read(ifd, iobuf, BUFSIZ)) > 0 ) - write(ofd, iobuf, nbytes); - close(ofd); - close(ifd); - } - } - } while (!index("eps", c)); - if (c != 'e') - post_article(); /* will exit if posted successfully */ - }; -} - -/* - * Find out the topic of interest. - */ -get_newsgroup() -{ - int n; - long i; - char canpost; - static int first = 1; - - printf("Newsgroups (enter one at a time, end with a blank line):\n"); - if (first) { - printf("\nThe most relevant newsgroup should be the first, you should\n"); - printf("add others only if your article really MUST be read by people\n"); - printf("who choose not to read the appropriate group for your article.\n"); - printf("But DO use multiple newsgroups rather than posting many times.\n\n"); - first = 0; - } - printf("For a list of newsgroups, type ?\n"); - n = 0; - newsgroups[0] = '\0'; - - for(;;) { - getpr("> ", buf); - if (buf[0] == '\0') - if (n == 0) - return FALSE; - else - return TRUE; - if (buf[0] == '?'){ - char *pager = getenv("PAGER"); - char lbuf[BUFLEN]; - if (pager == NULL) { -#ifdef PAGE -# ifdef IHCC - (void) sprintf(lbuf,"%s/bin/%s", logdir(HOME), PAGE); -# else /* !IHCC */ - (void) strcpy(lbuf, PAGE); -# endif /* !IHCC */ - pager = lbuf; -#else /* !PAGE */ - pager = "cat"; -#endif /* !PAGE */ - } - printf("These are the currently active groups:\n"); - sprintf(buf, "exec %s %s/newsgroups", pager, LIB); - (void) system(buf); - continue; - } - if (valid_ng(buf, &i, &i, &canpost)) { - if (n++ != 0) - (void) strcat(newsgroups, ngsep); - (void) strcat(newsgroups, buf); - } else { - if (canpost == 'n') - printf("You are not allowed to post to %s\n", - buf); - else if (canpost == 'i') - printf("%s is not a valid newsgroup.\n", buf); - } - } -} - -/* - * Find out how widely the author wants the message distributed. - */ -get_distribution(deflt) - char *deflt; -{ - register int i; - register char *r; - char def[BUFLEN]; - char *lastgroup; - - lastgroup = newsgroups; - (void) strcpy(def, newsgroups); - r = index(def, NGDELIM); - if (r) - *r = '\0'; - r = index(def, '.'); - if (r) { - *r = '\0'; - if (strcmp(def, "net") == 0) - (void) strcpy(def, "world"); - } else { - distribution[0] = '\0'; - return; - } - - if (strcmp(def, "to") == 0) { - /* - * This only works if "to.xx" is the first (or only) - * newsgroup, but it usually is .. - * Perhaps we should make the distribution be "to.xxx" ?? - */ - distribution[0] = '\0'; - return; /* He's probably testing something */ - } - if (deflt != (char *)0) - (void) strcpy(def, deflt); - if (ngmatch("net.test", newsgroups)) - (void) strcpy(def, "local"); - for(;;) { - do { - (void) sprintf(buf, "Distribution (default='%s', '?' for help) : ", def); - getpr(buf, distribution); - if (distribution[0] == '\0') { - if (strcmp(def, "*None*") == 0) - printf("You must enter a distribution, '?' for help.\n"); - (void) strcpy(distribution, def); - } - } while (strcmp(distribution, "*None*") == 0); - - /* Did the user ask for help? */ - if (distribution[0] == '?') { - printf("How widely should your article be distributed?\n\n"); - for (i=0; distr[i].abbr[0]; i++) - printf("%s\t%s\n", distr[i].abbr, distr[i].descr); - printf("\nEnter the word that specifies the distribution that you require.\n"); - continue; - } - - /* Check that it's a proper distribution */ - for (i=0; distr[i].abbr[0]; i++) { - if (strncmp(distr[i].abbr, distribution, sizeof(distr[0].abbr)) == 0) { - register int n; - /* Found a match. Do any special rewriting. */ - r = newsgroups; - n = strlen(distribution); - /* - * A distribution of foo is useless - * if all the newsgroups are in foo.all - */ - for (;;) { - if (strncmp(r, distribution, n)) - return; - if ((r = index(r, NGDELIM)) == NULL) - break; - ++r; - } - distribution[0] = '\0'; - return; - } - } - if (strcmp(distribution, def) != 0) - printf("Type ? for help.\n"); - else { - int once = TRUE; - - do { - r = lastgroup; - while (r = index(r, NGDELIM)) - if (!prefix(++r, def)) - break; - if (r == NULL) { - /* - * no newsgroups are distribution - * names, and user simply will - * not type a valid distribution, - * assume that the default is OK. - */ - distribution[0] = '\0'; - return; - } - lastgroup = r; - if (once) - printf("Sorry, '%s' is an unknown distribution. Type ? for help.\n", def); - once = FALSE; - strcpy(def, r); - r = index(def, NGDELIM); - if (r) - *r = '\0'; - r = index(def, '.'); - } while (r == NULL); - *r = '\0'; - if (strcmp(def, "net") == 0) - strcpy(def, "world"); - } - } -} - -/* - * Do sanity checks before the author types in the message. - */ -pre_checks() -{ - if (recording(newsgroups)) - return 1; - return 0; -} - -/* - * Set up the temp file with headers. - */ -prep_article() -{ - FILE *tf, *of; - struct stat stbuf; - - (void) strcpy(tempfname, "/tmp/postXXXXXX"); - (void) mktemp(tempfname); - - /* insert a header */ - tf = xfopen(tempfname, "w"); - fprintf(tf, "Subject: %s\n", subject); - fprintf(tf, "Newsgroups: %s\n", newsgroups); - if (distribution[0] != '\0' && strcmp(distribution, "world")) - fprintf(tf, "Distribution: %s\n", distribution); - - if (keywords[0] != '\0') - fprintf(tf, "Keywords: %s\n", keywords); - if (summary[0] != '\0') - fprintf(tf, "Summary: %s\n", summary); - - if (references[0] != '\0') { - fprintf(tf, "References: %s\n\n", references); - - if (askyes("Do you want to include a copy of the article? ", "no")){ - of = xfopen(original, "r"); - while (fgets(buf, BUFSIZ, of) != NULL) - if (buf[0] == '\n') /* skip headers */ - break; - fprintf(tf, "In article %s, %s writes:\n", msgid, isfrom); - while (fgets(buf, BUFSIZ, of) != NULL) - fprintf(tf, "> %s", buf); - (void) fclose(of); - printf("OK, but please edit it to suppress unnecessary verbiage, signatures, etc.\n"); - } - } - - fprintf(tf, "\n\n"); - (void) fflush(tf); - (void) fstat(fileno(tf), &stbuf); - fmodtime = stbuf.st_mtime; - (void) fclose(tf); -} - -edit_article() -{ - register char *p; - char *editor; - char *endflag = ""; - char *getenv(); - - /* edit the file */ - editor = getenv("EDITOR"); - if (editor == NULL) - editor = DFTEDITOR; - - p = editor + strlen(editor) - 2; - if (strcmp(p, "vi") == 0) - endflag = "+"; - - (void) sprintf(buf, "A=%s;export A;exec %s %s %s", - original, editor, endflag, tempfname); - - (void) system(buf); -} - -/* - * Do sanity checks after the author has typed in the message. - */ -post_checks() -{ - char group[BUFLEN]; - register char *c, *p; - struct stat stbuf; - - if (stat(tempfname, &stbuf) < 0) { - printf("File deleted - no message posted.\n"); - (void) UNLINK(tempfname); - exit(1); - } - if (stbuf.st_size < 5) { - printf("File too small (<5 characters) - no message posted.\n"); - (void) UNLINK(tempfname); - exit(1); - } - - if (stbuf.st_mtime == fmodtime) { - printf("File not modified - no message posted.\n"); - (void) UNLINK(tempfname); - exit(1); - } - - /* - * Is this the right number? Most of the headers are yet to be added - */ - if (stbuf.st_size > 64000) { - printf("\nYour message will probably be truncated when it\n"); - printf("passes through a notesfile site, since it is\n"); - printf("greater than 64000 characters.\n\n"); - if (!askyes("Do you still want to post it? ","")) { - sprintf(ccname, "%s/dead.article", homedir); - save_article(); - (void) UNLINK(tempfname); - exit(1); - } - } - - /* - * get the newsgroups from the edited article, in - * case they were altered in the editor - */ - if (!article_line(tempfname, "Newsgroups: ", group)) { - nogroups: - printf("Not sending to any newsgroups - no message posted\n"); - (void) UNLINK(tempfname); - exit(1); - } - c = &group[11]; - while (*c == ' ' || *c == '\t') - c++; - if (*c == '\0') - goto nogroups; - for (p = newsgroups; *c; c++) /* copy to newsgroups, w/o blanks */ - if (*c != ' ' && *c != '\t') - *p++ = *c; - *p = '\0'; - - /* Sanity checks for certain newsgroups */ - if (ngmatch(newsgroups, "all.wanted") && ngmatch(distribution,"net,na,usa,att,btl,eunet,aus")) { - printf("Is your message something that might go in your local\n"); - printf("newspaper, for example a used car ad, or an apartment\n"); - printf("for rent? "); - if (askyes("","")) { - printf("It's pointless to distribute your article widely, since\n"); - printf("people more than a hundred miles away won't be interested.\n"); - printf("Please use a more restricted distribution.\n"); - get_distribution("*None*"); - modify_article(tempfname, "Distribution: ", distribution,REPLACE); - } - } - - if (ngmatch(newsgroups, "all.jokes")) { - if (askyes("Could this be offensive to anyone? ","")) { - getpr("Whom might it offend? ", group); - (void) sprintf(buf," - offensive to %s (rot 13)",group); - modify_article(tempfname, "Subject: ", buf, APPEND); - encode(tempfname); - } - } - - if (ngmatch(newsgroups, "net.general")) { - if (index(newsgroups, NGDELIM)) { - printf("Everybody in the world reads net.general, so it doesn't make\n"); - printf("sense to post to newsgroups in addition to net.general. If your\n"); - printf("article belongs in one of these other newsgroups, then you\n"); - printf("should not post to net.general. If it is important enough\n"); - printf("for net.general, then you shouldn't post it in other places\n"); - printf("as well. Please reenter the newsgroups.\n"); - while (!get_newsgroup()) - ; - modify_article(tempfname, "Newsgroups: ", newsgroups,REPLACE); - } - if (ngmatch(newsgroups, "net.general")) { - printf("net.general is for important announcements.\n"); - printf("It is not for items for which you couldn't think\n"); - printf("of a better place - those belong in net.misc.\n"); - if (!askyes("Are you sure your message belongs in net.general? ","")) { - while (!get_newsgroup()) - ; - modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); - } - } - } - - if (ngmatch(newsgroups, "net.sources,!net.sources.all")) { - if (!article_line(tempfname, "Subject: ", group)) { - nosubj: - printf("There seems to be no subject for this article.\n"); - getpr("Subject: ", subject); - modify_article(tempfname, "Subject: ", subject, REPLACE); - } else { - c = &group[8]; - while (*c == ' ' || *c == '\t') - c++; - if (*c == '\0') - goto nosubj; - strcpy(subject, c); - } - if (ngmatch(newsgroups, "all.wanted") || iswanted(subject)) { - printf("Requests for sources should not be posted to any of\n"); - printf("the net.sources newsgroups, please post such requests\n"); - printf("to net.wanted.sources only. Please reenter the newsgroups.\n\n"); - while (!get_newsgroup()) - ; - modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); - } - if (ngmatch(newsgroups, "net.sources")) { - if (!ngmatch(newsgroups, "net.sources.all") && - stbuf.st_size < (4*1024)) { - printf("Your article seems rather small to be a source distribution.\n"); - if (!askyes("Are you certain that this is really source? ", "")) { - - while (!get_newsgroup()) - ; - modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); - } - } - if (index(newsgroups, NGDELIM)) { - printf("Sources should be posted to one newsgroup only.\n"); - printf("Please pick the most appropriate group for your article.\n\n"); - while (!get_newsgroup()) - ; - modify_article(tempfname, "Newsgroups: ", newsgroups, REPLACE); - } - } - } -} - -iswanted(str) -register char *str; -{ - while (*str == ' ') - str++; - - if (prefix(str, "Re:")) - return (FALSE); - - if (isin(str, " wanted ") || isin(str, " can any") || - isin(str, " need ") || isin(str, " please ") || isin(str, " help ") - || isin(str, " looking ") || index(str, '?')) - return (TRUE); - - return (FALSE); -} - -isin(str, words) -register char *str, *words; -{ - register char *p; - register sc, wc; - - p = words; - while (sc = *str++) { - if ((wc = *p++) == '\0') - return (TRUE); - if (wc == ' ') { - if (index(".,!?-; \t\n", sc)) - continue; - } else { - if (isupper(wc)) - wc = tolower(wc); - if (isupper(sc)) - sc = tolower(sc); - if (wc == sc) - continue; - } - str -= p - words - 1; - p = words; - } - if (*p == '\0') - return (TRUE); - return (FALSE); -} - -/* - * Save a copy of the article in the users NEWSARCHIVE directory. - */ -save_article() -{ - FILE *in, *out; - int c; - time_t timenow, time(); - char *today, *ctime(); - struct stat stbuf; - char filename[BUFLEN]; - - if (stat(ccname, &stbuf) == 0 && (stbuf.st_mode&S_IFMT) == S_IFDIR) { - /* - * It would be much nicer here to write articles - * in MH format (numbered files, in rfc822 format) - * - * one day .. - */ - (void) sprintf(filename, "%s/author_copy", ccname); - (void) strcpy(ccname, filename); - } - in = xfopen(tempfname, "r"); - out = xfopen(ccname, "a"); - timenow = time((time_t)0); - today = ctime(&timenow); - fprintf(out,"From postnews %s",today); - while ((c=getc(in)) != EOF) - putc(c, out); - putc('\n', out); - (void) fclose(in); - (void) fclose(out); -} - -/* - * Post the article to the net. - */ -post_article() -{ - int status; - - printf("Posting article...\n"); - fflush(stdout); - (void) sprintf(buf, "exec %s/%s -h < %s", LIB, "inews", tempfname); - status = system(buf); - - if (status) { - printf("Article not posted - exit status %d\n", status); - return; - } else - printf("Article posted successfully.\n"); - - if (ccname[0]) { - printf("A copy has been saved in %s\n", ccname); - save_article(); - } - - (void) UNLINK(tempfname); - exit(0); -} - -/* - * Initialization. - */ -init() -{ - FILE *fd; - register char *p; - int i; - char *getenv(); - struct passwd *pw; - - references[0] = '\0'; - distribution[0] = '\0'; - - uid = getuid(); - pw = getpwuid(uid); - if (pw == NULL) { - fprintf(stderr,"You're not in /etc/passwd\n"); - exit(1); - } - p = getenv("HOME"); - if (p == NULL) { - p = getenv("LOGDIR"); - if (p == NULL) - p = pw->pw_dir; - } - (void) strncpy(user, pw->pw_name, SBUFLEN); - (void) strcpy(homedir, p); - - p = getenv("NEWSARCHIVE"); - if (p != NULL) { - if (*p == '\0') - sprintf(ccname, "%s/author_copy", homedir); - else - strcpy(ccname, p); - } - - pathinit(); - (void) sprintf(buf, "%s/%s", LIB, "distributions"); - fd = xfopen(buf, "r"); - for (i=0; i < MAXDISTR; i++) { - if (fscanf(fd, "%s %[^\n]", distr[i].abbr, distr[i].descr) - != 2) - break; - } - (void) fclose(fd); -} - -/* - * Get a yes or no answer to a question. A default may be used. - */ -askyes(msg, def) -char *msg, *def; -{ - for(;;) { - printf("%s", msg); - buf[0] = 0; - (void) gets(buf); - switch(buf[0]) { - case 'y': - case 'Y': - return TRUE; - case 'n': - case 'N': - return FALSE; - case '\0': - switch(*def) { - case 'y': - case 'Y': - return TRUE; - case 'n': - case 'N': - return FALSE; - } - default: - printf("Please answer yes or no.\n"); - } - } -} - -/* - * Get a character string into buf, using prompt msg. - */ -getpr(msg, bptr) -char *msg, *bptr; -{ - static int numeof = 0; - printf("%s", msg); - (void) gets(bptr); - (void) nstrip(bptr); - if (feof(stdin)) { - if (numeof++ > 3) { - fprintf(stderr,"Too many EOFs\n"); - exit(1); - } - clearerr(stdin); - } -} - -byebye(mesg) -char *mesg; -{ - printf("%s\n", mesg); - exit(1); -} - -/* - * make a modification to the header of an article - * - * fname -- name of article - * field -- header field to modify - * line -- modification line - * how -- APPEND or REPLACE - * - * example: - * modify_article("/tmp/article" , "Subject:" , "new subject" , REPLACE); - * - * - */ -modify_article(fname, field, line, how) -char *fname, *field, *line; -{ - FILE *fpart, *fptmp; - char *temp2fname = "/tmp/postXXXXXX"; - char lbfr[BUFLEN]; - register found = FALSE; - - mktemp(temp2fname); - - fptmp = xfopen(temp2fname, "w"); - fpart = xfopen(fname, "r"); - - while (fgets(lbfr, BUFLEN, fpart) != NULL) { - if (prefix(lbfr, field)) { - found = TRUE; - (void) nstrip(lbfr); - if (how == APPEND) { - /* append to current field */ - (void) strcat(lbfr, line); - (void) strcat(lbfr, "\n"); - } else - /* replace current field */ - (void) sprintf(lbfr, "%s%s\n", field, line); - } - (void) fputs(lbfr, fptmp); - } - - fclose(fpart); - fclose(fptmp); - - fptmp = xfopen(temp2fname, "r"); - fpart = xfopen(fname, "w"); - - if (!found) - fprintf(fpart, "%s%s\n", field, line); - while (fgets(buf,BUFLEN,fptmp) != NULL) - (void) fputs(buf, fpart); - - (void) fclose(fpart); - (void) fclose(fptmp); - (void) UNLINK(temp2fname); -} - - -/* verify that newsgroup exists, and get number of entries */ -valid_ng(ng, maxart, minart, canpost) -char *ng; -long *maxart, *minart; -char *canpost; -{ - char ng_check[BUFLEN], ng_read[BUFLEN]; - FILE *fp; - - fp = xfopen(ACTIVE, "r"); - while (fgets(ng_read, BUFLEN, fp) != NULL) { - switch (sscanf(ng_read, "%s %ld %ld %c", ng_check, maxart, minart, canpost)) { - case 2: - *minart = 1; - /* fall through */ - case 3: - *canpost = 'y'; - /* fall through */ - case 4: - break; - - default: - printf("Active file (%s) corrupted. ", ACTIVE); - byebye("Seek help!"); - } - - if (strcmp(ng_check, ng) == 0) { - (void) fclose(fp); - if (*canpost != 'n') { -#ifdef FASCIST - if (uid && uid != ROOTID && fascist(user, ng)) { - *canpost = 'n'; - return FALSE; - } -#endif FASCIST - return TRUE; - } else - return FALSE; - } - } - *canpost = 'i'; - *maxart = 0; - *minart = 0; - (void) fclose(fp); - return FALSE; -} - -/* get the line specified by field from an article */ -article_line(article, field, line) -char *article, *field, *line; -{ - FILE *fp; - char *c; - - fp = xfopen(article,"r"); - while ((c=fgets(line,BUFLEN,fp)) != NULL && !prefix(line, field)) - if (line[0] == '\n') { - c = NULL; - break; - } - (void) fclose(fp); - if (c != NULL) { - (void) nstrip(line); - return TRUE; - } else { - line[0] = '\0'; - return FALSE; - } -} - -/* get the header information for a followup article */ -followup(baseart) -register char *baseart; -{ - register char *p; - - /* subject */ - if (article_line(baseart, "Subject: ", buf)) { - p = buf+9; - for ( ; ; ) { - while (*p == ' ' || *p == '\t') - ++p; - if ((*p != 'r' && *p != 'R') || - (p[1] != 'e' && p[1] != 'E') || - (p[2] != ':' && p[2] != ' ')) - break; - p += 3; - } - (void) sprintf(subject, "Re: %s", p); - } else { - if (article_line(baseart, "From: ", buf)) - (void) sprintf(subject, "Re: orphan response from %s", buf); - else - (void) strcpy(subject, "Re: orphan response"); - } - - /* newsgroup */ - if (article_line(baseart, "Newsgroups: ", buf)) - (void) strcpy(newsgroups, buf+12); - if (ngmatch(newsgroups, "net.general")) - (void) strcpy(newsgroups,"net.followup"); - if (ngmatch(newsgroups, "net.sources,!net.sources.all")) - (void) strcpy(newsgroups,"net.sources.d"); - if (ngmatch(newsgroups, "net.jobs")) { - printf("net.jobs is for the direct posting of job announcements and requests.\n"); - printf("it is not for discussion. You followup has been directed to net.misc\n"); - (void) strcpy(newsgroups,"net.misc"); - } - - /* distribution */ - if (article_line(baseart, "Distribution: ", buf)) - (void) strcpy(distribution, buf+14); - - /* references */ - if (article_line(baseart, "References: ", buf)) { - register char *rcp; - (void) strcpy(references, buf+12); - (void) strcat(references, " "); - /* keep the number of references to a reasonable number */ - rcp = rindex(references, ' '); /* Can not fail */ - while ((int)(rcp - references) > 70) { - while (*--rcp != ' ') - ; - rcp[1] = '\0'; - } - } - if (article_line(baseart, "Message-ID: ", buf)) { - (void) strcat(references, buf+12); - (void) strcpy(msgid, buf+12); - } - - if (article_line(baseart, "From: ", buf)) - (void) strcpy(isfrom, buf+6); - - if (article_line(baseart, "Keywords: ", buf)) - (void) strcpy(keywords, buf+10); - - if (article_line(baseart, "Followup-To: ", buf)) { - (void) strcpy(newsgroups, buf+13); - if (strcmp(newsgroups, "poster") == 0) - byebye("Mail followups directly to poster."); - } - - get_summary(); -} - -get_summary() -{ - register char *p; - register i; - - printf("Please enter a short summary of your contribution to the discussion\n"); - printf("Just one or two lines ... (end with a blank line)\n"); - p = summary; - for (i = 0; i < 3; i++) { /* 3 * 80 < 256, should be safe .. */ - getpr(">\t", p); - if (*p == '\0') - break; - p = index(p, '\0'); - (void) strcpy(p, "\n\t "); - p += 3; - } - if (p > summary) - p[-3] = '\0'; -} - -encode(article) -char *article; -{ - FILE *fpart, *fphead, *fpcoded; - char *headerfile = "/tmp/pheadXXXXXX"; - char *codedfile = "/tmp/pcodeXXXXXX"; - - (void) mktemp(headerfile); - (void) mktemp(codedfile); - - fpart = xfopen(article, "r"); - - /* place article header in "headerfile" file */ - fphead = xfopen(headerfile, "w"); - while (fgets(buf, BUFLEN, fpart) != NULL) { - (void) fputs(buf, fphead); - if (buf[0] == '\n') - break; - } - (void) fclose(fphead); - - /* place article body in "codedfile" file */ - fpcoded = xfopen(codedfile, "w"); - while (fgets(buf, BUFLEN, fpart) != NULL) - (void) fputs(buf, fpcoded); - (void) fclose(fpcoded); - (void) fclose(fpart); - - /* encode body and put back together with header */ - (void) rename(headerfile, article); - - (void) sprintf(buf,"exec %s/%s 13 < %s >> %s\n", LIB, "caesar", codedfile, article); - printf("Encoding article -- please stand by\n"); - if (system(buf)) { - printf("encoding failed"); - exit(2); - } - (void) UNLINK(codedfile); -} - - -/* - * Print a recorded message warning the poor luser what he is doing - * and demand that he understands it before proceeding. Only do - * this for newsgroups listed in LIBDIR/recording. - */ -recording(ngrps) -char *ngrps; -{ - char recbuf[BUFLEN]; - FILE *fd; - char nglist[BUFLEN], fname[BUFLEN]; - int c, n, yes, retval = 0; - - (void) sprintf(recbuf, "%s/%s", LIB, "recording"); - fd = fopen(recbuf, "r"); - if (fd == NULL) - return 0; - while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) { - (void) sscanf(recbuf, "%s %s", nglist, fname); - if (ngmatch(ngrps, nglist)) { - (void) fclose(fd); - if (fname[0] == '/') - (void) strcpy(recbuf, fname); - else - (void) sprintf(recbuf, "%s/%s", LIB, fname); - fd = fopen(recbuf, "r"); - if (fd == NULL) - return 0; - while ((c = getc(fd)) != EOF) - putc(c, stderr); - fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: "); - n = read(2, recbuf, 100); - c = recbuf[0]; - yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0); - if (n <= 0 || !yes) - retval = -1; - } - } - return retval; -} - -xxit(i) -{ - exit(i); -} - -#if !defined(BSD4_2) && !defined(BSD4_1C) -rename(from,to) -register char *from, *to; -{ - (void) unlink(to); - if (link(from, to) < 0) - return -1; - - (void) unlink(from); - return 0; -} -#endif /* !BSD4_2 && ! BSD4_1C */ *-*-END-of-src/postnews.c-*-* echo x - src/control.c 1>&2 sed 's/.//' >src/control.c <<'*-*-END-of-src/control.c-*-*' -/* - * This software is Copyright (c) 1986 by Rick Adams. - * - * Permission is hereby granted to copy, reproduce, redistribute or - * otherwise use this software as long as: there is no monetary - * profit gained specifically from the use or reproduction or this - * software, it is not sold, rented, traded or otherwise marketed, and - * this copyright notice is included prominently in any copy - * made. - * - * The author make no claims as to the fitness or correctness of - * this software for any use whatsoever, and it is provided as is. - * Any use of this software is at the user's own risk. - * - * Control message handling code. Deal with messages which are to be - * acted on by netnews itself rather than by people. - * - * See defs.h "news_version" for the real version of netnews. - */ - -#ifdef SCCSID -static char *SccsId = "@(#)control.c 2.48 10/30/86"; -#endif /* SCCSID */ - -#include "iparams.h" - -#define eq(msg) (strcmp(msg, cargv[0]) == 0) - -int cargc; -char **cargv; - -FILE *hfopen(); -FILE *popen(), *mhopen(), *mailhdr(); - -char *senderof(); -#ifdef u370 -static struct hbuf htmp; -#endif /* u370 */ - -/* - * The global structure is initialized to NOTIFY as the default (if defined) - * uid to send mail to for every state. The following conditions are - * dealt with (assumes NOTIFY defined): - * - * 1) LIB/notify exists and is empty (or contains no recognizable control - * message types). - * Action: force TELLME = ""; - * 2) LIB/notify contains the control message name "all" and no associated - * address. - * Action: force TELLME = ""; - * 3) LIB/notify contains the control message name "all" and has an address. - * Action: set TELLME = AlloCpy(address); - * 4) LIB/notify contains only some of the known control message types. - * Action: initialize all addresses to "" and set declared addresses - * to listed address. - */ - -control(h) -struct hbuf *h; -{ - register char *ctlmsgtext; - register struct msgtype *mp; - - if (strncmp(h->title, "cmsg ", 5) == 0) { - register char *cp1, *cp2; - cp1 = h->title; - cp2 = h->title + 5; - while (*cp1++ = *cp2++) - ; - } - - if (*h->ctlmsg) - ctlmsgtext = h->ctlmsg; - else - ctlmsgtext = h->title; - log("Ctl Msg %s from %s: %s", h->nbuf, h->path, ctlmsgtext); - /* - * Control messages have the standard format - * command [args] - * much like shell commands. Each site has the option - * of customizing this code to deal with control messages - * as they see fit, but we would like to buy back the - * code, ifdeffed or otherwise parameterized, to simplify - * the maintenence issues. - */ - argparse(ctlmsgtext); - - /* - * We look for a match of the control message name and then - * set TELLME to the value parsed from the LIB/notify file - * (if any). - */ - for(mp=msgtype; mp->m_name; mp++) { - if(eq(mp->m_name) ) { /* hit */ -#ifdef NOTIFY - TELLME = mp->m_who_to; /* reset whom to tell */ -#endif /* NOTIFY */ - if(strcmp(mp->m_name, "cancel") == 0) /* special case */ - return (*mp->m_func)(cargc, cargv); - (*mp->m_func)(cargc, cargv); /* do the function */ - break; - } - } - if( !mp->m_name ) { -#ifdef NOTIFY - TELLME = NOTIFY; -#endif /* NOTIFY */ - c_unknown(h, ctlmsgtext); - } - return 0; -} - -/* - * Parse the string str into separate words in cargc and cargv - * as per the usual UNIX convention. Nothing fancy here, just - * blanks and tabs separating words. - */ -argparse(str) -char *str; -{ - static char *cavpbuf[20]; - static char cavbuf[256]; - char *nextfree = cavbuf; - - if (str == '\0') - error("Control message %s has no title", header.ident); - cargc = (*str != '\0'); - cargv = cavpbuf; - cargv[0] = cavbuf; - - while (*str) { - if (*str <= ' ') { - *nextfree++ = 0; - cargv[cargc] = nextfree; - cargc++; - /* skip over white space */ - while (*str != '\0' && *str <= ' ') - str++; - if (*str == '\0') /* line ends in white space */ - return; - } else - *nextfree++ = *str++; - } -} - -/* - * ihave <artid> ... <remotesys> - * or - * ihave <remotesys> - * with <artid>s in message body. - * - * The other system is telling you it has article <artid>, in case - * you decide you want it to transmit it to you. - * The assumption is that the other system only tells you about articles - * in newsgroups you subscribe to. - * - * We turn the incoming ihave into an outgoing sendme on the fly. - * It then gets saved in the SPOOL directory and transmitted to the - * remote system. (This way the sendme messages can be batched.) - */ -c_ihave(argc, argv) -register char ** argv; -{ - register int i; - char list[sizeof header.title]; - extern char * findhist(); - - if (argc < 2) - error("ihave: Too few arguments."); - if (strncmp(FULLSYSNAME, argv[argc - 1], SNLN) == 0) - return; - list[0] = '\0'; - if (argc > 2) { - for (i = 1; i < (argc - 1); ++i) - if (findhist(argv[i]) == NULL) { - (void) strcat(list, " "); - (void) strcat(list, argv[i]); - } - if (list[0] == '\0') - return; - } else { - register FILE * outfp; - register long outpos, inpos; - char myid[256]; - - outfp = xfopen(INFILE, "a"); - outpos = ftell(outfp); - inpos = ftell(infp); - while (ftell(infp) < outpos) { - if (fgets(myid, sizeof myid, infp) != myid) - error("iline: Can't rerear article"); - myid[strlen(myid) - 1] = '\0'; - if (findhist(myid) == NULL) - (void) fprintf(outfp, "%s\n", myid); - } - if (outpos == ftell(outfp)) { /* if nothing is wanted */ - (void) fclose(outfp); - (void) fseek(infp, inpos, 0); - return; - } - (void) fclose(outfp); - /* - ** The close and open may just be paranoia. - */ - (void) fclose(infp); - infp = xfopen(INFILE, "r"); - (void) fseek(infp, outpos, 0); - } - /* - ** Turn the ihave into a sendme. - */ - (void) sprintf(header.nbuf, "to.%s.ctl", argv[argc - 1]); - (void) sprintf(header.title, "sendme%s %s", list, FULLSYSNAME); - (void) strcpy(header.ctlmsg, header.title); - getident(&header); - (void) sprintf(header.from, "%s@%s%s", "usenet", FULLSYSNAME, MYDOMAIN); - (void) strcpy(header.path, NEWSUSR); - header.subdate[0] = header.expdate[0] = '\0'; - dates(&header); - /* - ** What else of this kind should be done? - */ - header.organization[0] = header.distribution[0] = '\0'; - for (i = 0; i < NUNREC && header.unrec[i] != NULL; ++i) { - free(header.unrec[i]); - header.unrec[i] = NULL; - } - /* - ** Note that we do *not* change the history line - ** so that if the "ihave" message comes in again it gets rejected. - */ -} - -/* - * sendme <artid> ... <remotesys> - * or - * sendme <remotesys> - * with <artid>s in message body. - * The other system wants me to send out article <artid>. - * Give it to them with no fuss. - */ -c_sendme(argc, argv) -register char ** argv; -{ - struct srec srec; - - if (argc < 2) - error("sendme: Too few arguments."); - if (strncmp(FULLSYSNAME, argv[argc - 1], SNLN) == 0) - return; - if (s_find(&srec, argv[argc - 1]) != TRUE) - error("sendme: Can't find sys record for %s", argv[argc - 1]); - /* Send the articles. */ - if (argc == 2) { - register FILE * fp; - char buf[256]; - - fp = xfopen(INFILE, "r"); - while (fgets(buf, sizeof buf, fp) == buf) { - buf[strlen(buf) - 1] = '\0'; /* zap trailing '\n' */ - sendmefunc(buf, &srec); - } - (void) fclose(fp); - } else { /* argc > 2 */ - register int i; - - for (i = 1; i < (argc - 1); ++i) - sendmefunc(argv[i], &srec); - } -} - -static -sendmefunc(id, sp) -register char * id; -register struct srec * sp; -{ - register FILE * fp; - register char * cp; - char savedbufname[256]; - extern char firstbufname[]; - extern char * dirname(); - extern char * findfname(); - - cp = findfname(id); - if (cp == NULL) { - logerr("System %s wants unavailable article %s.", - sp->s_name, id); - return; - } - cp = dirname(cp); - fp = fopen(cp, "r"); - if (fp == NULL) { - logerr("Article %s unopenable as %s.", id, cp); - return; - } - (void) strcpy(savedbufname, firstbufname); - (void) strcpy(firstbufname, cp); - transmit(sp, fp, FALSE, (char **) NULL, FALSE); - /* transmit closes fp */ - (void) strcpy(firstbufname, savedbufname); -} - -/* - * newgroup <groupname> - * A new newsgroup has been created. - * The body of the article, if present, is a description of the - * purpose of the newsgroup. - * - */ -c_newgroup(argc, argv) -char **argv; -{ - FILE *fd; - char abuf[BUFLEN], subjline[BUFLEN]; - int didcreate = 0; - register char *p, *q; -# ifdef NONEWGROUPS -# ifdef ORGDISTRIB - /* local or ORGDISTRIB */ - int can_change = (strcmp(header.distribution, "local") == 0) || - (strcmp(header.distribution, ORGDISTRIB) == 0); -# else /* ! ORGDISTRIB */ - /* local only */ - int can_change = strcmp(header.distribution, "local") == 0; -# endif /* ORGDISTRIB */ -# else /* ! NONEWGROUPS */ - int can_change = 1; /* allow changes for all distributions */ -# endif /* NONEWGROUPS */ - - if (argc < 2) - error("newgroup: Too few arguments."); - - if (header.approved[0] == '\0') - error("newgroup: %s not approved", argv[1]); - - /* see if it already exists */ - (void) rewind(actfp); clearerr(actfp); - while(fgets(abuf, BUFLEN, actfp) != NULL) { - p = abuf; - q = argv[1]; - while (*p++ == *q++) - ; - if (*--q == '\0' && *--p == ' ') { - int modified = 0; - /* Now check if it's correctly moderated/unmoderated */ - while (*p++) - ; - p -= 3; - if (argc > 2 && strcmp(argv[2], "moderated") == 0) { - if (*p == 'm') - return; -# ifdef NONEWGROUPS - if(can_change) { - *p = 'm'; - modified = 1; - } -# else /* ! NONEWGROUPS */ - *p = 'm'; - modified = 1; -#endif /* NONEWGROUPS */ - } else { - if (*p != 'm') - return; -# ifdef NONEWGROUPS - if(can_change) { - *p = 'y'; - modified = 1; - } -# else /* ! NONEWGROUPS */ - *p = 'y'; - modified = 1; -# endif /* NONEWGROUPS */ - } -# ifdef NOTIFY - (void) sprintf(subjline, - "Newsgroup %s change from %smoderated to %smoderated", - argv[1], *p=='y' ? "" : "un", - *p=='y' ? "un" : ""); - fd = mailhdr((struct hbuf *)NULL, subjline); - if (fd != NULL) { - if(modified) - fprintf(fd, -"%s has been changed from %smoderated to %smoderated as requested by\n%s\n", - argv[1], *p=='y' ? "" : "un", - *p=='y' ? "un":"", header.path); - else { - fprintf(fd, -"%s\nhas requested that %s be changed from %smoderated to %smoderated\n", - header.path, argv[1], - *p=='y' ? "un" : "", - *p=='y' ? "" : "un"); -#ifdef ORGDISTRIB - fprintf(fd, -"You can accomplish this by re-creating the newsgroup with a distribution\n"); - fprintf(fd, -"of '%s' by executing the command:\n", ORGDISTRIB); - fprintf(fd, - "%s/inews -d %s -C %s moderated\n", - LIB, ORGDISTRIB, argv[1]); -#else /* !ORGDISTRIB */ - fprintf(fd, -"You can accomplish this by re-creating the newsgroup by executing the command:\n"); - fprintf(fd, "%s/inews -C %s moderated\n", - LIB, argv[1]); -#endif /* !ORGDISTRIB */ - } - (void) mclose(fd); - } -# endif /* NOTIFY */ -# ifdef NONEWGROUPS - /* - * No permission to change - */ - if(!can_change) - return; -# endif /* NONEWGROUPS */ - /* The active file was wrong about the state of the - * group. Rewrite the active file - */ - (void) fseek(actfp, -2L, 1); /* back up 2 characters */ -#ifdef USG - /* - * U G L Y K L U D G E - * This utter piece of tripe is the only way I know of - * to get around the fact that ATT BROKE standard IO - * in System 5.2. Basically, you can't open a file for - * "r+" and then try and write to it. This hack works - * on all "real" USG Unix systems, It will probably - * break on some obscure look alike that doesnt use the - * real ATT stdio.h - * Don't blame me, blame ATT. stdio should have - * already done the following line for us, but it didn't - */ - actfp->_flag |= _IOWRT; -#endif /* USG */ - putc(*p, actfp); - fflush(actfp); - if (*p != 'm') - logerr("Newsgroup %s changed from moderated to unmoderated", - argv[1]); - else - logerr("Newsgroup %s changed from unmoderated to moderated", - argv[1]); - return; - } - } - - /* It doesn't already exist, we must create it */ - - if(can_change) { - didcreate++; - (void) fseek(actfp, 0L, 2); clearerr(actfp); - fprintf(actfp, "%s 00000 00001 %c\n", argv[1], - (argc > 2 && strcmp(argv[2], "moderated") == 0) - ? 'm' : 'y'); - fflush(actfp); - } - -# ifdef NOTIFY - (void) sprintf(subjline, "Newsgroup %s created", argv[1]); - fd = mailhdr((struct hbuf *)NULL, subjline); - if (fd != NULL) { - if (didcreate) - fprintf(fd, - "A new newsgroup called '%s' has been created by %s.\n", - argv[1], header.path); - else { - fprintf(fd, - "%s requested that a new newsgroup called '%s' be created.\n", - header.path, argv[1]); - fprintf(fd,"It was approved by %s\n\n",header.approved); - fprintf(fd, - "You can accomplish this by creating the newgroup yourself\n"); -# ifdef ORGDISTRIB - fprintf(fd,"with a distribution of '%s'.\n", - ORGDISTRIB); - fprintf(fd, - "In other words, by executing the command:\n"); - fprintf(fd, "%s/inews -d %s -C %s\n", LIB, - ORGDISTRIB, argv[1]); -# else /* !ORGDISTRIB */ - fprintf(fd, "In other words, by executing the command:\n"); - fprintf(fd, "%s/inews -C %s\n", LIB, argv[1]); -# endif /* !ORGDISTRIB */ - } - (void) mclose(fd); - } -# endif /* NOTIFY */ -} - -/* - * rmgroup <groupname> - * An old newsgroup is being cancelled on a network wide basis. - */ -c_rmgroup(argc, argv) -char **argv; -{ - FILE *fd; - int shouldremove = 0; -#ifdef NOTIFY - char subjline[BUFLEN]; -#endif /* NOTIFY */ - - if (argc < 2) - error("rmgroup: Too few arguments."); - if (!validng(argv[1])) - return; - if (header.approved[0] == '\0') - error("rmgroup: %s not approved", argv[1]); - -#ifndef MANUALLY -#ifdef ORGDISTRIB - /* - * Allow local as well as organizational removals - */ - if (!strcmp(ORGDISTRIB, header.distribution) - || !strcmp("local", header.distribution)) -#else /* !ORGDISTRIB */ - if (!strcmp("local", header.distribution)) -#endif /* !ORGDISTRIB */ - shouldremove++; -#endif /* !MANUALLY */ -#ifdef NOTIFY - sprintf(subjline, "Recevied rmgroup for %s", argv[1]); - fd = mailhdr((struct hbuf *)NULL, subjline); - if (fd != NULL) { - if (shouldremove) { - fprintf(fd, "Newsgroup '%s' has been removed by %s.\n\n", - argv[1], header.path); -# ifdef USG - fprintf(fd, "You may need to remove the directory %s by hand\n", - dirname(argv[1])); -# endif - } else { - fprintf(fd, "%s requested that newsgroup %s be removed.\n", - header.path, argv[1]); - fprintf(fd, "You should remove it by hand\n"); - fprintf(fd, "To do this, execute the command\n"); - fprintf(fd, "\t%s/rmgroup %s\n", LIB, argv[1]); - } - (void) mclose(fd); - } -#endif /* NOTIFY */ - - if (shouldremove) { - int rc; - /* We let the shell do all the work. - * See the rmgrp shell script. */ - (void) setuid(geteuid()); /* otherwise it won't rmdir the dir */ - (void) sprintf(bfr, "exec %s/rmgroup %s", LIB, argv[1]); - rc = system(bfr); - log("system(%s) status %d", bfr, rc); - } -} - -/* - * cancel <artid> - * Cancel the named article - */ -c_cancel(argc, argv) -char **argv; -{ - char *line, *p, *q, *r, *poster; - char *findhist(); - register FILE *fp; - char whatsisname[BUFLEN], nfilename[BUFLEN]; - time_t t; - int su = 0; -#ifndef u370 - struct hbuf htmp; -#endif /* !u370 */ - - if (argc < 2) - error("cancel: Too few arguments."); - (void) strcpy(whatsisname, senderof(&header)); - line = findhist(argv[1]); - if (line == NULL) { - struct tm *tm; - log("Can't cancel %s: non-existent", argv[1]); - (void) time(&t); - tm = localtime(&t); -#ifdef USG - sprintf(bfr,"%s\t%2.2d/%2.2d/%d %2.2d:%2.2d\tcancelled", -#else /* !USG */ - sprintf(bfr,"%s\t%02d/%02d/%d %02d:%02d\tcancelled", -#endif /* !USG */ - argv[1], tm->tm_mon+1, tm->tm_mday, tm->tm_year, tm->tm_hour, - tm->tm_min); - savehist(bfr); - return 1; - } - - q = index(line, '\t'); - p = index(q+1, '\t'); - if (p == NULL || *++p == '\0' || *p == '\n') { - *q = '\0'; - log("Expired article %s", line); - return 1; - } - if (strcmp(p, "cancelled") == 0) { - *q = '\0'; - log("Already Cancelled %s", line); - return 1; - } else - log("Cancelling %s", line); - if ((uid == ROOTID||uid == 0) && strcmp(header.distribution, "local") == 0) - su = 1; - while (*p) { - q = index(p, ' '); - if (q) - *q = '\0'; - (void) strcpy(nfilename, dirname(p)); - fp = fopen(nfilename, "r"); - if (fp == NULL) { - log("Already Cancelled %s", line); - return 1; - } - htmp.unrec[0] = NULL; - if (hread(&htmp, fp, TRUE) == NULL) { - if (bfr[0] == '/') { - fp = fopen(bfr, "r"); - if (fp == NULL - || hread(&htmp, fp, TRUE) == NULL) - error("Article is garbled."); - } else - error("Article is garbled."); - } - (void) fclose(fp); - poster = senderof(&htmp); - /* only compare up to '.' or ' ' */ - r = index(poster,'.'); - if (r == NULL) - r = index(poster,' '); - if (r != NULL) - *r = '\0'; - if (!su && strncmp(whatsisname, poster,strlen(poster))) { - error("Not contributor: posted by %s, and you are %s", poster, whatsisname); - } - - (void) unlink(nfilename); - p = q+1; - } - return 0; -} - -/* - * sendsys (no arguments) - * - * Mail the sys file to the person submitting the article. - * POLICY: the contents of your sys file are public information - * and as such, you should not change this code. You may feel - * free to arrange for it to manually notify you, in the event - * that you want to do something to clean it up before it goes out. - * Secret sites on the net are expressly frowned on. - * - * The purpose of this command is for making a network map. The - * details of your link and which newsgroups are forwarded are not - * important, in case you want to sanitize them. Since the definition - * of USENET is those sites getting net.announce, you can disable this - * on sites not getting net articles, but if you take out the list of - * forwarded newsgroups, and you have sites that only get local newsgroups, - * you should make this clear, or remove those sites from what you send out. - */ -/* ARGSUSED */ -c_sendsys(argc, argv) -char **argv; -{ - register FILE *f, *u; - int c; - -#ifdef NOTIFY - f = mailhdr((struct hbuf *)NULL, "sendsys control message"); - if (f != NULL) { - fprintf(f, "%s requested your %s/sys file.\n", header.path, LIB); - fprintf(f, "It has been sent.\n"); - (void) mclose(f); - } -#endif /* NOTIFY */ - f = mailhdr(&header, "response to your sendsys request"); - u = fopen(SUBFILE, "r"); - if (f != NULL && u != NULL) { - while ((c=getc(u)) != EOF) - putc(c, f); - (void) fclose(u); - (void) mclose(f); - } -} - -/* - * senduuname (no arguments) - * - * Run the "uuname" command and send it back to the person who submitted - * the article. The purpose of this control message is for attempting to - * make a uucp net map. - * - * POLICY: If you view this information as not public (because you have - * a connection you consider secret, or know a site that considers itself - * secret) you can feel free to change this code in whatever way is - * appropriate, so long as it sends some response back to the sender. If - * you don't run uucp, this code does not make sense, and so an error - * message (or garbage, such as "research") will be mailed back. - * - * If you wish to add or remove sites from the output of uuname, you - * may wish to use the euuname.sh shell script here. - */ -/* ARGSUSED */ -c_senduuname(argc, argv) -char **argv; -{ - char buf[256]; - FILE *fd, *u; - int c; - -#ifdef NOTIFY - fd = mailhdr((struct hbuf *)NULL, "uuname control message"); - fprintf(fd, "%s requested your uuname output\n", header.path); - (void) mclose(fd); -#endif /* NOTIFY */ - fd = mailhdr(&header, "response to your senduuname request"); -#ifdef UUPROG - if (UUPROG[0] == '/') - (void) strcpy(buf, UUPROG); - else - (void) sprintf(buf, "%s/%s", LIB, UUPROG); -#else - (void) strcpy(buf, "uuname"); -#endif - u = popen(buf, "r"); - if (fd != NULL && u != NULL) { - while ((c=getc(u)) != EOF) - putc(c, fd); - (void) pclose(u); - (void) mclose(fd); - } -} - -/* - * Send the version number to the right person. - */ -/* ARGSUSED */ -c_version(argc, argv) -char **argv; -{ - register FILE *f; - - f = mailhdr(&header, "Our news version"); - if (f == NULL) - error("Cannot send back error message"); - fprintf(f, "Currently running news version %s.\n\n", news_version); - fprintf(f, "The header of your message follows:\n\n"); - (void) hwrite(&header, f); - (void) mclose(f); -} - -/* - * Check the active file for old or missing newsgroups - * Body of article is list of valid groups - */ -/* ARGSUSED */ -c_checkgroups(argc, argv) -char **argv; -{ - int rc; - - (void) setuid(geteuid()); - /* dont change the cat %s| to < %s, it breaks some "unix" systems */ - (void) sprintf(bfr, "cat %s | %s/checkgroups %s", INFILE, LIB, -#ifdef NOTIFY - (TELLME && *TELLME) ? TELLME : NEWSUSR ); -#else /* !NOTIFY */ - NEWSUSR); -#endif /* !NOTIFY */ - rc = system(bfr); - log("system(%s) status %d", bfr, rc); -} - -/* - * An unknown control message has been received. - */ -c_unknown(h, ctlmsgtext) -struct hbuf *h; -char *ctlmsgtext; -{ - register FILE *f; - - log("UNKNOWN Ctl Msg %s from %s", ctlmsgtext, h->path); -#ifdef NOTIFY - f = mailhdr((struct hbuf *)NULL, "Unrecognized Control Message"); - if (f != NULL) { - fprintf(f, "Currently running news version %s.\n\n", news_version); - fprintf(f, "The header of the message follows:\n\n"); - (void) hwrite(h, f); - (void) mclose(f); - } -#endif /* NOTIFY */ -} - -/* ARGSUSED */ -c_unimp(argc, argv) -char **argv; -{ - register FILE *f; - -#ifdef NOTIFY - f = mailhdr((struct hbuf*)NULL, "Unimplemented Control Message"); - if (f != NULL) { - fprintf(f, "Currently running news version B %s.\n\n", news_version); - fprintf(f, "The header of the message follows:\n\n"); - (void) hwrite(&header, f); - (void) mclose(f); - } -#endif /* NOTIFY */ -} - -/* - * This is a modified version of popen, made more secure. Rather than - * forking off a shell, you get a bare process. You must have exactly - * one argument, and the command must be mail (or sendmail if you have it). - */ -#define RDR 0 -#define WTR 1 -static int mopen_pid[20]; -char *replyname(); - -FILE * -mhopen(hptr) -struct hbuf *hptr; -{ - int p[2]; - register myside, hisside, pid; - char *sendto = "usenet"; - - if (hptr) - sendto = replyname(hptr); - else { -#ifdef NOTIFY - if (TELLME) - sendto = TELLME; -#endif /* NOTIFY */ - if (sendto == NULL || *sendto == NULL) - return NULL; - } - verifyname(sendto); - if(pipe(p) < 0) - return NULL; - myside = p[WTR]; - hisside = p[RDR]; - if((pid = vfork()) == 0) { - /* myside and hisside reverse roles in child */ - (void) close(myside); - (void) close(0); - (void) dup(hisside); - (void) close(hisside); - (void) setgid(gid); - (void) setuid(uid); -#ifdef SENDMAIL - execl(SENDMAIL, "sendmail", "-oi", "-oeq", sendto, (char *)NULL); -#endif /* SENDMAIL */ -#ifdef MMDF - execl(MMDF, "inews-mail", "-smuxto,cc*", (char *)NULL); -#endif /* MMDF */ - execl("/bin/mail", "mail", sendto, (char *)NULL); - execl("/usr/bin/mail", "mail", sendto, (char *)NULL); - execl("/usr/ucb/mail", "mail", sendto, (char *)NULL); - _exit(1); - } - if(pid == -1) - return NULL; - mopen_pid[myside] = pid; - (void) close(hisside); - return(fdopen(myside, "w")); -} - -mclose(ptr) -FILE *ptr; -{ - register f, r, (*hstat)(), (*istat)(), (*qstat)(); - int status; - - f = fileno(ptr); - (void) fclose(ptr); - istat = signal(SIGINT, SIG_IGN); - qstat = signal(SIGQUIT, SIG_IGN); - hstat = signal(SIGHUP, SIG_IGN); - while((r = wait(&status)) != mopen_pid[f] && r != -1) - ; - if(r == -1) - status = -1; - signal(SIGINT, istat); - signal(SIGQUIT, qstat); - signal(SIGHUP, hstat); - return status; -} - -/* - * mhopen a pipe to mail, write out a std header, and return the file ptr. - * - * We don't include a From: field because this is probably uucp, i.e. - * explicitly routed. Leave it up to the recipient's mailer. - * Always include the To: field because if we ge back failed mail, we - * might be able to deliver it by hand if we know to wom it was addressed. - * By convention, hptr==NULL means to send the message to the local contact person. - */ -FILE * -mailhdr(hptr, subject) -struct hbuf *hptr; -char *subject; -{ - FILE *fp; - time_t now; - char *to = "usenet"; - -#ifdef NOTIFY - if (TELLME && *TELLME) - to = TELLME; -#endif /* NOTIFY */ - if (hptr) - to = replyname(hptr); - - if ((fp = mhopen(hptr)) != NULL) { - (void) time(&now); - fprintf(fp, "Date: %s\n", arpadate(&now)); -#ifdef MMDF - fprintf(fp, "From: The News System <usenet@%s%s>\n", - FULLSYSNAME, MYDOMAIN); -#endif /* MMDF */ - fprintf(fp, "To: %s\n", to); - fprintf(fp, "Subject: %s\n", subject); -#ifdef HIDDENNET - if (strcmp(LOCALSYSNAME, FULLSYSNAME)) - fprintf(fp, "Responding-System: %s.%s%s\n\n", - LOCALSYSNAME, FULLSYSNAME, MYDOMAIN); - else -#endif /* !HIDDENNET */ - fprintf(fp, "Responding-System: %s%s\n\n", - FULLSYSNAME, MYDOMAIN); - } - return fp; -} - -/* - * verify that the name mail is being sent to does not contain any - * nasty hooks to invoke funny functions from the shell or the like. - */ -verifyname(sendto) -char *sendto; -{ - /* Be sure we DO allow alphabetics, !, :, ., -, @. *. */ - char *nasty = "\"'\\`^|;& <>/~"; - register char *p; - - if (sendto[0] <= ' ') { - log("nasty mail name %s from %s", sendto, header.path); - xxit(1); - } - for (p=sendto; *p; p++) { - if (*p == ' ') { - *p = 0; - break; - } - } - if (strpbrk(sendto, nasty) != NULL) - error("nasty mail name %s from %s", sendto, header.path); - - for (nasty = sendto; (nasty = index(nasty, '.')) != NULL; ) { - if (*++nasty == '.') /* check for .. */ - error("nasty mail name %s from %s", sendto, header.path); - } -} - -/* - * Checks to make sure the control message is OK to post. - */ -ctlcheck() -{ - char msg[BUFLEN]; - char *p; - - if (!is_ctl) - return; - - if (header.ctlmsg[0]) - (void) strcpy(msg, header.ctlmsg); - else - (void) strcpy(msg, header.title); - - p = index(msg, ' '); - if (p) - *p = 0; - - if (strcmp(msg, "ihave") == 0 || strcmp(msg, "sendbad") == 0 || - strcmp(msg, "sendme") == 0) { - return; /* no restrictions */ - } else if (strcmp(msg, "newgroup") == 0) { - suser(); - } else if (strcmp(msg, "rmgroup") == 0) { - suser(); - } else if (strcmp(msg, "sendsys") == 0) { - suser(); - } else if (strcmp(msg, "senduuname") == 0) { - suser(); - } else if (strcmp(msg, "checkgroups") == 0) { - suser(); - } else if (strcmp(msg, "version") == 0) { - return; /* no restrictions */ - } else if (strcmp(msg, "cancel") == 0) { - return; /* no restrictions at this level */ - } else if (strcmp(msg, "delsub") == 0) { - if (!prefix(header.nbuf, "to.")) { - printf("Must be in a 'to.system' newsgroup."); - xxit(0); - } - return; - } else { - printf("Unrecognized control message - %s\n", msg); - xxit(0); - } -} - -/* Make sure this guy is special. */ -suser() -{ - if (uid == 0 || uid == ROOTID) - return; - /* - * We assume that since our real uid is the same as NEWSUSR - * (the euid) we were run by rootid and it did a setuid. - * Too bad we can't set just the effective uid like suid does. - */ - if (uid == geteuid()) - return; -#ifdef IHCC - printf("Please use the command:\n\ttoolnews providers\n"); - printf("then call one of the news people.\n"); -#else - printf("Get your local netnews contact to do it for you.\n"); -#endif - xxit(0); -} *-*-END-of-src/control.c-*-* echo x - src/unbatch.c 1>&2 sed 's/.//' >src/unbatch.c <<'*-*-END-of-src/unbatch.c-*-*' -/* - * unbatchnews: extract news in batched format and process it one article - * at a time. The format looks like - * #! rnews 1234 - * article containing 1234 characters - * #! rnews 4321 - * article containing 4321 characters - * - * or - * - * #! command [args] - * calls LIBDIR/command [args] to process the news - */ - -#ifdef SCCSID -static char *SccsId = "@(#)unbatch.c 1.22 10/23/86"; -#endif /* SCCSID */ - -#define MAXARGS 20 - -#include "defs.h" -#include <stdio.h> -#include <ctype.h> -#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) -#include <fcntl.h> -#endif /* USG */ - -char buf[BUFSIZ]; -char sibuf[BUFSIZ]; - -main() -{ - register int c; - register FILE *pfn; - register long size; - char *filename; - int pid, wpid, exstat; - char *mktemp(), *gets(); - long atol(); - - filename = mktemp("/tmp/unbnewsXXXXXX"); - setbuf(stdin, (char *)NULL); /* only for the first line */ - if (gets(buf) == NULL) { - (void) unlink(filename); - exit(0); - } - if (strncmp(buf, "#! rnews ", 9) != 0) { - docmd(buf); - /* should not return */ - logerr("unbatch: docmd returned!"); - exit(1); - } - - setbuf(stdin, sibuf); /* buffer the rest of the file */ - - do { - while (strncmp(buf, "#! rnews ", 9) - && strncmp(buf, "! rnews ", 8)) { /* kludge for bug */ - register char *cp; - for (cp = buf; *cp != '\0'; ++cp) - if (!isascii(*cp) || - (!isprint(*cp) && !isspace(*cp))) - *cp = '?'; - logerr("out of sync, skipping %s", buf); - if (gets(buf) == NULL) - exit(0); - } - size = atol(buf + (buf[0] == '#' ? 9 : 8)); - if(size <= 0) { - logerr("nonsense size %ld", size); - continue; - } -#ifdef VMS -/* The loop is to delete all versions. */ - while (unlink(filename) == 0) - ; -#endif /* VMS */ - pfn = fopen(filename, "w"); - while(--size >= 0 && (c = getc(stdin)) != EOF) - putc(c, pfn); - if (ferror(pfn) || fclose(pfn)) { /* disk full? */ - logerr("error writing temporary file"); - break; - } - - /* - * If we got a truncated batch, don't process the - * last article; it will probably be received again. - */ - if (size > 0) { - logerr("truncated batch"); - break; - } - - /* - * rnews < filename - */ - while ((pid = vfork()) == -1) { - logerr("fork failed, waiting...\n"); - sleep(60); - } - if (pid == 0) { - (void) close(0); - (void) open(filename, 0); -#ifdef IHCC - (void) sprintf(buf, "%s/%s/rnews", logdir(HOME), LIBDIR); -#else - (void) sprintf(buf, "%s/rnews", BINDIR); -#endif -#ifdef SPOOLNEWS - execlp(buf, "rnews", "-S", (char *)0); -#else /* !SPOOLNEWS */ - execlp(buf, "rnews", (char *)0); -#endif /* !SPOOLNEWS */ - perror("rnews"); - exit(1); - } - while ((wpid = wait(&exstat)) >= 0 && wpid != pid) - ; - } while (gets(buf) != NULL); - (void) unlink(filename); - exit(0); -} - -docmd(p) -register char *p; -{ - char *args[MAXARGS]; - register char **ap = args; - char path[BUFSIZ]; - char *rindex(), *cp; - - while (*p && !isspace(*p)) /* skip leading #! crud */ - p++; - - while (isspace(*p)) - p++; - - while (*p != '\0') { - *ap++ = p; - if (ap >= &args[MAXARGS]) { - logerr("unbatch: Too many args to %s", args[0]); - exit(2); - } - while (*p && !isspace(*p)) - p++; - if (*p) - *p++ = '\0'; - while (isspace(*p)) - p++; - } - *ap = (char *)0; - - if (ap == args) { - logerr("unbatch: no command to execute"); - exit(2); - } - - /* strip off any leading pathname in case someone gets tricky */ - cp = rindex(args[0], '/'); - if (cp++ == NULL) - cp = args[0]; - - sprintf(path, "%s/%s", LIBDIR, cp); - - /* - * "path" is absolute, no searching is needed, we use - * 'execvp' solely so that sh scripts will be handled - */ - (void) execvp(path, args); - perror(path); - exit(2); -} - -/* - * Log the given message, with printf strings and parameters allowed, - * on the log file, if it can be written. - */ -/* VARARGS1 */ -logerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) -char *fmt; -{ - FILE *logfile; - char lfname[BUFSIZ]; /* the log file */ - char bfr[BUFSIZ]; - char *logtime, *ctime(); - long t; - - (void) time(&t); - logtime = ctime(&t); - logtime[16] = 0; - logtime += 4; - -#ifdef IHCC - (void) sprintf(lfname, "%s/%s/errlog", logdir(HOME), LIBDIR); -#else - (void) sprintf(lfname, "%s/errlog", LIBDIR); -#endif - - (void) sprintf(bfr, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); - (void) fprintf(stderr, "%s\n", bfr); - if (access(lfname, 0) == 0 && (logfile = fopen(lfname, "a")) != NULL) { -#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) - int flags; - flags = fcntl(fileno(logfile), F_GETFL, 0); - (void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND); -#else /* v7 */ - (void) lseek(fileno(logfile), 0L, 2); -#endif /* v7 */ - fprintf(logfile, "%s\tbatch\t%s\n", logtime, bfr); - (void) fclose(logfile); - } -} *-*-END-of-src/unbatch.c-*-* echo x - src/euninstal.com 1>&2 sed 's/.//' >src/euninstal.com <<'*-*-END-of-src/euninstal.com-*-*' -$ ! @(#)euninstal.com 1.2 10/28/86 -$ ! This DCL script installs inews and rnews with the necessary -$ ! privileges in a Eunice system. -$ SET PROCESS/PRIV=CMKRNL -$ RUN SYS$SYSTEM:INSTALL -EUN_USR:[USR.BIN]RNEWS. /OPEN/SHARED/PRIV=SYSPRV -EUN_USR:[USR.LIB.NEWS]INEWS. /OPEN/SHARED/PRIV=SYSPRV -$ EXIT *-*-END-of-src/euninstal.com-*-* exit