[net.sources] DMAIL, Bug Fixes et all, Part 3 of 4

dillon@ucbvax.BERKELEY.EDU (Matt Dillon) (12/22/85)

	Thank you all for your bug reports and everything, here is, what I
hope to be, the final v1 dmail with all the bug fixes.  It comes in four
parts.  DMAIL WORKS ON 4.2 AND 4.3 SYSTEMS.  I cannot guarentee it will
work on other systems, though the code should be easy to port.

	Please make sure you get all four parts.  Do not mix this source
with the older version.

This is part 3 of 4

				-Matt
	

#-----cut here-----cut here-----cut here-----cut here-----
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	commands.c
#	do_lists.c
#	execom.c
#	globals.c
#	help.c
#	load_mail.c
# This archive created: Sun Dec 22 12:29:48 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'commands.c'" '(11207 characters)'
if test -f 'commands.c'
then
	echo shar: will not over-write existing file "'commands.c'"
else
cat << \!Funky!Stuff! > 'commands.c'

/*
 * COMMANDS.C
 *
 *  Matthew Dillon, 17 December 1985
 *
 *  DMAIL  (C) 1985  Matthew Dillon
 *
 *  Global Routines:    DO_QUIT()
 *                      DO_EXIT() 
 *                      DO_CD()
 *                      DO_ECHO()
 *                      DO_GO()
 *                      DO_SOURCE()
 *                      DO_SHELL()
 *                      DO_WRITE()
 *                      DO_DELNEXT()
 *                      DO_NUMBER()
 *                      DO_NEXT()
 *                      DO_HEADER()
 *                      DO_TYPE()
 *                      DO_DELETE()
 *                      DO_UNDELETE()
 *                      DO_MARK()
 *
 *  Static Routines:    None.
 *
 */

#include <stdio.h>
#include <sys/file.h>
#include "dmail.h"

#define LAST_TYPE   0
#define LAST_HEADER 1

static int Last_operation;
static int Last_deleted = -1;

do_quit(garbage, com)
char *garbage;
{
    int fd, r, back;
    char *str;
    char *nulav[3];

    nulav[0] = "";
    nulav[1] = "";
    nulav[2] = NULL;
    push_break();
    if (get_inode (mail_file) == get_inode (output_file)) {
        back = save_file (0, 0, ST_DELETED | ST_STORED);
    } else {
        r = write_file (output_file, O_CREAT, ST_READ, ST_DELETED | ST_STORED);
        if (r < 0) {
            printf ("Unable to write to %s\n", output_file);
            back = save_file (0, 0, ST_DELETED | ST_STORED);
        } else {
            back = save_file (0, 0, ST_READ | ST_DELETED | ST_STORED);
        }
    }
    if (back) 
        printf ("%d  kept in %s\n", back, mail_file);
    sleep (1);
    if ((fd = open (mail_file, O_RDONLY, 0)) >= 0) {
        read (fd, Buf, 1);
        close (fd);
    }
    if (!com) 
        done (0);
    free_entry();
    if (av[1] == 0) {
        if (!Silence)
            puts ("NO FROM FILE SPECIFIED");
        av[1] = mail_file;
        av[2] = NULL;
    }
    mail_file = realloc (mail_file, strlen(av[1]) + 1);
    strcpy (mail_file, av[1]);
    str = (av[2]) ? av[2] : mail_file;
    output_file = realloc (output_file, strlen(str) + 1);
    strcpy (output_file, str);
    initial_load_mail();
    m_select (nulav, M_RESET);
    pop_break();
    if (!Silence)
        printf ("\nRF %-20s   WF %-20s\n", mail_file, output_file);
}


do_exit(garbage, com)
char *garbage;
{
    char *str;
    char *nulav[3];

    nulav[0] = "";
    nulav[1] = "";
    nulav[2] = NULL;
    if (!com)
        done (0);
    push_break();
    free_entry();
    if (av[1] == 0) {
        if (!Silence)
            puts ("NO FROM FILE SPECIFIED");
        av[1] = mail_file;
        av[2] = NULL;
    }
    mail_file = realloc (mail_file, strlen(av[1]) + 1);
    strcpy (mail_file, av[1]);
    str = (av[2]) ? av[2] : mail_file;
    output_file = realloc (output_file, strlen(str) + 1);
    strcpy (output_file, str);
    initial_load_mail();
    m_select (nulav, M_RESET);
    pop_break();
    if (!Silence)
        printf ("\nRF %-20s   WF %-20s\n", mail_file, output_file);
}


do_cd()
{
    char *dir = (ac < 2) ? home_dir : av[1];

    if (chdir(dir) < 0) {
        printf ("Cannot CD to %s\n", dir);
        return (-1);
    }
    return (1);
}


do_echo(str)
char *str;
{
    puts (next_word(str));
    return (1);
}


do_go()
{
    int i;

    if (ac < 2) {
        puts ("go to which article?");
    }
    rewind_range (1);
    i = get_range();
    if (i < 0) {
        if (!Silence)
            printf ("Message #%d does not exist\n", i);
        return (-1);
    }
    if (i == 0) {
        if (!Silence)
            puts ("No Message");
        return (-1);
    }
    Current = indexof(i);
    return (1);
}


do_source()
{
    char comline[1024];
    FILE *fi = NULL;

    if (ac < 2) {
        puts ("No file argument to source");
        return (-1);
    }
    if (push_base()) {
        push_break();
        pop_base();
        if (fi != NULL)
            fclose (fi);
        pop_break();
        return (-1);
    }
    push_break();
    fi = fopen (av[1], "r");
    pop_break();
    if (fi == NULL) {
        printf ("Cannot open %s\n", av[1]);
        return (-1);
    }
    while (fgets (comline, 1024, fi) != NULL) {
        comline[strlen(comline) - 1] = '\0';
        exec_command (comline);
    }
    push_break();
    fclose (fi);
    fi = NULL;
    pop_break();
    pop_base();
    return (1);
}


do_shell(str)
char *str;
{
    int pid, ret;
    char *shell;
    char *args;

    shell = getenv("SHELL");
    if (shell == NULL)
        shell = "/bin/sh";
    args = "-fc";
    push_break();
    str = next_word (str);
    if (strlen (str)) {
        if ((pid = vfork()) == 0) {
            execl (shell, shell, args, str, NULL);
            _exit (1);
        }
    } else {
        if ((pid = vfork()) == 0) {
            execl (shell, shell, NULL);
            _exit (1);
        }
    }
    while ((ret = wait(0)) > 0) {
        if (ret == pid)
            break;
    }
    pop_break();
    return (1);
}


do_write()
{
    char *file;
    int r, count = 0;
    register int i, j;

    if (ac < 2) {
        puts ("You must specify at least a file-name");
        return (-1);
    }
    file = av[1];
    rewind_range (2);
    push_break();
    while (i = get_range()) {
        j = indexof (i);
        if (j >= 0  &&  !(Entry[j].status & ST_DELETED)) {
            Entry[j].status |= ST_STORED | ST_SCR;
            ++count;
        }
    }
    r = write_file (file, O_CREAT, ST_SCR, 0);
    rewind_range (2);
    if (r > 0) {
        while (i = get_range()) {
            j = indexof (i);
            if (j >= 0)
                Entry[j].status &= ~ST_SCR;
        }
        if (!Silence)
            printf ("%d Items written\n", count);
    } else {
        while (i = get_range()) {
            j = indexof (i);
            if (j >= 0)
                Entry[j].status &= ~(ST_SCR | ST_STORED);
        }
        printf ("Could not write to file %s\n", file);
    }
    pop_break();
    return (1);
}


do_delnext()
{
    static int warning;

    if (!warning  &&  Last_operation == LAST_HEADER) {
        ++warning;
        puts ("Note that the next command is displaying headers only at");
        puts ("this point.  (one-time warning, NOTHING deleted");
        return (-1);
    }
    if (do_mark("", ST_DELETED) > 0)
        return (do_next("", 1));
    return (-1);
}


do_number(str, com)
char *str;
int com;
{
    int x;

    x = indexof (atoi(str));
    if (x < 0) {
        puts ("Non existant message");
        return (-1);
    }
    Current = x;
    switch (Last_operation) {
    case LAST_TYPE:
        return (do_type());
    case LAST_HEADER:
        return (do_header());
    default:
        puts ("Internal Error NEXT");
        return (-1);
    }
}


do_next(str, com)
char *str;
{
    int ok;

    push_break();
    if (com > 0) {
        if (++Current > Entries)
            Current = Entries;
        if (fix() < 0) {
            puts ("End of file");
            pop_break();
            return (-1);
        }
        --com;
    }
    if (com < 0) {
        ++com;
        ok = 0;
        while (--Current >= 0) {
            if (Entry[Current].no  &&  !(Entry[Current].status & ST_DELETED)) {
                ok = 1;
                break;
            }
        }
        if (!ok) {
            puts ("Start of file");
            Current = 0;
            fix();
            pop_break();
            return (-1);
        }
    }
    pop_break();
    if (!com) {
        switch (Last_operation) {
        case LAST_TYPE:
            return (do_type());
        case LAST_HEADER:
            return (do_header());
        }
    }
    return (1);
}


do_header()
{
    char buf[1024];

    Last_operation = LAST_HEADER;
    if (push_base()) {
        push_break();
        pop_base();
        PAGER (-1);
        fseek (m_fi, 0, 0);
        fflush (stdout);
        pop_break();
        return (-1);
    }
    if (single_position() < 0)
        return (-1);
    PAGER (0);
    sprintf (Puf, "MESSAGE HEADER #%d (%d) %s\n",
            Entry[Current].no, 
            Current + 1,
            (Entry[Current].status & ST_DELETED) ? "  DELETED" : "");
    PAGER (Puf);
    sprintf (Puf, "From %s\n", Entry[Current].from);
    PAGER (Puf);
    while (fgets (buf, 1024, m_fi) != NULL) {
        FPAGER (buf);
        if (*buf == '\n') {
            PAGER (-1);
            pop_base();
            return (1);
        }
    }
    PAGER ("END OF FILE ENCOUNTERED");
    PAGER (-1);
    pop_base();
    return (-1);
}


do_type()
{
    char buf[1024];
    int i;

    Last_operation = LAST_TYPE;
    if (push_base()) {
        push_break();
        pop_base();
        PAGER (-1);
        fseek (m_fi, 0, 0);
        fflush (stdout);
        pop_break();
        return (-1);
    }
    if (single_position() < 0)
        return (-1);
    if (skip_to_data (m_fi) < 0) {
        printf ("Cannot find data for message %d\n", Entry[Current].no);
        return (-1);
    }
    PAGER (0);
    sprintf (Puf, "MESSAGE TEXT #%d (%d) %s\n", 
            Entry[Current].no, 
            Current + 1,
            (Entry[Current].status & ST_DELETED) ? "  DELETED" : "");
    PAGER (Puf);
    for (i = 0; i < Listsize; ++i) {
        if (*Entry[Current].fields[header[i]]) {
            sprintf (Puf, "%-10s %s", 
                    Find[header[i]].search,
                    Entry[Current].fields[header[i]]);
            PAGER (Puf);
        }
    }
    PAGER ("");
    while ((fgets (buf, 1024, m_fi) != NULL)  &&  strncmp (buf, "From ", 5)) 
        FPAGER (buf);
    Entry[Current].status |= ST_READ;
    PAGER (-1);
    pop_base();
    return (1);
}


do_mark(garbage, mask)
char *garbage;
{
    int count = 0;
    register int i, j;

    rewind_range (1);
    push_break();
    while (i = get_range()) {
        j = indexof (i);
        if (j >= 0) {
            if (mask & ST_DELETED)
                Last_deleted = j;
            if ((Entry[j].status & mask) != mask) {
                Entry[j].status |= mask;
                if (Entry[j].status & ST_DELETED)
                    Entry[j].status &= ~(ST_STORED | ST_READ | ST_TAG);
                ++count;
            }
        }
    }
    if (!Silence)
        printf ("%d  Items\n", count);
    pop_break();
    return (1);
}


do_unmark(garbage, mask)
char *garbage;
{
    int count = 0;
    register int i, j;
    register struct ENTRY *en;

    push_break();
    if (ac == 1 && (mask & ST_DELETED) && Last_deleted != -1)  {
        en = &Entry[Last_deleted];
        if (en->no) {
            en->status &= ~mask;
            printf ("Undeleted last deleted message (# %d)\n", en->no);
            Current = Last_deleted;
            Last_deleted = -1;
        } else {
            puts ("Last deleted message not within current select bounds");
            pop_break();
            return (-1);
        }
        pop_break();
        return (1);
    }
    rewind_range (1);
    while (i = get_range()) {
        j = indexof (i);
        if (j >= 0) {
            if (Entry[j].status & mask) {
                Entry[j].status &= ~mask;
                ++count;
            }
        }
    }
    if (!Silence)
        printf ("%d  Items\n", count);
    pop_break();
    return ((count) ? 1 : -1);
}


!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'do_lists.c'" '(4119 characters)'
if test -f 'do_lists.c'
then
	echo shar: will not over-write existing file "'do_lists.c'"
else
cat << \!Funky!Stuff! > 'do_lists.c'

/*
 *  DO_LISTS.C
 *
 *  Matthew Dillon, 17 December 1985
 *
 *
 *  (C) 1985  Matthew Dillon
 *
 *  Global Routines:    DO_SETLIST()
 *                      DO_LIST()
 *                      DO_SELECT()
 *                      DO_DEFER()
 *
 *  Static Routines:    None.
 *
 *      LIST associated commands.
 *
 */

#include <stdio.h>
#include "dmail.h"


do_setlist(str)
char *str;
{
    int i, fw, idx, localecho = 1;
    int sac = 1;

    push_break();
    if (strcmp (av[sac], "-s") == 0) {
        ++sac;
        localecho = 0;
    }
    hold_load();
    if (ac > sac) {
        Listsize = 0;
        for (i = sac; i < ac; ++i) {
            fw = atoi(av[i]);
            if (fw > 4096)
                fw = 4096;
            if (fw < 0  ||  (*av[i] < '0'  ||  *av[i] > '9'))
                fw = 20;
            else
                ++i;
            if (i >= ac)
                continue;
            idx = get_extra_ovr (av[i]);
            if (idx < 0) {
                printf ("To many entries, cannot load: %s\n", av[i]);
                fflush (stdout);
                continue;
            }
            header[Listsize] = idx;
            width[Listsize] = fw;
            ++Listsize;
        }
    }
    nohold_load();
    pop_break();
    if (localecho) {
        puts ("");
        printf ("Entry   Width   Field\n\n");
        for (i = 0; i < Listsize; ++i) 
            printf ("%-6d   %-5d   %s\n", i, width[i], Find[header[i]].search);
        puts ("");
    }
    return (1);
}


/*
 * Pre-position #   0 >     Current article
 *                  1 -     Read already
 *
 */


do_list()
{
    int i, j;
    int start = 0;
    int end   = Entries;
    static char curr[10] = { "    " };

    if (ac == 1) {
        av[1] = "all";
        ++ac;
    }
    if (push_base()) {
        push_break();
        pop_base();
        PAGER (-1);
        pop_break();
        return (-1);
    }
    PAGER (0);
    FPAGER ("\n         ");
    for (j = 0; j < Listsize; ++j) {
        if (width[j]) {
            sprintf (Puf, "%-*.*s",
                    2 + width[j],
                    2 + width[j],
                    Find[header[j]].search);
            FPAGER (Puf);
        }
    }
    FPAGER ("\n");
    rewind_range (1);
    while (i = get_range()) {
        i = indexof(i);
        if (Entry[i].no  &&  ((Entry[i].status & ST_DELETED) == 0)) {
            curr[0] = (Entry[i].status & ST_TAG) ? 'T' : ' ';
            curr[1] = (i == Current) ? '>' : ' ';
            curr[2] = (Entry[i].status & ST_READ)    ? 'r' : ' ';
            curr[3] = (Entry[i].status & ST_STORED)  ? 'w' : ' ';
            sprintf (Puf, "%s%-3d", curr, Entry[i].no);
            FPAGER (Puf);
            for (j = 0; j < Listsize; ++j) {
                if (width[j]) {
                    sprintf(Puf, "  %-*.*s",
                            width[j], 
                            width[j],
                            Entry[i].fields[header[j]]);
                    FPAGER (Puf);
                }
            }
            FPAGER ("\n");
        }
    }
    FPAGER ("\n");
    PAGER (-1);
    pop_base();
    return (1);
}



do_select(str, mode)
char *str;
{
    int ret = 1;
    int localecho = 1;
    int avi = 1;
    int scr;
    char *nulav[3];

    nulav[0] = "";
    nulav[1] = "";
    nulav[2] = NULL;
    if (strcmp (av[avi], "-s") == 0) {
        localecho = 0;
        ++avi;
        --ac;
    }
    switch (ac) {
    case 2:
        if (localecho)
            puts ("SELECT ALL");
        ret = m_select (nulav, mode);
        break;
    case 1:
        break;
    default:
        ret = m_select (av + avi, mode);
        scr = indexof(0);
        if (scr > 0  &&  localecho)
            printf ("%d  Entries selected\n", Entry[scr].no);
        break;
    }
    if (ret < 0  &&  localecho) {
        puts ("Null field");
        return (-1);
    }
    return (1);
}


do_defer()
{
    register int i, j;

    push_break();
    j = 1;
    for (i = 0; i < Entries; ++i) {
        if (Entry[i].no)
            Entry[i].no = (Entry[i].status & ST_READ) ? 0 : j++;
    }
    pop_break();
    return (1);
}

!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'execom.c'" '(14652 characters)'
if test -f 'execom.c'
then
	echo shar: will not over-write existing file "'execom.c'"
else
cat << \!Funky!Stuff! > 'execom.c'

/*
 *  EXECOM.C
 *
 *  Matthew Dillon, 17 December 1985
 *
 *
 *  (C) 1985  Matthew Dillon
 *
 *  Routines to parse and execute command lines.
 *
 *  Global Routines:    DO_COMMAND()
 *                      EXEC_COMMAND()
 *                      FIX()
 *
 *  Static Routines:    E_COMMAND()
 *                      BREAKOUT()
 *                      FIND_COMMAND()
 */


#include <pwd.h>
#include <stdio.h>
#include <strings.h>
#include "dmail.h"
#include "execom.h"

#define F_EXACT     0
#define F_ABBR      1
#define SCRBUF      1024

extern char *breakout();

extern int do_quit(), do_exit(), do_help(), do_list(), do_setlist();
extern int do_select(), do_type(), do_header(), do_next(), do_mark();
extern int do_unmark(), do_reply(), do_delnext();
extern int do_write(), do_shell(), do_set_var(), do_unset_var();
extern int do_number(), do_cd(), do_source(), do_defer(), do_echo();
extern int do_go();


struct COMMAND Command[] = {
        do_number   , 0,        0,                  "",
        do_mark     , 0,        ST_DELETED,         "delete",
        do_unmark   , 0,        ST_DELETED,         "undelete",
        do_header   , 0,        0,                  "header",
        do_type     , 0,        0,                  "type",
        do_echo     , 0,        0,                  "echo",
        do_go       , 0,        0,                  "go",
        do_reply    , 0,        R_REPLY,            "reply",
        do_reply    , 0,        R_INCLUDE,          "Reply", 
        do_reply    , 0,        R_MAIL,             "mail",
        do_reply    , 0,        R_FORWARD,          "forward",  
        do_select   , 0,        0,                  "select",
        do_select   , 0,        1,                  "reselect",
        do_defer    , 0,        1,                  "defer",
        do_list     , 0,        0,                  "list",
        do_next     , 0,        1,                  "next",
        do_next     , 0,        -1,                 "back",
        do_next     , 0,        2,                  "_next",
        do_next     , 0,        -2,                 "_back",
        do_delnext  , 0,        0,                  "dt",
        do_set_var  , 0,        0,                  "set",
        do_unset_var, 0,        0,                  "unset",    
        do_set_var  , 0,        1,                  "alias",
        do_unset_var, 0,        1,                  "unalias",  
        do_set_var  , C_NO,     2,                  "malias",
        do_unset_var, C_NO,     2,                  "munalias", 
        do_setlist  , 0,        0,                  "setlist",
        do_cd       , 0,        0,                  "cd",
        do_source   , 0,        0,                  "source",
        do_unmark   , 0,        ST_READ | ST_STORED,"preserve",
        do_mark     , 0,        ST_READ,            "mark",
        do_mark     , 0,        ST_TAG,             "tag",
        do_unmark   , 0,        ST_TAG,             "untag",
        do_unmark   , 0,        ST_STORED,          "unwrite",
        do_write    , 0,        0,                  "write",
        do_shell    , 0,        0,                  "!",
        do_exit     , 0,        0,                  "x",
        do_quit     , 0,        0,                  "quit",
        do_exit     , 0,        1,                  "xswitch",
        do_quit     , 0,        1,                  "qswitch",
        do_help     , 0,        0,                  "help",
        do_help     , 0,        0,                  "?",
        NULL        , 0,        0,                  NULL };

char *Desc[] = {
        "",
        "<list>                   mark messages for deletion",
        "<list>                   UNDELETE & UNMARK messages",
        "[msg]                    Display header of a message",
        "[msg]                    type a message",
        "args....                 Echo to the screen",
        "#                        Go to a message, don't print out",
        "                         reply to mail",
        "                         reply to mail, include recv'd text",
        "user user ...            send mail to users",
        "user user ...            forward mail to users",
        "Field [!]match [match][ , Field match.]  SELECT from entire message list",
        "Field [!]match [match][ , Field match.]  SELECT from current message list",
        "                         De-select any read messages",
        "<list>                   list mail as specified by SETLIST",
        "[msg]                    type/header next or message #",
        "[msg]                    type/header previous or message #",
        "[msg]                    go to next or message #",
        "[msg]                    go to previous or message #",
        "                         delete current, type next",
        "[var [string]]           set a variable",
        "var var var ...          unset a variable",
        "[var [string]]           set an alias",
        "var var var ...          unset an alias",
        "[var [string]]           set a mail alias",
        "var var var ...          unset a mail alias",
        "[-s] [cols] Field [cols] Field...    SET LIST format for LIST",
        "path                     CD to a directory",
        "file                     Source a file",
        "<list>                   UNREAD & UNMARK messages",
        "<list>                   mark messages as 'read'",
        "<list>                   tag messages for whatever",
        "<list>                   untag messages",
        "<list>                   unwrite messages",
        "file <list>              append messages to a file, delete on quit",
        "[command]                execute a shell [command]",
        "                         EXIT, do not save changes",
        "                         QUIT, update files",
        "from to                  Exit and switch to a new from/to file",
        "from to                  Quit and switch to a new from/to file",
        "[topic]                  help on a topic",
        "[topic]                  alternate form of HELP",
        NULL };


do_command()
{
    int i;
    char *str;
    static char comline[1024];

    printf ("%3d:", Entry[Current].no);
    fflush (stdout);
    if (gets (comline) == NULL)
        done (1);
    exec_command(comline);
    return (1);
}



/*
 * EXEC_COMMAND()
 *
 *
 */


struct MLIST {
    struct MLIST *next;
};

static struct MLIST *Mlist;

char *
mpush(amount)
int amount;
{
    struct MLIST *ml;

    push_break();
    ml = (struct MLIST *)malloc (amount + sizeof(Mlist));
    ml->next = Mlist;
    Mlist = ml;
    pop_break();
    return ((char *)Mlist + sizeof(Mlist));
}


char *
mpop()
{
    char *old = NULL;

    push_break();
    if (Mlist == NULL) {
        puts ("MLIST INTERNAL ERROR");
    } else {
        old = (char *)Mlist + sizeof(Mlist);
        free (Mlist);
        Mlist = Mlist->next;
    }
    pop_break();
    return (old);
}

mrm()
{
    push_break();
    while (Mlist) {
        free (Mlist);
        Mlist = Mlist->next;
    }
    pop_break();
}


exec_command(base)
char *base;
{
    char *str;
    int i;

    if (push_base()) {
        push_break();
        pop_base();
        mrm();
        pop_break();
        return (-1);
    }
    strcpy (str = mpush(strlen(base) + 1), base);
    i = e_command(str);
    if (mpop() != str) 
        puts ("POP ERROR");
    pop_base();
    return (i);
}


static
e_command(base)
char *base;
{
    char *com, *start, *Scr, *avline, *alias;
    int flag = 0;
    int i, pcount, len, ccno;

loop:
    com = breakout (&base, &flag);
    if (*com == '\0') {
        if (flag > 1)
            return (1);
        goto loop;
    }
    if ((ccno = find_command(com, F_EXACT)) < 0) {
        if (*com == '$') 
            alias = get_var (LEVEL_SET, com + 1);
        else
            alias = get_var (LEVEL_ALIAS, com);
        if (alias == NULL) {
            if ((ccno = find_command (com, F_ABBR)) < 0) {
                printf ("%s Command Not found\n", com);
                return (-1);
            } else {
                goto good_command;
            }
        }

        /* At this point, base points to arguments */

        start = (flag == 0) ? base : "";
        while (flag == 0) {             /* find ';' or end of string        */
            flag = -1;                  /* disable breakout's "" terminator */
            breakout (&base, &flag);
        }

        /*
         * At this point, start points to all arguments, base set up for next
         * string
         */

        if (*alias == '%') {
            int xx = 0;
            char *select;

            alias = strcpy (mpush (strlen(alias) + 1), alias);
            select = breakout (&alias, &xx);
            set_var (LEVEL_SET, select + 1, start);
            i = e_command (alias);
            unset_var (LEVEL_SET, select + 1);
            mpop();
        } else {
            com = mpush (strlen(alias) + strlen(start) + 2);
            strcpy (com, alias);
            strcat (com, (flag == 1) ? ";" : " ");
            strcat (com, start);
            i = e_command (com);
            if (mpop() != com)
                puts ("ME BAE ERROR");
        }
        if (i < 0)
            return (-1);
        if (flag > 1)
            return (1);
        goto loop;
    }
good_command:
    pcount = 0;
    if (Command[ccno].stat & C_NO  &&  Debug == 0) {
        printf ("%s  Is currently being developed\n", Command[ccno].name);
        return (-1);
    }
    if (Debug)
        printf ("Good command, Raw: %s\n", com);
    i = pcount = 0;
    av[i] = mpush (strlen(com) + 1);
    ++pcount;
    strcpy (av[i++], com);
    while (flag < 1) {
        com = breakout (&base, &flag);
        if (Debug)
            printf ("BREAKOUT %d %s\n", strlen(com), com);
        if (*com == '\0')
            continue;
        switch (*com) {
        case '~':
            if (com[1] == '/'  ||  com[1] == '\0') {
                av[i] = mpush (strlen(home_dir) + strlen(com + 1) + 1);
                ++pcount;
                strcpy (av[i], home_dir);
                strcat (av[i], com + 1);
            } else {
                struct passwd *passwd;
                char *user = com;

                while (*com) {
                    if (*com == '/') {
                        *com = '\0';
                        ++com;
                        break;
                    }
                    ++com;
                }
                if ((passwd = getpwnam(user)) == NULL) {
                    printf ("USER %s Not found\n", user);
                    while (pcount--)
                        mpop();
                    return (-1);
                }
                av[i] = mpush (strlen(passwd->pw_dir) + strlen(com) + 2);
                ++pcount;
                strcpy (av[i], passwd->pw_dir);
                if (*com) {
                    strcat (av[i], "/");
                    strcat (av[i], com);
                }
            }
            break;
        case '\"':
            av[i] = com + 1;
            while (*++com && *com != '\"');
            *com = '\0';
            break;
        case '$':
            av[i] = get_var (LEVEL_SET, com + 1);
            if (av[i] == NULL) {
                printf ("Variable: %s Not found\n", com + 1);
                while (pcount--)
                    mpop();
                return (-1);
            }
            av[i] = strcpy (mpush(strlen(av[i]) + 1), av[i]);
            ++pcount;
            break;
        default:
            av[i] = com;
            break;
        }
        ++i;
    }
    av[i] = NULL;
    ac = i;
    for (len = 0, i = 0; i < ac; ++i) 
        len += strlen (av[i]) + 1;
    avline = mpush (len + 1);
    *avline = '\0';
    for (i = 0; i < ac; ++i) {
        strcat (avline, av[i]);
        if (i + 1 < ac)
            strcat (avline, " ");
    }
    if (Debug)
        printf ("DEST: %s\n", avline);
    i = (*Command[ccno].func)(avline, Command[ccno].val);
    if (mpop() != avline)
        puts ("AVLINE ERROR");
    while (pcount--)
        mpop();
    fix();
    if (i < 0)
        return (i);
    if (flag < 2)
        goto loop;
    return (1);
}


/*
 * BREAKOUT
 *
 * Breakout next argument.  If FLAG is set to 1 on return, the argument 
 * returned is the last in the command.  If FLAG is set to 2 on return, the
 * argument returned is the last, period.
 *
 */

static char *
breakout(base, flag)
int *flag;
char **base;
{
    register char *str, *scr;

loop:
    str = *base;                        /* next start           */
    while (*str == ' ' || *str == 9)    /* skip spaces and such */
        ++str;
    switch (*str) {
    case '\0':                          /* no more arguments    */
        *flag = 2;
        *base = str;
        return (str);
    case ';':                           /* no more args in this command */
        *flag = 1;
        *str = '\0';
        *base = str + 1;
        return (str);
    }
    scr = str;
    for (;;) {                          /* valid argument of somesort   */
        switch (*scr) {
        case ' ':
        case 9:
            if (*flag >= 0)
                *scr = '\0';
            *base = scr + 1;
            *flag = 0;
            return (str);
        case '\"':
            ++scr;
            while (*scr && (*scr++ != '\"'));   /* place to end of quote */
            break;
        case '\0':
            *flag = 2;
            *base = scr;
            return (str);
        case ';':
            *flag = 1;
            *base = scr + 1;
            *scr = '\0';
            return (str);
        default:
            ++scr;
        }
    }
}



fix()
{
    register int i;

    for (i = Current; i < Entries; ++i) {
        if (Entry[i].no  &&  !(Entry[i].status & ST_DELETED)) {
            Current = i;
            return (1);
        }
    }
    if (Current >= Entries) {
        Current = Entries - 1;
        if (Current < 0)
            Current = 0;
    }
    for (i = Current; i >= 0; --i) {
        if (Entry[i].no  &&  !(Entry[i].status & ST_DELETED)) {
            Current = i;
            return (-1);
        }
    }
    Current = 0;
    return (-1);
}


static
find_command(str, arg)
char *str;
int arg;
{
    int i;
    int len = strlen (str);

    if (*str >= '0'  &&  *str <= '9')
        return (0);
    for (i = 0; Command[i].func; ++i) {
        if (strncmp (str, Command[i].name, len) == 0) {
            if (arg == F_ABBR)
                return (i);
            if (strcmp (str, Command[i].name) == 0)
                return (i);
            return (-1);
        }
    }
    return (-1);
}

!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'globals.c'" '(1959 characters)'
if test -f 'globals.c'
then
	echo shar: will not over-write existing file "'globals.c'"
else
cat << \!Funky!Stuff! > 'globals.c'

/*
 * GLOBALS.C
 *
 *  Matthew Dillon, 17 December 1985
 *
 *
 *  (C) 1985  Matthew Dillon
 *
 *  Declarations for most global variables.
 *
 */

#include <stdio.h>
#include "dmail.h"

FILE *m_fi;                         /* open file ptr to spool file  */
char *mail_file;                    /* name of from (spool) file    */
char *output_file;                  /* name of out file (i.e. mbox) */
char *user_name;                    /* user name from password entry*/
char *home_dir;                     /* home directory of user       */
char *visual;                       /* visual editor path           */
char Buf[MAXFIELDSIZE];             /* Scratch Buffer               */
char Puf[MAXFIELDSIZE];             /* Another Scratch Buffer       */
jmp_buf env[LONGSTACK];             /* Holds longjump (break) stack */
int  Debug;                         /* Debug mode                   */
int  Longstack, Breakstack;         /* longjump/break level stack   */
int  Entries, Current;              /* #Entries and Current entry   */
int  ac;                            /* internal argc, from/to stat  */
int  No_load_mail;                  /* disable loading of mail      */
int  Silence;                       /* -s command option status     */
struct ENTRY *Entry;                /* Base of Entry list           */
char *av[128];                      /* internal argv[]              */

int width[MAXLIST]  = { 18, 38, 10 };   /* Default setlist params       */
int header[MAXLIST] = {  0,  2,  1 };
int Listsize = 3;

/* The following are globals variables definable from the 'set' command */

char  *S_sendmail;                  /* sendmail program path        */
int   S_page;                       /* Paging status                */
int   S_novibreak;                  /* vi-break status              */
int   S_verbose;                    /* sendmail verbose status      */
int   S_ask;                        /* Ask what to do after mail ed */


!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'help.c'" '(2903 characters)'
if test -f 'help.c'
then
	echo shar: will not over-write existing file "'help.c'"
else
cat << \!Funky!Stuff! > 'help.c'

/*
 * HELP.C
 *
 *  Matthew Dillon, 17 December 1985
 *
 *
 *  (C) 1985  Matthew Dillon
 *
 *  Global Routines:    DO_HELP()
 *
 */

#include <stdio.h>
#include "dmail.h"
#include "execom.h"

#ifndef HELPFILE
static char *help[] = {
#include ".dmkout"
};

do_help()
{
    int i, j;
    char *ptr;

    if (push_base()) {
        push_break();
        pop_base();
        PAGER (-1);
        pop_break();
        return;
    }
    PAGER (0);
    if (ac == 1) {
        for (j = 0; help[j] && *help[j] != '.'; ++j)
            PAGER (help[j]);
        for (i = 0; Command[i].name != NULL; ++i) {
            if (*Command[i].name && !(Command[i].stat & C_NO)) {
                sprintf (Puf, "%-10s %s", Command[i].name, Desc[i]);
                PAGER (Puf);
            }
        }
    }
    PAGER ("");
    for (i = 1; i < ac; ++i) {
        j = 0;
again:
        while (help[j]  &&  *help[j] != '.')
            ++j;
        if (help[j]) {
            if (strncmp (av[i], help[j] + 1, strlen(av[i]))) {
                ++j;
                goto again;
            }
            while (help[j]  &&  *help[j] == '.')
                ++j;
            while (help[j]  &&  *help[j] != '.')
                PAGER (help[j++]);
            PAGER ("");
            goto again;
        }
    }
    PAGER (-1);
    pop_base();
}

#else

do_help()
{
    int i, j;
    FILE *fi = NULL;
    char *ptr;
    char *eof;

    if (push_base()) {
        push_break();
        pop_base();
        PAGER (-1);
        if (fi != NULL) {
            fclose (fi);
            fi = NULL;
        }
        pop_break();
        return (-1);
    }
    fi = fopen (HELPFILE, "r");
    if (fi == NULL) {
        printf ("Cannot open help file: %s\n", HELPFILE);
        PAGER (-1);
        pop_base();
        return (-1);
    }
    PAGER (0);
    if (ac == 1) {
        while (fgets (Puf, MAXFIELDSIZE, fi)  &&  *Puf != '.')
            FPAGER (Puf);
        fclose (fi);
        fi = NULL;
        for (i = 0; Command[i].name != NULL; ++i) {
            if (*Command[i].name) {
                sprintf (Puf, "%-10s %s", Command[i].name, Desc[i]);
                PAGER (Puf);
            }
        }
        PAGER (-1);
        pop_base();
        return (1);
    }
    PAGER ("");
    for (i = 1; i < ac; ++i) {
        fseek (fi, 0, 0);
again:
        while ((eof = fgets (Puf, MAXFIELDSIZE, fi))  &&  *Puf != '.');
        if (!eof)
            continue;
        if (strncmp (av[i], Puf + 1, strlen(av[i]))) 
            goto again;
        while ((eof = fgets (Puf, MAXFIELDSIZE, fi))  &&  *Puf == '.');
        if (!eof)
            continue;
        FPAGER (Puf);
        while ((eof = fgets (Puf, MAXFIELDSIZE, fi))  &&  *Puf != '.')
            FPAGER (Puf);
        PAGER ("");
        if (!eof)
            continue;
        goto again;
    }
    fclose (fi);
    fi = NULL;
    PAGER (-1);
    pop_base();
}

#endif

!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'load_mail.c'" '(13792 characters)'
if test -f 'load_mail.c'
then
	echo shar: will not over-write existing file "'load_mail.c'"
else
cat << \!Funky!Stuff! > 'load_mail.c'

/*
 *  LOAD_MAIL.C
 *
 *  Matthew Dillon, 17 December 1985
 *
 *
 *  file-io routines to scan the mail file and load required information.
 *
 *
 *  Global Routines:    HOLD_LOAD()         hold on loading mail after change
 *                      NOHOLD_LOAD()       hold off.. load if changes
 *                      LOAD_CHANGES()      reload mail if changed 
 *                      LOAD_MAIL()         load/reload mail
 *                      SAVE_FILE()         save mail items back to spool
 *                      CHECK_NEW_MAIL()    check for new mail
 *                      WRITE_FILE()        append mail items to a file
 *                      GET_EXTRA_OVR()     ret index of Field (create if not)
 *                      ADD_EXTRA()         add another field (reloads mail)
 *                      DELETE_EXTRA()      delete a field
 *                      GET_EXTRA()         ret index of Field, or error
 *                      M_SELECT()          select on current message list
 *
 *
 *  Static Routines:    LOAD_HASH()         load hash table from fields list
 *                      FREE_ENTRY()        unload EVERYTHING
 *                      FREE_TABLE()        unload all Fields table
 *                      LOAD_FILE()         raw file loading/counting
 *                      
 *
 */

#include <stdio.h>
#include <sys/file.h>
#include "dmail.h"

#define NOHOLD  0
#define HOLD    1

#define NO_BASE     0
#define NO_FIELDS   1
#define ENTRY_OK    2

struct FIND Find[MAXTYPE + 1] = {
        "From:"   , 5, 1,
        "To:"     , 3, 1,
        "Subject:", 8, 1 };

static int  File_size;
static int  changed, load_hold;
static int  Hash[256];


hold_load()
{
    load_hold = 1;
}


nohold_load()
{
    load_hold = 0;
    load_changes();
}


load_changes()
{
    if (changed  &&  !load_hold)
        load_mail(Entries, 1);
}

initial_load_mail()
{
    if (load_mail (0, 0) < 0)
        return (-1);
    return ((Entries) ? 1 : -1);
}


static
load_mail(at, from0)
{
    FILE *fi;
    int i, count, file_size;

    if (No_load_mail)
        return (-1);
    load_hash();
    if (from0)
        free_table (0, HOLD);
    else
        free_table (at, NOHOLD);
    fi = fopen (mail_file, "r");
    if (m_fi != NULL)
        fclose (m_fi);
    m_fi = fopen (mail_file, "r");
    if (fi == NULL  ||  m_fi == NULL)
        return (-1);
    flock (m_fi->_file, LOCK_EX);
    if (at)
        fseek (fi, Entry[at].fpos, 0);
    else
        fseek (fi, 0, 0);
    count = Entries;
    while (search_from(fi))
        ++count;
    if (Entries != count) {
        printf ("%d New Items loaded\n", count - Entries);
        Entry = (struct ENTRY *)realloc (Entry, sizeof(*Entry) * (count + 1));
    }
    Entries = count;
    for (i = at; i < Entries; ++i)
        Entry[i].no  =  Entry[i].status = 0;
    Entry[i].fpos = File_size = file_size = ftell (fi);
    fclose (fi);
    load_file ((from0) ? 0 : at);
    if (file_size != File_size) {       /* Last entry incomplete?       */
        free_table (Entries - 1, NOHOLD);
    }
    changed = 0;
    flock (m_fi->_file, LOCK_UN);
    return (1);
}


static
load_file(at)
int at;
{
    FILE *fi;
    char *next, *ptr;
    int i, bit, maxbit, len, count, havefrom;

    maxbit = 0;
    for (i = 0; Find[i].search != NULL; ++i) 
        maxbit = (maxbit << 1) | 1;
    fi = fopen (mail_file, "r");
    count = -1;
    havefrom = 0;
    while (havefrom  ||  search_from (fi)) {
        havefrom = 0;
        if (++count >= Entries)
            break;
        len = strlen(Buf) - 1;
        Buf[len] = '\0';
        next = next_word(Buf);
        len -= next - Buf;
        Entry[count].fpos = ftell (fi);
        Entry[count].from = malloc (len + 1);
        bcopy (next, Entry[count].from, len + 1);

        /* SEARCH FIELD LIST */

        bit = 0;
        if (Debug)
            printf ("No %d  ---------------------\n", count + 1);
        while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
            if (Buf[0] == '\n')
                break;
            if (isfrom(Buf)) {
                havefrom = 1;
                break;
            }
            len = strlen(Buf) - 1;
            Buf[len] = '\0';
            if (Debug)
                printf ("CHECK: %s\n", Buf);
            next = next_word(Buf);
            len -= next - Buf;
            if (Hash[*Buf] == 0)
                continue;
            if (Hash[*Buf] > 0) {
                i = Hash[*Buf] & 0xff;
                if (strncmp (Find[i].search, Buf, Find[i].len) == 0) 
                    goto found;
                continue;
            }
            for (i = -Hash[*Buf] & 0xff; Find[i].search; ++i) {
                if (*Find[i].search != *Buf)
                    break;
                if (strncmp (Find[i].search, Buf, Find[i].len) == 0)
                    goto found;
            }
            continue;
found:
            if (Debug)
                printf ("Found: %d %s\n", i, Buf);
            if (Find[i].notnew == 0) {
                Find[i].notnew = 1;
                ptr = Buf;
                while (*ptr  &&  *ptr != ':')
                    ++ptr;
                ++ptr;
                Find[i].search =
                        realloc (Find[i].search, ptr - Buf + 1);
                strncpy (Find[i].search, Buf, ptr - Buf);
                *(Find[i].search + (ptr - Buf)) = '\0';
                Find[i].len = strlen(Find[i].search);
            }
            compile_field (Buf, fi);
            Entry[count].fields[i] = 
                    malloc (strlen(next) + 1);
            strcpy (Entry[count].fields[i], next);
            if ((bit |= (1 << i)) == maxbit) 
                break;
        }
        if (bit != maxbit) {
            for (i = 0; Find[i].search != NULL; ++i) {
                if (((1 << i) & bit) == 0) {
                    Entry[count].fields[i] = malloc (1);
                    *(Entry[count].fields[i]) = '\0';
                }
            }
        }
    } 
    File_size = ftell (fi);
    fclose (fi);
    return (1);
}


static
load_hash()
{
    register int i, c;

    bzero (Hash, sizeof(Hash));
    for (i = 0; Find[i].search; ++i) {
        c = *Find[i].search;
        if (Hash[c] > 0)
            Hash[c] = -Hash[c];
        if (Hash[c] == 0)
            Hash[c] = i | 0x100;
    }
}


free_entry()
{
    free_table(0, NOHOLD);
    Entry = (struct ENTRY *)realloc (Entry, sizeof(*Entry));
    File_size = Entries = 0;
    Entry->status = Entry->no = Entry->fpos = Current = 0;
    if (m_fi)
        fclose (m_fi);
}


static
free_table(at, hold)
{
    int i, j;

    for (i = at; i < Entries; ++i) {
        free (Entry[i].from);
        for (j = 0; Find[j].search != NULL; ++j) 
            free (Entry[i].fields[j]);
    }
    Entries = (hold == HOLD) ? Entries : at;
    File_size = (at) ? Entry[Entries].fpos : 0;
}

static
search_from(fi)
FILE *fi;
{
    while (fgets (Buf, MAXFIELDSIZE, fi) != NULL) {
        if (isfrom (Buf))
            return (1);
    }
    return (0);
}


save_file(reload, mark, notmark)
{
    FILE *fi, *fiscr;
    int fd, fdscr;
    int new_size, i;
    char scratch[64];
    char buf[MAXFIELDSIZE];
    char *avnul[3];

    avnul[0] = "";
    avnul[1] = "";
    avnul[2] = NULL;
    if (m_fi)
        fclose (m_fi);
    for (i = 0; i < Entries; ++i) {
        if ((Entry[i].status & mark) != mark  ||
                (~Entry[i].status & notmark) != notmark) 
            break;
    }
    if (i == Entries) {
        m_select (avnul, M_RESET);
        puts ("No Changes Made");
        return (Entries);
    }
    sprintf (scratch, "/tmp/dmail%d", getpid());
    fd = open (mail_file, O_RDWR, 0);
    if (fd < 0)
        return (-1);
    flock (fd, LOCK_EX);
    fdscr = open (scratch, O_RDWR | O_CREAT | O_TRUNC, MAILMODE);
    fi    = fdopen (fd, "r+");
    fiscr = fdopen (fdscr, "a+");
    for (i = 0; i < Entries; ++i) {
        if ((Entry[i].status & mark) == mark  &&
                (~Entry[i].status & notmark) == notmark) {
            fputs ("From ", fiscr);
            fputs (Entry[i].from, fiscr);
            fputc ('\n', fiscr);
            fseek (fi, Entry[i].fpos, 0);
            while (fgets (buf, MAXFIELDSIZE, fi) != NULL) {
                if (isfrom(buf))
                    break;
                fputs (buf, fiscr);
            }
        }
    }

    /* If NEW MAIL has come in, append that to the scratch file also */

    if ((new_size = fseek (fi, 0, 2)) >= 0)
        new_size = ftell (fi);
    if (File_size != new_size) {
        fseek (fi, File_size, 0);
        while (fgets (buf, MAXFIELDSIZE, fi) != NULL)
            fputs (buf, fiscr);
    }

    /* Write scratch file back to mail file, or try to */

    fflush (fi);
    fflush (fiscr);
    fseek (fi   , 0, 0);
    fseek (fiscr, 0, 0);
    lseek (fd   , 0, 0);
    lseek (fdscr, 0, 0);
    while ((i = read (fdscr, buf, MAXFIELDSIZE)) > 0) 
        write (fd, buf, i);
    ftruncate (fd, lseek (fd, 0, 1));
    if (lseek (fd, 0, 2) == 0  &&  !reload) {
        printf ("%s  Removed\n", mail_file);
        unlink (mail_file);
    }
    fclose (fi);
    fclose (fiscr);
    unlink (scratch);
    if (reload) {
        free_entry();
        load_mail(0, 0);
    }
    m_select (avnul, M_RESET);
    return (0);
}


check_new_mail()
{
    push_break();
    if (m_fi == NULL) {
        m_fi = fopen (mail_file, "r");
        if (m_fi == NULL) {
            pop_break();
            return;
        }
    }
    if (fseek (m_fi, 0, 2) < 0 || ftell(m_fi) != File_size)
        load_mail(Entries, 1);
    pop_break();
}


write_file(file, modes, mark, notmark)
char *file;
{
    int i, fd, notopen = 1;
    FILE *fi;
    char buf[MAXFIELDSIZE];

    for (i = 0; i < Entries; ++i) {
        if ((Entry[i].status & mark) == mark  &&
                (~Entry[i].status & notmark) == notmark) {
            if (notopen) {
                notopen = 0;
                fd = open (file, O_APPEND | O_WRONLY | modes, MAILMODE);
                if (fd < 0)
                    return (-1);
                flock (fd, LOCK_EX);
                fi = fdopen (fd, "a");
            }
            fputs ("From ", fi);
            fputs (Entry[i].from, fi);
            fputc ('\n', fi);
            if (m_fi) {
                fseek (m_fi, Entry[i].fpos, 0);
                while (fgets (buf, MAXFIELDSIZE, m_fi) != NULL) {
                    if (isfrom(buf))
                        break;
                    fputs (buf, fi);
                }
            }
        }
    }
    if (!notopen)
        fclose (fi);
    return (1);
}


get_extra_ovr(str)
char *str;
{
    register int i;

    i = get_extra (str);
    if (i < 0) {
        i = add_extra (str);
        load_changes();
    }
    return (i);
}


add_extra(str)
char *str;
{
    int i, j;

    for (i = 0; i < MAXTYPE; ++i) {
        if (Find[i].search == NULL)
            break;
    }
    if (i == MAXTYPE)
        i = EXSTART;
    for (; i < MAXTYPE; ++i) {
        for (j = 0; j < Listsize; ++j) {
            if (i == header[j])
                break;
        }
        if (j == Listsize)
            break;
    }
    if (i >= MAXTYPE)
        return (-1);
    if (Find[i].search != NULL)
        free (Find[i].search);
    Find[i].len = strlen(str);
    Find[i].search = malloc (Find[i].len + 1);
    Find[i].notnew = 0;
    strcpy (Find[i].search, str);
    changed = 1;
    return (i);
}


delete_extra(str)
char *str;
{
    int i;

    for (i = EXSTART; Find[i].search; ++i) {
        if (strncmp (Find[i].search, str, strlen(str)) == 0) {
            free (Find[i].search);
            do {
                Find[i].search = Find[i + 1].search;
            } while (Find[++i].search);
            changed = 1;
            return (i);
        }
    }
    return (-1);
}


delete_all()
{
    int i;

    for (i = EXSTART; Find[i].search; ++i) {
        free (Find[i].search);
        changed = 1;
    }
    return (1);
}


get_extra(str)
char *str;
{
    int i;

    for (i = 0; Find[i].search; ++i) {
        if (strncmp (str, Find[i].search, strlen(str)) == 0)
            return (i);
    }
    return (-1);
}


m_select(sav, mode)
register char *sav[];
{
    char *ptr, *dest;
    char l_map[256];
    int idx[MAXLIST], ix = 0;
    int ok, not, len, scr;
    register int i, j, avi;
        
    for (i = 0;i < 256; ++i)
        l_map[i] = i;
    for (i = 'A'; i <= 'Z'; ++i)
        l_map[i] += 'a' - 'A';
    hold_load();
    i = 0;
    idx[ix++] = get_extra_ovr (sav[i++]);
    for (; sav[i]; ++i) {
        if (strcmp (sav[i], ",") == 0  &&  sav[i + 1])
            idx[ix++] = get_extra_ovr (sav[++i]);
    }
    idx[ix] = -1;
    nohold_load();
    j = 1;
    for (i = 0; i < Entries; ++i) {
        if (mode == M_CONT  &&  Entry[i].no == 0)
            continue;
        ix = ok = 0;
        avi = 1;
        while ((ptr = sav[avi]) != NULL) {
            if (ptr[0] == ','  &&  ptr[1] == '\0' && sav[avi+1]) {
                ++ix;
                avi += 2;
                continue;
            }
            if (not = (*ptr == '!'))
                ++ptr;
            len = strlen (ptr);
            dest = Entry[i].fields[idx[ix]];
            if (*ptr == '\0') {
                ok = 1;
                goto gotit;
            }
            while (*dest) {
                scr = 0;
                while (l_map[dest[scr]] == l_map[ptr[scr]] && ptr[scr])
                    ++scr;
                if (ptr[scr] == '\0') {
                    ok = 1;
                    goto gotit;
                }
                ++dest;
            }
            ++avi;
        }
gotit:
        Entry[i].no = (ok ^ not) ? j++ : 0;
    }
    if (Entry[Current].no == 0) {
        Current = indexof (1);
        if (Current < 0) {
            Current = 0;
            return (-1);
        }   
    }
    return (1);
}


!Funky!Stuff!
fi # end of overwriting check
#	End of shell archive
exit 0