home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume36 / slurp / part01 / newnews.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-12  |  8.8 KB  |  422 lines

  1. /*
  2.  * newnews - Read in list of ids of new articles
  3.  *
  4.  * Copyright (C) 1992/93 Stephen Hebditch. All rights reserved.
  5.  * TQM Communications, BCM Box 225, London, WC1N 3XX.
  6.  * steveh@orbital.demon.co.uk  +44 836 825962
  7.  *
  8.  * See README for more information and disclaimers
  9.  *
  10.  * Using a previously initialised list of newsgroups, carries out a series
  11.  * of NEWNEWS requests to the connected NNTP server, storing the message
  12.  * ids of new articles in a binary tree in memory.
  13.  *
  14.  * $Id: newnews.c,v 1.5 1993/03/01 17:45:16 root Exp $
  15.  *
  16.  * $Log: newnews.c,v $
  17.  * Revision 1.5  1993/03/01  17:45:16  root
  18.  * Added cast to bzeroing of used_not_group_array.
  19.  *
  20.  * Revision 1.4  1993/02/14  14:55:41  root
  21.  * Malloc msgid space separately from mnode.
  22.  * Split-out process_id from do_newnews so it can be used in get_ntime
  23.  * to load the tree with the unretrieved message ids.
  24.  *
  25.  * Revision 1.3  1992/12/14
  26.  * Only malloc enough space for msgid, not whole mnode structure.
  27.  * Minor tidy-ups.
  28.  *
  29.  * Revision 1.1  1992/12/06
  30.  * Set no_time_flag if hit max no of messages
  31.  * Print line before it is sent to server when debugging is on.
  32.  * No longer need to handle null nn_distributions.
  33.  *
  34.  * Revision 1.0  1992/11/30
  35.  * Transferred functions from slurp.c
  36.  *
  37.  */
  38.  
  39. #include "slurp.h"
  40.  
  41. static int hit_max = FALSE;
  42.  
  43. static char **group_array;
  44. static char **not_group_array;
  45. static int  *used_not_group_array;
  46.  
  47. static int  groups_no;
  48. static int  not_groups_no;
  49.  
  50.  
  51. static void parse_groups ();
  52. static int  add_id (char *msgid);
  53. static void do_newnews (char *line);
  54. static int  restreql (register char *w, register char *s);
  55. static int  get_not_groups (char *group);
  56.  
  57.  
  58. /*
  59.  * parse_groups - Turn list of groups into two arrays containing 
  60.  * pointers to groups to include and groups to exclude.
  61.  */
  62.  
  63.     static void
  64. parse_groups ()
  65.     {
  66.     int i, got, not;
  67.     char *cp;
  68.  
  69.     /* Calculate number of group entries */
  70.     for (i = 1, cp = nn_newsgroups; *cp != '\0'; cp++)
  71.         if (*cp == ',')
  72.             i++;
  73.  
  74.     /* Malloc space for include and exclude group arrays */
  75.     if ((group_array = (char **) malloc (i * (sizeof (char *)))) == NULL)
  76.         log_sys ("parse_groups: malloc %d bytes", i * sizeof (char **));
  77.  
  78.     if ((not_group_array = (char **) malloc (i * (sizeof (char *)))) == NULL)
  79.         log_sys ("parse_groups: malloc %d bytes", i * sizeof (char **));
  80.  
  81.     if ((used_not_group_array = (int *) malloc (i * (sizeof (int)))) == NULL)
  82.         log_sys ("parse_groups: malloc %d bytes", i * sizeof (int));
  83.  
  84.     /* Now start parsing the newsgroup list */
  85.     groups_no = 0;
  86.     not_groups_no = 0;
  87.     got = TRUE;
  88.     not = FALSE;
  89.  
  90.     for (cp = nn_newsgroups; *cp != '\0'; ++cp)
  91.         {
  92.         if (*cp == '!')
  93.             got = FALSE;
  94.  
  95.         if (got)
  96.             {
  97.             group_array [groups_no] = cp;
  98.             groups_no++;
  99.             got = FALSE;
  100.             }
  101.  
  102.         if (not)
  103.             {
  104.             not_group_array [not_groups_no] = cp;
  105.             not_groups_no++;
  106.             not = FALSE;
  107.             }
  108.  
  109.         if (*cp == ',')
  110.             {
  111.             *cp = '\0';
  112.             got = TRUE;
  113.             }
  114.  
  115.         if (*cp == '!')
  116.             not = TRUE;
  117.         }
  118.     }
  119.  
  120.  
  121. /*
  122.  * store_node - Store a new node in the binary tree
  123.  */
  124.  
  125.     static struct mnode *
  126. store_node (char *msgid)
  127.     {
  128.     struct mnode *node;
  129.  
  130.     node = (struct mnode *) malloc (sizeof (struct mnode));
  131.     if (node == NULL)
  132.         log_sys ("add_id: malloc %d bytes", sizeof (struct mnode));
  133.     node->left = NULL;
  134.     node->right = NULL;
  135.     node->used = FALSE;
  136.     node->msgid = (char *) malloc (strlen (msgid) + sizeof (char));
  137.     if (node->msgid == NULL)
  138.         log_sys ("store_node: malloc %d bytes",
  139.                  strlen (msgid) + sizeof (char));
  140.     (void) strcpy (node->msgid, msgid);
  141.     entries++;
  142.     return (node);
  143.     }
  144.  
  145.  
  146. /*
  147.  * add_id - Add a message id to the binary tree if not already present.
  148.  * Returns -1 if the maximum number of entries in the tree has been
  149.  * reached, 0 if the item is added okay, 1 if an entry with that 
  150.  * particular message id already exists.
  151.  */
  152.  
  153.     static int
  154. add_id (char *msgid)
  155.     {
  156.     struct mnode *current;
  157.     int test;
  158.  
  159.     /* Test if hit the maximum number of entries in the cache */
  160.     if (entries >= MAXCACHE)
  161.         return (-1);
  162.  
  163.     /* Handle the case when the tree is empty */
  164.     if (root == NULL) {
  165.         root = store_node (msgid);
  166.         return (0);
  167.     }
  168.  
  169.     /* Search the tree for correct position to insert node */
  170.     current = root;
  171.     
  172.     for (;;)
  173.         {
  174.         test = strcmp (msgid, current->msgid);
  175.         if (test < 0)
  176.             {
  177.             if (current->left == NULL)
  178.                 {
  179.                 current->left = store_node (msgid);
  180.                 return (0);
  181.                 }
  182.             else
  183.                 current = current->left;
  184.             }
  185.         else if (test > 0)
  186.             {
  187.             if (current->right == NULL) {
  188.                 current->right = store_node (msgid);
  189.                 return (0);
  190.                 }
  191.             else
  192.                 current = current->right;
  193.             }
  194.         else
  195.             return (1);
  196.         }
  197.     }
  198.  
  199.  
  200. /*
  201.  * process_id - Check if id already exists in local history file, if not
  202.  * then add it to the message id tree if it isn't already in there.
  203.  */
  204.  
  205.     void
  206. process_id (char *msgid)
  207.     {
  208.     char *cp;
  209.  
  210.     /* Modify the message id appropriate to C-News history files */
  211.     cp = (char *) strchr (msgid, '@');
  212.     if (cp != NULL)
  213.         {
  214.         for (; *cp != '\0'; ++cp)
  215.             if (isupper (*cp))
  216.                 *cp = tolower (*cp);
  217.         }
  218.  
  219.     if (debug_flag)
  220.         (void) fprintf (stderr, "-> %s", msgid);
  221.  
  222.     if (check_id (msgid))
  223.         {
  224.         switch (add_id (msgid))
  225.             {
  226.             case -1 :
  227.                 hit_max = TRUE;
  228.                 break;
  229.             case  0 :
  230.                 newart++;
  231.                 if (debug_flag)
  232.                     (void) fprintf (stderr, " new\n");
  233.                 break;
  234.             default :
  235.                 break;
  236.             }
  237.         }
  238.     else
  239.         {
  240.         dupart++;
  241.         if (debug_flag)
  242.             (void) fprintf (stderr, " dup\n");
  243.         }
  244.     }
  245.  
  246.  
  247. /*
  248.  * do_newnews - Process a newnews for supplied list of groups, adding the
  249.  * resultant data to the message id tree.
  250.  */
  251.  
  252.     static void
  253. do_newnews (char *line)
  254.     {
  255.     char buf [NNTP_STRLEN];
  256.  
  257.     /* Create a full string to send to the server */
  258.     (void) sprintf (buf, "NEWNEWS %s %s GMT %s", line, nn_time,
  259.                     nn_distributions);
  260.  
  261.     /* Do the actual NEWNEWS */
  262.     if (debug_flag)
  263.         (void) fprintf (stderr, "<- %s\n", buf);
  264.     put_server (buf);
  265.     
  266.     /* Get the response and check it's okay */
  267.     get_server (buf, sizeof (buf));
  268.     if (debug_flag)
  269.         (void) fprintf (stderr, "-> %s\n", buf);
  270.     if (atoi (buf) != OK_NEWNEWS)
  271.         {
  272.         log_msg ("do_newnews: NNTP protocol error: got '%s'", buf);
  273.         exit (4);
  274.         }
  275.                     
  276.     /* Now get the data and stick it in the tree */
  277.     for (;;)
  278.         {
  279.         get_server (buf, sizeof (buf));
  280.         if (!strcmp (buf, "."))
  281.             break;
  282.  
  283.         process_id (buf);
  284.         }
  285.     }
  286.  
  287.  
  288. /*
  289.  * restreql -- A small regular expression string equivalence routine
  290.  * purloined from nntp 1.5.11 which credits <lai@shadow.berkeley.edu>
  291.  * for its creation. Returns 1 if the string pointed to by 's' matches
  292.  * the asterisk-broadened regexp string pointed to by 'w', otherwise
  293.  * returns 0.
  294.  */
  295.  
  296.     static int
  297. restreql (register char *w, register char *s)
  298.     {
  299.     while (*s && *w)
  300.         {
  301.         switch (*w)
  302.             {
  303.             case '*':
  304.                 for (w++; *s; s++)
  305.                     if (restreql(w, s))
  306.                         return (1);
  307.                 break;
  308.             default:
  309.                 if (*w != *s)
  310.                     return (0);
  311.                 w++, s++;
  312.                 break;
  313.             }
  314.         }
  315.     if (*s)
  316.         return (0);
  317.     while (*w)
  318.         if (*w++ != '*')
  319.             return 0;
  320.  
  321.     return (1);
  322.     }
  323.  
  324.  
  325. /*
  326.  * get_not_groups - Add appropriate groups from the exclusion list to
  327.  * a group that is to be requested from the server.
  328.  */
  329.  
  330.     static int
  331. get_not_groups (char *group)
  332.     {
  333.     char matchgroups [NNTP_STRLEN];
  334.     int i;
  335.     size_t tlen;
  336.  
  337.     matchgroups [0] = '\0';
  338.     tlen = strlen (group);
  339.     for (i = 0 ; i < not_groups_no ; i ++)
  340.         if (!used_not_group_array [i])
  341.             if (restreql (group, not_group_array [i]))
  342.                 if ((strlen (matchgroups) + tlen + 3) < NNTP_STRLEN)
  343.                     {
  344.                     (void) strcat (matchgroups, ",!");
  345.                     (void) strcat (matchgroups, not_group_array [i]);
  346.                     used_not_group_array [i] = TRUE;
  347.                     }
  348.                 else
  349.                     return (1);
  350.     (void) strcat (group, matchgroups);
  351.     return (0);
  352.     }
  353.  
  354.  
  355. /*
  356.  * get_ids - Store in memory a tree of the message ids of new article at
  357.  * the server which match the specified set of groups and distributions
  358.  * for the currently connected host.
  359.  */
  360.  
  361.     void
  362. get_ids ()
  363.     {
  364.     char line [NNTP_STRLEN];
  365.     char newgroups [NNTP_STRLEN];
  366.     int i, add_comma;
  367.  
  368.     parse_groups ();
  369.  
  370.     line [0] = '\0';
  371.     bzero ((char *) used_not_group_array, not_groups_no * sizeof (int));
  372.     add_comma = FALSE;
  373.  
  374.     for (i = 0 ; i < groups_no ; i++)
  375.         {
  376.         (void) strcpy (newgroups, group_array [i]);
  377.  
  378.         if (get_not_groups (newgroups))
  379.             {
  380.             log_msg ("get_ids: Not enough room in NNTP line for exclusion list %s",
  381.                      newgroups);
  382.             exit (2);
  383.             }
  384.  
  385.         if ((strlen (line) + strlen (newgroups) + 
  386.              strlen (nn_distributions) + (size_t) 31) > NNTP_STRLEN)
  387.             {
  388.             do_newnews (line);
  389.             line [0] = '\0';
  390.             bzero ((char *) used_not_group_array, not_groups_no * sizeof (int));
  391.             add_comma = FALSE;
  392.             }
  393.  
  394.         if ((strlen (line) + strlen (newgroups) + 
  395.              strlen (nn_distributions) + (size_t) 31) > NNTP_STRLEN)
  396.             {
  397.             log_msg ("get_ids: Not enough room in NNTP line for newsgroup %s",
  398.                      newgroups);
  399.             exit (2);
  400.             }
  401.         else
  402.             {
  403.             if (add_comma)
  404.                 (void) strcat (line, ",");
  405.             else
  406.                 add_comma = TRUE;
  407.             (void) strcat (line, newgroups);
  408.             }
  409.         }
  410.  
  411.     do_newnews (line);
  412.  
  413.     /* Report if couldn't fit everything in the tree */
  414.     if (hit_max)
  415.         {
  416.         log_msg ("Maximum limit of %d messages hit", MAXCACHE);
  417.         no_time_flag++;
  418.         }
  419.     }
  420.  
  421. /* END-OF-FILE */
  422.