#module NEWSADD "V5.6"

/*
**++
**  FACILITY:
**
**      NEWSADD
**
**  ABSTRACT:
**
**      This module parses input files according to the NEWS message format
**      standards and adds parsed items into the local NEWS database.
**
**      The local acceptance filter (as defined in NEWS.SYS) is applied
**      to the newsgroups and distribution control lines before adding to the
**      local database.
**
**      The module also passes items to the outgoing mailbox routines to
**      determine whether the item should be passed to downstream sites.
**
**  AUTHOR:
**
**      Geoff Huston
**
**  COPYRIGHT:
**
**      Copyright © 1988
**
**  MODIFICATION HISTORY:
**
**      V5.5     7-Oct-1988     GIH
**          Improve junking algorithm to prevent empty item generation
**          Correct checkgroup execution algorithm for /EXECUTE pass
**
**      V5.6    11-Nov-1988     GIH
**        - Support for /MODERATOR qualifier to alow moderators to
**          add news items into moderated newsgroups.
**        - Add /EXECUTE=RETAIN | LOCAL | DELETE parameters to /EXECUTE
**          qualifier to allow more control options on receipt of
**          rmgroup and checkgroups control messages
**        - Correct bug preventing automatic creation of newsgroups
**
**--
**/

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

#define OHEADERS 18
#define NHEADERS 20
#define MAX_UNK  50

#define PATH            0
#define NEWSGROUPS      1
#define SUBJECT         2
#define MESSAGE_ID      3
#define FROM            4
#define DATE            5
#define REPLY_TO        6
#define SENDER          7
#define FOLLOWUP_TO     8
#define EXPIRES         9
#define REFERENCES      10
#define CONTROL         11
#define DISTRIBUTION    12
#define ORGANIZATION    13
#define KEYWORDS        14
#define SUMMARY         15
#define APPROVED        16
#define SUPERSEDES      17
#define LINES           18
#define XREF            19

static char inline[512] = "",
            fline[512] = "",
            xbuf[512],
            scratchfile[256],
            def_newsgroup[256],
            scanline[2048],
            junk[] = "junk",
            itm[NHEADERS][512],
            mail_cmd[132],
            mod[256],
            *unk_headers[MAX_UNK],
            *headers[] = {"path",
                   "newsgroups",
                   "subject",
                   "message-id",
                   "from",
                   "date",
                   "reply-to",
                   "sender",
                   "followup-to",
                   "expires",
                   "references",
                   "control",
                   "distribution",
                   "organization",
                   "keywords",
                   "summary",
                   "approved",
                   "supersedes",
                   "lines",
                   "xref"};
            *fheaders[] ={"Path: ",
                   "Newsgroups: ",
                   "Subject: ",
                   "Message-ID: ",
                   "From: ",
                   "Date: ",
                   "Reply-To: ",
                   "Sender: ",
                   "Followup-To: ",
                   "Expires: ",
                   "References: ",
                   "Control: ",
                   "Distribution: ",
                   "Organization: ",
                   "Keywords: ",
                   "Summary: ",
                   "Approved: ",
                   "Supersedes: ",
                   "Lines: ",
                   "Xref: "},
            *mail_scratch = "SYS$SCRATCH:NEWS_MAIL.TMP",
            *log_scratch = "SYS$SCRATCH:NEWS_LOG.TMP";

static int next_eof = 0,
           infile_eof = 0,
           infile_eom = 0,
           headers_out = 0,
           skip_blank_lines = 0,
           bsize = 0,
           line_count = 0,
           n_stripping = 0,
           del_after = 0,
           execute_control = 1,
           exec_opt = 0,
           skip_loop_test,
           junk_it = 1,
           accept_it = 0,
           unk_index = 0,
           no_add = 0,
           mod_add = 0,
           loc_junk = 0;

static FILE *fpr = 0,
            *fpt = 0,
            *fpm = 0,
            *fpl = 0;

/*
 *++
 *  Function:
 *      control_version
 *
 *  Description:
 *      Mail the News version level back to poster
 *
 *  Parameters:
 *      None
 *
 *  Side effects:
 *      None
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_version()
{
    char vms_address[256],
         *mail_replyto = itm[REPLY_TO];

    if (!*mail_replyto) mail_replyto = itm[FROM];
    if (*mail_replyto) {
        strcpy(vms_address,add_transform(mail_replyto));
        if (fpm = fopen(mail_scratch,"w")) {
            fprintf(fpm,"Response-To-Control: %s message\n",itm[CONTROL]);
            fprintf(fpm,"Responding-System: %s\n",Node_address);
            fprintf(fpm,"News-Software: %s\n",NEWS_VERSION);
            fclose(fpm);
            fpm = 0;
            sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"Reply to News version Control message\" %s",mail_scratch,vms_address);
            printf("\tControl: version - Reply sent to %s\n",vms_address);
            _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
            while (!(delete(mail_scratch)));
            }
        else printf("\tControl: version - Cannot open scratch file\n");
        }
    else printf("\tControl: version - No reply address\n");
}

/*
 *++
 *  Description:
 *      Mail the UUCP control file back to poster - mail error text for VMS
 *
 *  Parameters:
 *      None
 *
 *  Side effects:
 *      None
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_senduuname()
{
    char vms_address[256],
         *mail_replyto = itm[REPLY_TO];

    if (!*mail_replyto) mail_replyto = itm[FROM];
    if (*mail_replyto) {
        strcpy(vms_address,add_transform(mail_replyto));
        if (fpm = fopen(mail_scratch,"w")) {
            fprintf(fpm,"Response-To-Control: %s message\n",itm[CONTROL]);
            fprintf(fpm,"Responding-System: %s\n",Node_address);
            fprintf(fpm,"News-Software: %s\n",NEWS_VERSION);
            fprintf(fpm,"This is a VAX/VMS NEWS node - there are no UUCP neighbours\n");
            fclose(fpm);
            fpm = 0;
            sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"Reply to News version Control message\" %s",mail_scratch,vms_address);
            printf("\tControl: senduuname - Reply sent to %s\n",vms_address);
            _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
            while (!(delete(mail_scratch)));
            }
        else printf("\tControl: senduuname - Cannot open tmp file\n");
        }
    else printf("\tControl: senduuname - No reply address\n");
}

/*
 *++
 *  Description:
 *      Mail the NEWS.SYS control file back to poster
 *
 *  Parameters:
 *      None
 *
 *  Side effects:
 *      None
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_sendsys()
{
    char sysname[132],
         il[512],
         vms_address[256],
         *mail_replyto = itm[REPLY_TO];
    FILE *fpr;

    if (!*mail_replyto) mail_replyto = itm[FROM];
    if (*mail_replyto) {
        strcpy(vms_address,add_transform(mail_replyto));
        if (fpm = fopen(mail_scratch,"w")) {
            fprintf(fpm,"Response-To-Control: %s message\n",itm[CONTROL]);
            fprintf(fpm,"Responding-System: %s\n",Node_address);
            fprintf(fpm,"News-Software: %s\n",NEWS_VERSION);
            strcpy(sysname,newsmgr_dir);
            strcat(sysname,"NEWS.SYS");
            sysprv();
            if (!(fpr = fopen(sysname,"r"))) fprintf(fpm,"No-SYS: No NEWS.SYS file defined on this node\n");
            else {
                while (fgets(il,510,fpr)) if (*il != '#') fputs(il,fpm);
                fclose(fpr);
                }
            nosysprv();
            fclose(fpm);
            fpm = 0;
            sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"Reply to News version Control message\" %s",mail_scratch,vms_address);
            printf("\tControl: sendsys - Reply sent to %s\n",vms_address);
            _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
            while (!(delete(mail_scratch)));
            }
        else printf("\tControl: sendsys - Cannot open tmp file\n");
        }
    else printf("\tControl: sendsys - No reply address\n");
}

/*
 *++
 *  Description:
 *      Create new newsgroup control message - if auto execution enabled then
 *      new newsgroup is created, otherwise DCL is posted to USENET
 *
 *  Parameters:
 *      None
 *
 *  Side effects:
 *      New newsgroup is created if auto exec is enabled
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_newgroup()
{
    char *c,
         locname[132];
    int g,
        mod;

    if (*itm[APPROVED]) {
        fpm = 0;
        c = itm[CONTROL] + 8;
        while (isspace(*c)) c++;
        if (*c) {
            strcpy(locname,c);
            c = locname;
            while (isgraph(*c)) c++;
            *c++ = '\0';
            mod = ((*c) && substrcmp(s_to_lower(c),"moderated"));
            util_cvrt(locname,locname);
            if (!(g = ga_exact_name(locname)) && execute_control) {
                int sc = auto_cre_grp;

                auto_cre_grp = 1;
                do_newg(locname,0);
                auto_cre_grp = sc;

                if ((g = ga_exact_name(locname)) && (fpm = fopen(mail_scratch,"w")))
                    fprintf(fpm,"Control: newgroup - created %s\n",ga[g]->grp_name);
                }
            if (g) {
                if ((ga[g]->grp_local & 1) || (ga[g]->grp_moderator != mod)) {
                    if (execute_control) {
                        if (ga[g]->grp_local & 1) ga[g]->grp_local &= ~1;
                        if (mod != ga[g]->grp_moderator) ga[g]->grp_moderator = mod;
                        update_newsgrp(g);
                        }
                    if (fpm || (fpm = fopen(mail_scratch,"w"))) {
                        if (!execute_control) {
                            fprintf(fpm,"$ ! Generated Command file from newgroup message:\n");
                            fprintf(fpm,"$ ! use EXTRACT/NOHEAD then execute this file\n$ !\n");
                            fprintf(fpm,"$ NEWS/NOSCREEN\n");
                            if (ga[g]->grp_local & 1) fprintf(fpm,"Set NEWSGROUP %s/NOLOCAL\n",ga[g]->grp_name);
                            if (mod) fprintf(fpm,"Set NEWSGROUP %s/MOD\n\n",ga[g]->grp_name);
                            else if ((!mod) && ga[g]->grp_moderator) fprintf(fpm,"Set NEWSGROUP %s/NOMOD\n",ga[g]->grp_name);
                            fprintf(fpm,"EXIT\n");
                            }
                        else fprintf(fpm,"Control: newgroup - modified %s/NOLOCAL%s\n",ga[g]->grp_name,(mod ? "/MOD" : ""));
                        }
                    }
                }
            else if (fpm = fopen(mail_scratch,"w")) {
                fprintf(fpm,"$ !Generated Command file from newgroup message:\n");
                fprintf(fpm,"$ ! use EXTRACT/NOHEAD then execute this file\n$ !\n");
                fprintf(fpm,"$ ! CHECK THIS FILE BEFORE EXECUTION\n$ !\n");
                fprintf(fpm,"$ NEWS/NOSCREEN\n");
                fprintf(fpm,"CREATE NEWSGROUP %s",locname);
                if (mod) fprintf(fpm,"/MOD");
                fprintf(fpm,"\nY\n");
                if (mod) fprintf(fpm,"\n");
                fprintf(fpm,"EXIT\n");
                }
            else printf("\tControl: newgroup - Cannot open tmp file\n");
            if (fpm) {
                fclose(fpm);
                fpm = 0;
                sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"NEWS newgroup control message\" %s",mail_scratch,USENET);
                printf("\tControl: newgroup %s - Mail to Usenet\n",locname);
                _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
                while (!(delete(mail_scratch)));
                }
            else if (g) printf("\tControl: newgroup - newsgroup %s already exists\n",locname);
            }
        else printf("\tControl: newgroup - No newsgroup name extracted from header\n");
        }
    else printf("\tControl: newgroup - Non-Approved Control posting\n");
}

/*
 *++
 *  Description:
 *      Delete a newsgroup control message - if auto execution enabled then
 *      newsgroup is deleted, otherwise DCL is posted to USENET
 *
 *  Parameters:
 *      None
 *
 *  Side effects:
 *      Newsgroup is deleted if auto exec is enabled
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_rmgroup()
{
    char *c,
         locname[132];
    int g;
    FILE *fpw;

    if (*itm[APPROVED]) {
        c = itm[CONTROL] + 7;
        while (isspace(*c)) c++;
        if (*c) {
            strcpy(locname,c);
            while (isgraph(*c)) c++;
            *c = '\0';
            util_cvrt(locname,locname);
            if ((g = ga_exact_name(locname)) && !(ga[g]->grp_local & 1)) {
                fpm = fopen(mail_scratch,"w");
                if (execute_control) {
                    if (exec_opt == 1) {
                        delgrp_file(g);
                        if (fpm) fprintf(fpm,"Control: rmgroup %s - Deleted\n",locname);
                        }
                    else if (exec_opt == 2) {
                        ga[g]->grp_local |= 1;
                        update_newsgrp(g);
                        if (fpm) fprintf(fpm,"Control: rmgroup %s - Set /LOCAL\n",locname);
                        }
                    else {
                        ga[g]->grp_life = 7;
                        update_newsgrp(g);
                        if (fpm) fprintf(fpm,"Control: rmgroup %s - Set /HOLD=7\n",locname);
                        }
                    }
                if (fpm) {
                    if (!execute_control) {
                        fprintf(fpm,"$ ! Generated Command file from rmgroup message\n");
                        fprintf(fpm,"$ ! use EXTRACT/NOHEAD then execute this file\n$ !\n");
                        fprintf(fpm,"$ NEWS/NOSCREEN\n");
                        fprintf(fpm,"! Remove NEWSGROUP %s (or set to /LOCAL)\n",ga[g]->grp_name);
                        fprintf(fpm,"!SET NEWSGROUP %s/LOCAL\n",ga[g]->grp_name);
                        fprintf(fpm,"! Or:\n");
                        fprintf(fpm,"DELETE NEWSGROUP %s\nY\n",ga[g]->grp_name);
                        fprintf(fpm,"EXIT\n");
                        }
                    fclose(fpm);
                    fpm = 0;
                    sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"NEWS rmgroup control message\" %s",mail_scratch,USENET);
                    printf("\tControl: rmgroup %s - Mail to Usenet\n",locname);
                    _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
                    while (!(delete(mail_scratch)));
                    }
                else printf("\tControl: rmgroup - Cannot open tmp file\n");
                }
            else if (g) printf("\tControl: rmgroup %s - Newsgroup defined /LOCAL\n",locname);
            else printf("\tControl: rmgroup %s - Newsgroup not located\n",locname);
            }
        else printf("\tControl: rmgroup - No newsgroup name extracted from header\n");
        }
    else printf("\tControl: rmgroup - Non-Approved Control posting\n");
}

/*
 *++
 *  Description:
 *      Check the local newsgroup set against the network distribution list,
 *      removing any detected inconsistencies
 *
 *  Parameters:
 *      address of asciz string of file name containing checkgroup list
 *
 *  Side effects:
 *      Local newsgroups created/deleted as per list
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_checkgroups(fn)
    char *fn;
{
    char locname[132];
    FILE *fpr,
         *fpw,
         *fpw1 = 0,
         *fpnet;
    GRP_MEM_PTR *ca;
    int i,
        g,
        mail_msg = 0,
        indx;
    struct glist {
        char glname[SUBJLEN];
        int glmod;
        struct glist *gnext;
        } *add_head, *del_head, *at, *dt, *tmp;

    add_head = del_head = at = dt = 0;
    if (*itm[APPROVED]) {
        fpm = fopen(mail_scratch,"w");
        fpl = fopen(log_scratch,"w");
        fpnet = fopen("NEWS_ROOT:NEWSGROUPS.NET","w");

        if (!fpm) printf("\tControl: checkgroups - cannot open tmp mail file\n");
        if (!fpl) printf("\tControl: checkgroups - cannot open tmp log file %s\n");
        if (fpm) {
            if (execute_control) {
                fprintf(fpm,"Generated Log file from checkgroup message\n");
                }
            else {
                fprintf(fpm,"$ ! Generated Command file from checkgroup message\n");
                fprintf(fpm,"$ ! use EXTRACT/NOHEAD then execute this item\n$ !\n");
                fprintf(fpm,"$ NEWS/NOSCREEN\n");
                }
            }
        if (fpl) fprintf(fpl,"#NETWORK NEWSGROUPS: Newsgroup Descriptions\n");
        if (fpr = fopen(fn,"r")) {
            ca = malloc((ga_size + 1) * (sizeof *ca));
            for (i = 1 ; i <= ga_size ; ++i) ca[i] = ga[i];
            while ((fgets(xbuf,510,fpr)) && (*xbuf != '\n'));
            while (fgets(xbuf,510,fpr)) {
                if (*xbuf == '\n') continue;
                if (fpl) fputs(xbuf,fpl);
                fputs(xbuf,fpnet);
                if (indx = strcspn(xbuf," \t")) xbuf[indx] = '\0';
                util_cvrt(locname,xbuf);
                if (g = ga_exact_name(locname)) {
                    ca[g] = 0;
                    if (indx && substrcmp(&xbuf[indx+1],"(Moderated)")) {
                        if (!ga[g]->grp_moderator) {
                            xbuf[indx] = '\t';
                            ++mail_msg;
                            if (execute_control) {
                                ga[g]->grp_moderator = 1;
                                update_newsgrp(g);
                                }
                            if (fpm) {
                                if (execute_control) {
                                    fprintf(fpm,"Set Newsgroup %s to Moderated\n",locname);
                                    }
                                else {
                                    fprintf(fpm,"! ADD MODERATOR: %s\n",locname);
                                    fprintf(fpm,"SET NEWSGROUP %s/MOD\n\n",locname);
                                    }
                                }
                            continue;
                            }
                        }
                    else if (ga[g]->grp_moderator) {
                        if (indx) xbuf[indx] = '\t';
                        ++mail_msg;
                        if (execute_control) {
                            ga[g]->grp_moderator = 0;
                            update_newsgrp(g);
                            }
                        if (fpm) {
                            if (execute_control) {
                                fprintf(fpm,"Set Newsgroup %s to Unmoderated\n",locname);
                                }
                            else {
                                fprintf(fpm,"! REMOVE MODERATOR: %s\n",locname);
                                fprintf(fpm,"SET NEWSGROUP %s/NOMOD\n",locname);
                                }
                            }
                        continue;
                        }
                    }
                else {
                    if (indx) xbuf[indx] = '\t';
                    ++mail_msg;
                    if (execute_control) {
                        tmp = malloc(sizeof *tmp);
                        if (at) at->gnext = tmp;
                        else add_head = tmp;
                        at = tmp;
                        at->gnext = 0;
                        strcpy(at->glname,locname);
                        at->glmod = 0;
                        }
                    if (fpm) {
                        if (!execute_control) {
                            fprintf(fpm,"! ADD Net NEWSGROUP: %s",xbuf);
                            fprintf(fpm,"CREATE NEWSGROUP %s\nY\n",locname);
                            }
                        }
                    if (substrcmp(xbuf,"(Moderated)")) {
                        if (execute_control) at->glmod = 1;
                        if (fpm) {
                            if (!execute_control) {
                                fprintf(fpm,"! Add MODERATOR: %s\n",locname);
                                fprintf(fpm,"SET NEWSGROUP %s/MOD\n\n",locname);
                                }
                            }
                        }
                    continue;
                    }
                }
            g = 1;
            while (g <= ga_size) {
                if (ca[g]) {
                    if (!(ga[g]->grp_local & 1)) {
                        ++mail_msg;
                        if (execute_control) {
                            tmp = malloc(sizeof *tmp);
                            if (dt) dt->gnext = tmp;
                            else del_head = tmp;
                            dt = tmp;
                            dt->gnext = 0;
                            strcpy(dt->glname,ga[g]->grp_name);
                            }
                        else if (fpm) {
                            if (!execute_control) {
                                fprintf(fpm,"! Remove NEWSGROUP %s (or set to /LOCAL)\n",ga[g]->grp_name);
                                fprintf(fpm,"!SET NEWSGROUP %s/LOCAL\n",ga[g]->grp_name);
                                fprintf(fpm,"! Or:\n");
                                fprintf(fpm,"!DELETE NEWSGROUP %s\n!Y\n",ga[g]->grp_name);
                                }
                            }
                        }
                    }
                g++;
                }
            free(ca);
            fclose(fpr);
            at = add_head;
            while (add_head) {
                int sc = auto_cre_grp;

                auto_cre_grp = 1;
                tmp = add_head ;
                do_newg(tmp->glname,0);
                auto_cre_grp = sc;
                if (g = ga_exact_name(tmp->glname)) {
                    ++mail_msg;
                    fprintf(fpm,"Created new Network Newsgroup: %s",tmp->glname);
                    if (tmp->glmod) {
                        fprintf(fpm,"/Moderated");
                        ga[g]->grp_moderator = 1;
                        update_newsgrp(g);
                        }
                    tmp->glmod = 0;
                    fprintf(fpm,"\n");
                    }
                else tmp->glmod = 1;
                add_head = add_head->gnext;
                }
            while (del_head) {
                tmp = del_head;
                ++mail_msg;
                if (g = ga_exact_name(tmp->glname)) {
                    if (exec_opt == 1) {
                        fprintf(fpm,"Delete Newsgroup %s\n",tmp->glname);
                        delgrp_file(g);
                        }
                    else if (exec_opt == 2) {
                        fprintf(fpm,"Set Newsgroup %s/LOCAL\n",tmp->glname);
                        ga[g]->grp_local |= 1;
                        update_newsgrp(g);
                        }
                    else {
                        fprintf(fpm,"Set Newsgroup %s/HOLD=7\n",tmp->glname);
                        ga[g]->grp_life = 7;
                        update_newsgrp(g);
                        }
                    }
                else fprintf(fpm,"Cannot locate Newsgroup %s (Delete required)\n",tmp->glname);
                del_head = del_head->gnext;
                free(tmp);
                }
            add_head = at;
            while (add_head) {
                tmp = add_head ;
                if (tmp->glmod) {
                    ++mail_msg;
                    fprintf(fpm,"\n* NO Create of Network Newsgroup: %s\n",
                        tmp->glname);
                    fprintf(fpm,"\t(SYS filter rejection)\n");
                    }
                add_head = add_head->gnext;
                free(tmp);
                }
            if (fpm) {
                if (!execute_control) fprintf(fpm,"EXIT\n");
                fclose(fpm);
                fpm = 0;
                if (mail_msg) {
                    sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"NEWS control message\" %s",mail_scratch,USENET);
                    printf("\tControl: checkgroups - Mail to Usenet\n");
                    _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
                    }
                }
            if (!mail_msg) printf("\tControl: checkgroups - No changes required\n");
            fclose(fpnet);
            if (fpl) {
                fclose(fpl);
                fpl = 0;
                sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"NEWS control message\" %s",log_scratch,USENET);
                printf("\tControl: checkgroups - Mail Description file to Usenet\n");
                _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
                }
            while (!(delete(log_scratch)));
            while (!(delete(mail_scratch)));
            }
        else printf("\tControl: checkgroups - Cannot read file contents\n");
        }
    else printf("\tControl: checkgroups - Non-Approved Control posting\n");
}

/*
 *++
 *  Description:
 *      Cancel a news item
 *
 *  Parameters:
 *      address of asciz string of file name containing cancel message
 *
 *  Side effects:
 *      Local newsitem canceled - message id added to history file
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_cancel(fn)
    char *fn;
{
    char *id,
         *ide,
         control[132],
         net_sender[132],
         *mail_sender = itm[SENDER];

    strcpy(control,itm[CONTROL]);
    if ((id = strchr(control,'<')) && (ide = strchr(control,'>'))) {
        *(ide + 1) = '\0';
        if (!*mail_sender) mail_sender = itm[FROM];
        if (ide = strchr(mail_sender,'<')) {
            strcpy(net_sender,++ide);
            if (ide = strchr(net_sender,'>')) *ide = '\0';
            if (ide = strchr(net_sender,'\n')) *ide = '\0';
            }
        else {
            char *cp = net_sender,
                 *cp1 = mail_sender;

            while (isspace(*cp1)) cp1++;
            while ((*cp1) && (!isspace(*cp1))) *cp++ = *cp1++;
            *cp = '\0';
            if (cp = strchr(net_sender,'(')) *cp = '\0';
            }
        if (del_id(id,net_sender)) {
            sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"NEWS control message - cancel successful\" %s",fn,USENET);
            printf("\tControl: cancel - item located and deleted\n");
            }
        else {
            sprintf(mail_cmd,"MAIL/NOEDIT %s/SUBJECT=\"NEWS control message - cancel NOT successful\" %s",fn,USENET);
            printf("\tControl: cancel - item NOT located - added to History file\n");
            hist_add(id);
            }
        _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
        }
    else printf("\tControl: cancel - no message-id in header\n");
}

/*
 *++
 *  Description:
 *      If a message identifier is NOT located in the local id file, and the
 *      id is NOT in the history file, then write the id to the request file.
 *
 *  Parameters:
 *      address of asciz string of the message-id
 *      pointer to the request file
 *
 *  Side effects:
 *      None
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      1 (true) if id added to request file, 0 otherwise
 *--
 */

c_ihave_id(id,f)
    char *id;
    FILE *f;
{
    char l_id[IDLEN + 2];
    int i;

    for (i = 0; i < (IDLEN + 2); ++i) l_id[i] = '\0';
    strncpy(l_id,id,IDLEN);
    s_to_lower(l_id);

    itmrab.rab$l_kbf = l_id;
    itmrab.rab$b_ksz = IDLEN + 2;
    itmrab.rab$b_krf = 1;
    itmrab.rab$l_rop = RAB$M_KGE | RAB$M_RRL | RAB$M_NLK;
    itmrab.rab$b_rac = RAB$C_KEY;

    if (((!(sys$get(&itmrab) & 1)) || (strcmp(l_id,newsitm.itm_id)))
            && !hist_check(id))
        return(fprintf(f,"%s\n",id),1);
    return(0);
}

/*
 *++
 *  Description:
 *      Check the local database of message-ids against the incoming ihave
 *      set. Any ids not held locally are added to a request file for a
 *      sendme response.
 *
 *  Parameters:
 *      address of asciz string of file name containing ihave list
 *
 *  Side effects:
 *      None
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_ihave(fn)
    char *fn;
{
    char s_str[132],
         newsgroups[132],
         *il = itm[CONTROL] + 5,
         *cp;
    FILE *fpw = 0,
         *fpr;
    int line_count = 0;

    sprintf(s_str,"to.%s",usr_nodename);
    strcpy(newsgroups,itm[NEWSGROUPS]);
    s_to_lower(newsgroups);
    if (strcmp(newsgroups,s_str)) {
        printf("Control: %s - Directed to foreign node: %s\n",itm[CONTROL],newsgroups);
        return;
        }
    if (cp = strrchr(il,'>')) il = ++cp;
    while (isspace(*il)) il++;
    if (!*il) {
        printf("Control: ihave - Error (No remote system specified)\n");
        return;
        }
    strcpy(s_str,"to.");
    strcat(s_str,il);
    cp = s_str;
    while (isgraph(*cp)) cp++;
    *cp++ = '\0';
    if (!s_str[3]) {
        printf("Control: ihave - Error (No remote system specified)\n");
        return;
        }
    s_to_lower(s_str);
    fpw = fopen("SYS$SCRATCH:SENDME.MAIL","w");

    il = itm[CONTROL] + 5;
    while (cp = strchr(il,'<')) {
        il = cp;
        if (cp = strchr(il,'>')) {
            *cp++ = '\0';
            line_count += c_ihave_id(il,fpw);
            il = cp;
            }
        else ++il;
        }
    if (fpr = fopen(fn,"r")) {
        while ((fgets(xbuf,510,fpr)) && (*xbuf != '\n'));
        while (fgets(xbuf,510,fpr)) {
            if (*xbuf == '\n') continue;
            if ((cp = strchr(xbuf,'<')) && (il = strchr(cp,'>'))) {
                *++il = '\0';
                line_count += c_ihave_id(cp,fpw);
                }
            }
        }
    fclose(fpw);
    if (line_count) {
        char *p,
             post_dist = '\0',
             post_path[132],
             loc_id[IDLEN];
        int cur_time;
        struct tm *stm;

        fpr = fopen("SYS$SCRATCH:SENDME.MAIL","r");
        fpw = fopen("SYS$SCRATCH:SENDME.MAIL","w");
        sprintf(post_path," %s!%s",usr_nodename,usr_username);
        fprintf(fpw,"Path: %s\n",post_path);
        fprintf(fpw,"From: %s@%s",usr_username,Node_address);
        if (*usr_persname) fprintf(fpw," (%s)",usr_persname);
        fprintf(fpw,"\n");
        fprintf(fpw,"Newsgroups: %s\n",s_str);
        fprintf(fpw,"Control: sendme %s\n",usr_nodename);
        fprintf(fpw,"Subject: sendme %s\n",usr_nodename);
        time(&cur_time);
        p = ctime(&cur_time);
        p += 4;
        stm = localtime(&cur_time);
        strcpy(loc_id,gen_id());
        fprintf(fpw,"Message-ID: %s\n",loc_id);
        fprintf(fpw,"Date: %d %.3s %d %02d:%02d:%02d %s\n",
            stm->tm_mday,p,stm->tm_year,stm->tm_hour,stm->tm_min,stm->tm_sec,
            news_timezone);
        fprintf(fpw,"Organization: %s\n",Organisation_name);
        fprintf(fpw,"Lines: %d\n",line_count);
        fprintf(fpw,"\n");
        while (fgets(xbuf,510,fpr)) fputs(xbuf,fpw);
        fclose(fpr);
        fclose(fpw);
        sys_remote_send(post_path,s_str,post_dist,"SYS$SCRATCH:SENDME.MAIL",loc_id,0);
        }
    while (!(delete("SYS$SCRATCH:SENDME.MAIL")));
}

/*
 *++
 *  Description:
 *      Check the requested message-id list against the local database,
 *      and forward all requested messages that are held locally
 *
 *  Parameters:
 *      address of asciz string of file name containing sendme list
 *
 *  Side effects:
 *      None
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static control_sendme(fn)
    char *fn;
{
    char s_str[132],
         *il = itm[CONTROL] + 5,
         *cp,
         l_id[IDLEN + 2],
         post_dist = '\0',
         post_path[132];
    int i,
        gn;
    FILE *fpr;

    sprintf(post_path," %s!%s",usr_nodename,usr_username);
    itmrab.rab$l_kbf = l_id;
    itmrab.rab$b_ksz = IDLEN + 2;
    itmrab.rab$b_krf = 1;
    itmrab.rab$l_rop = RAB$M_KGE | RAB$M_RRL | RAB$M_NLK;
    itmrab.rab$b_rac = RAB$C_KEY;

    sprintf(s_str,"to.%s",usr_nodename);
    strcpy(xbuf,itm[NEWSGROUPS]);
    s_to_lower(xbuf);
    if (strcmp(xbuf,s_str)) {
        printf("Control: %s - Directed to foreign node: %s\n",itm[CONTROL],xbuf);
        return;
        }
    if (cp = strrchr(il,'>')) il = ++cp;
    while (isspace(*il)) il++;
    if (!*il) {
        printf("Control: sendme - Error (No remote system specified)\n");
        return;
        }
    strcpy(s_str,"to.");
    strcat(s_str,il);
    cp = s_str;
    while (isgraph(*cp)) cp++;
    *cp++ = '\0';
    if (!s_str[3]) {
        printf("Control: sendme - Error (No remote system specified)\n");
        return;
        }
    s_to_lower(s_str);

    il = itm[CONTROL] + 5;
    while (cp = strchr(il,'<')) {
        il = cp;
        if (cp = strchr(il,'>')) {
            *cp++ = '\0';
            for (i = 0; i < (IDLEN + 2); ++i) l_id[i] = '\0';
            strncpy(l_id,il,IDLEN);
            s_to_lower(l_id);
            if ((sys$get(&itmrab) & 1) && (!strcmp(l_id,newsitm.itm_id))
                    && (gn = ga_locate(newsitm.itm_grp)) && (fpr = do_oitem(&newsitm,"r",ga[gn]->grp_name,0,(ga[gn]->grp_local & NEWS_RESTRICT_SET)))) {
                fclose(fpr);
                sys_remote_send(post_path,s_str,post_dist,itm_fname,l_id,0);
                }
            il = cp;
            }
        else ++il;
        }
    if (fpr = fopen(fn,"r")) {
        while ((fgets(xbuf,510,fpr)) && (*xbuf != '\n'));
        while (fgets(xbuf,510,fpr)) {
            if (*xbuf == '\n') continue;
            if ((cp = strchr(xbuf,'<')) && (il = strchr(cp,'>'))) {
                *++il = '\0';
                for (i = 0; i < (IDLEN + 2); ++i) l_id[i] = '\0';
                strncpy(l_id,cp,IDLEN);
                s_to_lower(l_id);
                if ((sys$get(&itmrab) & 1) && (!strcmp(l_id,newsitm.itm_id))
                        && (gn = ga_locate(newsitm.itm_grp)) && (fpr = do_oitem(&newsitm,"r",ga[gn]->grp_name,0,(ga[gn]->grp_local & NEWS_RESTRICT_SET)))) {
                    fclose(fpr);
                    sys_remote_send(post_path,s_str,post_dist,itm_fname,l_id,0);
                    }
                }
            }
        }
}

/*
 *++
 *  Description:
 *      Parse a Control: header item and call appropriate execution routine
 *
 *  Parameters:
 *      address of asciz string of file name containing control item
 *
 *  Side effects:
 *      None
 *
 *  Exceptions:
 *      None
 *
 *  Result:
 *      None
 *--
 */

static parse_control_item(fn)
    char *fn;
{
    char loc_cmd[132];

    strcpy(loc_cmd,itm[CONTROL]);
    s_to_lower(loc_cmd);

    if (!strncmp(loc_cmd,"version",7)) return(control_version());
    if (!strncmp(loc_cmd,"senduuname",10)) return(control_senduuname());
    if (!strncmp(loc_cmd,"sendsys",7)) return(control_sendsys());
    if (!strncmp(loc_cmd,"newgroup",8)) return(control_newgroup());
    if (!strncmp(loc_cmd,"rmgroup",7)) return(control_rmgroup());
    if (!strncmp(loc_cmd,"checkgroups",11)) return(control_checkgroups(fn));
    if (!strncmp(loc_cmd,"cancel",6)) return(control_cancel(fn));
    if (!strncmp(loc_cmd,"ihave",5)) return(control_ihave(fn));
    if (!strncmp(loc_cmd,"sendme",6)) return(control_sendme(fn));
    printf("\tControl: No handler defined for %s\n",loc_cmd);
}

/*
 *  parse_date
 *
 *  parse a usenet-format date into Unix-time value
 */

parse_date(s)
    char *s;
{
    char *cp,
         mon[10],
         pdate[15];
    int dom = 0,
        yr = 0,
        udate,
        cdate;

    if (!*s) return(0);
    if (cp = strchr(s,',')) s = ++cp;
    while (isspace(*s)) s++;
    *mon = '\0';
    if (isdigit(*s)) {
        sscanf(s,"%d %s %d",&dom,mon,&yr);
        yr += 1900;
        }
    else sscanf(s,"%*s %s %d %*s %d",mon,&dom,&yr);
    if (!*(cp = mon)) return(0);
    while (*cp) { *cp = toupper(*cp); ++cp; }
    sprintf(pdate,"%d-%s-%d",dom,mon,yr);
    if (!(udate = cvt_date_val(pdate))) return(0);
    time(&cdate);
    if (udate <= cdate) return(3);
    udate = ((udate - cdate) / 84600) + 1;
    if (udate < 3) udate = 3;
    if (udate > 366) udate = 366;
    return(udate);
}

/*
 *  mail_add_item
 *
 *  Add the temporary output file into the News database, creating new
 *  newsgroups where required
 */

static mail_add_item(fn,linecount)
    char *fn;
    int linecount;
{
    char newsgroup[512],
         *subject = itm[SUBJECT];
    int  i;
    unsigned short cre_grp[100];

    strcpy(newsgroup,itm[NEWSGROUPS]);
    mail_add_expiry = parse_date(itm[EXPIRES]);
    if (*itm[CONTROL]) {
        if (sys_local_accept(newsgroup,itm[DISTRIBUTION])) {
            strcpy(newsgroup,"control");
            if ((!skip_loop_test) && (!sys_looping(itm[PATH]))) printf("\tControl: Ignored (Loop Detected)\n");
            else parse_control_item(fn);
            }
        else printf("\tControl: Ignored (SYS filter)\n");
        }
    printf("Add %s %s",itm[MESSAGE_ID],newsgroup);
    if (!strcmp(newsgroup,"junk") && !junk_it) return(printf(": REJECT (/NOJUNK)\n"));
    subject[SUBJLEN-1] = '\0';
    for (i = strlen(subject); i < SUBJLEN ; ++i) subject[i] = '\0';
    if (!*newsgroup) {
        if (!junk_it) return(printf(": REJECT (No Newsgroup)\n"));
        printf(": JUNK (No Newsgroup)");
        strcpy(newsgroup,junk);
        }
    if ((!skip_loop_test) && (!sys_looping(itm[PATH]))) return(printf(": REJECT (Path Loop)\n"));
    if ((!sys_local_accept(newsgroup,itm[DISTRIBUTION])) && (strcmp(newsgroup,junk))) {
        if (!junk_it) return(printf(": REJECT (SYS filter)\n"));
        printf(": JUNK (SYS filter)");
        strcpy(newsgroup,junk);
        }
    do_new_group(newsgroup,0,cre_grp);
    if ((!*cre_grp) && (strcmp(newsgroup,junk))) {
        if (!junk_it) return(printf(": REJECT (No local Newsgroup match)\n"));
        printf(": JUNK (No local Newsgroup match)");
        strcpy(newsgroup,junk);
        do_new_group(newsgroup,0,cre_grp);
        }
    if ((!*cre_grp) && (!strcmp(newsgroup,junk))) printf(": REJECT (No JUNK)");
    *itm_fname = '\0';
    status = 0;
    if (*cre_grp) {
        if (status = do_new_item(cre_grp,itm[MESSAGE_ID],subject,fn,1,skip_loop_test,linecount)) {
            if ((status == 0xb00184ec) || (status == 0xb0010001)) return(printf(": REJECT (Duplicate)\n",no_new_item));
            else {
                if (strcmp(newsgroup,junk)) {
                    if (*itm_fname) sys_remote_send(itm[PATH],itm[NEWSGROUPS],itm[DISTRIBUTION],itm_fname,itm[MESSAGE_ID],1);
                    else sys_remote_send(itm[PATH],itm[NEWSGROUPS],itm[DISTRIBUTION],fn,itm[MESSAGE_ID],1);
                    if (!junk_it) return(printf(": REJECT (%s)\n",no_new_item));
                    printf(": JUNK (%s)\n",no_new_item);
                    strcpy(itm[NEWSGROUPS],junk);
                    *itm[CONTROL] = '\0';
                    mail_add_item(fn,linecount);
                    return;
                    }
                else printf(": REJECT (%s)",no_new_item);
                }
            }
        else if (*itm[SUPERSEDES]) {
            char *id,
                 *ide,
                 *mail_sender = itm[SENDER],
                 net_sender[132];

            if ((id = strchr(itm[SUPERSEDES],'<')) && (ide = strchr(itm[SUPERSEDES],'>'))) {
                *(ide + 1) = '\0';
                if (!*mail_sender) mail_sender = itm[FROM];
                if (ide = strchr(mail_sender,'<')) {
                    strcpy(net_sender,++ide);
                    if (ide = strchr(net_sender,'>')) *ide = '\0';
                    if (ide = strchr(net_sender,'\n')) *ide = '\0';
                    }
                else {
                    char *cp = net_sender,
                    *cp1 = mail_sender;

                    while (isspace(*cp1)) cp1++;
                    while ((*cp1) && (!isspace(*cp1))) *cp++ = *cp1++;
                    *cp = '\0';
                    if (cp = strchr(net_sender,'(')) *cp = '\0';
                    }
                if (!del_id(id,net_sender)) hist_add(id);
                printf(" (Supersedes %s)",itm[SUPERSEDES]);
                }
            }
        }
    if (*itm_fname) sys_remote_send(itm[PATH],itm[NEWSGROUPS],itm[DISTRIBUTION],itm_fname,itm[MESSAGE_ID],1);
    else {
        sys_remote_send(itm[PATH],itm[NEWSGROUPS],itm[DISTRIBUTION],fn,itm[MESSAGE_ID],1);
        if (strcmp(newsgroup,junk)) {
            if (!junk_it) return(printf(": REJECT\n"));
            strcpy(itm[NEWSGROUPS],junk);
            *itm[CONTROL] = '\0';
            printf("\n");
            mail_add_item(fn,linecount);
            return;
            }
        }
    printf("\n");
}

/*
 *  open_out_file
 *
 *  open output file
 */

static FILE *open_out_file()
{
    if (fpt) return(fpt);
    if (fpt = fopen(scratchfile,"w")) return(fpt);
    printf("\tError: Cannot open scratchfile %s\n",scratchfile);
    del_after = 0;
    return(0);
}

/*
 *  out_header
 *
 *  Output header lines
 */

static out_header()
{
    FILE *fpl = open_out_file();
    char oline[512],
         head[30];
    int i;

    if (!fpl) return(0);
    headers_out = 1;
    if (!*itm[MESSAGE_ID]) strcpy(itm[MESSAGE_ID],gen_id());
    for (i = 0; i < OHEADERS; ++i) {
        ++bsize;
        if (i == PATH) fprintf(fpl,"%s%s!%s\n",fheaders[i],usr_nodename,itm[i]);
        else if ((i == APPROVED) && mod_add) continue;
        else if (i == NEWSGROUPS) {
            s_to_lower(itm[i]);
            fprintf(fpl,"%s%s\n",fheaders[i],itm[i]);
            }
        else if (*itm[i]) fprintf(fpl,"%s%s\n",fheaders[i],itm[i]);
        }
    for (i = 0; i < unk_index; ++i) fprintf(fpl,"%s\n",unk_headers[i]);
    fprintf(fpl,"\n");
}

/*
 *  out_data
 *
 *  output data line
 */

static out_data(s)
    char *s;
{
    FILE *fpl = open_out_file();
    char *c;

    if (!fpl) return(0);
    if (!headers_out) {
        out_header();
        skip_blank_lines = 1;
        }
    if (skip_blank_lines) {
        c = s;
        while (isspace(*c)) c++;
        if (!*c) return;
        skip_blank_lines = 0;
        }
    bsize += strlen(s);
    ++line_count;
    fprintf(fpl,"%s",s);
}

/*
 *  process_item
 *
 *  Rebuild an item file with all necessary headers
 */

static process_item()
{
    char xbuf[512],
         lines[132],
         *xx,
         *cp1,
         *cp2,
         lg[132],
         *pa,
         post_address[132],
         mod_group[132];
    int g,
        self_mod = 0;
    FILE *fpw;

    if (fpt) {
        fclose(fpt);
        fpt = 0;
        if (bsize) {
            if (mod_add) {
                strcpy((xx = malloc(strlen(itm[NEWSGROUPS]) + 1)),itm[NEWSGROUPS]);
                cp1 = xx;
                while ((cp1) && (*cp1)) {
                    if (cp2 = strchr(cp1,',')) *cp2++ = '\0';
                    util_cvrt(lg,cp1);
                    if ((g = ga_exact_name(lg)) && ga[g]->grp_moderator) {
                        if (strcmp(mod,(pa = moderator_address(ga[g]->grp_name)))) {
                            strcpy(mod_group,ga[g]->grp_name);
                            strcpy(post_address,pa);
                            }
                        else {
                            self_mod = 1;
                            *post_address = '\0';
                            strcpy(itm[APPROVED],mod);
                            itm_approved = 1;
                            }
                        }
                    else if (g && (ga[g]->grp_local & NEWS_MOD_ACCESS)) {
                        self_mod = 1;
                        *post_address = '\0';
                        strcpy(itm[APPROVED],mod);
                        itm_approved = 1;
                        }
                    cp1 = cp2;
                    }
                free(xx);
                if (!self_mod) {
                    printf("Add %s, %s",itm[FROM],itm[MESSAGE_ID]);
                    printf("Item does not reference moderated newsgroup:\n");
                    printf("  Newsgroups: %s\n",itm[NEWSGROUPS]);
                    printf("Item NOT added to News\n");
                    no_add = 1;
                    }
                else if (*post_address)  {
                    printf("Add %s, %s",itm[FROM],itm[MESSAGE_ID]);
                    printf("Additional moderated newsgroup specified: %s\n",mod_group);
                    printf("  Newsgroups: %s\n",itm[NEWSGROUPS]);
                    printf("  Next Moderator: %s\n",post_address);
                    sprintf(err_oline,"Post item to next moderator ? [y]");
                    status = get_input(&command,c$dsc(err_oline),&response_length);
                    if (status == SMG$_EOF) *response = 'n';
                    if (!((!response_length) || (tolower(*response) == 'y')))
                        *post_address = '\0';
                    no_add = 1;
                    }
                }
            sprintf(lines,"Lines: %d\n",line_count);
            if (!(fpt = fopen(scratchfile,"r"))) return(0);
            if (!(fpw = fopen(scratchfile,"w"))) {
                printf("\tError: Add - Cannot open output file %s\n",scratchfile);
                del_after = 0;
                return(0);
                }
            while (fgets(xbuf,510,fpt)) {
                if ((*xbuf == '\n') && (*lines)) {
                    if (mod_add && itm_approved)
                        fprintf(fpw,"%s%s\n",fheaders[APPROVED],itm[APPROVED]);
                    fputs(lines,fpw);
                    *lines = '\0';
                    }
                fputs(xbuf,fpw);
                }
            fclose(fpt);
            fpt = 0;
            fclose(fpw);
            if (!no_add) mail_add_item(scratchfile,line_count);
            else if (mod_add && *post_address) {
                char mail_cmd[256];

                sprintf(mail_cmd,"MAIL/NOEDIT/NOSELF %s/SUBJECT=\"%s\" %s",
                    scratchfile,itm[SUBJECT],add_transform(post_address));
                printf("Post to next Moderator (%s)\nSpawning MAIL task ..\n",post_address);
                _c$cks(lib$spawn(c$dsc(mail_cmd),0,0,0,0,0,0,0,0,0,0,0));
                }
            }
        while (!delete(scratchfile));
        }
}

/*
 *  init_strings, init_context
 *
 *  Reset all globals at the start of each item
 */

static init_strings()
{
    struct tm *stm;
    int cur_time,
        i;
    char *p;
    static char *node_name = 0;
    static int seq = 0;

    for (cur_time = 0; cur_time < NHEADERS; ++cur_time) *itm[cur_time] = '\0';
    strcpy(itm[FROM],"** Sender Unknown **");
    time(&cur_time);
    p = ctime(&cur_time);
    p += 4;
    stm = localtime(&cur_time);
    sprintf(itm[DATE],"%d %.3s %d %02d:%02d:%02d %s",
        stm->tm_mday,p,stm->tm_year,stm->tm_hour,stm->tm_min,stm->tm_sec,
        news_timezone);
    strcpy(itm[NEWSGROUPS],def_newsgroup);
    no_add = loc_junk;
    strcpy(itm[SUBJECT],"<None>");
    if (!node_name) node_name = getenv("SYS$NODE");
    *itm[MESSAGE_ID] = '\0';
    strcpy(itm[PATH],"Path-Lost");

    for (i = 0; i < unk_index; ++i) free(unk_headers[i]);
    unk_index = 0;
}

static init_context()
{
    init_strings();
    headers_out = 0;
    skip_blank_lines = 0;
    bsize = 0;
    line_count = 0;
    n_stripping = 0;
    itm_approved = accept_it;

    if (fpt) {
        fclose(fpt);
        fpt = 0;
        while (!delete(scratchfile));
        }
}

/*
 *  get_line
 *
 *  Read the next line from the input file - Scan for VMS MAIL end of
 *  message strings ("\f\nFrom:")
 */

static get_line()
{
    if (infile_eof) return(0);
    if (next_eof) {
        infile_eof = 1;
        return(0);
        }

    if (n_stripping) {
        if (*fline == 'N') strcpy(inline,&fline[1]);
        else return(infile_eom = 1);
        }
    else strcpy(inline,fline);
    if (fgets(fline,512,fpr)) {
        if (!strcmp(inline,"\f\n") && !strncmp(fline,"From:",5)) infile_eom = 1;
        else if (!strncmp(inline,"#! rnews ",9)) infile_eom = 1;
        else if (!strncmp(inline,"N#! rnews ",10)) infile_eom = 1;
        return(1);
        }
    next_eof = 1;
    strcpy(fline,"");
    return(1);
}

/*
 *  scan
 *
 *  Parse a header line, storing only acceptable NEWS headers
 */

static scan(s)
    char *s;
{
    char head_word[132],
         *p = s,
         *h = head_word;
    int i;

    while (isalnum(*p) || *p == '_' || *p == '-') p++;
    if ((*p == ':') && (isspace(*(p+1)))) {
        *p = '\0';
        strcpy(head_word,s);
        if (!*head_word) return(0);
        *p++ = ':';
        while (isspace(*p)) p++;
        if (strlen(p)) {
            while (*h) { *h = tolower(*h); h++; }
            h = head_word;
            i = 0;
            while (i < NHEADERS) {
                if (!strcmp(h,headers[i])) {
                    strcpy(itm[i],p);
                    if (i == NEWSGROUPS) no_add = 0;
                    break;
                    }
                ++i;
                }
            if (!strcmp(h,"subj") && !strcmp(itm[SUBJECT],"<None>")) {
                i = SUBJECT;
                strcpy(itm[i],p);
                }
            if ((i == NHEADERS) && (*s == 'N')) {
                ++h;
                i = 0;
                while (i < NHEADERS) {
                    if (!strcmp(h,headers[i])) break;
                    ++i;
                    }
                if (i < NHEADERS) {
                    init_strings();
                    strcpy(itm[i],p);
                    if (i == NEWSGROUPS) no_add = 0;
                    n_stripping = 1;
                    }
                }
            if (i == APPROVED) itm_approved = 1;
            if ((i == NHEADERS) && (unk_index < MAX_UNK)) {
                if (   (unk_index)
                    && (strlen(s) >= strlen(unk_headers[unk_index - 1]))
                    && (!strncmp(unk_headers[unk_index-1],s,strlen(unk_headers[unk_index - 1]))))
                  free(unk_headers[--unk_index]);
                strcpy((unk_headers[unk_index++] = malloc(strlen(s) + 1)),s);
                }
            }
        else if (unk_index < MAX_UNK) {
            if (   (unk_index)
                && (strlen(s) >= strlen(unk_headers[unk_index - 1]))
                && (!strncmp(unk_headers[unk_index-1],s,strlen(unk_headers[unk_index - 1]))))
              free(unk_headers[--unk_index]);
            strcpy((unk_headers[unk_index++] = malloc(strlen(s) + 1)),s);
            }
        return(1);
        }
    else {
        if (!strncmp(s,"From ",5)) return(1);
        else if (!*(p+1)) return(1);
        return(0);
        }
}

/*
 *  scan_header
 *
 *  pick off a set of header lines
 */

static scan_header()
{
    char *c;
    int recall = 0;

    get_line();
    if (infile_eof || infile_eom) return(0);

    if (c = strchr(inline,'\n')) *c = '\0';
    strcpy(scanline,inline);
    if (*scanline && !scan(scanline)) {
        strcat(scanline,"\n");
        out_data(scanline);
        return(0);
        }
    else if (*scanline) ++recall;

    while (*inline) {
        get_line();
        if (infile_eof || infile_eom) break;
        if (c = strchr(inline,'\n')) *c = '\0';
        if (isspace(*inline)) {
            if (*scanline && !scan(scanline)) {
                strcat(scanline,"\n");
                out_data(scanline);
                strcat(inline,"\n");
                out_data(inline);
                return(0);
                }
            else if (*scanline) ++recall;
            else {
                strcat(inline,"\n");
                out_data(inline);
                return(0);
                }

            c = inline;
            while (isspace(*c)) c++;
            if (*c) {
                strcat(scanline," ");
                strcat(scanline,c);
                }
            else return(recall);
            }
        else {
            if (*scanline && !scan(scanline)) {
                strcat(scanline,"\n");
                out_data(scanline);
                strcat(inline,"\n");
                out_data(inline);
                return(0);
                }
            else if (*scanline) ++recall;
            strcpy(scanline,inline);
            }
        }
    if (*scanline) scan(scanline);
    return(recall);
}

/*
 *  scan_data
 *
 *  pick off text body of message
 */

static scan_data()
{
    while (!(infile_eof || infile_eom)) {
        get_line();
        if (!(infile_eof || infile_eom)) out_data(inline);
        }
}

/*
 *  add_file
 *
 *  Read in file "fnam" into the news system.
 */

static add_file(fnam)
    char *fnam;
{
    int retval = 0;

    if (!strlen(fnam)) return(printf("\tError: Add - No filename specified\n"),0);
    if (!(fpr = fopen(fnam,"r"))) return(printf("\tError: Add - Cannot read %s\n",fnam),0);
    printf("\nAdd - Reading file: %s\n\n",fnam);
    *inline = *fline = '\0';
    infile_eof = next_eof = n_stripping = 0;
    get_line();
    while (!infile_eof) {
        infile_eom = 0;
        init_context();
        if (!strncmp(inline,"N#! rnews ",10)) n_stripping = 1;
        while (scan_header());
        if (infile_eom) {
            if (!headers_out) out_header();
            }
        else scan_data();
        process_item();
        ++retval;
        }
    fclose(fpr);
    if (fpt) {
        fclose(fpt);
        fpt = 0;
        }
    while (!delete(scratchfile));
    return(retval);
}

/*
 *  do_add_net
 *
 * Add network forwarded news into the local database
 */

do_add_net()
{
    char fnam[256],
         rnam[255],
         exec[255],
         *p;
    short fnam_len,
          defn_len,
          exec_len;
    int savscrn = 0;
    struct FAB *context = 0;
    $DESCRIPTOR(defn_dsc,def_newsgroup);
    $DESCRIPTOR(fnam_dsc,fnam);
    $DESCRIPTOR(rnam_dsc,rnam);
    $DESCRIPTOR(add_dsc,fnam);
    $DESCRIPTOR(exec_opt_dsc,exec);

    if (mod_add = (cli$present(c$dsc("MODERATOR")) & 1)) {
        sprintf(mod,"%s@%s",usr_username,Node_address);
        if (!check_moderator(mod))
            return(err_line("\tError: Add/mod - Not a moderator\n"),0);
        }
    else if (no_priv())
        return(err_line("\tError: Add - No privilege for operation\n"),0);

    if (screen_active) {
        savscrn = 1;
        noscreen();
        }
    set_level(1);

    strcpy(scratchfile,"SYS$SCRATCH:ADD.ITM");
    auto_cre_grp = cli$present(c$dsc("CREGRP")) & 1;
    del_after = (cli$present(c$dsc("DELETE")) & 1);
    skip_loop_test = cli$present(c$dsc("RETRY")) & 1;

    exec_opt = 0;
    if (execute_control = cli$present(c$dsc("EXECUTE")) & 1) {
        if (cli$get_value(c$dsc("EXECUTE"),&exec_opt_dsc,&exec_len) & 1) {
            exec[exec_len] = '\0';
            if (!strcmp(exec,"DELETE")) exec_opt = 1;
            else if (!strcmp(exec,"LOCAL")) exec_opt = 2;
            }
        }

    loc_junk = 0;
    if (cli$get_value(c$dsc("DEFNEWSGROUP"),&defn_dsc,&defn_len) & 1) def_newsgroup[defn_len] = '\0';
    else {
        strcpy(def_newsgroup,junk);
        loc_junk = 1;
        }
    net_news = (cli$present(c$dsc("NETFEED")) & 1);
    junk_it = 1;
    if (cli$present(c$dsc("JUNK")) == CLI$_NEGATED) junk_it = 0;
    accept_it = 0;
    if (cli$present(c$dsc("ACCEPT")) & 1) accept_it = 1;

    if (cli$get_value(c$dsc("FILE"),&fnam_dsc,&fnam_len) == CLI$_ABSENT) get_input(&fnam_dsc,c$dsc("Add File: "),&fnam_len);
    do {
        fnam[fnam_len] = '\0';
        auto_cre_grp = cli$present(c$dsc("CREGRP")) & 1;
        del_after = (cli$present(c$dsc("DELETE")) & 1);
        skip_loop_test = cli$present(c$dsc("RETRY")) & 1;

        exec_opt = 0;
        if (execute_control = cli$present(c$dsc("EXECUTE")) & 1) {
            if (cli$get_value(c$dsc("EXECUTE"),&exec_opt_dsc,&exec_len) & 1) {
                exec[exec_len] = '\0';
                if (!strcmp(exec,"DELETE")) exec_opt = 1;
                else if (!strcmp(exec,"LOCAL")) exec_opt = 2;
                }
            }

        net_news = (cli$present(c$dsc("NETFEED")) & 1);
        junk_it = 1;
        if (((status = cli$present(c$dsc("JUNK"))) == CLI$_NEGATED) ||
            (status == CLI$_LOCNEG)) junk_it = 0;
        accept_it = 0;
        if (cli$present(c$dsc("ACCEPT")) & 1) accept_it = 1;
        if (cli$get_value(c$dsc("DEFNEWSGROUP"),&defn_dsc,&defn_len) & 1) {
            loc_junk = 0;
            def_newsgroup[defn_len] = '\0';
            }
        else {
            strcpy(def_newsgroup,junk);
            loc_junk = 1;
            }
        s_to_lower(def_newsgroup);

        add_dsc.dsc$w_length = strlen(fnam);
        while ((status = lib$find_file(&add_dsc,&rnam_dsc,&context,0,0,0,0)) & 1) {
            rnam[254] = '\0';
            if (p = strchr(rnam,' ')) *p = '\0';
            if (add_file(rnam) && del_after) delete(rnam);
            }
        lib$find_file_end(&context);
        } while (cli$get_value(c$dsc("FILE"),&fnam_dsc,&fnam_len) & 1);
    no_more_news = 0;
    mail_add_expiry = 0;
    if (savscrn) init_screen();
    return(0);
}
