home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / snews-20.zip / HISTORY.C < prev    next >
C/C++ Source or Header  |  1992-08-02  |  8KB  |  362 lines

  1. /*
  2.     SNEWS 2.0
  3.  
  4.     History routines
  5.  
  6.  
  7.     Copyright (C) 1991  John McCombs, Christchurch, NEW ZEALAND
  8.                         john@ahuriri.gen.nz
  9.                         PO Box 2708, Christchurch, NEW ZEALAND
  10.  
  11.     This program is free software; you can redistribute it and/or modify
  12.     it under the terms of the GNU General Public License, version 1, as
  13.     published by the Free Software Foundation.
  14.  
  15.     This program is distributed in the hope that it will be useful,
  16.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.     GNU General Public License for more details.
  19.  
  20.     See the file COPYING, which contains a copy of the GNU General
  21.     Public License.
  22.  
  23.  */
  24.  
  25.  
  26. #include "defs.h"
  27. #include "history.h"
  28.  
  29.  
  30. FILE *hist;
  31. HIST_LIST *hlist;
  32.  
  33.  
  34. /*----------------------- open hist file for writing ------------------------*/
  35. FILE *open_hist_file(void)
  36. {
  37.     /*
  38.      *  This routine opens the history file for writing, positioned after
  39.      *  the last record.
  40.      */
  41.  
  42.     char fn[256];
  43.  
  44.     sprintf(fn, "%shistory", my_stuff.news_dir);
  45.  
  46.     if ((hist = fopen(fn, "ab")) == NULL) {
  47.         fprintf(stderr, "history: cannot open file %s for append\n", fn);
  48.         exit(1);
  49.     }
  50.  
  51.     return(hist);
  52. }
  53.  
  54.  
  55.  
  56. /*---------------------------- close hist file ---------------------------*/
  57. void close_hist_file(void)
  58. {
  59.     /*
  60.      *  This routine closes the history file
  61.      */
  62.  
  63.     fclose(hist);
  64. }
  65.  
  66.  
  67. /*---------------------------- add record -------------------------------*/
  68. void add_hist_record(char *msg_id, char *ng)
  69. {
  70.     /*
  71.      *  This routine adds a record to the history files.  It is passed the
  72.      *  message id, and the newsgroup list.  The newsgroup list is unwound,
  73.      *  and the article numbers are added to the record.
  74.      *
  75.      *  If there is only one newsgroup no history record is written
  76.      *
  77.      *  We assume that this routine is called after the article has been
  78.      *  posted, so that the article counters are correct.
  79.      */
  80.  
  81.  
  82.     char   *p, buf[512];
  83.     ACTIVE *a;
  84.     time_t t;
  85.     int    ct;
  86.  
  87.     time(&t);
  88.  
  89.     /* count the newsgroups */
  90.     strcpy(buf, ng);
  91.     p = strtok(buf, " \t,\n\r");
  92.     ct = 0;
  93.  
  94.     while (p != NULL) {
  95.         ct++;
  96.         p = strtok(NULL, " \t,\n\r");
  97.     }
  98.  
  99.  
  100.     if (ct > 1) {
  101.  
  102.         strcpy(buf, ng);
  103.         p = strtok(buf, " \t,\n\r");
  104.  
  105.         if ((p != NULL) && (strlen(msg_id) > 0)) {
  106.  
  107.             fprintf(hist, "%s %09ld ", msg_id, t);
  108.  
  109.             while (p != NULL) {
  110.                 a = find_news_group(p);
  111.                 fprintf(hist, "%s %08ld  ", a->group, a->hi_num);
  112.                 p = strtok(NULL, " \t,\n\r");
  113.             }
  114.             fprintf(hist, "\n");
  115.         }
  116.     }
  117. }
  118.  
  119.  
  120.  
  121.  
  122.  
  123. /*--------------------- read history file into ram -------------------------*/
  124. HIST_LIST *load_history_list(void)
  125. {
  126.     /*
  127.      *  This routine opens and reads the history file, building and index
  128.      *
  129.      *  Load this after active and ng files.  Set HIST_MEM_LIMIT in defs.h
  130.      *  to ensure there is enough memory left
  131.      */
  132.  
  133.     char      buf[512], *p;
  134.     long      where;
  135.     HIST_LIST *h;
  136.  
  137.     sprintf(buf, "%shistory", my_stuff.news_dir);
  138.  
  139.     /* open the file */
  140.     if ((hist = fopen(buf, "rb")) == NULL) {
  141.         fprintf(stderr, "history: cannot open file %s for reading\n", buf);
  142.         exit(1);
  143.     }
  144.  
  145.     where = 0;
  146.     hlist = h = NULL;
  147.  
  148.     while (fgets(buf, 511, hist)) {
  149.  
  150.         p = strtok(buf, " \t\n\r");
  151.  
  152.         if (hlist == NULL) {
  153.             hlist = xmalloc(sizeof(HIST_LIST));
  154.             h = hlist;
  155.         } else {
  156.             h->next = xmalloc(sizeof(HIST_LIST));
  157.             h = h->next;
  158.         }
  159.  
  160.         h->mid = hash_msg_id(p);
  161.         h->offset = where;
  162.  
  163.         where = ftell(hist);
  164.     }
  165.  
  166.     if ( h )
  167.         h->next = NULL;
  168.  
  169.     return(hlist);
  170. }
  171.  
  172.  
  173.  
  174.  
  175. /*------------------------- release the history list ----------------------*/
  176. void free_hist_list(void)
  177. {
  178.     /*
  179.      *  Close the history file and free the memory list
  180.      */
  181.     HIST_LIST *h;
  182.  
  183.     close_hist_file();
  184.  
  185.     while (hlist != NULL) {
  186.         h = hlist->next;
  187.         free(hlist);
  188.         hlist = h;
  189.     }
  190. }
  191.  
  192.  
  193.  
  194.  
  195. /*-------------------------- find history entry -----------------------------*/
  196. HIST_LIST *find_msg_id(char *msg_id)
  197. {
  198.     /*
  199.      *  Look up the history list and return the entry for the req'd msg id
  200.      *  or NULL if not found.
  201.      */
  202.  
  203.     HIST_LIST *h;
  204.     long      hashed_id;
  205.  
  206.     hashed_id = hash_msg_id(msg_id);
  207.     h = hlist;
  208.  
  209.     while (h != NULL) {
  210.         if (h->mid == hashed_id) break;
  211.     }
  212.  
  213.     if (h->mid == hashed_id)
  214.         return(h);
  215.     else
  216.         return(NULL);
  217. }
  218.  
  219.  
  220.  
  221.  
  222. /*----------------------- lookup cross posts --------------------------------*/
  223. CROSS_POSTS *look_up_history(char *msg_id, char *ng)
  224. {
  225.     /*
  226.      *  This routine returns a linked list of the groups to which
  227.      *  an article has been crossposted.  Self is excluded.  To do
  228.      *  this we:
  229.      *      - hash the msg id
  230.      *      - search the list of id's
  231.      *      - if a hit is found we read it from the hist file
  232.      *      - decode the record, excluding self
  233.      *      - build a CROSS_POSTS list
  234.      *
  235.      *  NULL is returned if there were no crossposts.  ASSUMES global
  236.      *  file 'hist' is open.  If it isn't this routine always returns
  237.      *  NULL
  238.      */
  239.  
  240.     long        hid;
  241.     HIST_LIST   *h;
  242.     CROSS_POSTS *cx, *c;
  243.     char        buf[512], *p;
  244.  
  245.     hid = hash_msg_id(msg_id);
  246.  
  247.     /* look for the crosspost entry */
  248.     h = hlist;
  249.     while (h != NULL) {
  250.         if (h->mid == hid) break;
  251.         h = h->next;
  252.     }
  253.  
  254.     /* now look up the history file */
  255.     cx = NULL;
  256.     if (h && h->mid == hid) {
  257.         fseek(hist, h->offset, SEEK_SET);
  258.         if (fgets(buf, 511, hist) != NULL) {
  259.  
  260.             /*
  261.              *  Compare the target msg id with the one on the file.  If they
  262.              *  are different then the must be a hash collision - just abort
  263.              */
  264.             p = strtok(buf, " \t\n\r");
  265.             if (stricmp(p, msg_id) == 0) {
  266.  
  267.  
  268.                 /* skip the date field and leave pointiing to the first group */
  269.                 p = strtok(NULL, " \t\n\r");
  270.                 p = strtok(NULL, " \t\n\r");
  271.  
  272.                 while (p != NULL) {
  273.  
  274.                     /* exclude self */
  275.                     if (stricmp(p, ng) != 0) {
  276.                         if (cx == NULL) {
  277.                             cx = xmalloc(sizeof(CROSS_POSTS));
  278.                             c = cx;
  279.                         } else {
  280.                             c->next = xmalloc(sizeof(CROSS_POSTS));
  281.                             c = c->next;
  282.                         }
  283.  
  284.                         strcpy(c->group, p);
  285.                         p = strtok(NULL, " \t\n\r");
  286.                         c->art_num = atol(p);
  287.                         c->next = NULL;
  288.  
  289.                     } else {
  290.                         /* eat article number */
  291.                         p = strtok(NULL, " \t\n\r");
  292.                     }
  293.  
  294.                     p = strtok(NULL, " \t\n\r");
  295.                 }
  296.  
  297.             }
  298.         }
  299.     }
  300.  
  301.     return(cx);
  302.  
  303. }
  304.  
  305.  
  306.  
  307. /*----------------------- deallocate crosspost list --------------------------*/
  308. void free_cross_post_list(CROSS_POSTS *cx)
  309. {
  310.     CROSS_POSTS *c;
  311.  
  312.     while (cx != NULL) {
  313.         c = cx->next;
  314.         free(cx);
  315.         cx = c;
  316.     }
  317.  
  318. }
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325. /*------------------------ random number generator -------------------------*/
  326. long seed;
  327.  
  328. long xrand(void)
  329. {
  330.     seed = (seed * 16807) & 0x7FFFFFFFL;
  331.     return( seed );
  332. }
  333.  
  334.  
  335.  
  336. /*----------------------------- hash a key -----------------------------------*/
  337. long hash_key(long s, char *key)
  338. {
  339.     long hash_num;
  340.     int  i;
  341.  
  342.     hash_num = 0;
  343.     seed = s;
  344.  
  345.     for (i = 0; i < strlen(key); i++) {
  346.         hash_num += xrand() * (key[i] + 0xFF00);
  347.     }
  348.  
  349.     hash_num = hash_num & 0x7FFFFFFFL;
  350.     if (hash_num == 0) hash_num++;
  351.  
  352.     return(hash_num);
  353. }
  354.  
  355.  
  356. /*----------------------------- hash the message id -------------------------*/
  357. long hash_msg_id(char *msg_id)
  358. {
  359.  
  360.     return( hash_key(hash_key(26l, msg_id), msg_id) );
  361. }
  362.