Annotation of 43BSD/contrib/news/misc/keepnews, revision 1.1

1.1     ! root        1: From [email protected] (Chuq Von Rospach) Thu Jun  6 20:36:39 1985
        !             2: Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site seismo.UUCP
        !             3: Posting-Version: version B 2.10.2 9/17/84 chuqui version 1.7 9/23/84; site nsc.UUCP
        !             4: Path: seismo!nsc!chuqui
        !             5: From: [email protected] (Chuq Von Rospach)
        !             6: Newsgroups: net.sources
        !             7: Subject: YA News Archiver
        !             8: Message-ID: <[email protected]>
        !             9: Date: 7 Jun 85 00:36:39 GMT
        !            10: Date-Received: 7 Jun 85 06:25:58 GMT
        !            11: Distribution: net
        !            12: Organization: The Blue Parrot
        !            13: Lines: 566
        !            14: 
        !            15: Here is a netnews archiver similar to the recently posted keepnews but
        !            16: designed to work with much larger archives where the wonderful quadratic
        !            17: search time feature of the Unix (Unix is a trademark of AT&T Bell Labs,
        !            18: quadratic search times are a feature of Unix) becomes a real problem. This
        !            19: archive also knows how to walk through a directory tree so you can simply
        !            20: set it on /usr/spool/oldnews and let it do its work. There are lots of
        !            21: other nifty things I call features (and you might, too) that make it a lot
        !            22: easier to use than anything else I've seen set up to work on archives. Mine
        !            23: simply outgrew any capability to do anything with about the same time I got
        !            24: a request for information out of it. I found out (the hard way) that
        !            25: keepnews wasn't terribly reliable working under 2.10.2, so I finally
        !            26: decided to hack together my own.
        !            27: 
        !            28: Comments, enhancements, bug fixes, etc... are welcome, but I can only work
        !            29: on them on a time available basis...
        !            30: 
        !            31: chuq
        !            32: ------- 
        !            33: #      This is a shell archive.
        !            34: #      Remove everything above and including the cut line.
        !            35: #      Then run the rest of the file through sh.
        !            36: #-----cut here-----cut here-----cut here-----cut here-----
        !            37: #!/bin/sh
        !            38: # shar:        Shell Archiver
        !            39: #      Run the following text with /bin/sh to create:
        !            40: #      README
        !            41: #      Makefile
        !            42: #      savenews.c
        !            43: # This archive created: Thu Jun  6 17:28:50 1985
        !            44: # By:  Chuq Von Rospach (The Blue Parrot)
        !            45: cat << \SHAR_EOF > README
        !            46: Savenews --
        !            47: 
        !            48: Savenews is a short program designed to make handling of usenet archives
        !            49: generated by 'expire -a' easier, and to make it possible to find stuff in
        !            50: the archive once it is there. 
        !            51: 
        !            52: It was created by me when I had to get something out of my archives and
        !            53: realized that there was no way I was going to find anything in 70 megabytes
        !            54: of random data. It keeps a set of logs of the Subject lines of the articles
        !            55: and stores the articles themselves in a hashed subdirectory format designed
        !            56: to minimize the quadratic lookup hassles of the unix directory system
        !            57: (This, of course, is a feature). 
        !            58: 
        !            59: It has been put into the public domain by national semiconductor, and
        !            60: neither myself or national guarantee that this code even exists, much
        !            61: less that it does anything useful. This, BTW, is a disclaimer.
        !            62: 
        !            63: chuq von rospach
        !            64: national semiconductor
        !            65: nsc!chuqui
        !            66: SHAR_EOF
        !            67: cat << \SHAR_EOF > Makefile
        !            68: #
        !            69: # Makefile for savenews
        !            70: #
        !            71: CFLAGS = -g
        !            72: 
        !            73: savenews: savenews.c
        !            74:        ${CC} ${CFLAGS} savenews.c -o savenews
        !            75: 
        !            76: clean:
        !            77:        rm -f savenews
        !            78: 
        !            79: lint:
        !            80:        lint -hx savenews.c
        !            81: SHAR_EOF
        !            82: cat << \SHAR_EOF > savenews.c
        !            83: /*
        !            84:  * savenews filename [filename ...]
        !            85:  *
        !            86:  * Savenews is a program designed to clean up and compact a
        !            87:  * usenet archive. It will take the filename(s) given to it as arguments
        !            88:  * and save them in a netnews archive (defined by SAVENEWS, default is
        !            89:  * /usr/spool/savenews).
        !            90:  *
        !            91:  * This program was set up to do two main things:
        !            92:  *
        !            93:  * 1) compact out the useless parts of the message, specifically the lines
        !            94:  *    in the header that don't serve a useful purpose in an archive. This 
        !            95:  *    is done by removing all but the following header lines: From, Date,
        !            96:  *    Newsgroups, Subject, and Message-ID, and seems to save an average of
        !            97:  *    500 bytes an article.
        !            98:  *
        !            99:  * 2) keep the quadratic nature of unix(TM AT&T Bell labs) directory searches
        !           100:  *    from making your life miserable. Storing a raw archive of
        !           101:  *    net.unix-wizards is a silly thing to do, for example. What I do is
        !           102:  *    create a one level subdirectory set to keep any one directory from
        !           103:  *    getting too large, but this program is currently set so that there
        !           104:  *    are enough directories to keep the total number of files in any one
        !           105:  *    directory below about 150 in the largest parts of my archive. The
        !           106:  *    algorithm I use is abs(atoi(Message-ID)%HASHVAL)) with HASHVAL being
        !           107:  *    prime. This quick and dirty hash gives you directories with the
        !           108:  *    numbers 0 to HASHVAL-1, and about the same number of files in each
        !           109:  *    given a random distribution of Message-ID numbers (not bad, in
        !           110:  *    reality)
        !           111:  *
        !           112:  * The program will add the name of the file and the subject line of the
        !           113:  * article in a logfile in subdirectory LOGS, the filename being the 
        !           114:  * newsgroup.
        !           115:  *
        !           116:  * As currently written, an article will be saved only to the first 
        !           117:  * newsgroup in the Newsgroups header line. This means that something
        !           118:  * posted to 'net.source,net.flame' will end up in net.sources, but that
        !           119:  * somethine posted to 'net.flame,net.sources' will end up in net.flame.
        !           120:  * I consider this a feature. Others may disagree.
        !           121:  *
        !           122:  * If an article is saved that has a duplicate message-ID of one already
        !           123:  * in the archive, then it will be saved by adding the character '_' and
        !           124:  * some small integer needed to make the filename unique. You can then
        !           125:  * use ls or find to look for these and see if they are duplicates (and
        !           126:  * remove them) or if they are simply botches by some other site (it does
        !           127:  * happen, unfortunately).
        !           128:  *
        !           129:  * This program will do intelligent things if given a non-news article,
        !           130:  * such as nothing. Don't push it, though -- I haven't tried it on
        !           131:  * special devices, symbolic links, and other wierdies and it is likely
        !           132:  * to throw up on some of them since I didn`t feel like protecting someone
        !           133:  * from trying to archive /dev (if tar can consider this a feature, so can
        !           134:  * I...)
        !           135:  *
        !           136:  * This program uses the 4.2 Directory routines (libndir). If you don't
        !           137:  * run 4.2, get ahold of a copy of the compatibility library for your
        !           138:  * system and use it, or hack up do_dir and is_dir to get around it
        !           139:  * if you believe in messing around with primitive hacks (I LIKE libndir)
        !           140:  *
        !           141:  * General usage: every so often run the program with 
        !           142:  * 'savenews /usr/spool/oldnews'. Look through /usr/spool/savenews
        !           143:  * for duplicated articles and remove them, and then copy all of the
        !           144:  * stuff to tape. Remove everything except the LOGS directory, so that
        !           145:  * people can use grep to look for things in the archive. It should be
        !           146:  * easy to get things back off of tape and make the archive useful this
        !           147:  * way. Thinking about it, if you can't use the archive, you might as well
        !           148:  * not have it, which is why this program got written (I needed something
        !           149:  * out of my archive, and it took me a week to find it).
        !           150:  *
        !           151:  * This program is designed to run under 2.10.2, but should work under any
        !           152:  * B news system. Anyone else is on their own. This is in
        !           153:  * the public domain by the kindness of my employer, national
        !           154:  * semiconductor, but neither I nor national make any guarantee that it
        !           155:  * will work, that we will support this program, or even admit that it
        !           156:  * exists. This is called a disclaimer, and means that if you use this 
        !           157:  * program, you are on your own. It DOES, however, pass lint cleanly, which
        !           158:  * is more than I can say for most stuff posted to the net. Feel free to 
        !           159:  * fix, break, enhance, change, or do anything to this program except
        !           160:  * claim it to be your own (unless, of course, you break it...). Passing
        !           161:  * enhancements back to me would be nice, too.
        !           162:  *
        !           163:  *     chuq von rospach, national semiconductor (nsc!chuqui)
        !           164:  *
        !           165:  */
        !           166: 
        !           167: #include <stdio.h>
        !           168: #include <sys/types.h>
        !           169: #include <sys/stat.h>
        !           170: #include <sys/dir.h>
        !           171: #include <ctype.h>
        !           172: 
        !           173: #define FALSE          0
        !           174: #define TRUE           1
        !           175: #define HASHVAL                37      /* hash value for sub-dirs. Prime number! */
        !           176: #define NUMDIRS                1024    /* number of dirs that can be pushed */
        !           177: #define SAVENEWS       "/usr/spool/savenews" /* home of the archive */
        !           178: #define LOGFILE                "LOGS"  /* subdir in SAVENEWS to save logs in */
        !           179: #define JOBLOG         "joblog" /* where log of this job is put */
        !           180: #define DIRMODE                0755    /* mkdir with this mode */
        !           181: #define COPYBUF                8192    /* block read/write buffer size */
        !           182: 
        !           183: char *Progname;                        /* name of the program for Eprintf */
        !           184: char line[BUFSIZ];             /* general purpose line buffer */
        !           185: 
        !           186: #define NUM_HEADERS    5       /* number of headers we are saving */
        !           187: #define GROUP_HEADER   1       /* where Newsgroup will be found */
        !           188: #define SUBJECT_HEADER 2       /* where Subject will be found */
        !           189: #define MESSAGE_HEADER 3       /* where Message-ID will be found */
        !           190: char header_data[NUM_HEADERS][BUFSIZ];
        !           191: char *headers[NUM_HEADERS] =
        !           192: {
        !           193:     "From:",
        !           194:     "Newsgroups:",
        !           195:     "Subject:",
        !           196:     "Message-ID:",
        !           197:     "Date:"
        !           198: };
        !           199: 
        !           200: long num_saved = 0;            /* number of articles saved */
        !           201: FILE *logfp;                   /* file pointer to joblog file */
        !           202: 
        !           203: char *rindex(), *strcat(), *pop_dir(), *strcpy(), *strsave(), *index();
        !           204: 
        !           205: main(argc,argv)
        !           206: int argc;
        !           207: char *argv[];
        !           208: {
        !           209:     register int i;
        !           210:     char joblogfile[BUFSIZ];
        !           211:     char *dirname;
        !           212:     
        !           213:     /*
        !           214:      * This removes and preceeding pathname so that
        !           215:      * anything printed out by Eprintf has just the 
        !           216:      * program name and not where it came from
        !           217:      */
        !           218:     if ((Progname = rindex(argv[0],'/')) == NULL)  
        !           219:        Progname = argv[0];                        
        !           220:     else
        !           221:        Progname++;                               
        !           222: 
        !           223:     if (argc == 1) {
        !           224:        fprintf(stderr,"Usage: %s file [file ...]\n",Progname);
        !           225:        exit(1);
        !           226:     }
        !           227: 
        !           228:     sprintf(joblogfile,"%s/%s",SAVENEWS,JOBLOG);
        !           229:     if ((logfp = fopen(joblogfile,"w")) == NULL)
        !           230:        fprintf(stderr,"Can't open %s, logging suspended\n",joblogfile);
        !           231: 
        !           232:     for (i = 1 ; i < argc; i++) {      /* process each parameter */
        !           233:        register int rc;
        !           234:        if ((rc = is_dir(argv[i])) == -1)
        !           235:            continue;
        !           236:        else if (rc == TRUE)
        !           237:            do_dir(argv[i]);
        !           238:        else
        !           239:            save_file(argv[i]);
        !           240:     }
        !           241:     while((dirname = pop_dir()) != NULL) {
        !           242:        do_dir(dirname);        /* process whatever is left on dirstack */
        !           243:     }
        !           244:     printf("Total articles saved was %d\n",num_saved);
        !           245:     exit(0);
        !           246: }
        !           247: 
        !           248: do_dir(dname) /* process a directory, push other directories on stack */
        !           249:              /* to be handled recursively later */
        !           250: char *dname;
        !           251: {
        !           252:     DIR *dirp;
        !           253:     struct direct *dp;
        !           254:     char fullname[BUFSIZ];
        !           255: 
        !           256:     if ((dirp = opendir(dname)) == NULL) {
        !           257:        Eprintf("can't opendir %s\n",dname);
        !           258:        return;
        !           259:     }
        !           260: 
        !           261:     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
        !           262:        register int rc;
        !           263: 
        !           264:        if(dp->d_namlen == 2 && !strcmp(dp->d_name,"..") 
        !           265:        || (dp->d_namlen == 1 && !strcmp(dp->d_name,".")))
        !           266:            continue; /* skip . and .. */
        !           267: 
        !           268:        sprintf(fullname,"%s/%s",dname,dp->d_name);
        !           269:        if((rc = is_dir(fullname)) == -1)
        !           270:            continue;
        !           271:        else if (rc == TRUE)
        !           272:            push_dir(fullname);
        !           273:        else
        !           274:            save_file(fullname);
        !           275:     }
        !           276:     closedir(dirp);
        !           277: }
        !           278: 
        !           279: is_dir(name)
        !           280: char *name;
        !           281: {
        !           282:     struct stat sbuf;
        !           283: 
        !           284:     if (stat(name,&sbuf) == -1) {
        !           285:        Eprintf("can't stat '%s'\n",name);
        !           286:        return(-1);
        !           287:     }
        !           288:     return((sbuf.st_mode & S_IFDIR) ? TRUE : FALSE);
        !           289: }
        !           290: 
        !           291: /* VARARGS */
        !           292: Eprintf(s1,s2,s3,s4,s5,s6,s7,s8,s9)
        !           293: char *s1,*s2,*s3,*s4,*s5,*s6,*s7,*s8,*s9;
        !           294: {
        !           295:     if (logfp == NULL)
        !           296:        return;
        !           297:     fprintf(logfp,"%s: ",Progname);
        !           298:     fprintf(logfp,s1,s2,s3,s4,s5,s6,s7,s8,s9);
        !           299:     fflush(logfp);
        !           300: }
        !           301: 
        !           302: /*
        !           303:  * quick and dirty stack routines.
        !           304:  *
        !           305:  * push_dir(name) char *name; 
        !           306:  *     stores the given string in the stack
        !           307:  * char *pop_dir()
        !           308:  *     returns a string from the stack, or NULL if none.
        !           309:  */
        !           310: 
        !           311: static char *dirstack[NUMDIRS];
        !           312: static int lastdir = 0;
        !           313: static char pop_name[BUFSIZ];
        !           314: 
        !           315: push_dir(name)
        !           316: char *name;
        !           317: {
        !           318:     if (lastdir >= NUMDIRS) {
        !           319:        Eprintf("push_dir overflow!\n");
        !           320:        return;
        !           321:     }
        !           322:     dirstack[lastdir] = strsave(name);
        !           323:     if (dirstack[lastdir] == NULL)
        !           324:     {
        !           325:        Eprintf("malloc failed!\n");
        !           326:        return;
        !           327:     }
        !           328:     lastdir++;
        !           329: }
        !           330: 
        !           331: char *pop_dir()
        !           332: {
        !           333:     if(lastdir == 0)
        !           334:        return(NULL);
        !           335:     lastdir--;
        !           336:     strcpy(pop_name,dirstack[lastdir]);
        !           337:     dirstack[lastdir] = NULL;
        !           338:     free(dirstack[lastdir]);
        !           339:     return(pop_name);
        !           340: }
        !           341: 
        !           342: char *strsave(s)
        !           343: char *s;
        !           344: {
        !           345:     char *p, *malloc();
        !           346: 
        !           347:     if ((p = malloc((unsigned)strlen(s)+1)) != NULL)
        !           348:        strcpy(p,s);
        !           349:     return(p);
        !           350: }
        !           351: 
        !           352: save_file(name)                /* save the article in the archive */
        !           353: char *name;
        !           354: {
        !           355:     FILE *fp, *ofp, *fopen(), *output_file();
        !           356:     register int i, nc;
        !           357:     char diskbuf[COPYBUF];
        !           358: 
        !           359:     Eprintf("saving '%s'\n",name);
        !           360:     if ((fp = fopen(name,"r")) == NULL) {
        !           361:        Eprintf("can't open\n");
        !           362:        return;
        !           363:     }
        !           364: 
        !           365:     if ((fgets(line,BUFSIZ,fp) == NULL)) {
        !           366:        Eprintf("0 length file\n");
        !           367:        fclose(fp);
        !           368:        return;
        !           369:     }
        !           370:     if (!start_header(line)) {
        !           371:        Eprintf("not a news article\n");
        !           372:        fclose(fp);
        !           373:        return;
        !           374:     }
        !           375:     read_header(fp);
        !           376:     if ((ofp = output_file()) == NULL) {
        !           377:        Eprintf("Can't save\n");
        !           378:        fclose(fp);
        !           379:        return;
        !           380:     }
        !           381: 
        !           382:     for (i = 0; i < NUM_HEADERS; i++)
        !           383:        fprintf(ofp,"%s\n",header_data[i]);
        !           384:     fputc('\n',ofp);
        !           385: 
        !           386:     while ((nc = fread(diskbuf,sizeof(char),COPYBUF,fp)) != 0)
        !           387:        fwrite(diskbuf,sizeof(char),nc,ofp);    /* copy body of article */
        !           388:     fclose(ofp);
        !           389:     fclose(fp);
        !           390:     num_saved++;
        !           391:     return;
        !           392: }
        !           393: 
        !           394: start_header(s) /* see if this is the start of a news article */
        !           395: char *s;
        !           396: {
        !           397:     /*
        !           398:      * If this is coming from B news, the first line will 'always' be
        !           399:      * Relay-Version (at least, on my system). Your mileage my vary.
        !           400:      */
        !           401:     if (!strncmp(s,"Relay-Version:",14))
        !           402:        return(TRUE);
        !           403:     /*
        !           404:      * If you are copying a section of archive already archived by 
        !           405:      * sendnews, then the first line will be From (unless you changed
        !           406:      * the headers data structure, then its up to you...)
        !           407:      */
        !           408:     if (!strncmp(s,"From:",5))
        !           409:        return(TRUE);
        !           410:     return(FALSE);
        !           411: }
        !           412: 
        !           413: /* 
        !           414:  * By the time we get here, the first line will already be read in and
        !           415:  * checked by start_header(). If we are re-copying a savenews archive
        !           416:  * (which happens when you decide to play with HASHVAL, trust me) then
        !           417:  * we need to save the From line, so we can't just throw it away. Hence
        !           418:  * the funky looking do-while setup instead of something a bit more
        !           419:  * straightforward
        !           420:  */
        !           421: read_header(fp)
        !           422: FILE *fp;
        !           423: {
        !           424:     register int i;
        !           425: 
        !           426:     for (i = 0; i < NUM_HEADERS; i++)
        !           427:        header_data[i][0] = '\0';               /* remove last articles data */
        !           428: 
        !           429:     do {
        !           430:        char *cp;
        !           431: 
        !           432:        if (line[0] == '\n')    /* always be a blank line after the header */
        !           433:            return;
        !           434: 
        !           435:        for (i = 0 ; i < NUM_HEADERS; i++) {
        !           436:            if (!strncmp(headers[i],line,strlen(headers[i]))) {
        !           437:                strcpy(header_data[i],line);
        !           438:                if (cp = index(header_data[i],'\n'))
        !           439:                    *cp = '\0';                         /* eat newlines */
        !           440:            }
        !           441:        }
        !           442:     } while (fgets(line,BUFSIZ,fp) != NULL);
        !           443: }
        !           444: 
        !           445: FILE *output_file() /* generate the name in the archive */
        !           446: {
        !           447:     int hashval, copy = 0;
        !           448:     FILE *fp, *fopen();
        !           449:     char *p, newsgroup[BUFSIZ], message_id[BUFSIZ];
        !           450:     char shortname[BUFSIZ], filename[BUFSIZ], filename2[BUFSIZ];
        !           451: 
        !           452:     /* get the first newsgroup */
        !           453:     p = index(header_data[GROUP_HEADER],':'); /* move past Newsgroups */
        !           454:     if (!p) {
        !           455:        Eprintf("Invalid newsgroups\n");
        !           456:        return(NULL);
        !           457:     }
        !           458:     p++;       /* skip the colon */
        !           459:     while (isspace(*p))
        !           460:        p++;    /* skip whitespace */
        !           461:     strcpy(newsgroup,p);
        !           462:     if (p = index(newsgroup,','))
        !           463:        *p= '\0';       /* newsgroup now only has one name in it */
        !           464:     
        !           465:     /* get the message-id */
        !           466:     p = index(header_data[MESSAGE_HEADER],':');
        !           467:     if (!p) {
        !           468:        Eprintf("Invalid message-id\n");
        !           469:        return(NULL);
        !           470:     }
        !           471:     p++;       /* skip the colon */
        !           472:     while (isspace(*p))
        !           473:        p++;    /* skip whitespace */
        !           474:     if (*p == '<' || *p == '(')
        !           475:        p++;
        !           476:     if (*p == '-') /* make negative article id numbers positive (hack) */
        !           477:        p++;
        !           478:     strcpy(message_id,p);
        !           479:     if (p = index(message_id,'.')) /* trim off the .UUCP if any */
        !           480:        *p = '\0';
        !           481:     else if (p = index(message_id,'>'))  /* or get the closing bracket */
        !           482:        *p = '\0';
        !           483:     else if (p = index(message_id,')')) /* or get the closing paren */
        !           484:        *p = '\0';
        !           485:     if (p = index(message_id,'@'))     /* change nnn@site */
        !           486:        *p = '.';                       /* to nnn.site */
        !           487: 
        !           488:     /* generate the hash value for the subdirectory */
        !           489:     hashval = atoi(message_id) % HASHVAL;
        !           490: 
        !           491:     /* setup the filename to save to */
        !           492:     sprintf(shortname,"%s/%d/%s",newsgroup,hashval,message_id);
        !           493:     sprintf(filename,"%s/%s",SAVENEWS,shortname);
        !           494:     while (exists(filename)) { /* make it unique if neccessary */
        !           495: 
        !           496:        sprintf(shortname,"%s/%d/%s_%d",newsgroup,hashval,message_id,++copy);
        !           497:        sprintf(filename,"%s/%s",SAVENEWS,shortname);
        !           498:     }
        !           499:     
        !           500:     strcpy(filename2,filename);                        /* must chop off the filename */
        !           501:     if (p = rindex(filename2,'/'))             /* since we don't want to */
        !           502:        *p = '\0';                              /* to makeparents */
        !           503:     makeparents(filename2);
        !           504: 
        !           505:     if ((fp = fopen(filename,"w")) == NULL) {
        !           506:        Eprintf("Can't open %s for output\n",filename);
        !           507:        return(NULL);
        !           508:     }
        !           509:     log(newsgroup,shortname);
        !           510:     return(fp);
        !           511: }
        !           512: 
        !           513: exists(name)
        !           514: char *name;
        !           515: {
        !           516:     struct stat sbuf;
        !           517: 
        !           518:     if (stat(name,&sbuf) == -1) {
        !           519:        return(FALSE);
        !           520:     }
        !           521:     return(TRUE);
        !           522: }
        !           523: 
        !           524: makeparents(name) /* recursively make parent directories */
        !           525: char *name;
        !           526: {
        !           527:     char *p, buf[BUFSIZ];
        !           528: 
        !           529:     if (exists(name))
        !           530:        return;
        !           531:     strcpy(buf,name);
        !           532:     if (!(p = rindex(buf,'/'))) {
        !           533:        Eprintf("makeparents failed!\n");
        !           534:        return;
        !           535:     }
        !           536:     *p = '\0';
        !           537:     makeparents(buf);
        !           538:     mkdir(name,DIRMODE);
        !           539: }
        !           540: 
        !           541: log(group,name) /* write to the logfile */
        !           542: char *group, *name;
        !           543: {
        !           544:     char *subject, logfile[BUFSIZ];
        !           545:     FILE *ofp, *fopen();
        !           546: 
        !           547:     /* get the subject */
        !           548:     subject = index(header_data[SUBJECT_HEADER],':');
        !           549:     if (!subject) {
        !           550:        Eprintf("Invalid subject, no log entry\n");
        !           551:        return;
        !           552:     }
        !           553:     subject++; /* skip the colon */
        !           554:     while (isspace(*subject))
        !           555:        subject++;      /* skip whitespace */
        !           556: 
        !           557:     /* generate the place where it goes */
        !           558:     sprintf(logfile,"%s/%s",SAVENEWS,LOGFILE);
        !           559:     makeparents(logfile);
        !           560:     strcat(logfile,"/");
        !           561:     strcat(logfile,group);
        !           562: 
        !           563:     if ((ofp = fopen(logfile,"a")) == NULL)
        !           564:     {
        !           565:        Eprintf("open failed on %s\n",logfile);
        !           566:        return;
        !           567:     }
        !           568:     fprintf(ofp,"%s\t%s\n", name, subject);
        !           569:     fclose(ofp);
        !           570: }
        !           571: 
        !           572: SHAR_EOF
        !           573: #      End of shell archive
        !           574: exit 0
        !           575: -- 
        !           576: :From the misfiring synapses of:                  Chuq Von Rospach
        !           577: {cbosgd,fortune,hplabs,ihnp4,seismo}!nsc!chuqui   [email protected]
        !           578: 
        !           579: The offices were very nice, and the clients were only raping the land, and
        !           580: then, of course, there was the money...
        !           581: 
        !           582: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.