/*
 * 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: move.c,v 1.28 88/07/22 20:03:11 howie Exp $";
#endif

/*
 * move.c - support for the move and copy commands
 */

#include "mm.h"				/* for msgvec */
#include "cmds.h"			/* for CMD_MOVE */
#include "parse.h"			/* for atmbuf */
#include "rd.h"				/* for PR_xxx's */

/* global guys just for move and copy */
static msgvec *dest;			/* file to copy to */
static int delete;			/* delete the message after copy? */
static int copy_err;			/* did we have a problem copying? */

msgvec *getdestfile();			/* get this type right... */
int do_copy();				/* this exists... */

/*
 * cmd_move:
 * copy a message from the current file to another file
 * if n = CMD_MOVE, delete it as well
 */
int
cmd_copy (n)
int n;
{
    string fname;			/* new file to copy to */
    int format;				/* format to use for new file */

    check_cf (false);			/* make sure we have current file */
    delete = (n == CMD_MOVE);		/* delete if it's "move" not "copy" */

    noise ("into file");		/* hint hint */
    parse_copyfile (fname, &format);	/* parse filename and maybe switches */

    parse_sequence ("current",NULL,NULL); /* parse a message sequence */

    if (delete && (cf->flags & MF_RDONLY)) { /* trying to delete? */
	if (modify_read_only == SET_NEVER) {
	   fprintf("Warning: cannot modify a file visited with \"examine\"\n");
	   delete = FALSE;		/* don't bother trying */
        }
	else if (modify_read_only == SET_ASK)
	   delete = yesno("File is read-only, delete messages anyway? ", "no");
    }
    dest = getdestfile (fname, format, TRUE); /* open file, interactive errs */
    if (dest == NULL) {
	cmerjnp(0);			/* XXX get rid of this */
    }
    sequence_loop (do_copy);		/* copy each message */
    (*msg_ops[dest->type].close)(dest->filep); /* close it */
    free (dest);			/* maybe free other guys too */
    if ((mode == MM_TOP_LEVEL) && !copy_err)
	seq_print (true);
    return true;
}

/*
 * parse_copyfile:
 * parse the switches for the move/copy command and the filename
 * switches are optional, filename is not
 */
parse_copyfile (name,ptype)
char name[];
int *ptype;
{
    pval parseval;
    fdb *used;
    extern keytab formattab;
    static char *def = NULL;
    extern char cmswbeg;
    static fdb formatfdb = {
	_CMSWI, 0, NULL, (pdat)&formattab, NULL, NULL, NULL };
    static fdb filefdb = {
	_CMFIL, FIL_SDH|FIL_PO, NULL, NULL, "file to copy to", NULL, NULL};
    filblk fb;
    static char *dirs[] = { "." , nil, nil };

    dirs[1] = mail_directory;
    fb.pathv = dirs;
    fb.exceptionspec = nil;
    fb.def_extension = nil;
    filefdb._cmdat = (pdat) &fb;

    /* set up defaults for parse */
    if (def != nil)			/* in case of reparse */
	free(def);
    if (default_mail_type.current != NULL) {
	def = (char *) malloc (strlen (default_mail_type.current) +2);
	def[0] = cmswbeg;
	strcpy (&def[1], default_mail_type.current); /* get our default */
    }
    else
	def = NULL;
    formatfdb._cmdef = def;		/* insert the default */
    *ptype = -1;			/* mark that it hasn't been set */

    if (directory_folders)
	filefdb._cmffl &= ~FIL_NODIR;
    else
	filefdb._cmffl |= FIL_NODIR;
    parse(fdbchn (&formatfdb,&filefdb,NULL), &parseval, &used);
    if (used == &formatfdb) {
	*ptype = parseval._pvint;	/* what they want */
	parse (fdbchn (&filefdb,NULL), &parseval, &used); /* NEED a file */
    }

    free (def);				/* free us some space */
    def = NULL;

    /* handle the parsed file now */
    strncpy(name, parseval._pvfil[0], STRLEN);
    
    if (access (name, F_OK) != 0)	{ /* does it exist? */
	int ok;
	char c = 0;
	char *p = rindex(name, '/');	/* no, check directory */
	
	if (p == NULL) p = name;	/* XXX depends on ("" == ".") */
	c = *p; *p = 0;			/* consider only the directory */
	ok = access(name, F_OK|W_OK);	/* can we create a file in there? */
	*p = c;				/* fix the path again */
	if (ok < 0)
	    cmerr(errstr(-1));		/* nope, complain */
    }
}

/*
 * getdestfile:
 * open up this file for appending to, figure out its type
 */
msgvec *
getdestfile(name,format,inter)
char name[];
int format;				/* default format */
int inter;				/* interactive errors */
{
    msgvec *df;
    int type;
    int flags;				/* flags for msg_ops.open */
    extern int num_msg_ops;		/* how many mail formats we know */
    extern int mail_probe();		/* to probe the mail */

    switch (mail_probe (name, &type))	/* can we read this? */
    {
    case PR_NAME:
	cmerr ("Badly formed filename: %s", name);
    case PR_PERM:
	cmerr ("Cannot determine mail format: %s", name); /* couldn't read */
    case PR_EMPTY:
    case PR_NOEX:			/* must make new file */
	if (format != -1)		/* did we parse something? */
	    type = format;		/* whatever we parsed in switch */
	else {
	    for (type = 0; type < num_msg_ops; type++) /* try default */
		if (strcmp (default_mail_type.current, msg_ops[type].typename)
		    == 0)
		    break;		/* use their default */
	    if (type == num_msg_ops)
		type = TYPE_MTXT;	/* no match, pick some type */
	}
	break;
    case PR_NOTOK:
	cmerr ("File is damaged or in unknown format: %s", name);
    default:
	if ((format != type) && (format != -1))	/* they guessed wrong */
	    fprintf (stderr, "File is in %s format, ignoring switch\n",
		     msg_ops[type].typename);
    }
    df = (msgvec *) malloc (sizeof (msgvec)); /* room to put all this stuff */
    if (df == NULL)
	cmerr ("No room to handle file: %s", name);

    df->type = type;
    df->flags = 0;			/* no flags (so far) */
    df->count = 0;			/* just in case */

    strcpy (df->filename, name);

    flags = inter ? (OP_INT|OP_APP) : OP_APP;
    if ((*msg_ops[df->type].open)(df,flags) != 0) /* open */
	return (NULL);
    return (df);			/* don't need data filled in */
}

/*
 * do_copy:
 * copy the nth message from cf (current file) into dest
 * delete it if in CMD_MOVE.
 */
static int
do_copy (n)
int n;					/* which message */
{
    if (n == 0) {
	copy_err = FALSE;		/* no errors yet */
	return (true);
    }
    if (n < 0)
	return (true);			/* no special ending */

    if (!copy_err && !ignore (n)) {
	/* copy this message to the end of dest (0 for this unused field) */
	if (copy_err = (*msg_ops[dest->type].wr_msg)
	             (dest,&cf->msgs[n],0,WR_COPY)) {
	    fprintf (stderr, "Trouble writing message %d to %s, aborting %s\n",
		     n, dest->filename, delete ? "move" : "copy");
	    return (false);
	}
	if (delete && !(cf->msgs[n].flags & M_DELETED)) { /* changing it? */
	    cf->msgs[n].flags |= (M_DELETED|M_MODIFIED); /* delete it */
	    cf->flags |= MF_DIRTY;	/* file (msg flags) must be saved */
	}
    }
    return (copy_err);
}


