/*
 * Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University
 * in the City of New York.  Permission is granted to any individual or
 * institution to use, copy, or redistribute this software so long as it
 * is not sold for profit, provided this copyright notice is retained.
 */

#ifndef lint
static char *rcsid = "$Header: mm.c,v 1.63 88/07/20 16:18:02 howie Exp $";
#endif

/*
 * mm.c - portable "mail manager" program
 */


#include "mm.h"
#include "parse.h"
#include "cmds.h"
#include "set.h"


char *progname;
int mode = MM_TOP_LEVEL;
int memdebug = false;
int debug = false;

#define CMDBUFLEN (10*BUFLEN)
int cmdbuf[CMDBUFLEN];			/* ccmd work buffers */
static buffer wrkbuf;
buffer atmbuf;				/* parsed field */
pval pv;				/* parse value */
fdb *used;				/* which fdb was used to parse field */
extern char cmcont;			/* line continuation character */

int mail_check = false;
typedef int (*(*acttab))();
acttab mmactini();
jmp_buf abortbuf;

char **Argv;
int Argc,doargs=false;
int gotargs=false;

main(argc, argv)
int argc;
char *argv[];
{
    int err;
    int new_mail();
    int doget;
    static fdb userfdb = { _CMUSR };
    char *root = "root";
    int pl;
    char **split_args();
    extern variable set_variables[];

#ifdef USAGEFILE
    usage_start();
#endif
    Argv = argv;
    Argc = argc;
    doargs = false;
#ifdef MDEBUG
    m_init();
#endif /* MDEBUG */

#if 1
    if (argv[0][0] == '.')
	debug = 1;
#define dmsg(msg) if (debug) { printf (msg); fflush(stdout); } else debug = 0
#endif

    dmsg ("initialize...");
    initialize (argv);			/* set up some variables */

    mode = MM_TOP_LEVEL;

    cmcont = '\\';			/* lines are continued with \ */
    cmbufs (cmdbuf, sizeof cmdbuf, atmbuf, sizeof atmbuf,
	    wrkbuf, sizeof wrkbuf);	/* set up buffers for ccmd */

    cmact(mmactini());
    cmcsb._cmntb = "#";			/* comments start with # */

    init_signals ();			/* see signals.c */

    printf ("%s\n", mm_version);

    dmsg ("crunch...");

    /* make ccmd generate the user-name keyword table */
#ifdef undef
    match(root, strlen(root), &userfdb, &pv, &used, &pl);
#endif
    cmseti(NULL, NULL, NULL);	      /* no files needed while reading those */
    cmhst(0);				/* turn off cmd history */

    dmsg ("system init...");
    system_init ();			/* take system init file */

    dmsg ("mailrc...");
    mailrc();
    cmseti(stdin, stdout, stderr);	/* DON'T TRY TO PARSE BEFORE HERE */

    dmsg ("user init...");
    user_init ();

    if (clear_screen) {			/* var is now appropriately set */
	cmcls();
	printf ("%s\n", mm_version);
    }
    printf ("\
This is a test version of MM.  Please report all bugs by using MM's bug\n\
command, or just send mail to bug-mm.  Suggestions are also welcome.\n");

    dmsg ("user rc...");
    user_rc ();
    if (editor == NULL && !set_variables[SET_EDITOR].changed) {
	char *ed;

	if ((ed = (char *) getenv ("EDITOR")) != NULL)
	    editor = split_args (ed);
	else
	    editor = split_args(EDITOR);
    }
    cmhst(100);				/* turn on command history */
    show_route(FALSE);			/* show mail routing if routed */

    dmsg ("\n");

    doget = true;
    cmseter();
    if (doget && cf == NULL && strlen(mail_file) != 0 && auto_startup_get &&
	Argc == 1) {
	doget = false;
	printf("Reading %s\n", mail_file);
	cf = getfile(mail_file,CMD_GET);
	if (cf != NULL)
	    do_flagged();		/* show flagged ones */
    }
    mail_check = true;
    doargs = true;
    while (true) {
	err = top_level_parser ();
	switch (err) {
	  case CMxEOF:
	    if (feof (stdin))
		done (0);
	    break;
	  default:
	    fprintf (stderr, "%s: main: fatal parser error\n", progname, err);
	    done (1);
	}
    }
}
    
int
top_level_parser ()
{
    fdb *fdbs;
    extern setkey default_send_command, default_read_command;
    static int level = 0;		/* see if we are here in a "take" */
    extern int user_aborted;

    level++;				/* count this entry */
    cmcsb._cmerr = CMxOK;		/* assume no error */
    while (true) {
	setjmp(abortbuf);
	allow_aborts = false;
	if (mail_check)
	    new_mail(true);		/* check for new mail. */
	if (cmseteof ()) {
	    level--;			/* count the return */
	    return CMxEOF;
	}
	if (cmseter ()) {		/* errors return here */
	    if (cmcsb._cmerr == CMxEOF) {
		level--;
		return CMxEOF;
	    }
	}

	if (user_aborted) {
	    mode &= ~(MM_SEND|MM_REPLY|MM_ANSWER);
	    user_aborted = false;
	}

	if (doargs && level <= 1) {
	    fdbs = fdbchn (&mm_top_abbr_fdb, &mm_top_fdb, &shell_fdb, nil);
	    if (cmargs(Argc,Argv)) 
		gotargs = true;
	}

	if (gotargs && doargs && level <= 1) {
	    cmsetrp();
	}
	else if (mode == MM_REPLY) {
	    cm_set_ind(TRUE);		/* allow indirections */
	    do_reply_many();
	    continue;
	} 
	else if (mode & MM_SEND) {
	    prompt (send_prompt);
	    cmsetrp ();			/* reparse comes back here */
	    fdbs = fdbchn (&send_abbr_fdb, &send_fdb, &hdr_cmd_fdb,
			   &shell_fdb, nil);
	    if (default_send_command.current[0] == '\0')
		send_fdb._cmdef = NULL;
	    else
		send_fdb._cmdef = default_send_command.current;
	}
	else if (mode & MM_BROWSE) {
	    browse_message();
	    continue;
	}
	else if (mode & MM_READ) {
	    prompt (read_prompt);
	    cmsetrp ();			/* reparse comes back here */
	    fdbs = fdbchn (&read_abbr_fdb, &read_fdb, &shell_fdb, nil);
	    if (default_read_command.current[0] == '\0')
		read_fdb._cmdef = NULL;
	    else
		read_fdb._cmdef = default_read_command.current;
	}
	else {
	    if (gotargs && level <= 1) {
		if (cf && !update(&cf,UPD_SAVEMOD) && (cf->flags & MF_WRITERR))
		    gotargs = FALSE;	/* don't exit if write fails */
		else
		    done(0);
	    }
	    prompt (top_level_prompt);
	    cmsetrp ();			/* reparse comes back here */
	    fdbs = fdbchn (&mm_top_abbr_fdb, &mm_top_fdb, &shell_fdb, nil);
	}
	cmcsb._cmerh = ccmd_error;	/* reset in case of reparse */
	cm_set_ind(TRUE);		/* allow indirections */
	if (fdbs->_cmdef != nil)
	    cmcsb._cmflg |= CM_PRS;	/* XXX kludge! */
	doargs = false;
	parse (fdbs, &pv, &used);
	alarm(0);
	if (used == &shell_fdb)
	    (void) shell_escape ();
	else
	    (void) (*mm_cmds[pv._pvkey]) (pv._pvkey);

    }
}

/* 
 * parse an (optional) shell command and invoke the shell
 */ 

shell_escape ()
{
    static fdb cmdfdb = { _CMTXT };

    parse (&cmdfdb, &pv, &used);	/* parse a line of text */
    if (strlen (atmbuf) == 0)
	shell (nil);
    else
	shell (atmbuf);
}

cmd_debug (n)
int n;
{
    debug = parse_yesnoask("yes");
}

cmd_debug_memory (n)
int n;
{
    memdebug = parse_yesnoask("yes");
}
