home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume19 / rkive / part03 / header.c next >
Encoding:
C/C++ Source or Header  |  1989-06-29  |  14.9 KB  |  495 lines

  1. /*
  2. **
  3. ** This software is Copyright (c) 1989 by Kent Landfield.
  4. **
  5. ** Permission is hereby granted to copy, distribute or otherwise 
  6. ** use any part of this package as long as you do not try to make 
  7. ** money from it or pretend that you wrote it.  This copyright 
  8. ** notice must be maintained in any copy made.
  9. **
  10. **  History:
  11. **    Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
  12. **                                                               
  13. */
  14. #ifndef lint
  15. static char SID[] = "@(#)header.c    1.1 6/1/89";
  16. #endif
  17.  
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <sys/types.h>
  21. #include "article.h"
  22.  
  23. int its(s1)
  24. register char *s1;
  25. {
  26.     if (strncmp(s,s1,strlen(s1)) == 0)
  27.         return(TRUE);
  28.     return(FALSE);
  29. }
  30.  
  31. int line_type()
  32. {
  33.     if (its("Path: "))
  34.         return PATH;
  35.     if (its("From: "))
  36.         return FROM;
  37.     if (its("Newsgroups: "))
  38.         return NEWSGROUP;
  39.     if (its("Subject: "))
  40.         return SUBJECT;
  41.     if (its("Keywords: "))
  42.         return KEYWORDS;
  43.     if (its("Date: "))
  44.         return DATE;
  45.     if (its("Message-ID: "))
  46.         return MSG_ID;
  47.     if (its("Lines: "))
  48.         return NUMLINES;
  49.     if (its("Approved: "))
  50.         return APPROVED;
  51.  
  52.     /* The following is the auxilliary headers used by */
  53.     /* the moderators of the sources groups. In some  */
  54.     /* cases, line checks are done with "historical"  */
  55.     /* auxilliary headers. Most of the moderators have */
  56.     /* now standardized on comp.sources.unix's format.*/
  57.  
  58.     /* Archive header lines for comp.sources.unix     */
  59.     /* for comp.sources.amiga, comp.sources.atari.st, */
  60.     /* comp.sources.misc, and comp.sources.x.         */
  61.  
  62.     if (its("Submitted-by: "))         
  63.         return SUBMITTED_BY;
  64.     if (its("Posting-number: "))       
  65.         return POSTING_NUMBER;
  66.     if (its("Archive-name: "))
  67.         return ARCH_NAME;
  68.  
  69.     /* Archive header lines for historical purposes */
  70.     /* once used in comp.sources.misc               */
  71.  
  72.     if (its("Submitted-By: "))        
  73.         return SUBMITTED_BY;
  74.     if (its("comp.sources.misc: "))
  75.         return POSTING_NUMBER;
  76.     if (its("Archive-Name: "))
  77.         return ARCH_NAME;
  78.  
  79.     /* Archive header lines used in comp.sources.games   */
  80.     /* Archive-name is the same as comp.sources.unix     */
  81.  
  82.     if (its("Submitted by: "))        
  83.         return SUBMITTED_BY;
  84.     if (its("Comp.sources.games: "))
  85.         return POSTING_NUMBER;
  86.  
  87.     /* Auxiliary header used as a backward reference   */
  88.     /* to the location of the initially posted sources */
  89.     /* in the event of a patch. This line only exists  */
  90.     /* if the current article is a patch.              */
  91.  
  92.     if (its("Patch-To: "))
  93.         return PATCH_TO;
  94.  
  95.     /* Archive header lines for historical purposes */
  96.     /* once used in mod.sources articles.           */
  97.  
  98.     if (its("Mod.sources: "))       
  99.         return POSTING_NUMBER;
  100.  
  101.     /* The remainder are other types of lines included */
  102.     /* headers and are includes for formatting output  */
  103.     /* and for potential future use.                   */
  104.  
  105.     if (its("References: "))
  106.         return REFERENCES;
  107.     if (its("Organization: "))
  108.         return ORGANIZATION;
  109.     if (its("Distribution: "))
  110.         return DISTRIBUTION;
  111.     if (its("Xref: "))
  112.         return XREF;
  113.     if (its("Expires: "))
  114.         return EXPIRE;
  115.     if (its("Article-I.D.: "))
  116.         return ARTICLEID;
  117.     if (its("Reply-To: "))
  118.         return REPLY_TO;
  119.     if (its("Control: "))
  120.         return CONTROL;
  121.     if (its("Sender: "))
  122.         return SENDER;
  123.     if (its("Followup-To: "))
  124.         return FOLLOWUP_TO;
  125.     if (its("Summary: "))
  126.         return SUMMARY;
  127.     if (its("Supersedes: "))
  128.         return SUPERSEDES;
  129.  
  130.     return OTHER;
  131. }
  132.  
  133. data(hpfield, size, fldname)
  134. char    *hpfield;
  135. int    size;
  136. char    *fldname;
  137. {
  138.     register char *ptr;
  139.     register char *p;
  140.     char *strncpy();
  141.     char *strchr();
  142.  
  143.     for (ptr = strchr(s, ':'); isspace(*++ptr); )
  144.         ;
  145.     if (*ptr != '\0') {
  146.         (void) strncpy(hpfield, ptr, size - 1);
  147.         /*
  148.          * Strip trailing newlines, blanks, and tabs from hpfield.
  149.          */
  150.         for (p = hpfield; *p; ++p)
  151.              ;
  152.         while (--p >= hpfield && (*p == '\n' || *p == ' ' || *p == '\t'))
  153.              ;
  154.         *++p = '\0';
  155.     }
  156.     if (debug)
  157.        (void) fprintf(logfp,"%s: %s\n",fldname, hpfield);
  158. }
  159.  
  160. dump_article()
  161. {
  162.     char *type_str;
  163.  
  164.     switch(article.rectype) {
  165.              case PATCH  : type_str = "PATCH";
  166.                            break;
  167.       case INFORMATIONAL : type_str = "INFORMATIONAL"; 
  168.                            break;
  169.                  default : type_str = "NORMAL"; 
  170.                            break;
  171.     }
  172.  
  173.     (void) fprintf(logfp,"Article:           [%s]\n",article.newsarticle);
  174.     (void) fprintf(logfp,"   newsgroup:      [%s]\n",article.newsgroup);
  175.     (void) fprintf(logfp,"   filename:       [%s]\n",article.filename);
  176.     (void) fprintf(logfp,"   volume:         [%d]\n",article.volume);
  177.     (void) fprintf(logfp,"   issue:          [%d]\n",article.issue);
  178.     (void) fprintf(logfp,"   record type:    [%s]\n", type_str);
  179.     if (article.rectype == PATCH) {
  180.         (void) fprintf(logfp,"   patch volume:   [%d]\n",article.patch_volume);
  181.         (void) fprintf(logfp,"   patch issue:    [%d]\n",article.patch_issue);
  182.     }
  183.     (void) fprintf(logfp,"   reposted:       [%s]\n", 
  184.                    article.repost ? "YES": "NO");
  185.     (void) fprintf(logfp,"   description:    [%s]\n",article.description);
  186.     (void) fprintf(logfp,"   author's name:  [%s]\n",article.author_name);
  187.     (void) fprintf(logfp,"   author's logon: [%s]\n\n",article.author_signon);
  188. }
  189.  
  190. init_article()
  191. {
  192.     article.newsgroup[0] = '\0';
  193.     article.newsarticle[0] = '\0';
  194.     article.filename[0] = '\0';
  195.     article.volume = -1;
  196.     article.issue = -1;
  197.     article.rectype = NORMAL;
  198.     article.repost = FALSE;
  199.     article.patch_volume = -1;
  200.     article.patch_issue = -1;
  201.     article.description[0] = '\0';
  202.     article.author_name[0] = '\0';
  203.     article.author_signon[0] = '\0';
  204.  
  205.     header.from[0] = '\0';         /* From:                 */
  206.     header.path[0] = '\0';         /* Path:                 */
  207.     header.nbuf[0] = '\0';         /* Newsgroups:           */
  208.     header.subject[0] = '\0';      /* Subject:              */
  209.     header.ident[0] = '\0';        /* Message-ID:           */
  210.     header.replyto[0] = '\0';      /* Reply-To:             */
  211.     header.references[0] = '\0';   /* References:           */
  212.     header.subdate[0] = '\0';      /* Date: (submission)    */
  213.     header.subtime = 0;            /* subdate in secs       */
  214.     header.expdate[0] = '\0';      /* Expires:              */
  215.     header.ctlmsg[0] = '\0';       /* Control:              */
  216.     header.sender[0] = '\0';       /* Sender:               */
  217.     header.followup_to[0] = '\0';  /* Followup-to:          */
  218.     header.distribution[0] = '\0'; /* Distribution:         */
  219.     header.organization[0] = '\0'; /* Organization:         */
  220.     header.numlines[0] = '\0';     /* Lines:                */
  221.     header.intnumlines = 0;        /* Integer Version       */
  222.     header.keywords[0] = '\0';     /* Keywords:             */
  223.     header.summary[0] = '\0';      /* Summary:              */
  224.     header.approved[0] = '\0';     /* Approved:             */
  225.     header.xref[0] = '\0';         /* Xref:                 */
  226.     header.supersedes[0] = '\0';   /* Supersedes:           */
  227.     header.submitted_by[0] = '\0'; /* Submitted_by:         */
  228.     header.posting_num[0] = '\0';  /* Posting-number:       */
  229.     header.archive_name[0] = '\0'; /* Archive-name:         */
  230.     header.patch_to[0] = '\0';     /* Patch-To:             */
  231. }
  232.  
  233. store_line()
  234. {
  235.     char *strchr(), *strcpy(), *strstrip(), *substr();
  236.     char *dp, *sp;
  237.     char wrk[20];
  238.  
  239.     switch(line_type()) {
  240.  
  241.     case PATH: /*PATH REQUIRED************************/
  242.         data(header.path, sizeof(header.path), "PATH:");
  243.         break;
  244.  
  245.     case FROM: /*FROM REQUIRED************************/
  246.         data(header.from, sizeof(header.from), "FROM:");
  247.         break;
  248.  
  249.     case NEWSGROUP: /*NEWSGROUP REQUIRED**************/
  250.         data(header.nbuf, sizeof(header.nbuf), "NEWSGROUPS:");
  251.         if ((sp = strchr(s,':')) != NULL) {
  252.              do {
  253.                  ++sp;
  254.              } while(!isalpha(*sp));
  255.              /* remove all crossposting labels */
  256.              if ((dp = strchr(sp,',')) != NULL)
  257.                  *dp = '\0';
  258.              (void) strcpy(article.newsgroup,sp);
  259.         }
  260.         break;
  261.  
  262.     case SUBJECT: /*SUBJECT REQUIRED******************/
  263.         data(header.subject, sizeof(header.subject), "SUBJECT:");
  264.         /* 
  265.         ** Save the subject as the description for articles
  266.         ** that have no volume/issue format. Later in the
  267.         ** code, this subject line minus the volume/issue
  268.         ** is stored back in the .description element if
  269.         ** the volume/issue indicator is found.
  270.         */
  271.         (void) strcpy(article.description, header.subject);
  272.  
  273.         /*
  274.         ** Check to see if this article is a repost of
  275.         ** a previously posted article.
  276.         */
  277.         if (substr(s, "REPOST") != NULL)
  278.             article.repost = TRUE;
  279.  
  280.         /*
  281.         ** Time to get the filename. Assure that it is in a 
  282.         ** volume/issue (v01INF1 or v01i001) format.
  283.         */
  284.         if ((sp = strchr(s,'v')) == NULL) 
  285.             return;          /* no volume indicator */
  286.  
  287.         /* 
  288.         ** Is there a number that follows 
  289.         ** the volume indicator ? 
  290.         */
  291.         if (*(sp+1) < '0' || *(sp+1) > '9')
  292.             return;   /* The volume number is missing */
  293.  
  294.         /*
  295.         ** Is there a second ':' as well ?
  296.         */
  297.         (void) strcpy(article.filename,sp);
  298.         if ((dp = strchr(article.filename,':')) == NULL) 
  299.             return;   /* not in v01i001: format */
  300.  
  301.         /*
  302.         ** terminate the article's filename and 
  303.         ** store the article's description 
  304.         */
  305.         *dp = '\0';
  306.         (void) strcpy(article.description, strstrip(++dp));
  307.  
  308.         /*
  309.         ** Store the filename in a work 
  310.         ** buffer so I can stomp on it. 
  311.         */
  312.         (void) strcpy(wrk, article.filename);
  313.  
  314.         /* 
  315.         ** This is an informational posting.
  316.         */
  317.         if ((dp = substr(wrk, "INF")) != NULL) {
  318.             article.rectype = INFORMATIONAL;
  319.             article.issue = atoi((dp+3));
  320.             ++sp;
  321.             *dp = '\0';
  322.             article.volume = atoi(sp);
  323.         }
  324.  
  325.         /*
  326.         **  check to see if there is an issue indicator 
  327.         */
  328.         else if ((dp = strchr(++sp,'i')) == NULL) 
  329.             return;   /* proven guilty. not volume/issue format */
  330.  
  331.         /* parse the volume from the filename */
  332.         *dp = '\0';
  333.         article.volume = atoi(sp);
  334.       
  335.         /* parse the issue from the filename */
  336.         sp = ++dp;
  337.         while (isdigit(*dp)) ++dp;
  338.         *dp = '\0';
  339.         article.issue = atoi(sp);
  340.  
  341.         break;
  342.  
  343.     case DATE:
  344.         data(header.subdate, sizeof(header.subdate), "DATE:");
  345.         break;
  346.  
  347.     case EXPIRE:
  348.         data(header.expdate, sizeof(header.expdate), "EXPIRES:");
  349.         break;
  350.  
  351.     case MSG_ID:
  352.         data(header.ident, sizeof(header.ident), "MESSAGE-ID:");
  353.         break;
  354.  
  355.     case REPLY_TO:
  356.         data(header.replyto, sizeof(header.replyto), "REPLY-TO:");
  357.         break;
  358.  
  359.     case REFERENCES:
  360.         data(header.references, sizeof(header.references), "REFERENCES:");
  361.         break;
  362.  
  363.     case SENDER:
  364.         data(header.sender, sizeof(header.sender), "SENDER:");
  365.         break;
  366.  
  367.     case FOLLOWUP_TO:
  368.         data(header.followup_to, sizeof(header.followup_to),"FOLLOWUP-TO:");
  369.         break;
  370.  
  371.     case CONTROL:
  372.         data(header.ctlmsg, sizeof(header.ctlmsg),"CONTROL:");
  373.         break;
  374.  
  375.     case DISTRIBUTION:
  376.         data(header.distribution, sizeof(header.distribution),"DISTRIBUTION:");
  377.         break;
  378.  
  379.     case ORGANIZATION:
  380.         data(header.organization, sizeof(header.organization),"ORGANIZATION:");
  381.         break;
  382.  
  383.     case NUMLINES:
  384.         data(header.numlines, sizeof(header.numlines),"LINES:");
  385.         header.intnumlines = atoi(header.numlines);
  386.         break;
  387.  
  388.     case KEYWORDS:
  389.         data(header.keywords, sizeof(header.keywords), "KEYWORDS:");
  390.         break;
  391.  
  392.     case APPROVED:
  393.         data(header.approved, sizeof(header.approved), "APPROVED:");
  394.         break;
  395.  
  396.     case SUPERSEDES:
  397.         data(header.supersedes, sizeof(header.supersedes),"SUPERSEDES:");
  398.         break;
  399.  
  400.     case XREF:
  401.         data(header.xref, sizeof(header.xref),"XREF:");
  402.         break;
  403.  
  404.     case SUMMARY:
  405.         data(header.summary, sizeof(header.summary),"SUMMARY:");
  406.         break;
  407.  
  408.     case POSTING_NUMBER:
  409.         data(header.posting_num, sizeof(header.posting_num), "POSTING_NUMBER:");
  410.         break;
  411.  
  412.     case SUBMITTED_BY:
  413.         data(header.submitted_by, sizeof(header.submitted_by), "SUBMITTED_BY:");
  414.         /* 
  415.         ** Save the author's name and sign on if specified 
  416.         ** Can be in any of the following formats:
  417.     **    kent@ssbell.uucp 
  418.     **    kent@ssbell.uucp (Kent Landfield)
  419.     **    Kent Landfield <kent@ssbell.uucp>
  420.         */
  421.         if ((sp = strchr(s,':')) != NULL) {
  422.             (void) strcpy(article.author_signon,(sp+2));
  423.             /*
  424.             ** Has a name been attached to the signon ?
  425.             */
  426.             if ((dp = strchr(article.author_signon,'<')) != NULL) {
  427.                 *(dp-1) = '\0';
  428.                 (void) strcpy(article.author_name, article.author_signon);
  429.                 (void) strcpy(article.author_signon, ++dp);
  430.                 /*
  431.                 ** Save the name, removing the <>.
  432.                 */
  433.                 if ((dp = strchr(article.author_signon,'>')) != NULL)
  434.                     *dp = '\0';
  435.             }
  436.             else if ((dp = strchr(article.author_signon,'(')) != NULL) {
  437.                 *(dp-1) = '\0';
  438.                 /*
  439.                 ** Save the name, removing the ().
  440.                 */
  441.                 (void) strcpy(article.author_name, ++dp);
  442.                 if ((dp = strchr(article.author_name,')')) != NULL)
  443.                     *dp = '\0';
  444.             }
  445.         }
  446.         break;
  447.  
  448.     case ARCH_NAME:
  449.         data(header.archive_name,sizeof(header.archive_name),"ARCH_NAME:");
  450.         break;
  451.  
  452.     case PATCH_TO:
  453.         data(header.patch_to,sizeof(header.patch_to),"PATCH_TO:");
  454.         article.rectype = PATCH;        /* set the article type */
  455.  
  456.         /*
  457.     ** Parse the initially posted article's volume and issue.
  458.         ** The format of the auxiliary header is
  459.         ** 
  460.         ** Patch-To: Volume 5, Issue 110
  461.         **
  462.         ** In the case of multipart initial postings, the Patch-To:
  463.         ** line points to the first issue.
  464.         */
  465.  
  466.         /* 
  467.         ** First get the volume number.
  468.         */
  469.  
  470.         dp = s;
  471.         while (*dp && (!isdigit(*dp)))
  472.               ++dp;
  473.         sp = dp;
  474.         while (*dp && (isdigit(*dp)))
  475.               ++dp;
  476.         *dp = '\0';
  477.         article.patch_volume = atoi(sp);
  478.  
  479.         /* 
  480.         ** Now get the issue number. 
  481.         */
  482.  
  483.         ++dp;
  484.         while (*dp && (!isdigit(*dp)))
  485.               ++dp;
  486.         sp = dp;
  487.         while (*dp && (isdigit(*dp)))
  488.               ++dp;
  489.         *dp = '\0';
  490.         article.patch_issue = atoi(sp);
  491.         break;
  492.     }
  493.     return;
  494. }
  495.