#module NEWSSKIM "V5.6"

/*
**++
**  FACILITY:
**
**      NEWSSKIM
**
**  ABSTRACT:
**
**      SKIM/ITEMS
**         Delete all items which are unreadable, or have been on the
**         system for longer than EXP_TIME days, or have no message identifier.
**      SKIM/NEWSGROUPS:
**         Delete all newsgroups which have had no new items entered
**         in the last GRP_TIME days, and have no current items.
**      SKIM/FILES:
**         Delete all ITM files which are backversions or are not
**         referenced by the item file.
**
**  AUTHOR:
**
**      Geoff Huston
**
**  COPYRIGHT:
**
**      Copyright © 1988
**
**  MODIFICATION HISTORY:
**
**      V5.5     7-Oct-1988     GIH
**          Add directory scan to delete subdirectories which do not match
**          current active newsgroups
**      V5.6    11-Nov-1988     GIH
**          Bug fix to directory scan module
**
**--
**/

#include "newsdefine.h"
#include "newsinclude.h"
#include "newsextern.h"

#include "sortdef.h"

static struct {
    short numkeys,
          keytype,
          keyorder,
          keyoffset,
          keylength;
    } keys = {1, DSC$K_DTYPE_T, 0, 0, /*IDLEN*/ 5};

static int served_cmd = 1;

static int skim_all;

static struct sk {
    unsigned short sk_num;
    struct sk *sk_next;
    char sk_name[256];
    } *sk_head = 0,
      *sk_expanded = 0;

static struct gl_list {
    unsigned short gl_num;
    struct gl_list *gl_next;
    } *gl_head = 0, *ns_head = 0;

/*
 *  add_check_id
 *
 *  Add item identifier to list to check against items held on server node
 */

static struct grps *check_id_head = 0;

add_check_id(gn,ii,ig,ng,etime,proto)
    char *gn,
         *ii,
         *ng;
    unsigned short ig;
    int etime;
    int proto;
{
    struct gl_list *gt = gl_head;
    struct grps *tmp = check_id_head;
    struct itms *itmp;

    while (gt && (gt->gl_num != ig)) gt = gt->gl_next;
    if (gt) return;
    while (tmp && (tmp->itmgrp != ig)) tmp = tmp->grpsnext;
    if (!tmp) {
        tmp = malloc(sizeof *tmp);
        strcpy(tmp->grpname,gn);
        strcpy(tmp->grpnode,ng);
        tmp->itmgrp = ig;
        tmp->ids = tmp->idr = 0;
        tmp->grptime = etime;
        tmp->grpsnext = check_id_head;
        tmp->nproto = proto;
        check_id_head = tmp;
        }
    if (ii) {
        itmp = malloc(sizeof *itmp);
        strcpy(itmp->itmid,ii);
        itmp->itmsnext = tmp->ids;
        tmp->ids = itmp;
        }
}

clear_gl()
{
    struct gl_list *gt;

    while (gl_head) {
        gt = gl_head;
        gl_head = gl_head->gl_next;
        free(gt);
        }
}

server_check(reset,served_cmd)
    int reset,
        served_cmd;
{
    struct grps *ig = check_id_head;
    struct itms *it, *ip, *ic, *icp, *irecheck;
    char itmkey[IDLEN + 2];
    unsigned short *idgrp;
    int del_remainder;
    int s_screen_active = 0;
    struct gl_list *gt;

    if (check_id_head) {
        if (screen_active) {
            noscreen();
            s_screen_active = 1;
            }
        grprab.rab$b_ksz = 2;
        grprab.rab$b_krf = 1;
        grprab.rab$l_rop = RAB$M_WAT;
        grprab.rab$b_rac = RAB$C_KEY;

        idgrp = &itmkey[IDLEN];
        itmrab.rab$l_kbf = itmkey;
        itmrab.rab$b_krf = 1;
        itmrab.rab$b_ksz = IDLEN + 2;
        itmrab.rab$l_rop = RAB$M_WAT ;
        itmrab.rab$b_rac = RAB$C_KEY;

        if (served_cmd) {
            printf("\n\t/SERVED - remote server scan:\n");
            server_check_ids(check_id_head);
            }
        printf("\n\t/SERVED - local verify pass\n");
        while (check_id_head) {

            gt = malloc(sizeof *gt);
            gt->gl_num = check_id_head->itmgrp;
            gt->gl_next = gl_head;
            gl_head = gt;

            del_remainder = 0;
            ig = check_id_head;
            if (served_cmd) printf("\tWorking on %s\n",ig->grpname);
            if (check_id_head->idr) {
                grprab.rab$l_kbf = &(ig->itmgrp);
                if (!(sys$get(&grprab) & 1)) newsgrp.grp_num = 0;
                }
            if ((it = check_id_head->idr) && (!it->itmsize)) {
                irecheck = 0;
                del_remainder = 1;
                while (it = check_id_head->idr) {
                    ip = 0;
                    while (it->itmsnext) {
                        ip = it;
                        it = it->itmsnext;
                        }
                    icp = 0;
                    ic = check_id_head->ids;
                    s_to_lower(it->itmid);
                    while (ic && strcmp(ic->itmid,it->itmid)) {
                        icp = ic;
                        ic = ic->itmsnext;
                        }
                    if (ic) {
                        if (icp) icp->itmsnext = ic->itmsnext;
                        else check_id_head->ids = 0;
                        free(ic);
                        free(it);
                        }
                    else {
                        newsitm.itm_date = it->itmdate;
                        newsitm.itm_new = 0;
                        newsitm.itm_size = it->itmsize;
                        newsitm.itm_life = 0;
                        newsitm.itm_unread = 0;
                        newsitm.itm_locdate = 0;
                        util_cpy(newsitm.itm_title,"-- Title not Obtained --");
                        util_idcpy(newsitm.itm_id,it->itmid);
                        newsitm.itm_grp = ig->itmgrp;
                        newsitm.itm_num = ++newsgrp.grp_topnum;
                        time(&newsgrp.grp_entdate);
                        itmrab.rab$w_rsz = sizeof newsitm;
                        itmrab.rab$l_rbf = &newsitm;
                        if (sys$put(&itmrab) & 1) {
                            ++newsgrp.grp_count;
                            if (irecheck) it->itmsnext = irecheck;
                            irecheck = it;
                            }
                        else {
                            --newsgrp.grp_topnum;
                            free(it);
                            }
                        }
                    if (ip) ip->itmsnext = 0;
                    else check_id_head->idr = 0;
                    }
                if (irecheck) {
                    server_get_titles(check_id_head,irecheck);
                    itmrab.rab$l_kbf = itmkey;
                    itmrab.rab$b_krf = 1;
                    itmrab.rab$b_ksz = IDLEN + 2;
                    itmrab.rab$l_rop = RAB$M_WAT ;
                    itmrab.rab$b_rac = RAB$C_KEY;
                    }
                while (irecheck) {
                    it = irecheck;
                    if (*it->itmid) {
                        strncpy(itmkey,it->itmid,IDLEN);
                        *idgrp = check_id_head->itmgrp;
                        if (sys$get(&itmrab) & 1) {
                            util_cpy(newsitm.itm_title,it->itmtitle);
                            sys$update(&itmrab);
                            }
                        }
                    irecheck = it->itmsnext;
                    free(it);
                    }
                }
            else {
                while (it = check_id_head->idr) {
                    ip = 0;
                    while (it->itmsnext) {
                        ip = it;
                        it = it->itmsnext;
                        }
                    if (it->itmdate) {
                        newsitm.itm_date = it->itmdate;
                        newsitm.itm_new = 0;
                        newsitm.itm_size = it->itmsize;
                        newsitm.itm_life = 0;
                        newsitm.itm_unread = 0;
                        newsitm.itm_locdate = 0;
                        util_cpy(newsitm.itm_title,it->itmtitle);
                        s_to_lower(it->itmid);
                        util_idcpy(newsitm.itm_id,it->itmid);
                        newsitm.itm_grp = ig->itmgrp;
                        newsitm.itm_num = ++newsgrp.grp_topnum;
                        time(&newsgrp.grp_entdate);
                        itmrab.rab$w_rsz = sizeof newsitm;
                        itmrab.rab$l_rbf = &newsitm;
                        if (sys$put(&itmrab) & 1) ++newsgrp.grp_count;
                        else --newsgrp.grp_topnum;
                        }
                    else {
                        s_to_lower(it->itmid);
                        strncpy(itmkey,it->itmid,IDLEN);
                        *idgrp = ig->itmgrp;
                        if (sys$get(&itmrab) & 1) {
                            sys$delete(&itmrab);
                            hist_add(newsitm.itm_id);
                            --newsgrp.grp_count;
                            }
                        }
                    if (ip) ip->itmsnext = 0;
                    else check_id_head->idr = 0;
                    free(it);
                    }
                }
            it = check_id_head->ids;
            while (it) {
                if (del_remainder) {
                    strncpy(itmkey,it->itmid,IDLEN);
                    *idgrp = ig->itmgrp;
                    if (sys$get(&itmrab) & 1) {
                        sys$delete(&itmrab);
                        hist_add(newsitm.itm_id);
                        --newsgrp.grp_count;
                        }
                    }
                it = it->itmsnext;
                free(check_id_head->ids);
                check_id_head->ids = it;
                }
            if (newsgrp.grp_num) sys$update(&grprab);
            ig = ig->grpsnext;
            free(check_id_head);
            check_id_head = ig;
            }
        if (s_screen_active) screen_active = news_context;
        if (reset) mem_reset(cur_dir_type);
        }
    return(0);
}

/*
 *  files_skim
 *
 *  Delete all unreferenced ITM files in NEWS area
 */

files_skim()
{
    char fnam[257],
         grp[132],
         lstgrp[132],
         ifiles[250],
         *sf,
         *s,
         *p;
    short itm_key[2];
    int   g,
          m,
          last_g = 0,
          last_m = 0,
          no_grp = 0;
    $DESCRIPTOR(fnam_dsc,fnam);
    $DESCRIPTOR(itm_dsc,ifiles);
    int context = 0,
        version;
    struct sk *tmp;

    *lstgrp = '\0';
    itmrab.rab$l_kbf = itm_key;
    itmrab.rab$b_krf = 0;
    itmrab.rab$b_ksz = 4;
    itmrab.rab$l_rop= RAB$M_RRL | RAB$M_NLK ;
    itmrab.rab$b_rac = RAB$C_KEY;

    grprab.rab$l_kbf = grp;
    grprab.rab$b_ksz = SUBJLEN;
    grprab.rab$b_krf = 0;
    grprab.rab$l_rop = RAB$M_RRL | RAB$M_NLK ;
    grprab.rab$b_rac = RAB$C_KEY;

    if (skim_all) strcpy(ifiles,Itm_files);
    else {
        tmp = sk_expanded;
        sprintf(ifiles,Itmg_template,tmp->sk_name);
        }

    itm_dsc.dsc$w_length = strlen(ifiles);
    for (;;) {
        status = lib$find_file(&itm_dsc,&fnam_dsc,&context,0,0,0,0);
        if (skim_all) {
            if (!(status & 1)) break;
            }
        else {
            if (!(status & 1)) {
                if (!(tmp = tmp->sk_next)) break;
                lib$find_file_end(&context);
                sprintf(ifiles,Itmg_template,tmp->sk_name);
                itm_dsc.dsc$w_length = strlen(ifiles);
                continue;
                }
            }

        fnam[256] = '\0';
        if (s = strchr(fnam,' ')) *s = '\0';
        if (!(sf = strrchr(fnam,':'))) continue;
        if (!(sf = strrchr(fnam,'['))) continue;
        ++sf;
        if (!(p = strchr(sf,']'))) continue;
        *p = ' ';
        if (*sf == '0') {
            if (!(sf = strchr(sf,'.'))) continue;
            sf++;
            }
        if (sscanf(sf,"%s %d.ITM;%d",grp,&m,&version) != 3) {
            *p = ']';
            printf("\tUnrecognised file - ?%s?\n",fnam);
            continue;
            }
        *p = ']';
        strcpy(grp,util_undir(grp));
        util_cvrt(grp,grp);

        if (strcmp(grp,lstgrp)) {
            util_cvrt(lstgrp,grp);
            if (!(sys$get(&grprab) & 1)) {
                printf("\tCannot match directory to groupname - %s\n",lstgrp);
                no_grp = 1;
                last_g = 0;
                }
            else {
                no_grp = 0;
                g = newsgrp.grp_num;
                printf("\tWorking on %s\n",newsgrp.grp_name);
                }
            }
        if (no_grp) {
            printf("\tDelete %s - no group record\n",fnam);
            delete(fnam);
            continue;
            }
        else {
            itm_key[0] = m;
            itm_key[1] = g;
            if ((last_g == itm_key[1]) && (last_m == itm_key[0])) {
                printf("\tDelete %s - back version\n",fnam);
                delete(fnam);
                continue;
                }
            if (!(sys$get(&itmrab) & 1)) {
                printf("\tDelete %s - no item record\n",fnam);
                delete(fnam);
                }
            last_g = itm_key[1];
            last_m = itm_key[0];
            }
        }
    lib$find_file_end(&context);
    printf("\n");
}

/*
 *  dir_skim
 *
 *  Delete all Sub-Directories which are no longer valid
 */

dir_skim()
{
    char gfiles[250],
         gnam[257],
         grp[132],
         *p,
         *ext,
         *sf,
         *s;
    int context = 0,
        i,
        j,
        version;
    $DESCRIPTOR(grp_dsc,gfiles);
    $DESCRIPTOR(gnam_dsc,gnam);

    grprab.rab$l_kbf = grp;
    grprab.rab$b_ksz = SUBJLEN;
    grprab.rab$b_krf = 0;
    grprab.rab$l_rop = RAB$M_RRL | RAB$M_NLK ;
    grprab.rab$b_rac = RAB$C_KEY;

    if (!skim_all) {
        printf("\tSKIM/DIRECTORIES phase not performed on partial skim\n");
        return(0);
        }

    for (i = 7; i >= 0 ; --i) {
        strcpy(gfiles,"NEWS_DEVICE:[000000");
        for (j = 0 ; j < i ; ++j) strcat(gfiles,".*");
        strcat(gfiles,"]*.DIR;*");

        grp_dsc.dsc$w_length = strlen(gfiles);
        for (;;) {
            if (!(lib$find_file(&grp_dsc,&gnam_dsc,&context,0,0,0,0) & 1)) break;
            gnam[256] = '\0';
            if (s = strchr(gnam,' ')) *s = '\0';
            if (!(sf = strrchr(gnam,':'))) continue;
            if (!(sf = strrchr(gnam,'['))) continue;
            sf += 7;
            if (*sf == ']') p = sf;
            else if (!(p = strchr(sf,']'))) continue;
            ++sf;
            *p = ' ';
            if (!(ext = strrchr(p,'.'))) continue;
            *ext = ' ';
            *p = '.';
            if (sscanf(sf,"%s DIR;%d",grp,&version) != 2) {
                *p = ']';
                *ext = '.';
                printf("\tUnrecognised file - ?%s?\n",gnam);
                continue;
                }
            if (version != 1) {
                *p = ']';
                *ext = '.';
                printf("\t.DIR file with version greater then 1\n");
                printf("\t%s - DELETED",gnam);
                delete(gnam);
                continue;
                }
            strcpy(grp,util_undir(grp));
            util_cvrt(grp,grp);
            if (!strlen(grp)) {
                *p = ']';
                *ext = '.';
                printf("\t%s - Unknown file - ignored\n",gnam);
                continue;
                }
            if (!(sys$get(&grprab) & 1)) {
                strcat(grp,".");
                grprab.rab$b_ksz = strlen(grp);
                if ((sys$get(&grprab) & 1) && !strncmp(newsgrp.grp_name,grp,strlen(grp))) {
                    grprab.rab$b_ksz = SUBJLEN;
                    continue;
                    }
                grprab.rab$b_ksz = SUBJLEN;
                sysprv();
                *p = ']';
                *ext = '.';
                if (!delete(gnam)) printf("\t%s Deleted - no newsgroup\n",gnam);
                nosysprv();
                }
            }
        lib$find_file_end(&context);
        context = 0;
        }
    printf("\n");
}

/*
 *  grp_skim
 *
 *  Delete all empty old groups (GRP_TIME life time after last item entered
 */

grp_skim()
{
    int cur_time,
        glob_exp_time,
        grp_exp_time,
        glob_iexp_time,
        grp_iexp_time,
        itm_count,
        itm_key,
        grp_counter = 0,
        gloop = 0;
    unsigned short glob_exp_val,
                   grp_exp_val,
                   glob_iexp_val,
                   grp_iexp_val;
    struct sk *tmp;


    time(&cur_time);
    glob_exp_val = GRP_TIME ;

    grprab.rab$l_kbf = c$rfi(0);
    grprab.rab$b_ksz = 2;
    grprab.rab$b_krf = 1;
    grprab.rab$l_rop = RAB$M_RRL | RAB$M_NLK;
    grprab.rab$b_rac = RAB$C_KEY;

    if ((sys$get(&grprab) & 1) && (newsgrp.grp_life)) glob_exp_val = newsgrp.grp_life ;
    glob_exp_time = cur_time - (glob_exp_val * 84600);

    glob_iexp_val = EXP_TIME ;
    if ((sys$get(&grprab) & 1) && (newsgrp.grp_itmlife)) glob_iexp_val = newsgrp.grp_itmlife ;
    glob_iexp_time = cur_time - (glob_iexp_val * 84600);

    itmrab.rab$l_kbf = &itm_key;
    itmrab.rab$l_rop= RAB$M_RRL | RAB$M_KGE | RAB$M_NLK;
    itmrab.rab$b_rac = RAB$C_KEY;
    itmrab.rab$b_krf = 0;
    itmrab.rab$b_ksz = 4;

    if (skim_all) {
        grprab.rab$b_krf = 1;
        grprab.rab$b_rac = RAB$C_SEQ;
        sys$rewind(&grprab);
        }
    else {
        tmp = sk_expanded;
        grprab.rab$l_kbf = &(tmp->sk_num);
        grprab.rab$b_ksz = 2;
        grprab.rab$b_krf = 1;
        grprab.rab$b_rac = RAB$C_KEY;
        }
    grprab.rab$l_rop = RAB$M_WAT;

    for (;;) {
        status = sys$get(&grprab);
        if (skim_all) {
            if (!(status & 1)) break;
            }
        else {
            if ((!(status & 1)) || (gloop++)) {
                if (!(tmp = tmp->sk_next)) break;
                grprab.rab$l_kbf = &(tmp->sk_num);
                gloop = 0;
                }
            }

        if (!newsgrp.grp_num)continue;
        printf("\n\t%s",newsgrp.grp_name);
        if (grp_iexp_val = newsgrp.grp_itmlife) grp_iexp_time = cur_time - (grp_iexp_val * 84600);
        else {
            grp_iexp_val = glob_iexp_val ;
            grp_iexp_time = glob_iexp_time ;
            }
        if ((*(newsgrp.grp_server)) && (served_cmd))
            add_check_id(newsgrp.grp_name,0,newsgrp.grp_num,newsgrp.grp_server,grp_iexp_time,newsgrp.grp_srvproto);
        itm_count = 0;
        itm_key = (newsgrp.grp_num << 16);
        itmrab.rab$l_kbf = &itm_key;
        itmrab.rab$l_rop= RAB$M_RRL | RAB$M_KGE | RAB$M_NLK;
        itmrab.rab$b_rac = RAB$C_KEY;
        itmrab.rab$b_krf = 0;
        itmrab.rab$b_ksz = 4;
        while (sys$get(&itmrab) & 1) {
            itmrab.rab$l_rop = RAB$M_RRL | RAB$M_NLK ;
            itmrab.rab$b_rac = RAB$C_SEQ;
            if (newsitm.itm_grp != newsgrp.grp_num) break;
            else ++itm_count;
            }
        itmrab.rab$l_rop= RAB$M_RRL | RAB$M_KGE | RAB$M_NLK;
        itmrab.rab$b_rac = RAB$C_KEY;
        printf(" (%d)",itm_count);
        if (grp_exp_val = newsgrp.grp_life) grp_exp_time = cur_time - (grp_exp_val * 84600);
        else {
            grp_exp_val = glob_exp_val ;
            grp_exp_time = glob_exp_time ;
            }
        if ((!itm_count) && (grp_exp_val != 65535) && (newsgrp.grp_entdate < grp_exp_time)) {
            printf(" - DELETED");
            sys$delete(&grprab);
            }
        else {
            ++grp_counter;
            if (itm_count != newsgrp.grp_count) {
                newsgrp.grp_count = itm_count;
                _c$cks(sys$update(&grprab));
                }
            if (check_id_head) {
                unsigned short sav_contxt = newsgrp.grp_num;

                server_check(0,served_cmd);
                grprab.rab$b_ksz = 2;
                grprab.rab$b_krf = 1;
                grprab.rab$b_rac = RAB$C_KEY;
                if (skim_all) {
                    grprab.rab$l_kbf = &sav_contxt;
                    sys$get(&grprab);
                    grprab.rab$b_rac = RAB$C_SEQ;
                    }
                else grprab.rab$l_kbf = &(tmp->sk_num);
                itmrab.rab$l_kbf = &itm_key;
                itmrab.rab$l_rop= RAB$M_RRL | RAB$M_KGE | RAB$M_NLK;
                itmrab.rab$b_rac = RAB$C_KEY;
                itmrab.rab$b_krf = 0;
                itmrab.rab$b_ksz = 4;
                }
            }
        }
    if (skim_all) {
        grprab.rab$l_kbf = c$rfi(0);
        grprab.rab$b_ksz = 2;
        grprab.rab$b_krf = 1;
        grprab.rab$l_rop = RAB$M_WAT;
        grprab.rab$b_rac = RAB$C_KEY;
        _c$cks(sys$get(&grprab));
        newsgrp.grp_count = grp_counter;
        _c$cks(sys$update(&grprab));
        }
    printf("\n");
}

/*
 *  do_skim
 *
 *  Open the item and subject files for sharing
 */

static struct dlist {
        char *dg;
        int di;
        struct dlist *dn;
        } *dh = 0;

do_skim()
{
    int del_all_itms = 0,
        itm_count = 0,
        cur_time,
        glob_exp_time,
        grp_exp_time,
        itm_exp_time,
        s_screen_active = 0,
        sor_start = 0,
        itm_key,
        hist_date;
    unsigned short glob_exp_val,
                   grp_exp_val,
                   itm_exp_val,
                   cur_grp = 0,
                   arch_len,
                   newsgroups_len;
    char arch_file[256],
         sor_line[512],
         newsgroups[132];

    FILE *fpw = 0,
         *fpr;
    struct dlist *dt;
    struct sk *tmp, *extmp;

    $DESCRIPTOR(a_dsc,sor_line);
    $DESCRIPTOR(arch_dsc,arch_file);
    $DESCRIPTOR(newsgroups_dsc,newsgroups);
    short a_len;

    if (no_priv()) {
        printf("\tError: Skim - no priv\n");
        return(0);
        }

    while (sk_head) {
        tmp = sk_head;
        if (!(sk_head = sk_head->sk_next)) sk_head = sk_expanded;
        free(tmp);
        }
    sk_expanded = 0;

    if (cli$get_value(c$dsc("GROUPS"),&newsgroups_dsc,&newsgroups_len) & 1) {
        do {
            newsgroups[newsgroups_len] = '\0';
            util_cvrt(newsgroups,newsgroups);
            tmp = malloc(sizeof *tmp);
            tmp->sk_next = sk_head;
            strcpy(tmp->sk_name,newsgroups);
            sk_head = tmp;
            } while (cli$get_value(c$dsc("GROUPS"),&newsgroups_dsc,&newsgroups_len) & 1);
        grprab.rab$b_krf = 0;
        grprab.rab$l_rop = RAB$M_RRL | RAB$M_NLK;
        grprab.rab$b_rac = RAB$C_SEQ;
        sys$rewind(&grprab);
        skim_all = 1;
        while (sys$get(&grprab) & 1) {
            int fnd = 0;
            if (!newsgrp.grp_num)continue;
            tmp = sk_head;
            while (tmp) {
                if (wild_match(newsgrp.grp_name,tmp->sk_name)) {
                    fnd = 1;
                    extmp = sk_expanded;
                    while ((extmp) && (extmp->sk_num != newsgrp.grp_num)) extmp = extmp->sk_next;
                    if (!extmp) {
                        extmp = malloc(sizeof *extmp);
                        extmp->sk_next = sk_expanded;
                        strcpy(extmp->sk_name,newsgrp.grp_name);
                        extmp->sk_num = newsgrp.grp_num;
                        sk_expanded = extmp;
                        }
                    break;
                    }
                tmp = tmp->sk_next;
                }
            if (!fnd) skim_all = 0;
            }
        while (sk_head) {
            tmp = sk_head;
            if ((!(sk_head = sk_head->sk_next)) && (skim_all)) sk_head = sk_expanded;
            free(tmp);
            }
        if (skim_all) sk_expanded = 0;
        }
    else skim_all = 1;

    if ((!skim_all) && (!sk_expanded)) {
        err_line("\tWarning: SKIM - No newsgroups to scan\n");
        return(0);
        }

    if (screen_active) {
        noscreen();
        s_screen_active = 1;
        }

    printf("\nSKIM - Starting news scan\n");

    served_cmd = 0;
    if (cli$present(c$dsc("SERVED")) != CLI$_NEGATED) {
        grprab.rab$b_krf = 0;
        grprab.rab$b_rac = RAB$C_SEQ;
        grprab.rab$l_rop = RAB$M_NLK | RAB$M_RRL;
        sys$rewind(&grprab);
        do {
            if (((status = sys$get(&grprab)) & 1) && (*(newsgrp.grp_server))) break;
            } while (status & 1);
        if (status & 1) served_cmd = 1;
        else printf("\n\t/SERVED - No remote served newsgroups - /NOSERVED used\n");
        }

    if (cli$present(c$dsc("ITEMS")) == CLI$_NEGATED)
        printf("\n\t/NOITEMS - skipping item scan\n");
    else {
        printf("\n\t/ITEMS - item scan:\n");

        dh = 0;

        if (cli$present(c$dsc("ARCHIVE")) & 1) {
            cli$get_value(c$dsc("ARCHIVE"),&arch_dsc,&arch_len);
            arch_file[arch_len] = '\0';
            }
        else *arch_file = '\0';


        glob_exp_val = EXP_TIME ;
        time(&cur_time);
        newsgrp.grp_num = 0;

        grprab.rab$l_kbf = &cur_grp;
        grprab.rab$b_ksz = 2;
        grprab.rab$b_krf = 1;
        grprab.rab$l_rop = RAB$M_WAT;
        grprab.rab$b_rac = RAB$C_KEY;

        if ((sys$get(&grprab) & 1) && (newsgrp.grp_itmlife)) glob_exp_val = newsgrp.grp_itmlife ;
        glob_exp_time = cur_time - (glob_exp_val * 84600);

        if (skim_all) {
            itmrab.rab$b_rac = RAB$C_SEQ;
            itmrab.rab$b_krf = 0;
            itmrab.rab$l_rop = RAB$M_WAT;
            sys$rewind(&itmrab);
            }
        else {
            tmp = sk_expanded;
            itm_key = tmp->sk_num << 16;
            itmrab.rab$b_krf = 0;
            itmrab.rab$b_ksz = 4;
            itmrab.rab$l_kbf = &itm_key;
            itmrab.rab$b_rac = RAB$C_KEY;
            itmrab.rab$l_rop= RAB$M_WAT | RAB$M_KGE;
            }

        for (;;) {
            status = sys$get(&itmrab);

            if ((!(status & 1)) && (status != RMS$_EOF) && (status != RMS$_RNF)) {
                printf("ERROR FROM RMS - code returned was %X\n", status);
                printf("SKIM INCOMPLETE - NEWSITEM FILE CORRUPTED\n");
                }
            if (skim_all) {
                if (!(status & 1)) break;
                }
            else {
                itmrab.rab$b_rac = RAB$C_SEQ;
                if ((!(status & 1)) || (newsitm.itm_grp != tmp->sk_num)) {
                    if (!(tmp = tmp->sk_next)) break;
                    itm_key = tmp->sk_num << 16;
                    itmrab.rab$b_rac = RAB$C_KEY;
                    if (newsgrp.grp_num) {
                        if ((newsgrp.grp_count != itm_count) && (sys$get(&grprab) & 1)) {
                            newsgrp.grp_count = itm_count;
                            _c$cks(sys$update(&grprab));
                            }
                        if (check_id_head) {
                            server_check(0,served_cmd);
                            itmrab.rab$b_krf = 0;
                            itmrab.rab$b_ksz = 4;
                            itmrab.rab$l_kbf = &itm_key;
                            itmrab.rab$b_rac = RAB$C_KEY;
                            itmrab.rab$l_rop= RAB$M_WAT | RAB$M_KGE;

                            grprab.rab$l_kbf = &cur_grp;
                            grprab.rab$b_ksz = 2;
                            grprab.rab$b_krf = 1;
                            grprab.rab$l_rop = RAB$M_WAT;
                            grprab.rab$b_rac = RAB$C_KEY;
                            }
                        }
                    newsgrp.grp_num = 0;
                    continue;
                    }
                }
            if (!newsitm.itm_grp) {
                sys$delete(&itmrab);
                printf("\tLocated item with 0 group field value - item deleted\n");
                continue;
                }
            if (newsitm.itm_grp != newsgrp.grp_num) {
                if ((newsgrp.grp_num) && (newsgrp.grp_count != itm_count)) {
                    if (sys$get(&grprab) & 1) {
                        newsgrp.grp_count = itm_count;
                        _c$cks(sys$update(&grprab));
                        }
                    }

                if (check_id_head) {
                    int sav_contxt;

                    sav_contxt = (newsitm.itm_grp << 16) + newsitm.itm_num;
                    server_check(0,served_cmd);
                    itmrab.rab$b_krf = 0;
                    itmrab.rab$b_ksz = 4;
                    itmrab.rab$l_kbf = &itm_key;
                    itmrab.rab$b_rac = RAB$C_KEY;
                    itmrab.rab$l_rop= RAB$M_WAT;
                    sys$get(&itmrab);
                    itmrab.rab$b_rac = RAB$C_SEQ;

                    grprab.rab$l_kbf = &cur_grp;
                    grprab.rab$b_ksz = 2;
                    grprab.rab$b_krf = 1;
                    grprab.rab$l_rop = RAB$M_WAT;
                    grprab.rab$b_rac = RAB$C_KEY;
                    }
                cur_grp = newsitm.itm_grp;
                if (sys$get(&grprab) & 1) {
                    printf("\tWorking on %s\n",newsgrp.grp_name);
                    del_all_itms = 0;
                    if (grp_exp_val = newsgrp.grp_itmlife) grp_exp_time = cur_time - (grp_exp_val * 84600);
                    else {
                        grp_exp_val = glob_exp_val ;
                        grp_exp_time = glob_exp_time ;
                        }
                    }
                else del_all_itms = 1;
                itm_count = 0;
                }

            if (itm_exp_val = newsitm.itm_life) itm_exp_time = cur_time - (itm_exp_val * 84600);
            else {
                itm_exp_val = grp_exp_val ;
                itm_exp_time = grp_exp_time ;
                }

            if (     (del_all_itms)
                  || ((newsitm.itm_date < itm_exp_time) && (itm_exp_val != 65535))
                  || ((*(newsgrp.grp_server)) && (newsitm.itm_locdate) && (cur_time > (newsitm.itm_locdate + (newsgrp.grp_loccoplife * 84600))))) {
                if ((del_all_itms) || ((newsitm.itm_date < itm_exp_time) && (itm_exp_val != 65535))) {
                    printf("\t   #%d Item deleted (expiry)\n",newsitm.itm_num);
                    sys$delete(&itmrab);
                    hist_add(newsitm.itm_id);
                    }
                else {
                    printf("\t   #%d Item retained on remote server (local copy expiry)\n",newsitm.itm_num);
                    newsitm.itm_locdate = 0;
                    if (served_cmd) add_check_id(newsgrp.grp_name,newsitm.itm_id,newsgrp.grp_num,newsgrp.grp_server,grp_exp_time,newsgrp.grp_srvproto);
                    sys$update(&itmrab);
                    ++itm_count;
                    }
                if (*arch_file) {
                        /* If archiving deleted items, save deletion until
                            after the archive phase */

                    dt = malloc(sizeof *dt);
                    strcpy((dt->dg = malloc(strlen(newsgrp.grp_name) + 1)),newsgrp.grp_name);
                    dt->di = newsitm.itm_num;
                    dt->dn = dh;
                    dh = dt;

                        /* If archiving deleted items, then use callable sort
                            (based on the message id) to ensure that only one
                            copy of each item is archived */

                    if (!sor_start++) c$cks(sor$begin_sort(&keys,c$rfi(512),c$rfi(sor$m_nodups),0,0,0,0,0,0));
                    sprintf(itm_fname,Itm_template,util_dir(newsgrp.grp_name),newsitm.itm_num);
                    sprintf(sor_line,"%-*.*s %s",IDLEN,IDLEN,newsitm.itm_id,itm_fname);
                    c$cks(sor$release_rec(c$dsc(sor_line)));
                    }
                else news_delete_file(newsitm.itm_num,newsgrp.grp_name);
                continue;
                }

            if (!(fpr = do_oitem(&newsitm,"r",newsgrp.grp_name,0,(newsgrp.grp_local & NEWS_RESTRICT_SET)))) {
                if (*(newsgrp.grp_server)) {
                    newsitm.itm_locdate = 0;
                    sys$update(&itmrab);
                    if (served_cmd) add_check_id(newsgrp.grp_name,newsitm.itm_id,newsgrp.grp_num,newsgrp.grp_server,grp_exp_time,newsgrp.grp_srvproto);
                    }
                else {
                    printf("\t   #%d Item deleted (no text file)\n",newsitm.itm_num);
                    sys$delete(&itmrab);
                    continue;
                    }
                }
            else {
                fclose(fpr);
                if (!newsitm.itm_locdate) {
                    time(&newsitm.itm_locdate);
                    sys$update(&itmrab);
                    }
                }
            ++itm_count;
            }
        if (newsgrp.grp_num) {
            if (sys$get(&grprab) & 1) {
                newsgrp.grp_count = itm_count;
                _c$cks(sys$update(&grprab));
                }
            if (check_id_head) server_check(0,served_cmd);
            }
        }
    if (*arch_file) {
        FILE *fpi,
             *fpo;
        struct stat app_file,
                    inp_file;
        char xbuf[512];

        if (sor_start) {
            char *p;

            printf("\n\t/ARCHIVE - archive pass\n");
            c$cks(sor$sort_merge());
            while (sor$return_rec(&a_dsc,&a_len) & 1) {
                sor_line[a_len] = '\0';
                p = strrchr(sor_line,' ');
                p++;
                if (stat(p,&inp_file)) continue;
                if (!(fpi = fopen(p,"r"))) continue;
                if (!stat(arch_file,&app_file)) {
                    if ((app_file.st_size + inp_file.st_size) > NEWS_BATCH_SIZE)
                        fpo = fopen(arch_file,"w","rfm=var","rat=cr");
                    else fpo = fopen(arch_file,"a");
                    }
                else fpo = fopen(arch_file,"w","rfm=var","rat=cr");
                if (!fpo) {
                    fclose(fpi);
                    continue;
                    }
                fprintf(fpo,"#! rnews %d\n",inp_file.st_size);
                while (fgets(xbuf,510,fpi)) fputs(xbuf,fpo);
                fclose(fpo);
                fclose(fpi);
                }
            c$cks(sor$end_sort());
            }
        else printf("\n\t/ARCHIVE - no archive pass (No items to archive)\n");
        while (dh) {
            news_delete_file(dh->di,dh->dg);
            dt = dh;
            dh = dh->dn;
            free(dt->dg);
            free(dt);
            }
        }

    if (cli$present(c$dsc("NEWSGROUPS")) == CLI$_NEGATED)
        printf("\n\t/NONEWSGROUPS - skipping newsgroup scan\n");
    else {
        printf("\n\t/NEWSGROUPS - newsgroup scan:\n");
        grp_skim();
        }

    if (!served_cmd) printf("\n\t/NOSERVED - skipping remote server scan\n");

    if (cli$present(c$dsc("FILES")) == CLI$_NEGATED) printf("\n\t/NOFILES - skipping local file scan\n");
    else {
        printf("\n\t/FILES - local item file scan:\n");
        files_skim();
        }

    if (cli$present(c$dsc("DIRECTORIES")) == CLI$_NEGATED) printf("\n\t/NODIRECTORIES - skipping local directory scan\n");
    else {
        printf("\n\t/DIRECTORIES - local newsgroup directory scan:\n");
        dir_skim();
        }

    hist_date = (skim_all ? HIST_VAL : 0);
    if ((status = cli$present(c$dsc("HISTORY"))) & 1) {
        cli$get_value(c$dsc("HISTORY"),&arch_dsc,&arch_len);
        arch_file[arch_len] = '\0';
        if (!sscanf(arch_file,"%d",&hist_date)) hist_date = 0;
        }
    else if (status == CLI$_NEGATED) hist_date = 0;
    if (hist_date) {
        printf("\n\t/HISTORY=%d - history file skim",hist_date);
        time(&cur_time);
        hist_date = cur_time - (hist_date * 84600);
        hist_skim(hist_date);
        }
    clear_gl();
    printf("\n");
    if (s_screen_active) screen_active = news_context;
    mem_reset(cur_dir_type);
    return(0);
}

noserver_add(g)
    unsigned short g;
{
    struct gl_list *tmp;

    tmp = malloc (sizeof *tmp);
    tmp->gl_num = g;
    tmp->gl_next = ns_head;
    ns_head = tmp;
}

noserver_skim()
{
    struct gl_list *tmp = ns_head;
    int itm_key,
        itmcount,
        delcount = 0;
    FILE *fpr;

    while (tmp) {
        grprab.rab$l_kbf = &(tmp->gl_num);
        grprab.rab$b_ksz = 2;
        grprab.rab$b_krf = 1;
        grprab.rab$l_rop = RAB$M_WAT;
        grprab.rab$b_rac = RAB$C_KEY;

        if ((sys$get(&grprab) & 1) && (!*(newsgrp.grp_server))) {

            itm_key = newsgrp.grp_num << 16;
            itmrab.rab$l_kbf = &itm_key;
            itmrab.rab$b_ksz = 4;
            itmrab.rab$b_krf = 0;
            itmrab.rab$l_rop = RAB$M_WAT | RAB$M_KGE;
            itmrab.rab$b_rac = RAB$C_KEY;
            itmcount = 0;
            while (sys$get(&itmrab) & 1) {
                if (newsitm.itm_grp != newsgrp.grp_num) break;
                itmrab.rab$l_rop = RAB$M_WAT;
                itmrab.rab$b_rac = RAB$C_SEQ;
                if (!(fpr = do_oitem(&newsitm,"r",newsgrp.grp_name,0,(newsgrp.grp_local & NEWS_RESTRICT_SET)))) {
                    ++delcount;
                    sys$delete(&itmrab);
                    continue;
                    }
                ++itmcount;
                }
            if (itmcount != newsgrp.grp_count) {
                newsgrp.grp_count = itmcount;
                sys$update(&grprab);
                }
            }
        tmp = tmp->gl_next;
        free(ns_head);
        ns_head = tmp;
        }
    if (delcount) mem_reset(cur_dir_type);
}
