Annotation of 43BSD/contrib/notes/src/newsdump.c, revision 1.1.1.1

1.1       root        1: #include "parms.h"
                      2: #include "structs.h"
                      3: #include "newsgate.h"
                      4: 
                      5: #ifdef RCSIDENT
                      6: static char *RCSid = "$Header: newsdump.c,v 1.7.0.8 85/07/20 13:43:56 notes Rel $";
                      7: #endif RCSIDENT
                      8: 
                      9: /*
                     10:  *     newsnote - take a note and dump it in a format that news will
                     11:  *     understand. Submit the article to the news program as 
                     12:  *     defined in newsgate.h
                     13:  *
                     14:  *     newsresp - similar to newsnote, but it dumps a response instead.
                     15:  *
                     16:  *     The routines build some title lines and other headers for 
                     17:  *     submission to the news insertion program. The rest of the
                     18:  *     article is fed to the news program through a pipe.
                     19:  *     This turned out to be mucho mucho easier than building the
                     20:  *     properly formatted intersystem files.
                     21:  *
                     22:  *     Original Coding:        Ray Essick      April 1982
                     23:  *     Modified to produce cleaner looking output:
                     24:  *                             Ray Essick      May 1, 1982
                     25:  *                             (with good help from Brian Redman (harpo!ber)
                     26:  *     Modified to solve meta-character ("'`) problems in popen()
                     27:  *                             Ray Essick      September 1982
                     28:  *
                     29:  *     Lots of code by Tw Cook at Hewlett-Packard to implement
                     30:  *     compatibility with the USENET standards for news.
                     31:  *                     January 1984.
                     32:  */
                     33: 
                     34: extern char *mnames[];                                 /* month names */
                     35: FILE * popen ();
                     36: 
                     37: char   *Version = "$Revision: 1.7.0.8 $";              /* Use RCS info */
                     38: 
                     39: newsnote (io, note, notenum, ngroup, backwards)
                     40: struct io_f *io;
                     41: struct note_f  *note;
                     42: char   *ngroup;                                                /* to this newsgroup */
                     43: {
                     44:     FILE * rnews;                                      /* rnews pipe */
                     45:     char    cmdline[CMDLEN];                           /* command line  */
                     46:     char    line[TITLEN + 50];                         /* scratch line */
                     47:     int     i;
                     48:     char   *p,
                     49:            *q;
                     50:     char    ntitle[TITLEN + 10];                       /* title */
                     51:     char    from[SYSSZ + NAMESZ + 3];                  /* formatted author */
                     52:     char    path[BUFSIZ];                              /* path to author */
                     53:     char   *author;                                    /* for Path line */
                     54: 
                     55: /*
                     56:  *     format some of the internal data structures in a suitable
                     57:  *     format to send to the news system.
                     58:  */
                     59: 
                     60:     strcpy (ntitle, note -> ntitle);                   /* make a title */
                     61:     if (backwards)
                     62:     {
                     63:        strcat (ntitle, " ");                           /* separate */
                     64:        strcat (ntitle, NFSUFFIX);                      /* add suffix */
                     65:     }
                     66: 
                     67:     /* 
                     68:      * From:
                     69:      *         author information
                     70:      */
                     71:     sprintf (from, "%s@%s",                            /* author */
                     72:            note -> n_auth.aname, note -> n_auth.asystem);
                     73: #ifdef notdef
                     74:     /* 
                     75:      * decided it was better to NOT append a domain here...
                     76:      */
                     77:     if (index (note -> n_auth.asystem, '.') != (char *) NULL)/* domained */
                     78:     {
                     79:        sprintf (from, "%s@%s",
                     80:                note -> n_auth.aname, note -> n_auth.asystem);
                     81:     }
                     82:     else
                     83:     {
                     84:        sprintf (from, "%s@%s.%s",
                     85:                note -> n_auth.aname, note -> n_auth.asystem,
                     86:                DFLTDOMAIN);                            /* append default */
                     87:     }
                     88: #endif notdef
                     89:     /* 
                     90:      * Path:
                     91:      * where the article has been
                     92:      *  Maybe we want to use some format besides a!b!c, something like
                     93:      *  a,b,c
                     94:      */
                     95:     if (!strcmp (System, note -> n_id.sys))            /* local */
                     96:     {
                     97:        sprintf (path, "%s", note -> n_id.sys);
                     98:     }
                     99:     else
                    100:     {
                    101:        if (!strcmp (note -> n_id.sys, note -> n_from)) /* one hop */
                    102:        {
                    103:            sprintf (path, "%s!%s",
                    104:                    System,
                    105:                    note -> n_id.sys);
                    106:        }
                    107:        else
                    108:        {
                    109:            sprintf (path, "%s!%s!%s",                  /* several hops */
                    110:                    System, note -> n_from, note -> n_id.sys);
                    111:        }
                    112:     }
                    113: #ifdef UGLYPATH                                        /* usually so */
                    114:     /* 
                    115:      * Fill in the "authorname" with either a placeholder
                    116:      * or the real author name. Key this off whether the unique
                    117:      * id matches the author's home system.
                    118:      *
                    119:      * This will usually use AUTHORPLACEHOLDER on new systems
                    120:      * since the unique id's don't have the domains in yet.
                    121:      *
                    122:      * hacked at to satisfy the public at large still using the
                    123:      * Path line although it's not supposed to be good any longer.
                    124:      * new code checks to see if things are a common prefix. and
                    125:      * that the next character in the longer string is a "."
                    126:      * if so, it declares things good enough and uses the real author.
                    127:      */
                    128:     {
                    129:        int     idlen,
                    130:                authlen;
                    131:        int     isok;
                    132:        int     minlen;
                    133: 
                    134:        idlen = strlen (note -> n_id.sys);
                    135:        authlen = strlen (note -> n_auth.asystem);
                    136:        minlen = idlen < authlen ? idlen : authlen;     /* get shortest */
                    137:        isok = (strncmp (note -> n_id.sys, note -> n_auth.asystem, minlen) == 0);
                    138:        if (isok && idlen < authlen)                    /* id is short */
                    139:        {
                    140:            isok &= (note -> n_auth.asystem[idlen] == '.');
                    141:        }
                    142:        else
                    143:        {
                    144:            if (isok && authlen < idlen)
                    145:                isok &= (note -> n_id.sys[authlen] == '.');
                    146:        }
                    147:        if (isok)
                    148:            author = note -> n_auth.aname;              /* ok for him */
                    149:        else
                    150:            author = AUTHORPLACEHOLDER;                 /* not local */
                    151:     }
                    152: #else  !UGLYPATH
                    153:     /* 
                    154:      * the bnews code all assumes that the last component of
                    155:      * the Path line is a user name. If we don't append something,
                    156:      * that system will see the articles again, since news will
                    157:      * disregard it when comparing to see where things have been.
                    158:      */
                    159:     author = AUTHORPLACEHOLDER;
                    160: #endif UGLYPATH
                    161: /*
                    162:  *     dump the article
                    163:  */
                    164: 
                    165:     if ((rnews = popen (rnewscmd, "w")) == NULL)       /* open news pipe */
                    166:        return (-1);                                    /* report failure */
                    167: 
                    168:     fprintf (rnews, "Relay-Version: Notesfiles %s; site %s\n",
                    169:            Version, System);
                    170: /*
                    171:  *     Here we make a slight deviation from what one would expect.
                    172:  *     We use the LOCAL version of the notes/news gateway to pick
                    173:  *     the Posting Version line. This is because we are the version
                    174:  *     that actually makes the insertion into the news system.
                    175:  *
                    176:  *     To back it up, the Usenet Standards papr (rfc whatever) says
                    177:  *     that the Posting-version "identifies the software responsible
                    178:  *     for entering this message into the network".
                    179:  *     Whether the "site" field should be the gatewaying site or where
                    180:  *     the article originated is a good question.
                    181:  *     I chose to make it the notes->news gateway running locally and
                    182:  *     the site where the article originated.
                    183:  *
                    184:  *     The stuff with the #ifdef notdef is to preserve the old code
                    185:  *     that just labeled article we gateway with a Posting version
                    186:  *     of "Notesfiles" instead of "Notesfiles 1.x".
                    187:  */
                    188: #ifdef notdef
                    189:     if (!strcmp (System, note -> n_id.sys))            /* local note */
                    190: #endif notdef
                    191:     {
                    192:        /* 
                    193:         * always consider ourselves the posting version. We are the
                    194:         * site that posted it to news!  There could be a question
                    195:         * about articles gated in two places or which site should be
                    196:         * there.
                    197:         */
                    198:        fprintf (rnews, "Posting-Version: Notesfiles %s; site %s\n",
                    199:                Version, note -> n_id.sys);
                    200:     }
                    201: #ifdef notdef
                    202:     else                                               /* remote note */
                    203:        fprintf (rnews, "Posting-Version: Notesfiles; site %s.%s\n",
                    204:                note -> n_id.sys, DFLTDOMAIN);          /* unknown version */
                    205: #endif notdef
                    206:     fprintf (rnews, "From: %s\n", from);               /* formatted */
                    207: /*
                    208:  *     Sample format that is legal
                    209:  *  fprintf (rnews, "Date: 13-Jan-83 12:08 PST\n");
                    210:  */
                    211:     fprintf (rnews, "Date: %02d-%3s-%02d %02d:%02d %3s\n",
                    212:            note -> n_date.w_day,
                    213:            mnames[note -> n_date.w_month],
                    214:            note -> n_date.w_year - 1900,
                    215:            note -> n_date.w_hours,
                    216:            note -> n_date.w_mins,
                    217:            tzone (&note -> n_date));
                    218:     fprintf (rnews, "Newsgroups: %s\n", ngroup);
                    219:     fprintf (rnews, "Subject: %s\n", ntitle);
                    220:     fprintf (rnews, "Message-ID: <%ld@%s>\n", note -> n_id.uniqid,
                    221:            note -> n_id.sys);
                    222:     fprintf (rnews, "Path: %s!%s\n", path, author);
                    223: 
                    224: /*
                    225:  *     send out the notesfile specfic headers
                    226:  */
                    227:     if (note -> n_addr.addr == 0)                      /* make sure */
                    228:        note -> n_addr.textlen = 0;                     /* on empty text */
                    229: 
                    230:     fprintf (rnews, "%s: #N:%s:%ld:%03o:%ld\n",                /* nf header */
                    231:            NFLINE1,                                    /* "NF-line1" */
                    232:            note -> n_id.sys, note -> n_id.uniqid,
                    233:            note -> n_stat, ((long) note -> n_addr.textlen));
                    234: 
                    235:     fprintf (rnews, "%s: %s!%s    %3s %2d %02d:%02d:00 %4d\n",
                    236:            NFLINE2,                                    /* "Nf-line2" */
                    237:            note -> n_auth.asystem, note -> n_auth.aname,/* author */
                    238:            mnames[note -> n_date.w_month],             /* date written */
                    239:            note -> n_date.w_day,
                    240:            note -> n_date.w_hours,
                    241:            note -> n_date.w_mins,
                    242:            note -> n_date.w_year);
                    243: /*
                    244:  *     Optional headers that we don't hassle with right now:
                    245:  *        Organization:        make a table driven routine to grab
                    246:  */
                    247: 
                    248:     putc ('\n', rnews);                                        /* separator */
                    249:     if (backwards)                                     /* include old stuff */
                    250:     {
                    251:        fprintf (rnews, "#N:%s:%ld:%03o:%ld\n",         /* nf header */
                    252:                note -> n_id.sys, note -> n_id.uniqid,
                    253:                note -> n_stat, ((long) note -> n_addr.textlen));
                    254: 
                    255:        fprintf (rnews, "%s!%s    %3s %2d %02d:%02d:00 %4d\n",
                    256:                note -> n_auth.asystem, note -> n_auth.aname,/* author */
                    257:                mnames[note -> n_date.w_month],         /* date written */
                    258:                note -> n_date.w_day,
                    259:                note -> n_date.w_hours,
                    260:                note -> n_date.w_mins,
                    261:                note -> n_date.w_year);
                    262:     }
                    263:     putc ('\n', rnews);                                        /* separator */
                    264:     pageout (io, &note -> n_addr, rnews);              /* dump text */
                    265:     fprintf (rnews, "\n");                             /* ensure newline */
                    266:     pclose (rnews);                                    /* close it */
                    267:     sleep (SLEEPTIME);                                 /* wait a while */
                    268:     return (0);
                    269: }
                    270: 
                    271: /*
                    272:  *     newsresp
                    273:  *
                    274:  *     Dump a response to the news system.
                    275:  */
                    276: 
                    277: newsresp (io, note, notenum, rsprec, roffset, respnum, ngroup, backwards)
                    278: struct io_f *io;
                    279: struct note_f  *note;
                    280: struct resp_f  *rsprec;
                    281: char   *ngroup;
                    282: {
                    283:     char    cmdline[CMDLEN];                           /* leggo brand */
                    284:     char    line[TITLEN + 50];                         /* scratch */
                    285:     FILE * rnews;
                    286:     int     i;
                    287:     char   *p,
                    288:            *q;
                    289:     char    ntitle[TITLEN + 20];                       /* formatted title */
                    290:     char    from[SYSSZ + NAMESZ + 3];                  /* formatted author */
                    291:     char    path[BUFSIZ];                              /* path to author */
                    292:     char   *author;                                    /* for Path: */
                    293:     long    uniquenum;
                    294: 
                    295: /*
                    296:  *     pre-format a few fields like titles, author information,
                    297:  *     paths to authors, and that sort of gunk.
                    298:  */
                    299: 
                    300:     ntitle[0] = '\0';                                  /* empty string */
                    301:     if (strncmp (note -> ntitle, "Re:", 3) &&          /* is it already */
                    302:            strncmp (note -> ntitle, "RE:", 3) &&       /* a response-like */
                    303:            strncmp (note -> ntitle, "re:", 3))         /* title? */
                    304:     {                                                  /* flag it as a */
                    305:        strcat (ntitle, "Re: ");                        /* response */
                    306:     }
                    307:     strcat (ntitle, note -> ntitle);                   /* include title */
                    308:     if (backwards)
                    309:     {
                    310:        strcat (ntitle, " ");
                    311:        strcat (ntitle, NFSUFFIX);                      /* include old */
                    312:     }
                    313: 
                    314:     /* 
                    315:      * From:
                    316:      * author information
                    317:      */
                    318:     sprintf (from, "%s@%s",                            /* author */
                    319:            rsprec -> r_auth[roffset].aname, rsprec -> r_auth[roffset].asystem);
                    320: #ifdef notdef
                    321:     /* 
                    322:      * decided it was better to NOT append a domain at this point
                    323:      */
                    324:     if (index (rsprec -> r_auth[roffset].asystem, '.') != (char *) NULL)
                    325:     {                                                  /* already domained */
                    326:        sprintf (from, "%s@%s",
                    327:                rsprec -> r_auth[roffset].aname, rsprec -> r_auth[roffset].asystem);
                    328:     }
                    329:     else
                    330:     {
                    331:        sprintf (from, "%s@%s.%s",
                    332:                rsprec -> r_auth[roffset].aname, rsprec -> r_auth[roffset].asystem,
                    333:                DFLTDOMAIN);
                    334:     }
                    335: #endif notdef
                    336:     /* 
                    337:      * Path:
                    338:      * Where the article has been
                    339:      */
                    340:     if (!strcmp (System, rsprec -> r_id[roffset].sys)) /* local */
                    341:     {
                    342:        sprintf (path, "%s", rsprec -> r_id[roffset].sys);
                    343:     }
                    344:     else
                    345:     {
                    346:        if (!strcmp (rsprec -> r_id[roffset].sys, rsprec -> r_from[roffset]))
                    347:        {                                               /* one hop */
                    348:            sprintf (path, "%s!%s",
                    349:                    System,
                    350:                    rsprec -> r_id[roffset].sys);
                    351:        }
                    352:        else
                    353:        {
                    354:            sprintf (path, "%s!%s!%s",                  /* several hops */
                    355:                    System,
                    356:                    rsprec -> r_from[roffset],
                    357:                    rsprec -> r_id[roffset].sys);
                    358:        }
                    359:     }
                    360: #ifdef UGLYPATH                                        /* usually so */
                    361:     /* 
                    362:      * See if we can use the author's name instead of
                    363:      * AUTHORPLACEHOLDER.  Check this by comparin unique id's
                    364:      * and the author's system.
                    365:      *
                    366:      * see similar code above in newsnote() for explanation of the
                    367:      * gyrations here.
                    368:      */
                    369:     {
                    370:        int     idlen,
                    371:                authlen;
                    372:        int     isok;
                    373:        int     minlen;
                    374: 
                    375:        idlen = strlen (rsprec -> r_id[roffset].sys);
                    376:        authlen = strlen (rsprec -> r_auth[roffset].asystem);
                    377:        minlen = idlen < authlen ? idlen : authlen;
                    378:        isok = (strncmp (rsprec -> r_id[roffset].sys, rsprec -> r_auth[roffset].asystem, minlen) == 0);
                    379:        if (isok && idlen < authlen)                    /* id is short */
                    380:        {
                    381:            isok &= (rsprec -> r_auth[roffset].asystem[idlen] == '.');
                    382:        }
                    383:        else
                    384:        {
                    385:            if (isok && authlen < idlen)                /* author syste is short */
                    386:                isok &= (rsprec -> r_id[roffset].sys[authlen] == '.');
                    387:        }
                    388:        if (isok)
                    389:            author = rsprec -> r_auth[roffset].aname;
                    390:        else
                    391:            author = AUTHORPLACEHOLDER;
                    392:     }
                    393: #else  !UGLYPATH
                    394:     /* 
                    395:      * since bnews programs all assume the last component of the
                    396:      * path line is a user name, we have to put something there
                    397:      * to keep them from disregarding the system name when trying
                    398:      * to see where the article has been.
                    399:      */
                    400:     author = AUTHORPLACEHOLDER;
                    401: #endif UGLYPATH
                    402: 
                    403: /*
                    404:  *     Time to send the article to the news system
                    405:  */
                    406: 
                    407:     if ((rnews = popen (rnewscmd, "w")) == NULL)       /* will it work */
                    408:        return (-1);                                    /* report failure */
                    409: 
                    410:     fprintf (rnews, "Relay-Version: Notesfiles %s; site %s\n",
                    411:            Version, System);
                    412: #ifdef notdef
                    413:     if (!strcmp (System, rsprec -> r_id[roffset].sys)) /* local note */
                    414: #endif notdef
                    415:     {
                    416:        /* 
                    417:         * always consider ourselves the posting version. We are the
                    418:         * site that posted it to news!  There could be a question
                    419:         * about articles gated in two places or which site should be
                    420:         * there.
                    421:         *
                    422:         * See comments around similar lines within the newsnote()
                    423:         * routine above
                    424:         */
                    425:        fprintf (rnews, "Posting-Version: Notesfiles %s; site %s\n",
                    426:                Version, rsprec -> r_id[roffset].sys);
                    427:     }
                    428: #ifdef notdef
                    429:     else                                               /* remote note */
                    430:        fprintf (rnews, "Posting-Version: Notesfiles; site %s.%s\n",
                    431:                rsprec -> r_id[roffset].sys, DFLTDOMAIN);/* unknown version */
                    432: #endif notdef
                    433:     fprintf (rnews, "From: %s\n", from);               /* formatted */
                    434: /*
                    435:  *     Sample format that is legal
                    436:  *  fprintf (rnews, "Date: 13-Jan-83 12:08 PST\n");
                    437:  */
                    438:     fprintf (rnews, "Date: %02d-%3s-%02d %02d:%02d %3s\n",
                    439:            rsprec -> r_when[roffset].w_day,
                    440:            mnames[rsprec -> r_when[roffset].w_month],
                    441:            rsprec -> r_when[roffset].w_year - 1900,
                    442:            rsprec -> r_when[roffset].w_hours,
                    443:            rsprec -> r_when[roffset].w_mins,
                    444:            tzone (&rsprec -> r_when[roffset]));
                    445:     fprintf (rnews, "Newsgroups: %s\n", ngroup);
                    446:     fprintf (rnews, "Subject: %s\n", ntitle);
                    447:     fprintf (rnews, "Message-ID: <%ld@%s>\n",
                    448:            rsprec -> r_id[roffset].uniqid, rsprec -> r_id[roffset].sys);
                    449:     fprintf (rnews, "Path: %s!%s\n", path, author);
                    450: 
                    451: /*
                    452:  *     send out the notesfile specfic headers
                    453:  */
                    454:     fprintf (rnews, "%s: #R:%s:%ld:%s:%ld:%03o:%ld\n",
                    455:            NFLINE1,                                    /* Nf-ID */
                    456:            note -> n_id.sys, note -> n_id.uniqid,
                    457:            rsprec -> r_id[roffset].sys,
                    458:            rsprec -> r_id[roffset].uniqid,
                    459:            rsprec -> r_stat[roffset],
                    460:            ((long) rsprec -> r_addr[roffset].textlen));/* force it long */
                    461: 
                    462: 
                    463:     fprintf (rnews, "%s: %s!%s    %3s %2d %02d:%02d:00 %4d\n",
                    464:            NFLINE2,                                    /* NF-From */
                    465:            rsprec -> r_auth[roffset].asystem, rsprec -> r_auth[roffset].aname,
                    466:            mnames[rsprec -> r_when[roffset].w_month],  /* date written */
                    467:            rsprec -> r_when[roffset].w_day,
                    468:            rsprec -> r_when[roffset].w_hours,
                    469:            rsprec -> r_when[roffset].w_mins,
                    470:            rsprec -> r_when[roffset].w_year);
                    471:     if ((uniquenum = note -> n_id.uniqid) < 0)         /* re-invert news */
                    472:        uniquenum /= (-100);                            /* back to normal */
                    473:     fprintf (rnews, "References: <%ld@%s>\n",
                    474:            uniquenum, note -> n_id.sys);
                    475: 
                    476:     putc ('\n', rnews);                                        /* separator */
                    477:     if (backwards)                                     /* old stuff included */
                    478:     {
                    479:        fprintf (rnews, "#R:%s:%ld:%s:%ld:%03o:%ld\n",
                    480:                note -> n_id.sys, note -> n_id.uniqid,
                    481:                rsprec -> r_id[roffset].sys,
                    482:                rsprec -> r_id[roffset].uniqid,
                    483:                rsprec -> r_stat[roffset],
                    484:                ((long) rsprec -> r_addr[roffset].textlen));/* force it long */
                    485: 
                    486:        fprintf (rnews, "%s!%s    %3s %2d %02d:%02d:00 %4d\n",
                    487:                rsprec -> r_auth[roffset].asystem, rsprec -> r_auth[roffset].aname,
                    488:                mnames[rsprec -> r_when[roffset].w_month],/* date written */
                    489:                rsprec -> r_when[roffset].w_day,
                    490:                rsprec -> r_when[roffset].w_hours,
                    491:                rsprec -> r_when[roffset].w_mins,
                    492:                rsprec -> r_when[roffset].w_year);
                    493:     }
                    494:     putc ('\n', rnews);                                        /* separator */
                    495:     pageout (io, &rsprec -> r_addr[roffset], rnews);   /* dump text */
                    496:     fprintf (rnews, "\n");                             /* ensure a newline */
                    497:     pclose (rnews);                                    /* close it */
                    498:     sleep (SLEEPTIME);                                 /* and wait */
                    499:     return (0);
                    500: }
                    501: 
                    502: /*
                    503:  *     A quick and cheap way to calculate a timezone.
                    504:  *
                    505:  *     This routine makes the assumption that a notesfile site
                    506:  *     we gateway for is in the same timezone as our site.
                    507:  *
                    508:  */
                    509: 
                    510: char   *tzone (when)
                    511: struct when_f   when;                                  /* unused */
                    512: {
                    513: #ifdef BSD42
                    514: #include               <sys/time.h>                    /* it moved! */
                    515: #else
                    516: #include               <time.h>
                    517: #endif BSD42
                    518: #include       <sys/types.h>                           /* for ftime */
                    519: 
                    520:     struct tm  *ltime;
                    521:     extern struct tm   *localtime ();
                    522:     long    timenow;
                    523: 
                    524: #ifdef USG
                    525:     struct tm  *bp;
                    526:     extern char *tzname[];
                    527: 
                    528:     time (&timenow);
                    529:     ltime = localtime (&timenow);
                    530:     return (tzname[ltime -> tm_isdst]);
                    531: #else
                    532: /*
                    533:  *     for systems that still have the "timezone" function from V7
                    534:  */
                    535: #include       <sys/timeb.h>                           /* for ftime */
                    536:     struct timeb    rawtime;
                    537:     extern char *timezone ();                          /* please lint */
                    538: 
                    539:     ftime (&rawtime);                                  /* get information */
                    540:     time (&timenow);                                   /* get now */
                    541:     ltime = localtime (&timenow);                      /* see if DST */
                    542:     return (timezone ((int) rawtime.timezone, ltime -> tm_isdst));
                    543: #endif
                    544: }

unix.superglobalmegacorp.com

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