home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume28 / yapp / part03 / sum.c < prev   
Encoding:
C/C++ Source or Header  |  1994-05-29  |  20.2 KB  |  713 lines

  1. /* SUM.C */
  2. static    char sccsid[] = "@(#)sum.c 1.5 94/01/22 (c)1993 thalerd";
  3. #include <stdio.h>
  4. #include <time.h>
  5. #include <sys/types.h> /* for sys/stat.h under ultrix */
  6. #include <sys/stat.h>
  7. #include <string.h>
  8. #include <memory.h>
  9. #include <stdlib.h>   /* for getenv() */
  10. #include <errno.h>
  11. #include <dirent.h>
  12. #include "config.h"
  13. #include "struct.h"
  14. #include "globals.h"
  15. #include "lib.h"
  16. #include "sum.h"
  17. #include "item.h"
  18. #include "xalloc.h"
  19. #include "files.h"
  20. #include "macro.h"
  21. #include "sep.h"
  22. #include "news.h"
  23. #include "stats.h"
  24.  
  25. #define ST_LONG 0x01
  26. #define ST_SWAP 0x02
  27.  
  28. #define SHORT_MAGIC 0x00001537L
  29. #define SHORT_BACK  0x37150000L
  30. #define LONG_MAGIC  0x12345678L
  31. #define LONG_BACK   0x78563412L
  32. #define OLD_YAPP    0x58585858L
  33.  
  34. typedef struct {
  35.    long   flags,nr;
  36.    time_t last,first;
  37. } longsumentry_t;
  38.  
  39. long
  40. get_hash(str)
  41. char *str;
  42. {
  43.    long ret=0;
  44.    char *p;
  45.  
  46.    for (p=str; *p; p++)
  47.       ret = (ret*4) ^ (*p);
  48.    return ret;
  49. }
  50.  
  51. long
  52. get_sumtype(buff)
  53. char *buff;
  54. {
  55.    long temp, sumtype;
  56.    short       swap=BYTESWAP; /* constant used for byte swap check */
  57.  
  58.    /* Determine byte order & file type */
  59.    memcpy((char *)&temp, buff, sizeof(long));
  60.    switch(temp) {
  61.    case SHORT_MAGIC : sumtype = ST_LONG;            break;
  62.    case SHORT_BACK  : sumtype = ST_LONG  | ST_SWAP; break;
  63.    case LONG_MAGIC  : sumtype = 0;                  break;
  64.    case LONG_BACK   : sumtype = ST_SWAP;            break;
  65.    case OLD_YAPP    : swap=(*((char*)&swap)); 
  66.                       sumtype = swap * ST_SWAP;     break;
  67.    default: printf("invalid sum type = %08X\n", temp);
  68.             swap=(*((char*)&swap)); /* check which byte contains the 1 */
  69.             sumtype = swap * ST_SWAP;               break;
  70.    }
  71.  
  72. #ifdef SDEBUG
  73.    printf("sum type = %08X (%d)\n", temp, sumtype);
  74.    printf("%s %s\n", (sumtype & ST_LONG)? "long":"short", 
  75.     (sumtype & ST_SWAP)? "swap":"normal");
  76. #endif
  77.    return sumtype;
  78. }
  79.  
  80. /******************************************************************************/
  81. /* SWAP BYTES IF LOW BIT IN HIGH BYTE (INTEL)                                 */
  82. /* This is so machines with Intel processors and those with Motorola          */
  83. /* processors can both use the same data files on the same filesystem         */
  84. /******************************************************************************/
  85. static void           /* RETURNS: (nothing)        */
  86. byteswap(word,length) /* ARGUMENTS:                */
  87. char *word;           /*    Byte string to reverse */
  88. int length;           /*    Number of bytes        */
  89. {
  90.   int i;
  91.  
  92.   if (length>1)
  93.      for (i = 0; i <= (length - 2) / 2; i++)
  94.        word[i] ^= (word[length - 1 - i] ^= (word[i] ^= word[length - 1 - i]));
  95. }
  96.  
  97. #ifdef NEWS
  98. void
  99. save_article(art, idx)
  100. long art;
  101. short idx;
  102. {
  103.    FILE       *fp;
  104.    char        path[MAX_LINE_LENGTH];
  105.    struct stat st;
  106.    long        mod;
  107.  
  108.    sprintf(path,"%s/article",conflist[idx].location);
  109.  
  110.    /* Create if doesn't exist, else update */
  111.    if (stat(path,&st)) mod = O_W;
  112.    else                mod = O_RPLUS;
  113.  
  114.    /* if (stt->c_security & CT_BASIC) mod |= O_PRIVATE;*/
  115.    if ((fp=mopen(path, mod))==NULL) return;
  116.    fprintf(fp,"%ld\n",art);
  117.    mclose(fp);
  118. }
  119.  
  120. void
  121. load_article(art,idx)
  122. long *art;
  123. short idx;
  124. {
  125.    FILE       *fp;
  126.    char        path[MAX_LINE_LENGTH];
  127.  
  128.    sprintf(path,"%s/article",conflist[idx].location);
  129.  
  130.    if ((fp=mopen(path, O_R))==NULL) {
  131.       *art = 0;
  132.       return;
  133.    }
  134.    fscanf(fp,"%d\n",art);
  135.    mclose(fp);
  136. }
  137. #endif
  138.  
  139. /******************************************************************************/
  140. /* SAVE SUM FILE FOR CONFERENCE                                               */
  141. /******************************************************************************/
  142. void                       /* RETURNS: (nothing)              */
  143. save_sum(newsum,where,idx,stt) /* ARGUMENTS:                      */
  144. sumentry_t *newsum;        /*    Modified record              */
  145. short       where;         /*    Index of modified record     */
  146. short       idx;           /*    Conference to write file for */
  147. status_t   *stt;
  148. {
  149.    FILE       *fp;
  150.    short       i=1;
  151.    char        path[MAX_LINE_LENGTH], buff[17], 
  152.              **config;
  153.    sumentry_t  entry;
  154.    longsumentry_t  longentry;
  155.    short       swap=BYTESWAP; /* constant used for byte swap check */
  156.    long        mod;
  157.    struct stat st;
  158.    long         temp,
  159.                sumtype;
  160.  
  161.    if (flags & O_DEBUG)
  162.       printf("SAVE_SUM %x %d\n", newsum, where); 
  163.  
  164.    swap=(*((char*)&swap)); /* check which byte contains the 1 */
  165.  
  166.    sprintf(path,"%s/sum",conflist[idx].location); 
  167.  
  168.    /* Create if doesn't exist, else update */
  169.    if (stat(path,&st)) mod = O_W;
  170.    else                mod = O_RPLUS;
  171.  
  172.    if (stt->c_security & CT_BASIC) mod |= O_PRIVATE;
  173.    if ((fp=mopen(path,mod))==NULL) return;
  174.  
  175.    /* Determine file type */
  176.    if (mod==O_W || (i=fread(buff,16,1,fp)) <16) /* new file */
  177.       sumtype = ST_LONG;
  178.    else
  179.       sumtype = get_sumtype(buff+12);
  180.    rewind(fp);
  181.  
  182.    if (!(config=get_config(idx)))
  183.       return;
  184.  
  185.    /* Write header */
  186.    if (sumtype & ST_LONG) {
  187.       fwrite("!<sm02>\n",8,1,fp);
  188.       temp = get_hash( config[CF_PARTFILE] );
  189.       fwrite((char *)&temp,sizeof(long),1,fp);
  190.       temp = SHORT_MAGIC;
  191.       fwrite((char *)&temp,sizeof(long),1,fp);
  192.       temp = LONG_MAGIC;
  193.       fwrite((char *)&temp,sizeof(long),1,fp);
  194.    } else {
  195.       short tshort;
  196.  
  197.       fwrite("!<pr03>\n",8,1,fp);
  198.       tshort = get_hash( config[CF_PARTFILE] );
  199.       fwrite((char *)&tshort,sizeof(short),1,fp);
  200.       temp = SHORT_MAGIC;
  201.       fwrite((char *)&tshort,sizeof(short),1,fp);
  202.       temp = LONG_MAGIC;
  203.       fwrite((char *)&temp,sizeof(long),1,fp);
  204.    }
  205.  
  206.    for (i=1; i<=stt->i_last; i++) {
  207.       short t;
  208.  
  209.    /* if (newsum[i-1].nr) printf("%d: %d\n",i,newsum[i-1].nr); */
  210.       t=newsum[i-1].flags;
  211.       newsum[i-1].flags &= IF_SAVEMASK;
  212.  
  213.       if (sumtype & ST_LONG) {
  214.          longentry.nr    = newsum[i-1].nr;
  215.          longentry.flags = newsum[i-1].flags;
  216.          longentry.last  = newsum[i-1].last ;
  217.          longentry.first = newsum[i-1].first;
  218.          if (sumtype & ST_SWAP) {
  219.             byteswap((char*)&(longentry.nr   ),sizeof(long  ));
  220.             byteswap((char*)&(longentry.flags),sizeof(long  ));
  221.             byteswap((char*)&(longentry.first),sizeof(time_t));
  222.             byteswap((char*)&(longentry.last ),sizeof(time_t));
  223.          }
  224.          fwrite((char *)&longentry,sizeof(longsumentry_t),1,fp);
  225.       } else {
  226.          memcpy((char *)&entry,(char *)&(newsum[i-1]),sizeof(sumentry_t));
  227.          if (sumtype & ST_SWAP) {
  228.             byteswap((char*)&(entry.nr   ),sizeof(short ));
  229.             byteswap((char*)&(entry.flags),sizeof(short ));
  230.             byteswap((char*)&(entry.first),sizeof(time_t));
  231.             byteswap((char*)&(entry.last ),sizeof(time_t));
  232.          }
  233.          fwrite((char *)&entry,sizeof(sumentry_t),1,fp);
  234.       }
  235.  
  236.       newsum[i-1].flags=t;
  237.    }
  238.  
  239.    mclose(fp);
  240. }
  241.  
  242. void
  243. refresh_sum(item,idx,sum,part,stt)
  244. short item;
  245. short idx;
  246. sumentry_t  *sum;        /*    Item summary             */
  247. partentry_t *part;       /*    User participation info  */
  248. status_t    *stt;        /*    Status structure         */
  249. {
  250.    struct stat st;
  251.    char   path[MAX_LINE_LENGTH];
  252.    short  i,last,first;
  253.  
  254. #ifdef NEWS
  255.    char **config;
  256.  
  257.    if (!(config = get_config(idx)))
  258.       return;
  259.    if (stt->c_security & CT_NEWS) {
  260.       sprintf(path,"%s/%s",NEWSDIR,dot2slash(config[CF_NEWSGROUP]));
  261.       if (stat(path,&st)) {
  262.          stt->sumtime=0;
  263.          st.st_mtime    =1;
  264.       }
  265.       if (st.st_mtime!=stt->sumtime) {
  266.          load_sum(sum,part,stt,idx);
  267.          stt->sumtime = st.st_mtime; 
  268.       }
  269.       refresh_stats(sum,part,stt); /* update stt */
  270.       return;
  271.    }
  272. #endif
  273.  
  274.    /* Is global information current? */
  275.    sprintf(path,"%s/sum",conflist[idx].location);
  276.    if (stat(path,&st)) {
  277.       stt->sumtime=0;
  278.       st.st_mtime    =1;
  279.    }
  280.    if (st.st_mtime!=stt->sumtime) {
  281.  
  282.       /* Load global information */
  283.       load_sum(sum,part,stt,idx);
  284.       stt->sumtime = st.st_mtime;
  285.    }
  286.  
  287.    /* Are links current? */
  288.    last  = (item)? item : MAX_ITEMS;
  289.    first = (item)? item : 1;
  290.    for (i=first-1; i<last; i++)
  291.       refresh_link(stt,sum,part,idx,i);
  292.  
  293.    /* Need to refresh stats anyway, in case part[] changed */
  294.    refresh_stats(sum,part,stt); /* update stt */
  295. }
  296.  
  297. int                          /* RETURNS: 1 on valid, 0 else */
  298. item_sum(i,sum,part,idx,stt) /* ARGUMENTS: */
  299. short i;
  300. sumentry_t  *sum;            /*    Item summary array to fill in */
  301. partentry_t *part;           /*    Participation info */
  302. short idx;                   /*    Conference index */
  303. status_t *stt;
  304. {
  305.    FILE       *fp,*nfp;
  306.    char        path[MAX_LINE_LENGTH];
  307.    struct stat st;
  308.    char        buff[MAX_LINE_LENGTH];
  309.    long        art;
  310.    char      **config;
  311.  
  312.    sum[i].flags=sum[i].nr=0;
  313.  
  314.    sprintf(path,"%s/_%d",conflist[idx].location,i+1);
  315.    if (!(config = get_config(idx)))
  316.       return 0;
  317.    if (stat(path,&st)) 
  318.       return 0;
  319.    else
  320.       sum[i].flags |= IF_ACTIVE;
  321.    if (st.st_nlink > 1) 
  322.       sum[i].flags |= IF_LINKED;
  323.    if (!(st.st_mode & S_IWUSR))
  324.       sum[i].flags |= IF_FROZEN;
  325.    if (part[i].nr < 0)
  326.       sum[i].flags |= IF_FORGOTTEN;
  327.    sum[i].last = st.st_mtime;
  328.    if (!(st.st_mode & S_IRUSR) || !(fp = mopen(path,O_R))) {
  329.       sum[i].flags |= IF_RETIRED;
  330.       sum[i].nr     = 0;
  331.       sum[i].first  = 0;
  332.    } else {
  333.       if (st.st_mode & S_IXUSR)
  334.          sum[i].flags |= IF_RETIRED;
  335.       sum[i].nr     = 0; /* count them */
  336.  
  337.       ngets(buff,fp); /* magic - ignore */
  338.       ngets(buff,fp); /* H - ignore if FAST */
  339.       store_subj(idx, i, buff+2);
  340.       ngets(buff,fp); /* R - ignore */
  341.       ngets(buff,fp); /* U - ignore */
  342.       ngets(buff,fp); /* A - ignore */
  343.       ngets(buff,fp); /* date */
  344.       sscanf(buff+2,"%x",&(sum[i].first));
  345.       while (ngets(buff,fp)) {
  346.          if (!strcmp(buff,",T")) sum[i].nr++; 
  347.  
  348. #ifdef NEWS
  349.          if (!strncmp(buff,",N",2)) {
  350.             art = atoi(buff+2);
  351.  
  352.             /* Check to see if it has expired */
  353.             sprintf(buff,"%s/%s/%d",NEWSDIR,dot2slash(config[CF_NEWSGROUP]),
  354.              art);
  355. printf("Checking %s ",buff);
  356.             if ((nfp=mopen(buff,O_R|O_SILENT))==NULL) {
  357.                sum[i].flags |= IF_EXPIRED;
  358. printf("EXPIRED\n");
  359.             } else {
  360.                mclose(nfp);
  361. printf("OK\n");
  362.             }
  363.  
  364.             if (art > stt->c_article)
  365.                stt->c_article = art;
  366.             /* printf("Found article %d\n",art); */
  367.          }
  368. #endif
  369.       }
  370.       mclose(fp);
  371.    }
  372.    return 1;
  373. }
  374.  
  375. /******************************************************************************/
  376. /* Load SUM data for arbitrary conference (requires part be done previously)  */
  377. /******************************************************************************/
  378. void                         /* RETURNS: (nothing) */
  379. load_sum(sum,part,stt,idx) /* ARGUMENTS: */
  380. sumentry_t  *sum;            /*    Item summary array to fill in */
  381. partentry_t *part;           /*    Participation info */
  382. status_t *stt;
  383. short idx;                   /*    Conference index */
  384. {
  385.    FILE       *fp;
  386.    short       i=1,j;
  387.    char        path[MAX_LINE_LENGTH];
  388.    char      **config;
  389.    struct stat st;
  390.    char        buff[MAX_LINE_LENGTH];
  391.    short       confitems=0;
  392.    short       swap=BYTESWAP; /* constant used for byte swap check */
  393.    long        sumtype=0;
  394.    long        temp;
  395.    short       tshort;
  396.  
  397.    for (j=0; j<MAX_ITEMS; j++) {
  398.       sum[j].nr = sum[j].flags = 0;
  399.    }
  400.    
  401.    swap=(*((char*)&swap));
  402.    sprintf(path,"%s/sum",conflist[idx].location);
  403.  
  404.    /* If SUM doesn't exist */
  405.    if ((fp=mopen(path,O_R|O_LOCK|O_SILENT))==NULL) {
  406.       DIR *fp;
  407.       struct dirent *dp;
  408.       char fmt[6];
  409.  
  410.       strcpy(path,conflist[idx].location);
  411.       strcpy(fmt,"_%d");
  412.  
  413.       if ((fp = opendir(path))==NULL) {
  414.          error("opening ",path);
  415.          return;
  416.       }
  417.      
  418.       /* Load in stats 1 piece at a time - the slow stuff */
  419.       for (dp = readdir(fp); dp != NULL; dp = readdir(fp)) {
  420.          long i2;
  421.          if (sscanf(dp->d_name,fmt,&i2)==1) {
  422.             i = i2-1;
  423.             confitems += item_sum(i,sum,part,idx,stt);
  424.          }
  425.       }
  426.       closedir(fp);
  427.  
  428.       /* Load in stats 1 piece at a time - the slow stuff 
  429.       for (i=0; i<MAX_ITEMS; i++) {
  430.          confitems += item_sum(i,sum,part,idx,stt);
  431.       }
  432.       */
  433.  
  434. #ifdef NEWS
  435.       /* Update ITEM files with new articles */
  436.       /* printf("Article=%d\n",stt->c_article); */
  437.       if (stt->c_security & CT_NEWS)
  438.          refresh_news(sum,part,stt,idx);
  439. #endif
  440.  
  441.       return;
  442.    }
  443.  
  444.    /* Read in SUM file - the fast stuff */
  445.    if (!stat(path,&st)) 
  446.       stt->sumtime = st.st_mtime;
  447.  
  448.    if (!(i=fread(buff,16,1,fp)) 
  449.     || (strncmp(buff,"!<sm02>\n",8) && strncmp(buff,"!<pr03>\n",8))) {
  450.       mclose(fp);
  451.       errno=0;
  452.       error(path," failed magic check");
  453.       /* printf("WARNING: %s failed magic check\n",path); */
  454.  
  455.       /* Load in stats 1 piece at a time - the slow stuff */
  456.       for (i=0; i<MAX_ITEMS; i++)
  457.          confitems += item_sum(i,sum,part,idx,stt);
  458.  
  459.       refresh_stats(sum,part,stt);
  460.       save_sum(sum,(short)-1,idx,stt);
  461.       return;
  462.    }
  463.  
  464. /*
  465.    fread((char *)&confitems, sizeof(confitems),1,fp); * skip first 16 bytes *
  466.    fread((char *)sum,sizeof(sumentry_t),1,fp); *fseek fails for some reason *
  467. */
  468.  
  469.    /* Determine byte order & file type */
  470.    sumtype = get_sumtype(buff+12);
  471.    if (!(config = get_config(idx)))
  472.       return;
  473.  
  474.    if (sumtype & ST_LONG) {
  475.       fread((char *)&temp, sizeof(long), 1, fp); /* skip 4 more bytes */
  476.       memcpy((char *)&temp, buff+8, sizeof(long));
  477.  
  478.       if (temp != get_hash( config[CF_PARTFILE] )) {
  479.          errno = 0;
  480.          error("bad participation filename hash for ", config[CF_PARTFILE]);
  481.       }
  482.    } else {
  483.       memcpy((char *)&tshort, buff+8, sizeof(short));
  484.       if (tshort != (short)get_hash( config[CF_PARTFILE] )) {
  485.          errno = 0;
  486.          error("bad participation filename hash for ", config[CF_PARTFILE]);
  487.       }
  488.    }
  489.  
  490. #ifdef NEWS
  491.    if (stt->c_security & CT_NEWS)
  492.       load_article(&stt->c_article, idx);
  493. #endif
  494.  
  495.    if (sumtype & ST_LONG) {
  496.       longsumentry_t longsum[MAX_ITEMS];
  497.       int i;
  498.  
  499.       confitems=fread((char *)longsum, sizeof(longsumentry_t), MAX_ITEMS, fp);
  500.  
  501.       for (i=0; i<confitems; i++) {
  502.          if (!longsum[i].nr) 
  503.             continue; /* skip if deleted */
  504.  
  505.          if (sumtype & ST_SWAP) {
  506.             byteswap((char*)&(longsum[i].nr   ),sizeof(long  ));
  507.             byteswap((char*)&(longsum[i].flags),sizeof(long  ));
  508.             byteswap((char*)&(longsum[i].first),sizeof(time_t));
  509.             byteswap((char*)&(longsum[i].last ),sizeof(time_t));
  510.          }
  511.  
  512.          sum[i].nr    = longsum[i].nr;
  513.          sum[i].flags = longsum[i].flags;
  514.          sum[i].first = longsum[i].first;
  515.          sum[i].last  = longsum[i].last;
  516.       }
  517.  
  518.    } else {
  519.  
  520.       confitems=fread((char *)sum, sizeof(sumentry_t), MAX_ITEMS, fp);
  521.  
  522.       for (i=0; i<confitems; i++) {
  523.          if (!sum[i].nr) 
  524.             continue; /* skip if deleted */
  525.  
  526.          /* Check for byte swapping and such */
  527.          if (sumtype & ST_SWAP) {
  528.             byteswap((char*)&(sum[i].nr   ),sizeof(short ));
  529.             byteswap((char*)&(sum[i].flags),sizeof(short ));
  530.             byteswap((char*)&(sum[i].first),sizeof(time_t));
  531.             byteswap((char*)&(sum[i].last ),sizeof(time_t));
  532.          }
  533.       }
  534.    }
  535.  
  536.    mclose(fp);
  537.    /* printf("confitems=%d\n",confitems);*/
  538.  
  539.    for (i=0; i<confitems; i++) {
  540.       if (!sum[i].nr) 
  541.          continue; /* skip if deleted */
  542.  
  543. /*printf("i=%d : nr=%d fl=%d fi=%lX la=%lX\n",i,sum[i].nr,sum[i].flags,sum[i].first,sum[i].last);*/
  544.       if (sum[i].nr < 0 || sum[i].nr > MAX_RESPONSES) {
  545.          printf("UNK: Invalid format of sum file\n");
  546.          break;
  547.       }
  548.  
  549.       if (part[i].nr < 0)
  550.          sum[i].flags |= IF_FORGOTTEN;
  551.  
  552.       /* verify it's still linked, didnt used to check sumtime */
  553.       refresh_link(stt,sum,part,idx,i);
  554.    }
  555.  
  556.    for (; i<MAX_ITEMS; i++) {
  557.       sum[i].flags=sum[i].nr=0;
  558.    }
  559.  
  560. #ifdef NEWS
  561.    /* Update ITEM files with new articles */
  562.    if (stt->c_security & CT_NEWS)
  563.       refresh_news(sum,part,stt,idx);
  564. #endif
  565. }
  566.  
  567. void
  568. refresh_stats(sum,part,st)
  569. sumentry_t  *sum;            /*    Sum array to fill in (optional)    */
  570. partentry_t *part;           /*    Previously read participation data */
  571. status_t    *st;             /*    pointer to status structure */
  572. {
  573.    short i;
  574.  
  575.    st->i_numitems = st->i_brandnew = st->i_newresp = st->i_unseen = 0;
  576.    st->i_first = MAX_ITEMS+1;
  577.    st->i_last  = 0;
  578.  
  579.    for (i=1; i<=MAX_ITEMS; i++) {
  580.       if (sum[i-1].nr) {
  581.          if (!sum[i-1].flags || (sum[i-1].flags & IF_EXPIRED)) continue;
  582.          st->i_numitems++;
  583.          if (i<st->i_first) st->i_first=i;
  584.          if (i>st->i_last ) st->i_last =i;
  585.       }
  586.    }
  587.    for (i=1; i<=MAX_ITEMS; i++) {
  588.       if (sum[i-1].nr) {
  589.          if (!sum[i-1].flags) continue;
  590.          if ((sum[i-1].flags & (IF_RETIRED|IF_FORGOTTEN|IF_EXPIRED)) 
  591.      && (flags & O_FORGET))
  592.             continue;
  593.          if (!part[i-1].nr && sum[i-1].nr) {
  594.             st->i_unseen++; /* unseen */
  595.             /* if (part[i-1].last < sum[i-1].last) */
  596.             /* if (st->parttime < sum[i-1].last) before change new partfile */
  597.             if (part[i-1].last < sum[i-1].last)
  598.                st->i_brandnew++; 
  599.          } 
  600. /* 
  601.          else if (part[i-1].nr < sum[i-1].nr) st->i_newresp++;
  602.  * the problem with the following is that we may have recently read A
  603.    response, but not ALL the responses -- Ok acc to Russ
  604.  */
  605.          else if (part[i-1].last < sum[i-1].last) st->i_newresp++; 
  606.       }
  607.    }
  608. }
  609.  
  610. void
  611. refresh_link(stt,sum,part,idx,i)
  612. status_t    *stt;            /*    pointer to status structure */
  613. sumentry_t  *sum;            /*    Sum array to fill in (optional)    */
  614. partentry_t *part;           /*    Previously read participation data */
  615. short        idx;            /*    Index of conference to process     */
  616. short        i;
  617. {
  618.    char path[MAX_LINE_LENGTH];
  619.    struct stat st;
  620.  
  621.    if (sum[i].flags & IF_LINKED) { /* verify it's still linked */
  622.       sprintf(path,"%s/_%d",conflist[idx].location,i+1);
  623.       if (stat(path,&st) || st.st_nlink < 2)
  624.          sum[i].flags &= ~IF_LINKED;
  625.       if (st.st_mtime > stt->sumtime) { /* new activity */
  626.          item_sum(i,sum,part,idx,stt);
  627.       }
  628.    }
  629. }
  630.  
  631. /******************************************************************************/
  632. /* UPDATE THE GLOBAL STATUS STRUCTURE, OPTIONALLY GET ITEM SUBJECTS           */
  633. /******************************************************************************/
  634. /* note: does load_sum and not free_sum if argument is there */
  635. void                         /* RETURNS: (nothing) */
  636. get_status(st,s,part,idx) /* ARGUMENTS:                            */
  637. status_t *st;                /*    pointer to status structure */
  638. sumentry_t  *s;              /*    Sum array to fill in (optional)    */
  639. partentry_t *part;           /*    Previously read participation data */
  640. short        idx;            /*    Index of conference to process     */
  641. {
  642.    sumentry_t  s1[MAX_ITEMS];
  643.    sumentry_t *sum;
  644.    short i;
  645.  
  646.    sum  = (s)?   s : s1;
  647.    
  648.    if (st != (&st_glob))
  649.       st->sumtime=0; 
  650.    refresh_sum(0,idx,sum,part,st);
  651.  
  652.    /* Are links current? */
  653.    for (i=0; i<MAX_ITEMS; i++)
  654.       refresh_link(st,sum,part,idx,i);
  655.  
  656.    refresh_stats(sum,part,st);
  657. }
  658.  
  659. void
  660. refresh_list() {
  661.    char path[MAX_LINE_LENGTH];
  662.    struct stat st;
  663.  
  664.    sprintf(path,"%s/%s",work,".cflist");
  665.    if (stat(path,&st)) return;
  666.    if (st_glob.listtime < st.st_mtime) {
  667.       xfree(cflist);
  668.       cflist=grab_file(work,".cflist",GF_WORD|GF_SILENT|GF_IGNCMT);
  669.       st_glob.listtime = st.st_mtime;
  670.       current = -1;
  671.    }
  672. }
  673.  
  674. void
  675. check_mail(f) 
  676. int f;
  677. {
  678.    static int prev=0;
  679.    int f2=f;
  680.    char mbox[MAX_LINE_LENGTH],*mail;
  681.    struct stat st;
  682.  
  683.    /* Mail is currently only checked in conf.c, when should new mail
  684.     * be reported?  At Ok:? or only when join or display new? 
  685.     * If conf.c is the only place, perhaps it should be moved there.
  686.     * Note: the above was fixed when seps were added
  687.     */
  688.    mail = expand("mailbox",DM_VAR);
  689.    if (!mail) mail = getenv("MAIL");
  690.    if (!mail) {
  691.       sprintf(mbox,"%s/%s",MAILDIR,login);
  692.       mail = mbox;
  693.    }
  694.    if (!stat(mail,&st) && st.st_size>0) {
  695.       status |= S_MAIL;
  696.       if (st_glob.mailsize && st.st_size > st_glob.mailsize)
  697.          status |=  S_MOREMAIL;
  698.       st_glob.mailsize = st.st_size;
  699.    } else {
  700.       status &= ~S_MAIL;
  701.       st_glob.mailsize = 0;
  702.    }
  703.  
  704.    if (status & S_MAIL) {
  705.       if (!prev) f2=1;
  706.       if (status & S_MOREMAIL) { sepinit(IS_START|IS_ITEM); f2=1; }
  707.       if (f2)
  708.          confsep("mailmsg",confidx,&st_glob,part,0);
  709.       status &= ~S_MOREMAIL;
  710.    }
  711.    prev = (status & S_MAIL);
  712. }
  713.