#include "args.h"

#include "config.h"
/*
 * Copyright (c) 1986, 2014 by The Trustees of Columbia University in
 * the City of New York.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  + Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  + Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 *  + Neither the name of Columbia University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 */

#ifndef lint
static const char *rcsid = "$Header: /usr/local/src/mm/mm-0.94/mm/RCS/read.c,v 1.1 2005/05/28 22:27:53 beebe Exp $";
#endif

/*
 * read.c - support for the mm read command
 */
#include "mm.h"
#include "cmds.h"
#include "parse.h"

static int mark;			/* shall we mark message as seen? */

static int do_type ARGS((int n));
static void show_message ARGS((int n));

extern int use_crt_filter_always;

int
#if HAVE_STDC
cmd_read (int n)
#else /* K&R style */
cmd_read (n)
int n;
#endif /* HAVE_STDC */
{
    if (!check_cf (O_RDWR))		/* want writable, settle for read */
	return false;

    if (mode != MM_TOP_LEVEL)
	cmerr ("Previous READ command still active; type QUIT first");

    parse_sequence ((n == CMD_REVIEW) ? "" : "unseen",NULL,NULL);
    copy_sequence (cf->read_sequence, cf->sequence); /* XXX */
    check_mark();			/* can we mark things? */

    if (sequence_start (cf->read_sequence)) {
	mode |= MM_READ;
	mode &= ~MM_SEND;		/* quit from send mode */
	show_message (cf->current);
    }
    return true;
}

int ltype;				/* fdc 2014-02-26 (was static) */
static FILE *type_pipe = NULL;

static int
#if HAVE_STDC
do_type (int n)
#else /* K&R style */
do_type (n)
int n;
#endif /* HAVE_STDC */
{
    if (n > 0)
	if (!ignore (n)) {
	    display_message (type_pipe, &cf->msgs[n], false,
			     (ltype ? nil : only_type_headers),
			     (ltype ? nil : dont_type_headers));
	    if (!(cf->msgs[n].flags & M_SEEN) && mark) {
		cf->flags |= MF_MODIFIED; /* file (msg flags) must be saved */
		cf->msgs[n].flags |= M_SEEN|M_MODIFIED;
	    }
	}
    return true;
}

/*
 * cmd_type:
 * TYPE command.  Parse a sequence and hand everything off to real_type.
 */


void
#if HAVE_STDC
cmd_type (int n)
#else /* K&R style */
cmd_type (n)
int n;
#endif /* HAVE_STDC */
{
    int real_seq;

    if (!check_cf (O_RDONLY))
	return;
    real_seq = parse_sequence ("current",NULL,NULL);
    check_mark();			/* can we mark things? */
    real_type (n, real_seq);		/* this is the real function */
}


/*
 * real_type:
 * the real type command is here.  cmd_type (above) only parses a
 * sequence.  It will call this function.  The LITERAL command which
 * defaults to LITERAL TYPE will also call this after IT does a
 * sequence parse.
 */

int
#if HAVE_STDC
real_type (int n, int real_seq)
#else /* K&R style */
real_type (n, real_seq)
int n;
int real_seq;
#endif /* HAVE_STDC */
{
    int m;
    char *msg;
    int len;
    FILE *out;
    char * filter_to_use = mime_filter; /* fdc 2014-02-26 */

    ltype = (n == CMD_LITERAL);
    if (ltype) filter_to_use = crt_filter; /* fdc 2014-02-26 */

    if (real_seq) {
	out = cmcsb._cmoj ? cmcsb._cmoj : stdout;
	if (ltype && !use_crt_filter_always) /* must check the total length */
	    for (len = 0, m = sequence_start (cf->sequence);
		 m && (len < cmcsb._cmrmx);
		 m = sequence_next (cf->sequence)) {
		if (cf->msgs[m].flags & M_DELETED) /* deleted message? */
		    len++;		/* one line error */
		else {
		    msg = fmt_message (&(cf->msgs[m]),
				       (ltype ? nil : only_type_headers),
				       (ltype ? nil : dont_type_headers));
		    if (msg != NULL) {
			len += logical_lines (msg, cmcsb._cmrmx) +1;
			free (msg);
		    }
		}
	    }

	if (len >= cmcsb._cmrmx || !ltype) /* fdc */
	    type_pipe = more_pipe_open(out,filter_to_use); /* fdc */
	else
	    type_pipe = out;
	sequence_loop ((void (*) ARGS((int)))do_type);
	if (type_pipe == out)		/* not a pipe */
	    fflush (type_pipe);
	else
	    more_pipe_close(type_pipe);	/* really a pipe */
	type_pipe = NULL;		/* set back to NULL so other modules */
    }					/* can use ignore() too */
    else {
	/*
	 * Can't use do_type since do_type checks for message deleted.
	 */
	if (cf->current) {
	    display_message (stdout, &cf->msgs[cf->current], false,
			     (ltype ? nil : only_type_headers),
			     (ltype ? nil : dont_type_headers));
	    if (!(cf->msgs[cf->current].flags & M_SEEN) && mark) {
		cf->flags |= MF_MODIFIED; /* file (msg flags) must be saved */
		cf->msgs[cf->current].flags |= M_MODIFIED|M_SEEN;
	    }
	}
    }
    ltype = 0;				/* fdc - 2014/03/03 */
    return true;
}


int
#if HAVE_STDC
cmd_next (int cmd)
#else /* K&R style */
cmd_next (cmd)
int cmd;
#endif /* HAVE_STDC */
{
    confirm ();
    if (!check_cf (O_RDONLY))		/* no mod's needed */
	return false;
    if (cmd == CMD_KILL) {
	if (!mark)
	    fprintf (stderr,
		     "File %s \"examine\"d, not deleting message.\n",
		     cf->filename);
	else {
	    if (!(cf->msgs[cf->current].flags & M_DELETED)) {
		cf->msgs[cf->current].flags |= (M_DELETED|M_MODIFIED);
		cf->flags |= MF_MODIFIED; /* file (msg flags) must be saved */
	    }
	    if (!(mode & MM_READ))
		printf (" %d\n", cf->current);
	}
    }
    if (mode & MM_READ)
	if (sequence_next (cf->read_sequence))
	    show_message (cf->current);
	else
	    mode &= ~MM_READ;
    else
	if (cf->current < cf->count)
	    show_message (++cf->current);
	else
	    printf (" Currently at end, message %d\n", cf->current);
    return true;
}

int
#if HAVE_STDC
cmd_previous (int n)
#else /* K&R style */
cmd_previous (n)
int n;
#endif /* HAVE_STDC */
{
    confirm ();
    if (!check_cf (O_RDONLY))		/* no modifying intended */
	return false;

    if (mode & MM_READ)
	if (sequence_prev (cf->read_sequence))
	    show_message (cf->current);
	else
	    cmerr ("Already at start of sequence");
    else
	/*
	 * just step through the file
	 */
	if (cf->current > 1)
	    show_message (--cf->current);
	else
	    printf (" Currently at beginning, message %d\n", cf->current);

    return true;
}

void
#if HAVE_STDC
cmd_count (int cmd)
#else /* K&R style */
cmd_count (cmd)
int cmd;
#endif /* HAVE_STDC */
{
    if (!check_cf(O_RDONLY))		/* not wanting to modify */
	return;

    if (parse_sequence ("all",NULL,NULL)) {
	int count,n;
	for (count = 0, n = sequence_start (cf->sequence); n;
	     n = sequence_next (cf->sequence))
	    ++count;
	seq_print (false);
	printf ("%s %d message%s\n", count > 0 ? " =" : "",
		count, count != 1 ? "s" : "");
    } else
	cmerr ("Command not valid in this context");
}

void
#if HAVE_STDC
cmd_mark (int cmd)
#else /* K&R style */
cmd_mark (cmd)
int cmd;
#endif /* HAVE_STDC */
{
    int real_seq;

    if (!check_cf (O_RDONLY))		/* find out for ourselves */
	return;
    real_seq = parse_sequence ("current",NULL,NULL);
    check_mark();
    if (!mark)				/* can't do anything */
	return;

    if (!real_seq)
	change_flag (cf->current, cmd);
    else {
	int n;
	for (n = sequence_start (cf->sequence); n;
	     n = sequence_next (cf->sequence))
	    change_flag (n, cmd);
	seq_print (true);
    }
}

void
#if HAVE_STDC
change_flag (int n, int what)
#else /* K&R style */
change_flag (n, what)
int n, what;
#endif /* HAVE_STDC */
{
    message *m = & cf->msgs[n];

    switch (what) {
      case CMD_DELETE:
	if (!(m->flags& M_DELETED)) {
	    m->flags |= (M_DELETED|M_MODIFIED);
	    cf->flags |= MF_MODIFIED;
	}
	break;
      case CMD_UNDELETE:
	if (m->flags & M_DELETED) {
	    m->flags &= ~M_DELETED;
	    m->flags |= M_MODIFIED;
	    cf->flags |= MF_MODIFIED;
	}
	break;
      case CMD_UNMARK:
	if (m->flags & M_SEEN) {
	    m->flags |= M_MODIFIED;
	    m->flags &= ~M_SEEN;
	    cf->flags |= MF_MODIFIED;
	}
	break;
      case CMD_MARK:
	if (!(m->flags & M_SEEN)) {
	    m->flags |= (M_SEEN|M_MODIFIED);
	    cf->flags |= MF_MODIFIED;
	}
	break;
      case CMD_FLAG:
	if (!(m->flags & M_FLAGGED)) {
	    m->flags |= (M_FLAGGED|M_MODIFIED);
	    cf->flags |= MF_MODIFIED;
	}
	break;
      case CMD_UNFLAG:
	if (m->flags & M_FLAGGED) {
	    m->flags &= ~M_FLAGGED;
	    m->flags |= M_MODIFIED;
	    cf->flags |= MF_MODIFIED;
	}
	break;
      case CMD_UNANSWER:
	if (m->flags & M_ANSWERED) {
	    m->flags &= ~M_ANSWERED;
	    m->flags |= M_MODIFIED;
	    cf->flags |= MF_MODIFIED;
	}
	break;
    }
}

void
#if HAVE_STDC
cmd_jump (int n)
#else /* K&R style */
cmd_jump (n)
int n;
#endif /* HAVE_STDC */
{
    if (!check_cf(O_RDONLY))
	return;
    noise ("to message number");
    n = parse_number (10, "message number", nil);
    if (n < 1 || n > cf->count)
	cmerr("Number out of range");
    confirm();
    if (mode & MM_READ)
	if (!in_sequence(cf->sequence, n))
	    cmerr ("Number not in current message sequence");
    cf->current = n;
}

/*
 * decide whether to ignore a message, and tell the user why.
 */
int
#if HAVE_STDC
ignore (int n)
      					/* message number in current file */
#else /* K&R style */
ignore (n)
int n;					/* message number in current file */
#endif /* HAVE_STDC */
{
    if ((mode == MM_TOP_LEVEL) && (cf->msgs[n].flags & M_DELETED)) {
	fprintf (type_pipe ? type_pipe : stdout,
		 " Message %d deleted, ignored.\n", n);
	return true;
    }
    return false;
}

/*
 * show_message is used by read, next, previous.
 */

static void
#if HAVE_STDC
show_message (int n)
#else /* K&R style */
show_message (n)
int n;
#endif /* HAVE_STDC */
{
    message *m = &cf->msgs[n];

    if (m->flags & M_DELETED)
	printf (" Message %d deleted, ignored.\n", n);
    else {
	display_message (stdout, m, true,
			 only_type_headers, dont_type_headers);
	if (!(m->flags & M_SEEN) && mark) {
	    cf->flags |= MF_MODIFIED;	/* file (msg flags) must be saved */
	    m->flags |= (M_SEEN|M_MODIFIED);
	}
    }
}

/*
 * check_mark:
 * find out if we can mark the messages in the sequence, and set "mark"
 */
void
check_mark(VOID)
{
    if (!(cf->flags & MF_RDONLY))
	mark = TRUE;			/* go ahead! */
    else {				/* read-only */
	if (modify_read_only == SET_NEVER) {
	    fprintf (stderr,
	   "Warning: cannot mark messages in file visited with \"examine\"\n");
	    mark = FALSE;		/* don't bother trying */
	}
	else if (modify_read_only == SET_ASK)
	    mark=yesno("File is read-only, mark messages anyway? ", "no");
	else			/* SET_ALWAYS */
	    mark = TRUE;
    }
}
