/*
 *	Copyright (C) 1984, 1985  SRI International
 *	Copyright (C) 1989, 1991, 1993  TGV, Incorporated
 *
 *	Read SUBCOMMAND mode
 *
 */
#include "comnd.h"
#include <stdio.h>
#include "vax-mm.h"

extern int CMD_Blank(),		CMD_Continue(),		CMD_Daytime(),
	   CMD_File_List(),	CMD_Help(),		CMD_List(),
	   CMD_Send(),		CMD_Status(),		CMD_Take(),
	   CMD_Version(),	MM_Attach(),		MM_Push(),
	   CMD_Print(),		CMD_Unprint(),		MM_Spawn(),
	   CMD_Cd(),	    	CMD_Append();

static int Answer(),		Copy(),			Delete(),
	   Edit(),		Flag(),			Forward(),
	   Header(),		Keywords(),		Kill(),
	   Literal_Type(),	Mark(),			Move(),
	   Next(),		Previous(),		Remail(),
	   Type(),		Unanswer(),		Undelete(),
	   Unflag(),		Unkeywords(),		Unmark(),
	   Is_Deleted_Message();


struct {
	int current_entries;
	int maximum_entries;
	struct tbluk_keyword keywords[53];
	} Read_Keywords = {
	53,53,
	{{0,	"Answer",	(int)Answer},
	 {0,	"Append",	(int)CMD_Append},
	 {0,	"Attach",	(int)MM_Attach},
	 {0,	"Blank",	(int)CMD_Blank},
	 {0,	"Cd",	(int)CMD_Cd},
	 {0,	"Continue",	(int)CMD_Continue},
	 {0,	"Copy",	(int)Copy},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"D",	(int)&Read_Keywords.keywords[9]},
	 {0,	"Daytime",	(int)CMD_Daytime},
	 {0,	"Delete",	(int)Delete},
	 {0,	"Edit",	(int)Edit},
	 {0,	"File-list",	(int)CMD_File_List},
	 {0,	"Flag",	(int)Flag},
	 {0,	"Forward",	(int)Forward},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"H",	(int)&Read_Keywords.keywords[15]},
	 {0,	"Header",	(int)Header},
	 {0,	"Help",	(int)CMD_Help},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"K",	(int)&Read_Keywords.keywords[19]},
	 {0,	"Keywords",	(int)Keywords},
	 {0,	"Kill",	(int)Kill},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"L",	(int)&Read_Keywords.keywords[21]},
	 {0,	"List",	(int)CMD_List},
	 {0,	"Literal-type",	(int)Literal_Type},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"M",	(int)&Read_Keywords.keywords[26]},
	 {(COMND_INVISIBLE),	"Mail",	(int)CMD_Send},
	 {0,	"Mark",	(int)Mark},
	 {0,	"Move",	(int)Move},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"N",	(int)&Read_Keywords.keywords[28]},
	 {0,	"Next",	(int)Next},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"P",	(int)&Read_Keywords.keywords[30]},
	 {0,	"Previous",	(int)Previous},
	 {0,	"Print",	(int)CMD_Print},
	 {0,	"Push",	(int)MM_Push},
	 {0,	"Quit",	(int)0},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"R",	(int)&Read_Keywords.keywords[37]},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"Re",	(int)&Read_Keywords.keywords[37]},
	 {0,	"Remail",	(int)Remail},
	 {0,	"Reply",	(int)Answer},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"S",	(int)&Read_Keywords.keywords[39]},
	 {0,	"Send",	(int)CMD_Send},
	 {0,	"Spawn",	(int)MM_Spawn},
	 {0,	"Status",	(int)CMD_Status},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"T",	(int)&Read_Keywords.keywords[44]},
	 {0,	"Take",	(int)CMD_Take},
	 {0,	"Type",	(int)Type},
	 {(COMND_ABBREVIATION | COMND_INVISIBLE),	"U",	(int)&Read_Keywords.keywords[47]},
	 {0,	"Unanswer",	(int)Unanswer},
	 {0,	"Undelete",	(int)Undelete},
	 {0,	"Unflag",	(int)Unflag},
	 {0,	"Unkeywords",	(int)Unkeywords},
	 {0,	"Unmark",	(int)Unmark},
	 {0,	"Unprint",	(int)CMD_Unprint},
	 {0,	"Version",	(int)CMD_Version}}};

static int Current_Read_Message;
static int Leave_Read_Mode;
static struct comnd_function keyword =
	{COMND_KEYWORD,
	 COMND_DEFAULT_VALID,
	 0,
	 (int)&Read_Keywords,
	 0,
	 "NEXT"};
/*
 *	Read command
 */
CMD_Read()
{
	struct tbluk_keyword *t;
	int Status;
	jmp_buf Saved_Top_Level;

	/*
	 *	Get the message sequence
	 */
	Parse_Message_List("UNSEEN");
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Into READ MODE
	 */
	Read_Mode = 1;
	if (Next() < 0) {Read_Mode = 0; return;}
	Init_CMD_Help(HELP_FILE_READ, &Help_Read);
	/*
	 *	Save the Goto_Top_Level jmp_buf
	 */
	bcopy(&Goto_Top_Level, &Saved_Top_Level, sizeof(Goto_Top_Level));
	/*
	 *	Set us as the Top-Level Goto
	 */
	setjmp(Goto_Top_Level);
    	Leave_Read_Mode = 0;
	while(1) {
		/*
		 *	Initialize
		 */
		Command_State.prompt = Read_Prompt;
		COMMAND_PARSE_INIT(&Command_State);
		/*
		 *	Get keyword
		 */
		Status = comnd_jsys(&Command_State,&keyword,&t,0);
		if (Status < 0) {
			printf("\n?parse error (later)\n");
			continue;
		}
		/*
		 *	Call action routine
		 */
		if (!t->user_data) {
			Confirm();
			Read_Mode = 0;
			bcopy(&Saved_Top_Level, &Goto_Top_Level, sizeof(Goto_Top_Level));
			Update_Header_File(0);
			return;
		}
    	    	(*(int (*)())t->user_data)(&Command_State);
    	    	if (Leave_Read_Mode) {
			Read_Mode = 0;
			bcopy(&Saved_Top_Level, &Goto_Top_Level, sizeof(Goto_Top_Level));
			Update_Header_File(0);
			return;
		}
	}
}


/*	Local routines	 */

/*
 *	Answer the current message
 */
static int Answer()
{
	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[2];
		} All_or_Sender = {
			2,
			2,
			{{0,	"all",		0},
			 {0,	"sender",	0}}};
	static struct comnd_function reply_keywords =
		{COMND_KEYWORD,
		 COMND_DEFAULT_VALID,
		 0,
		 (int)&All_or_Sender};
	static struct {
		int current_entries;
		int maximum_entries;
		struct tbluk_keyword keywords[2];
		} Including_Not_Including = {
			2,
			2,
			{{0,	"including",		0},
			 {0,	"not-including",	0}}};
	static struct comnd_function include_keywords =
		{COMND_KEYWORD,
		 COMND_DEFAULT_VALID,
		 0,
		(int)&Including_Not_Including};
	int i;
	char *Reply_Keyword_String;
	char *Include_Keyword_String;
	struct tbluk_keyword *t;

	/*
	 *	Add the noise word
	 */
	Noise("to");
	/*
	 *	Setup the default and get the SENDER/ALL keyword
	 */
	reply_keywords.default_string =
		Reply_Sender_Only_Default ? "SENDER" : "ALL";
	i = comnd_jsys(&Command_State,&reply_keywords,&t,0);
	if (i < 0) return(0);
	Reply_Keyword_String = t->keyword;
	/*
	 *	Setup the default and get the include/don't include keyword
	 */
	include_keywords.default_string =
		Reply_Insert_Current_Msg ?
			"INCLUDING" : "NOT-INCLUDING";
	i = comnd_jsys(&Command_State,&include_keywords,&t,0);
	if (i < 0) return;
	Include_Keyword_String = t->keyword;
	Noise("message text in reply");
	/*
	 *	Confirm the command line
	 */
	Confirm();
	/*
	 *	Answer the message
	 */
	if (Answer_Message(Current_Message,Reply_Keyword_String,Include_Keyword_String)) {
		Messages[Current_Message-1].Flags |= MSG_ANSWERED;
		Update_Message(Current_Message);
	}
	return(0);
}

/*
 *	Delete the current message
 */
static int Delete()
{
	Confirm();
	Messages[Current_Message-1].Flags |= MSG_DELETED;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Kill the current message (and do an implicit "Next")
 */
static int Kill()
{
	int Message_Number;

	Confirm();
	/*
	 *	Delete the message
	 */
	Messages[Current_Message-1].Flags |= MSG_DELETED;
	Update_Message(Current_Message);
	/*
	 *	Get the next message
	 */
	if ((Message_Number = Next_Message(0)) < 0) return(-1);
	Current_Message = Message_Number;
	/*
	 *	Clear the screen and type the Message
	 */
	Blank_Screen();
	return(Type());
}


/*
 *	Edit the current message
 */
static int Edit()
{
	register struct Msg *Msg;

	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Edit the message
	 */
	if (Is_Deleted_Message()) return(0);
	Msg = &Messages[Current_Message-1];
	Edit_Buffer_Read_Only("mm-read-message",
				MESSAGE_HEADER(Current_Message) +
							Msg->Header_Size,
					       Msg->Real_Size - Msg->Header_Size);
	return(0);
}


/*
 *	Flag the current message
 */
static int Flag()
{
	Confirm();
	Messages[Current_Message-1].Flags |= MSG_FLAGGED;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Forward the current message
 */
static int Forward()
{
	Noise("message to");
	Get_Forward_To_List();
	Forward_Messages(1,0,1);
	return(0);
}

/*
 *	Print the current message header
 */
static int Header()
{
	Confirm();
	Print_Header(stdout,&Messages[Current_Message-1],Current_Message);
	return(0);
}

/*
 *	Set keyword flags
 */
static int Keywords()
{
	int Keyflag;

	/*
	 *	Get the Keyflags
	 */
	Keyflag = Get_Keyflags();
	if (Keyflag == 0) return(-1);
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Set the keyflags
	 */
	Messages[Current_Message-1].Keyword_Flags |= Keyflag;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Literal Type message
 */
static int Literal_Type()
{
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Type the message
	 */
	Print_Message(Current_Message,0);
	return(0);
}


/*
 *	Mark the current message as seen
 */
static int Mark()
{
	Confirm();
	Messages[Current_Message-1].Flags |= MSG_SEEN;
	Update_Message(Current_Message);
	return(0);
}


/*
 *	Next message
 */
static int Next()
{
	int Message_Number;

	Confirm();
	/*
	 *	Get the next message
	 */
	if ((Message_Number = Next_Message(0)) < 0) {
    	    Leave_Read_Mode = 1;
    	    return(-1);
    	}
	Current_Message = Message_Number;
	/*
	 *	Clear the screen and type the Message
	 */
	Blank_Screen();
	return(Type());
}

/*
 *	Previous Message
 */
static int Previous()
{
	int Message_Number;

	Confirm();
	/*
	 *	Get the previous message
	 */
	Message_Number = Previous_Message();
	if (Message_Number <= 0) {
		printf("?Already at start of sequence\n");
		return(0);
	}
	Current_Message = Message_Number;
	/*
	 *	Type the message
	 */
	return(Type());
}


/*
 *	Remail the current message
 */
static int Remail()
{
	Noise("message to");
	Remail_Messages(1);
	return(0);
}

/** TO DO **/
static int Spell(){printf("Spell called\n");}

/*
 *	Type the current message
 */
static int Type()
{
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Type the message
	 */
	Print_Message(Current_Message,1);
	return(0);
}

/*
 *	Reset ANSWERED flag
 */
static int Unanswer()
{
	Confirm();
	Messages[Current_Message-1].Flags &= ~MSG_ANSWERED;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Reset DELETED flag
 */
static int Undelete()
{
	Confirm();
	Messages[Current_Message-1].Flags &= ~MSG_DELETED;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Reset FLAGGED flag
 */
static int Unflag()
{
	Confirm();
	Messages[Current_Message-1].Flags &= ~MSG_FLAGGED;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Reset KEYWORD flags
 */
static int Unkeywords()
{
	int Keyflag;

	/*
	 *	Get the Keyflags
	 */
	Keyflag = Get_Keyflags();
	if (Keyflag == 0) return(-1);
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Clear the keyflags
	 */
	Messages[Current_Message-1].Keyword_Flags &= ~Keyflag;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Mark the current message as not seen
 */
static int Unmark()
{
	Confirm();
	Messages[Current_Message-1].Flags &= ~MSG_SEEN;
	Update_Message(Current_Message);
	return(0);
}

/*
 *	Copy current message to another message file
 */
static int Copy()
{
	char Filename[128];

	/*
	 *	Get the target file name
	 */
	if (Get_Move_File(Filename) < 0) return;
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Do it
	 */
	if (Open_Move_File(Filename) < 0) return 0;
	Move_Message(Current_Message);
	/*
	 *	Done
	 */
	Close_Move_File();
}

/*
 *	Move current message to another message file
 */
static int Move()
{
	char Filename[128];

	/*
	 *	Get the target file name
	 */
	if (Get_Move_File(Filename) < 0) return;
	/*
	 *	Confirm
	 */
	Confirm();
	/*
	 *	Do it
	 */
	if (Open_Move_File(Filename) < 0) return 0;
	Move_Message(Current_Message);
	Messages[Current_Message-1].Flags |= MSG_DELETED;
	Update_Message(Current_Message);
	/*
	 *	Done
	 */
	Close_Move_File();
}



/*
 *	Deal with deleted messages
 */
static int Is_Deleted_Message()
{

	if (Messages[Current_Message-1].Flags & MSG_DELETED) {
		printf(" Message %d deleted.\n",Current_Message);
		return(1);
	}
	return(0);
}
