home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume36 / unpost / part03 / parse.c next >
Encoding:
C/C++ Source or Header  |  1993-04-18  |  33.9 KB  |  1,093 lines

  1. /******************************************************************************
  2. * Module    :   Parse --- Search for a particular line.
  3. *
  4. * Author    :   John W. M. Stevens
  5. ******************************************************************************/
  6.  
  7. #include    "compiler.h"
  8.  
  9. #include    "unpost.h"
  10. #include    "regexp.h"
  11. #include    "uudec.h"
  12. #include    "modflnm.h"
  13. #include    "ident.h"
  14. #include    "parse.h"
  15. #include    "config.h"
  16. #include    "utils.h"
  17.  
  18. /*  These are the elements we have to parse out of either the header or
  19. *   the body of the message BEFORE we find the first UUencoded line.
  20. */
  21. typedef enum    {
  22.     ID_STRING,
  23.     SEGMENT_NO,
  24.     NO_SEGMENTS
  25. } PARSE_ELS;
  26.  
  27. /*
  28. *   Regular expression source strings.
  29. *
  30. *   To configure the program for different systems, these are the
  31. *   strings to change.
  32. */
  33. static  PART_RE Parts1[] =
  34. {
  35.     {   "^Subject:(.*)[[({]Part[_ \t]*([0-9]+)[^0-9]+([0-9]+)[)\\]}](.*)",
  36.         1,  2,  3,  4,  IGN_CASE,   NULL
  37.     },
  38.     {   "^Subject:(.*)Part[_ \t]*[[({]([0-9]+)[^0-9]+([0-9]+)[)\\]}](.*)",
  39.         1,  2,  3,  4,  IGN_CASE,   NULL
  40.     },
  41.     {   "^Subject:(.*)Part[_ \t]+([0-9]+)[^0-9]+([0-9]+)(.*)",
  42.         1,  2,  3,  4,  IGN_CASE,   NULL
  43.     },
  44.     {   "^Subject:(.*)[([{]([0-9]+)[^0-9]+([0-9]+)[)\\]}](.*)",
  45.         1,  2,  3,  4,  IGN_CASE,   NULL
  46.     },
  47.     {   "^Subject:(.*)([0-9]+)([/|]|[ \t]+of[ \t]+)([0-9]+)(.*)",
  48.         1,  2,  4,  5,  IGN_CASE,   NULL
  49.     },
  50.     {   "^Subject:(.*)",
  51.         1,  0,  0,  0,  IGN_CASE,   NULL
  52.     },
  53.     {   NULL,
  54.         0,  0,  0,  0,  IGN_CASE,   NULL
  55.     }
  56. };
  57.  
  58. static  PART_RE Parts3[] =
  59. {
  60.     {   "^X-File-Name:[ \t]+(.*)",
  61.         1,  0,  0,  0,  CASE_SENSITIVE,     NULL
  62.     },
  63.     {   NULL,
  64.         0,  0,  0,  0,  IGN_CASE,   NULL
  65.     }
  66. };
  67.  
  68. static  PART_RE Parts4[] =
  69. {
  70.     {   "^X-Part:[ \t]+([0-9]+)",
  71.         0,  1,  0,  0,  CASE_SENSITIVE,     NULL
  72.     },
  73.     {   NULL,
  74.         0,  0,  0,  0,  IGN_CASE,   NULL
  75.     }
  76. };
  77.  
  78. static  PART_RE Parts5[] =
  79. {
  80.     {   "^X-Part-Total:[ \t]+([0-9]+)",
  81.         0,  0,  1,  0,  CASE_SENSITIVE,     NULL
  82.     },
  83.     {   NULL,
  84.         0,  0,  0,  0,  IGN_CASE,   NULL
  85.     }
  86. };
  87.  
  88. static  PART_RE Parts6[] =
  89. {
  90.     {   "^Uusplit-part:[ \t]+([0-9]+)",
  91.         0,  1,  0,  0,  CASE_SENSITIVE,     NULL
  92.     },
  93.     {   NULL,
  94.         0,  0,  0,  0,  IGN_CASE,   NULL
  95.     }
  96. };
  97.  
  98. static  PART_RE Parts7[] =
  99. {
  100.     {   "^Uusplit-parts:[ \t]+([0-9]+)",
  101.         0,  0,  1,  0,  CASE_SENSITIVE,     NULL
  102.     },
  103.     {   NULL,
  104.         0,  0,  0,  0,  IGN_CASE,   NULL
  105.     }
  106. };
  107.  
  108. static  PART_RE Parts8[] =
  109. {
  110.     {   "^section ([0-9]+) of uuencode [0-9]+\\.[0-9]+ of file ([^ \t]+)[ \t]+by R.E.M.",
  111.         2,  1,  0,  0,  CASE_SENSITIVE,     NULL
  112.     },
  113.     {   NULL,
  114.         0,  0,  0,  0,  IGN_CASE,   NULL
  115.     }
  116. };
  117.  
  118. static  PART_RE Parts9[] =
  119. {
  120.     {   "^([^ \t]+)[ \t]+section[ \t]+([0-9]+)/([0-9]+)[ \t]+UUXFER ver ",
  121.         1,  2,  3,  0,  CASE_SENSITIVE,     NULL
  122.     },
  123.     {   NULL,
  124.         0,  0,  0,  0,  IGN_CASE,   NULL
  125.     }
  126. };
  127.  
  128. static  IDENT   Hdr1[] =
  129. {
  130.     {   "^Subject:",                            Parts1,     NULL            },
  131.     {   "^X-File-Name:",                        Parts3,     NULL            },
  132.     {   "^X-Part:",                             Parts4,     NULL            },
  133.     {   "^X-Part-Total:",                       Parts5,     NULL            },
  134.     {   "^Uusplit-part:",                       Parts6,     NULL            },
  135.     {   "^Uusplit-parts:",                      Parts7,     NULL            },
  136.     {   NULL,                                   NULL,       NULL            }
  137. };
  138.  
  139. static  IDENT   Body1[] =
  140. {
  141.     {   "^Subject:",                            Parts1,     NULL            },
  142.     {   "^section [0-9]+ of uuencode [0-9]+\\.[0-9]+ of file [^ \t]+    by R.E.M.",
  143.                                                 Parts8,     NULL            },
  144.     {   "^[^ \t]+[ \t]+section[ \t]+[0-9]+/[0-9]+[ \t]+UUXFER ver ",
  145.                                                 Parts9,     NULL            },
  146.     {   NULL,                                   NULL,       NULL            }
  147. };
  148.  
  149. /*=============================================================================
  150. ||  SEGMENT begin line regular expressions are defined below.
  151. ||
  152. ||  These can be set by command line switch.
  153. =============================================================================*/
  154.  
  155. static  SEGMENT RnSegs[] =
  156. {
  157.     {   "^(Article[:]?|X-NEWS:) ",  Hdr1,   Body1,  NULL    },
  158.     {   NULL,                       NULL,   NULL,   NULL    }
  159. };
  160.  
  161. static  SEGMENT NnSegs[] =
  162. {
  163.     {   "^From[:]? ",               Hdr1,   Body1,  NULL    },
  164.     {   NULL,                       NULL,   NULL,   NULL    }
  165. };
  166.  
  167. static  SEGMENT EmailSegs[] =
  168. {
  169.     {   "^From ",                   Hdr1,   Body1,  NULL    },
  170.     {   NULL,                       NULL,   NULL,   NULL    }
  171. };
  172.  
  173. static  SEGMENT GroupsSegs[] =
  174. {
  175.     {   "^Newsgroups: ",            Hdr1,   Body1,  NULL    },
  176.     {   NULL,                       NULL,   NULL,   NULL    }
  177. };
  178.  
  179. static  SEGMENT         *Segments = RnSegs;
  180. static  REG_EXP_NODE    *Begin = NULL;
  181. static  REG_EXP_NODE    *End = NULL;
  182. static  char            *BeginStr = "^begin[ \t]+([0-7]+)[ \t]+([^ \t]+)";
  183. static  char            *EndStr   = "^end[ \t]*$";
  184.  
  185. /*-----------------------------------------------------------------------------
  186. | Routine   :   GetBinFlNm() --- Get the binary file name.
  187. |
  188. | Inputs    :   InFlPtr - Pointer to source file.
  189. | Outputs   :   FlName  - Pointer to file name buffer.
  190. -----------------------------------------------------------------------------*/
  191.  
  192. void    GetBinFlNm(FILE     *InFlPtr,
  193.                    char     **RetStrs,
  194.                    char     *FlName)
  195. {
  196.     auto        long        LnOfs;
  197.     auto        char        *tp;
  198.     auto        char        *sp;
  199.     auto        int         OutLen;
  200.     auto        char        Exten[5];
  201.     auto        char        BeginName[FL_NM_SZ];
  202.  
  203.     /*  Externals used by this function.    */
  204.     extern      BYTE        OutBfr[];
  205.     extern      char        SegLine[];
  206.     extern      char        InBfr[];
  207.     extern      char        UULine[];
  208.     extern      FILE        *ErrFile;
  209.     extern      int         MsDosFileNms;
  210.  
  211.     /*  Extract the file name.    */
  212.     for (tp = BeginName, sp = RetStrs[2];
  213.          *sp && *sp != '\n' && *sp != ' ' && *sp != '\t';
  214.         )
  215.         *tp++ = *sp++;
  216.     *tp = '\0';
  217.  
  218.     /*  Munge file name?    */
  219.     if ( MsDosFileNms )
  220.     {
  221.         /*  Get the current file offset.    */
  222.         LnOfs = ftell( InFlPtr );
  223.  
  224.         /*  Get next line and identify file type.   */
  225.         *Exten = '\0';
  226.         if (ReadLine(InFlPtr, InBfr, BFR_SIZE) == EOF)
  227.         {
  228.             fprintf(ErrFile,
  229.                     "%s %d : Warning - Unexpected end of file in segment:\n",
  230.                     __FILE__,
  231.                     __LINE__);
  232.             fprintf(ErrFile,
  233.                     "\tSegment: '%s'\n",
  234.                     SegLine);
  235.         }
  236.         else if (DecUULine(InBfr, &OutLen, OutBfr) == NOT_UU_LINE)
  237.         {
  238.             fprintf(ErrFile,
  239.                     "%s %d : Warning - No UU line after begin.\n",
  240.                     __FILE__,
  241.                     __LINE__);
  242.             fprintf(ErrFile,
  243.                     "\tSegment: '%s'\n",
  244.                     SegLine);
  245.         }
  246.         else
  247.         {
  248.             /*  Attempt to ID the file. */
  249.             IdUUFile(OutBfr, OutLen, Exten);
  250.  
  251.             /*  Modify the file name to be MS-DOS compatible?   */
  252.             ModifyFlNm(BeginName, Exten, FlName);
  253.         }
  254.  
  255.         /*  Position file pointer to start of line. */
  256.         if (fseek(InFlPtr, LnOfs, SEEK_SET) != 0)
  257.         {
  258.             fprintf(ErrFile,
  259.                     "%s %d : Error - %s\n",
  260.                     __FILE__,
  261.                     __LINE__,
  262.                     sys_errlist[errno]);
  263.             exit( 1 );
  264.         }
  265.     }
  266.     else
  267.         strcpy(FlName, BeginName);
  268.  
  269. #if defined(UNPOST_DEBUG)
  270. printf("\tBinary File Name: '%s'\n", FlName);
  271. #endif
  272. }
  273.  
  274. /*-----------------------------------------------------------------------------
  275. | Routine   :   MatchEnd() --- Match a uuencode end line.
  276. |
  277. | Inputs    :   Line        - The line to attempt to match against.
  278. -----------------------------------------------------------------------------*/
  279.  
  280. int     MatchEnd(char   *Line)
  281. {
  282.     auto    char    **RetStrs;
  283.  
  284.     /*  Attempt to match the line.  */
  285.     return( ReMatch(Line, CASE_SENSITIVE, End, &RetStrs) );
  286. }
  287.  
  288. /*-----------------------------------------------------------------------------
  289. | Routine   :   MatchBegin() --- Match a uuencode begin line.
  290. |
  291. | Inputs    :   Line        - The line to attempt to match against.
  292. | Outputs   :   RetStrs     - Returned sub-strings.
  293. -----------------------------------------------------------------------------*/
  294.  
  295. int     MatchBegin(char     *Line,
  296.                    char     ***RetStrs)
  297. {
  298.     /*  Attempt to match the line.  */
  299.     return( ReMatch(Line, CASE_SENSITIVE, Begin, RetStrs) );
  300. }
  301.  
  302. /*-----------------------------------------------------------------------------
  303. | Routine   :   MatchSegment() --- Match a SEGMENT begin line.
  304. |
  305. | Inputs    :   Line    - The line to attempt to match against.
  306. | Outputs   :   Hdr     - Pointer to header ID line RE's.
  307. |               Body    - Pointer to body ID line RE's.
  308. -----------------------------------------------------------------------------*/
  309.  
  310. int     MatchSegment(char       *Line,
  311.                      IDENT      **Hdr,
  312.                      IDENT      **Body)
  313. {
  314.     register    int     i;
  315.     auto        char    **RetStrs;
  316.  
  317.     /*  Attempt to match the line.  */
  318.     for (i = 0; Segments[i].ReExprStr; i++)
  319.     {
  320.         /*  Attempt to match one of the segment begin lines.    */
  321.         if (ReMatch(Line,
  322.                     CASE_SENSITIVE,
  323.                     Segments[i].ReExpr,
  324.                     &RetStrs) != 0)
  325.         {
  326.             *Hdr = Segments[i].Header;
  327.             *Body = Segments[i].Body;
  328.             return( 1 );
  329.         }
  330.     }
  331.  
  332.     /*  Return not matched. */
  333.     Hdr = NULL;
  334.     Body = NULL;
  335.     return( 0 );
  336. }
  337.  
  338. /*-----------------------------------------------------------------------------
  339. | Routine   :   GetBinID() --- Get binary ID string.
  340. |
  341. | Inputs    :   SubStr  - Pointer to possible ID sub-string.
  342. | Outputs   :   IDStr   - Pointer to ID string buffer.
  343. -----------------------------------------------------------------------------*/
  344.  
  345. static
  346. void    GetBinID(char   *SubStr,
  347.                  char   *IDStr)
  348. {
  349.     register    int     i;
  350.     auto        int     ExtSep;
  351.     auto        int     MaxLen;
  352.     auto        char    *WordPtr;
  353.     auto        char    *DestPtr;
  354.     auto        char    *MaxPtr;
  355.     auto        char    *tp;
  356.  
  357.     extern      int     MsDosFileNms;
  358.  
  359.     /*  Filter string.  */
  360.     FlNmFilter( SubStr );
  361.  
  362.     /*  Attempt to guess at a file name.    */
  363.     for (tp = SubStr; *tp; )
  364.     {
  365.         /*  Skip white space.   */
  366.         while (*tp == ' ' || *tp == '\t')
  367.             tp++;
  368.  
  369.         /*  Get word. */
  370.         for (DestPtr = IDStr, ExtSep = 0;
  371.              *tp && *tp != ' ' && *tp != '\t';
  372.              tp++)
  373.         {
  374.             /*  Check to see if this is and extension separator
  375.             *   character, and if so, count how many.
  376.             */
  377.             if (*tp == EXT_SEP_CHAR)
  378.                 ExtSep++;
  379.  
  380.             /*  Copy character. */
  381.             *DestPtr++ = *tp;
  382.         }
  383.         *DestPtr = '\0';
  384.  
  385.         /*  Does this look like a file name?    */
  386.         if ( ExtSep )
  387.         {
  388. #if defined(UNPOST_DEBUG)
  389. printf("\tBinary ID: '%s'\n", IDStr);
  390. #endif
  391.             return;
  392.         }
  393.     }
  394.  
  395.     /*  OK, we didn't find anything that looks like it could possibly
  396.     *   be a file name, so get the longest word and use it.
  397.     */
  398.     MaxLen = 0;
  399.     MaxPtr = NULL;
  400.     for (tp = SubStr; *tp; )
  401.     {
  402.         /*  Skip white space.   */
  403.         while (*tp == ' ' || *tp == '\t')
  404.             tp++;
  405.  
  406.         /*  Copy string.    */
  407.         for (i = 0, WordPtr = tp;
  408.              *tp && *tp != ' ' && *tp != '\t';
  409.              i++)
  410.             IDStr[i] = *tp++;
  411.         IDStr[i] = '\0';
  412.  
  413.         /*  Is this the longest so far? */
  414.         if (i > MaxLen)
  415.         {
  416.             MaxPtr = WordPtr;
  417.             MaxLen = i;
  418.         }
  419.     }
  420.  
  421.     /*  OK, check for no non-white space characters in sub
  422.     *   string.
  423.     */
  424.     if (MaxPtr == NULL || MaxLen == 0)
  425.     {
  426.         *IDStr = '\0';
  427.         return;
  428.     }
  429.  
  430.     /*  Get word. */
  431.     for (DestPtr = IDStr, tp = MaxPtr;
  432.          *tp && *tp != ' ' && *tp != '\t';
  433.          tp++)
  434.         *DestPtr++ = *tp;
  435.     *DestPtr = '\0';
  436.  
  437. #if defined(UNPOST_DEBUG)
  438. printf("\tBinary ID: '%s'\n", IDStr);
  439. #endif
  440. }
  441.  
  442. /*-----------------------------------------------------------------------------
  443. | Routine   :   ParseIDLine() --- Extract the ID string, part number and
  444. |               total number of parts from the ID line.
  445. |
  446. | Inputs    :   IDLine      - Pointer to ID line.
  447. |               PartREs     - Array of part number parsing RE's.
  448. | Outputs   :   Elements    - Aqquisition flags for the three items to
  449. |                             parse out, ID string, Segment number and
  450. |                             total number of segments.
  451. |               SegInfo     - Pointer to segment information buffer.
  452. -----------------------------------------------------------------------------*/
  453.  
  454. static
  455. void    ParseIDLine(char        *IDLine,
  456.                     PART_RE     *PartREs,
  457.                     int         *Elements,
  458.                     SEG_INFO    *SegInfo)
  459. {
  460.     register    int     i;
  461.     auto        char    **RetStrs;
  462.     auto        PART_RE *PartRec;
  463.     auto        char    IDBfr[FL_NM_SZ];
  464.  
  465.     /*  Externals used in this function.    */
  466.     extern      FILE    *ErrFile;
  467.  
  468.     /*  Seach for a matching part number parsing regular expression.    */
  469.     for (PartRec = NULL, i = 0;
  470.          PartREs[i].ReExpStr;
  471.          i++)
  472.     {
  473.         /*  Does this RE match the ID line? */
  474.         if (ReMatch(IDLine,
  475.                     PartREs[i].Case,
  476.                     PartREs[i].ReExpr,
  477.                     &RetStrs) != 0)
  478.         {
  479. #if defined(UNPOST_DEBUG)
  480. printf("\tExtract RE: /%s/\n", PartREs[i].ReExpStr);
  481. #endif
  482.             PartRec = PartREs + i;
  483.             break;
  484.         }
  485.     }
  486.  
  487.     /*  If no match found, return.  */
  488.     if (PartRec == NULL)
  489.         return;
  490.  
  491.     /*  Get what elements we do not yet have.    */
  492.     for (i = ID_STRING; i <= NO_SEGMENTS; i++)
  493.     {
  494.         /*  Get this element, if it is available.   */
  495.         switch ( i )
  496.         {
  497.         case 0:     /*  Get ID string.  */
  498.             /*  Check for no ID string.    */
  499.             if (PartRec->IDStr == 0)
  500.                 break;
  501.  
  502.             /*  Extract ID string from sub string.  */
  503.             GetBinID(RetStrs[ PartRec->IDStr ], IDBfr);
  504.  
  505.             /*  Check to see if there was an ID string or not.  */
  506.             if (*IDBfr == '\0')
  507.             {
  508.                 /*  Is there an alternate regular expression for
  509.                 *   extracting the binary ID string?
  510.                 */
  511.                 if (PartRec->AltIDStr > 0)
  512.                 {
  513.                     /*  OK, try other side. */
  514.                     GetBinID(RetStrs[ PartRec->AltIDStr ], IDBfr);
  515.                     if (*IDBfr == '\0')
  516.                         break;
  517.                 }
  518.                 else
  519.                     break;
  520.             }
  521.  
  522.             /*  Duplicate the ID string.    */
  523.             if (SegInfo->IDString != NULL)
  524.                 free( SegInfo->IDString );
  525.             SegInfo->IDString = StrDup( IDBfr );
  526.             Elements[i] = 1;
  527.             break;
  528.         case 1:     /*  Get the segment number. */
  529.             /*  Check for no segment number.    */
  530.             if (PartRec->SegNo == 0)
  531.                 break;
  532.  
  533.             /*  Get the segment number.    */
  534.             if ((SegInfo->SegNo = atoi( RetStrs[ PartRec->SegNo ] )) < 0)
  535.                 break;
  536.             Elements[i] = 1;
  537.             break;
  538.         case 2:     /*  Get total number of segments.   */
  539.             /*  Check for no total number of segments.  */
  540.             if (PartRec->NoSegs == 0)
  541.                 break;
  542.  
  543.             /*  Get the total number of segments.  */
  544.             if ((SegInfo->NoSegs = atoi( RetStrs[ PartRec->NoSegs ] )) <= 0)
  545.                 break;
  546.             Elements[i] = 1;
  547.             break;
  548.         }
  549.     }
  550. }
  551.  
  552. /*-----------------------------------------------------------------------------
  553. | Routine   :   IdSearch() --- Search for an ID line.
  554. |
  555. | Inputs    :   InFlPtr     - Input file pointer.
  556. |               IdPtr       - Pointer to ID RE hierarchy for this SEGMENT.
  557. | Outputs   :   Elements    - Check list for data elements.
  558. |               IDLine      - Contains ID line.
  559. |               UULnType    - Type of UU encoded line found.
  560. |               RetStrs     - Returned sub strings from RE match.
  561. |               SegInfo     - Pointer to segment information buffer.
  562. |
  563. | Returns   :   Returns one of:
  564. -----------------------------------------------------------------------------*/
  565.  
  566. static
  567. long    IdSearch(FILE       *InFlPtr,
  568.                  IDENT      *IdPtr,
  569.                  int        *Elements,
  570.                  char       *IDLine,
  571.                  CHK_UU_ENC *UULnType,
  572.                  char       ***RetStrs,
  573.                  SEG_INFO   *SegInfo)
  574. {
  575.     register    int         i;
  576.     auto        long        LnOfs;
  577.     auto        int         EncLen;
  578.     auto        IDENT       *Hdr;
  579.     auto        IDENT       *Body;
  580.     extern      FILE        *ErrFile;
  581.  
  582.     /*  Search forwards through the file for the first ID line. */
  583.     for ( ; ; )
  584.     {
  585.         /*  Get the current file offset.    */
  586.         LnOfs = ftell( InFlPtr );
  587.  
  588.         /*  Get a line from the file.   */
  589.         if (ReadLine(InFlPtr, IDLine, BFR_SIZE) == EOF)
  590.         {
  591.             LnOfs = PRS_NO_UU_LN;
  592.             break;
  593.         }
  594.  
  595.         /*  Is this a SEGMENT begin line?    */
  596.         if ( MatchSegment(IDLine, &Hdr, &Body) )
  597.         {
  598.             /*  Position file pointer to start of line. */
  599.             if (fseek(InFlPtr, LnOfs, SEEK_SET) != 0)
  600.             {
  601.                 fprintf(ErrFile,
  602.                         "%s %d : Error - %s\n",
  603.                         __FILE__,
  604.                         __LINE__,
  605.                         sys_errlist[errno]);
  606.                 exit( 1 );
  607.             }
  608.  
  609.             /*  Return that no UU encoded line was found.   */
  610.             LnOfs = PRS_NO_UU_LN;
  611.             break;
  612.         }
  613.  
  614.         /*  Is this a UUencoded line?   */
  615.         *UULnType = ChkUULine(IDLine, RetStrs, &EncLen);
  616.         if (*UULnType == IS_UU_LINE ||
  617.             *UULnType == UU_BEGIN   ||
  618.             *UULnType == UU_END)
  619.         {
  620.             /*  Did we miss getting a piece of data we would like to
  621.             *   have?
  622.             */
  623.             if (Elements[SEGMENT_NO] == 0 && Elements[NO_SEGMENTS])
  624.             {
  625.                 /*  Error message.  */
  626.                 fprintf(ErrFile,
  627.                         "%s %d : Error - Got number of segments but not ",
  628.                         __FILE__,
  629.                         __LINE__);
  630.                 fprintf(ErrFile,
  631.                         "segment number.\n");
  632.  
  633.                 /*  Check for totally idiotic mess. */
  634.                 if (SegInfo->NoSegs == 1)
  635.                 {
  636.                     /*  Attempt assumption. */
  637.                     fprintf(ErrFile,
  638.                             "\tNumber of Segments: %d\n",
  639.                             SegInfo->NoSegs);
  640.                     fprintf(ErrFile,
  641.                             "\tAssuming Part 1 of 1\n");
  642.                     SegInfo->SegNo = SegInfo->NoSegs = 1;
  643.                 }
  644.                 else
  645.                     LnOfs = PRS_NO_SEG_NUM;
  646.             }
  647.             else if (Elements[SEGMENT_NO] && Elements[NO_SEGMENTS] == 0)
  648.             {
  649.                 /*  Error message.  */
  650.                 fprintf(ErrFile,
  651.                         "%s %d : Error - Got segment number but not number ",
  652.                         __FILE__,
  653.                         __LINE__);
  654.                 fprintf(ErrFile,
  655.                         "of segments.\n");
  656.  
  657.                 /*  Check segment number.   */
  658.                 if (SegInfo->SegNo == 1)
  659.                 {
  660.                     /*  Attempt assumption. */
  661.                     fprintf(ErrFile,
  662.                             "Segment Number: %d\n\tAssuming Part 1 of 1\n",
  663.                             SegInfo->SegNo);
  664.                     SegInfo->SegNo = SegInfo->NoSegs = 1;
  665.                 }
  666.                 else
  667.                     LnOfs = PRS_NO_NUM_SEGS;
  668.             }
  669.             else if (Elements[SEGMENT_NO] == 0 && Elements[NO_SEGMENTS] == 0)
  670.                 SegInfo->SegNo = SegInfo->NoSegs = 1;
  671.             break;
  672.         }
  673.  
  674.         /*  Is this an ID line? */
  675.         for (i = 0; IdPtr[i].ReExprStr; i++)
  676.         {
  677.             /*  Does this line match?   */
  678.             if (ReMatch(IDLine,
  679.                         CASE_SENSITIVE,
  680.                         IdPtr[i].ReExpr,
  681.                         RetStrs) != 0)
  682.             {
  683. #if defined(UNPOST_DEBUG)
  684. printf("\n\tID Line: '%s'\n", IDLine);
  685. printf("\tBody RE: /%s/\n", IdPtr[i].ReExprStr);
  686. #endif
  687.                 /*  Attempt to parse out one or more elements.  */
  688.                 ParseIDLine(IDLine, IdPtr[i].IdParts, Elements, SegInfo);
  689.                 break;
  690.             }
  691.         }
  692.     }
  693.  
  694.     /*  Return status.  */
  695.     return( LnOfs );
  696. }
  697.  
  698. /*-----------------------------------------------------------------------------
  699. | Routine   :   Header() --- Search for legal header ID lines.
  700. |
  701. | Inputs    :   InFlPtr     - Input file pointer.
  702. |               IdPtr       - Pointer to ID RE hierarchy for this SEGMENT.
  703. | Outputs   :   Elements    - Checklist for needed pieces of information.
  704. |               IDLine      - Contains ID line.
  705. |               SegInfo     - Pointer to segment information buffer.
  706. |
  707. | Returns   :   Returns one of:
  708. |                   PRS_NO_UU_LN    - For no uuencoded line found in segment.
  709. |                   1L              - OK.
  710. -----------------------------------------------------------------------------*/
  711.  
  712. static
  713. long    Header(FILE         *InFlPtr,
  714.                IDENT        *IdPtr,
  715.                int          *Elements,
  716.                char         *IDLine,
  717.                SEG_INFO     *SegInfo)
  718. {
  719.     register    int         i;
  720.     auto        char        **RetStrs;
  721.     auto        char        *tp;
  722.     extern      FILE        *ErrFile;
  723.  
  724.     /*  Search forwards through the file for the first ID line. */
  725.     for ( ; ; )
  726.     {
  727.         /*  Is this an ID line? */
  728.         for (i = 0; IdPtr[i].ReExprStr; i++)
  729.         {
  730.             /*  Does this line match?   */
  731.             if (ReMatch(IDLine,
  732.                         CASE_SENSITIVE,
  733.                         IdPtr[i].ReExpr,
  734.                         &RetStrs) != 0)
  735.             {
  736. #if defined(UNPOST_DEBUG)
  737. printf("\n\tID Line: '%s'\n", IDLine);
  738. printf("\tHeader RE: /%s/\n", IdPtr[i].ReExprStr);
  739. #endif
  740.                 /*  Attempt to parse out one or more elements.  */
  741.                 ParseIDLine(IDLine, IdPtr[i].IdParts, Elements, SegInfo);
  742.                 break;
  743.             }
  744.         }
  745.  
  746.         /*  Get a line from the file.   */
  747.         if (ReadLine(InFlPtr, IDLine, BFR_SIZE) == EOF)
  748.             return( PRS_NO_UU_LN );
  749.  
  750.         /*  Check for a blank line, which is the header delimiter.  */
  751.         for (tp = IDLine; *tp == ' ' || *tp == '\t'; tp++)
  752.             ;
  753.         if (*tp == '\0' || *tp == '\n')
  754.             break;
  755.     }
  756.  
  757.     /*  Return that no errors occured.  */
  758.     return( 1L );
  759. }
  760.  
  761. /*-----------------------------------------------------------------------------
  762. | Routine   :   Parse() --- Parse out a SEGMENT and ID line.
  763. |
  764. | Inputs    :   InFlPtr     - Input file pointer.
  765. | Outputs   :   SegLine     - Contains the segment line.
  766. |               IDLine      - Contains ID line.
  767. |               UULine      - Contains the first UU encoded line.
  768. |               SegInfo     - Pointer to segment information buffer.
  769. |
  770. | Returns   :   Returns one of:
  771. |                   PRS_NO_SEGMENT  - End of file found.
  772. |                   PRS_NO_UU_LN    - No uuencoded line found in article.
  773. |                   PRS_NO_ID_STR   - No ID string found at all.
  774. |                   PRS_NO_BEGIN    - No uuencode begin line found in first
  775. |                                     segment.
  776. -----------------------------------------------------------------------------*/
  777.  
  778. long    Parse(FILE      *InFlPtr,
  779.               char      *SegLine,
  780.               char      *IDLine,
  781.               SEG_INFO  *SegInfo)
  782. {
  783.     register    int         i;
  784.     auto        long        LnOfs;
  785.     auto        char        **RetStrs;
  786.     auto        IDENT       *Hdr;
  787.     auto        IDENT       *Body;
  788.     auto        CHK_UU_ENC  UULnType;
  789.     auto        int         Elements[NO_SEGMENTS + 1];
  790.     auto        char        FlName[FL_NM_SZ];
  791.  
  792.     /*  Externals used by this function.    */
  793.     extern      FILE        *ErrFile;
  794.     extern      int         MsDosFileNms;
  795.  
  796.     /*  Initialize the elements array to show that we have none of the
  797.     *   elements.
  798.     */
  799.     for (i = ID_STRING; i <= NO_SEGMENTS; i++)
  800.         Elements[i] = 0;
  801.  
  802.     /*  Search forwards through the file for the first SEGMENT
  803.     *   begin line.
  804.     */
  805.     for ( ; ; )
  806.     {
  807.         /*  Get the current file offset.    */
  808.         LnOfs = ftell( InFlPtr );
  809.  
  810.         /*  Get a line from the file.   */
  811.         if (ReadLine(InFlPtr, SegLine, BFR_SIZE) == EOF)
  812.             return( PRS_NO_SEGMENT );
  813.  
  814.         /*  Is this a SEGMENT begin line?    */
  815.         if ( MatchSegment(SegLine, &Hdr, &Body) )
  816.         {
  817. #if defined(UNPOST_DEBUG)
  818. printf("Segment Begin: '%s'\n", SegLine);
  819. #endif
  820.             strcpy(IDLine, SegLine);
  821.             break;
  822.         }
  823.     }
  824.  
  825.     /*  Initialize new segment. */
  826.     SegInfo->SegOfs = LnOfs;
  827.  
  828.     /*  Process header block.   */
  829.     LnOfs = Header(InFlPtr,
  830.                    Hdr,
  831.                    Elements,
  832.                    IDLine,
  833.                    SegInfo);
  834.     if (LnOfs < 0L)
  835.         return( LnOfs );
  836.  
  837.     /*  Process body to end of segment or first UU line.    */
  838.     LnOfs = IdSearch(InFlPtr,
  839.                      Body,
  840.                      Elements,
  841.                      IDLine,
  842.                      &UULnType,
  843.                      &RetStrs,
  844.                      SegInfo);
  845.     if (LnOfs < 0L)
  846.         return( LnOfs );
  847.  
  848.     /*  Is this the begin line? */
  849.     SegInfo->UUOfs = LnOfs;
  850.     if (UULnType != UU_BEGIN)
  851.     {
  852.         /*  If this is segment number 1 and we did not find a begin line,
  853.         *   that is BIG trouble, so report an error.
  854.         */
  855.         if (SegInfo->SegNo == 1)
  856.         {
  857.             fprintf(ErrFile,
  858.                     "%s %d : Error - No begin line in first segment:\n",
  859.                     __FILE__,
  860.                     __LINE__);
  861.             fprintf(ErrFile,
  862.                     "\tSegment: '%s'\n",
  863.                     SegLine);
  864.             return( PRS_NO_BEGIN );
  865.         }
  866.         return( 0L );
  867.     }
  868.  
  869.     /*  Get file name from begin line.  */
  870.     GetBinFlNm(InFlPtr, RetStrs, FlName);
  871. #if defined(UNPOST_DEBUG)
  872. printf("\tFile Name: '%s'\n", FlName);
  873. #endif
  874.  
  875.     /*  Return no errors occurred.  */
  876.     if ( *FlName )
  877.         SegInfo->FlName = StrDup( FlName );
  878.     return( 0L );
  879. }
  880.  
  881. /*-----------------------------------------------------------------------------
  882. | Routine   :   FreeCfg() --- Free a configuration that was created by
  883. |               reading a configuration file.
  884. -----------------------------------------------------------------------------*/
  885.  
  886. static
  887. void    FreeCfg(void)
  888. {
  889.     register    int         i;
  890.     register    int         j;
  891.     register    int         k;
  892.  
  893.     /*  If the default configuration is in place, do nothing, else
  894.     *   free the old configuration.
  895.     */
  896.     if (Segments != NnSegs     && Segments != RnSegs &&
  897.         Segments != GroupsSegs && Segments != EmailSegs)
  898.     {
  899.         /*  Free all ID prefix lists in SEGMENT list.   */
  900.         for (i = 0; Segments[i].ReExprStr; i++)
  901.         {
  902.             /*  Free all ID part lists in ID prefix list.   */
  903.             for (j = 0;
  904.                  Segments[i].Header[j].ReExprStr;
  905.                  j++)
  906.             {
  907.                 /*  Free all part extraction RE's, etc. */
  908.                 for (k = 0;
  909.                      Segments[i].Header[j].IdParts[k].ReExpStr;
  910.                      k++)
  911.                 {
  912.                      free( Segments[i].Header[j].IdParts[k].ReExpStr );
  913.                      FreeReExpr( Segments[i].Header[j].IdParts[k].ReExpr );
  914.                 }
  915.  
  916.                 /*  Free list memory and regular expression.    */
  917.                 free( Segments[i].Header[j].IdParts );
  918.                 free( Segments[i].Header[j].ReExprStr );
  919.                 (void) FreeReExpr( Segments[i].Header[j].ReExpr );
  920.             }
  921.             free( Segments[i].Header );
  922.  
  923.             /*  Free all ID part lists in ID prefix list.   */
  924.             for (j = 0;
  925.                  Segments[i].Body[j].ReExprStr;
  926.                  j++)
  927.             {
  928.                 /*  Free all part extraction RE's, etc. */
  929.                 for (k = 0;
  930.                      Segments[i].Body[j].IdParts[k].ReExpStr;
  931.                      k++)
  932.                 {
  933.                      free( Segments[i].Body[j].IdParts[k].ReExpStr );
  934.                      FreeReExpr( Segments[i].Body[j].IdParts[k].ReExpr );
  935.                 }
  936.  
  937.                 /*  Free list memory and regular expression.    */
  938.                 free( Segments[i].Body[j].IdParts );
  939.                 free( Segments[i].Body[j].ReExprStr );
  940.                 (void) FreeReExpr( Segments[i].Body[j].ReExpr );
  941.             }
  942.             free( Segments[i].Body );
  943.  
  944.             /*  Free the regular expression graph for the segment.  */
  945.             free( Segments[i].ReExprStr );
  946.             (void) FreeReExpr( Segments[i].ReExpr );
  947.         }
  948.  
  949.         /*  Free SEGMENT list.  */
  950.         free( Segments );
  951.     }
  952. }
  953.  
  954. /*-----------------------------------------------------------------------------
  955. | Routine   :   SetSegBegin() --- Set the segment begin line regular
  956. |               expression.
  957. |
  958. | Inputs    :   SegType - Either 'e', 'g', 'n', 'm', 'r'.
  959. -----------------------------------------------------------------------------*/
  960.  
  961. void    SetSegBegin(char    *SegType)
  962. {
  963.         register        int             i;
  964.  
  965.     /*  Free any previously allocated configurations (configurations
  966.     *   read in from a config file only.
  967.     */
  968.     FreeCfg();
  969.  
  970.     /*  Determine which type, based on input string.    */
  971.     switch ( tolower( *SegType ) )
  972.     {
  973.     case 'e':
  974.         Segments = EmailSegs;
  975.         break;
  976.     case 'g':
  977.         Segments = GroupsSegs;
  978.         break;
  979.     case 'n':
  980.         Segments = NnSegs;
  981.         break;
  982.     case 'r':
  983.     default:
  984.         Segments = RnSegs;
  985.         break;
  986.     }
  987.  
  988.         /*      Compile SEGMENT begin RE's.     */
  989.         for (i = 0; Segments[i].ReExprStr; i++)
  990.                 if (Segments[i].ReExpr == NULL)
  991.                         Segments[i].ReExpr = ReCompile( Segments[i].ReExprStr );
  992. }
  993.  
  994. /*-----------------------------------------------------------------------------
  995. | Routine   :   CompCfg() --- Compile a configuration.
  996. -----------------------------------------------------------------------------*/
  997.  
  998. static
  999. void    CompCfg(void)
  1000. {
  1001.     register    int         i;
  1002.     register    int         j;
  1003.     register    int         k;
  1004.     auto        PART_RE     *PartPtr;
  1005.     auto        IDENT       *IdPtr;
  1006.     auto        SEGMENT     *SegPtr;
  1007.  
  1008.         /*  Compile the regular expressions.    */
  1009.         for (i = 0; Segments[i].ReExprStr; i++)
  1010.         {
  1011.                 /*  Compile the unique SEGMENT line prefix. */
  1012.                 SegPtr = Segments + i;
  1013.                 if (SegPtr->ReExpr == NULL)
  1014.                         SegPtr->ReExpr = ReCompile( SegPtr->ReExprStr );
  1015.  
  1016.                 /*  Compile all Header ID line information.    */
  1017.                 for (j = 0; SegPtr->Header[j].ReExprStr; j++)
  1018.                 {
  1019.                         /*  Compile the unique ID line prefix.  */
  1020.                         IdPtr = SegPtr->Header + j;
  1021.                         IdPtr->ReExpr = ReCompile( IdPtr->ReExprStr );
  1022.  
  1023.                         /*  Compile the part number parsing RE's.   */
  1024.                         for (k = 0; IdPtr->IdParts[k].ReExpStr; k++)
  1025.                         {
  1026.                                 PartPtr = IdPtr->IdParts + k;
  1027.                                 PartPtr->ReExpr = ReCompile( PartPtr->ReExpStr );
  1028.                         }
  1029.                 }
  1030.  
  1031.                 /*  Compile all Body ID line information.    */
  1032.                 for (j = 0; SegPtr->Body[j].ReExprStr; j++)
  1033.                 {
  1034.                         /*  Compile the unique Body ID line prefix.  */
  1035.                         IdPtr = SegPtr->Body + j;
  1036.                         IdPtr->ReExpr = ReCompile( IdPtr->ReExprStr );
  1037.  
  1038.                         /*  Compile the part number parsing RE's.   */
  1039.                         for (k = 0; IdPtr->IdParts[k].ReExpStr; k++)
  1040.                         {
  1041.                                 PartPtr = IdPtr->IdParts + k;
  1042.                                 PartPtr->ReExpr = ReCompile( PartPtr->ReExpStr );
  1043.                         }
  1044.                 }
  1045.         }
  1046. }
  1047.  
  1048. /*-----------------------------------------------------------------------------
  1049. | Routine   :   LoadCfg() --- Load a configuration file.
  1050. |
  1051. | Inputs    :   CfgFlNm - Configuration file name.
  1052. -----------------------------------------------------------------------------*/
  1053.  
  1054. void    LoadCfg(char   *CfgFlNm)
  1055. {
  1056.         extern          FILE            *ErrFile;
  1057.  
  1058.     /*  Check for reading a configuration file. */
  1059.     if (CfgFlNm == NULL || *CfgFlNm == '\0')
  1060.         {
  1061.                 fprintf(ErrFile,
  1062.                                 "%s %d : Error - Missing configuraiton file name.\n",
  1063.                                 __FILE__,
  1064.                                 __LINE__);
  1065.                 return;
  1066.         }
  1067.  
  1068.         /*  Free any previously allocated configuration trees.  */
  1069.         FreeCfg();
  1070.  
  1071.         /*  Parse configuration file.   */
  1072.         Segments = ReadConfig( CfgFlNm );
  1073.  
  1074.         /*      Compile the configuration.      */
  1075.         CompCfg();
  1076. }
  1077.  
  1078. /*-----------------------------------------------------------------------------
  1079. | Routine   :   ParseInit() --- Compile regular expressions here that will
  1080. |                               not change during run time, and compile the default
  1081. |                               configuration.
  1082. -----------------------------------------------------------------------------*/
  1083.  
  1084. void    ParseInit(void)
  1085. {
  1086.         /*      Compile the RN default configuration.   */
  1087.         CompCfg();
  1088.  
  1089.     /*  Compile the UU encoding RE's.   */
  1090.         Begin = ReCompile( BeginStr );
  1091.         End = ReCompile( EndStr );
  1092. }
  1093.