#include <ascii.h>
#include "fido.h"
#include <xfbuf.h>
#include "fidomem.h"
#include "proto.h"

/* Low level message area support routines. All of these (and other)
functions use the following global variables:

	These functions use the statics struct msgarea for all work
on msg areas. If the override path ovpath is set, then that is used for
all msg operations; this is detected at msg count time, and is
special cased. 

int msgfile	Handle for currently open msg file

*msg_highest()	Returns a pointer to the highest message number
		for this area. If the number is out of range, it
		returns a pointer to the static counters below.
		This lets us use path override in a msg area. See
		msgcount().

*msg_total()	Same as above, only a pointer to ttotal messages.
		Same error checking.

killmsg(n)	Unconditionally deletes message # N from the current
		message area. If it is the highest message number,
		the messages are recounted. (ie. msgs N - 1 and below 
		may be missing, and affect highest msg #.)

msgcount()	Counts the messages in the selected message path and sets
		the global variables '*msg_total()' and '*msg_highest()'. If
		possible, it tries to use the last count found.
		This also blanks out the in-memory copy of the message
		so that we can't reply to private etc messages after
		changing areas or deleting the highest message.

wrtmsg()	Write out the message header for the current message.

closemsg()	Close the message file and mark the handle -1.

findmsg()	Searches for next/previous message, with many controls
		limits and options. Read the findmsg() comment.
		KLUDGE: it also assembles the msg_dest and msg_orig
		structures, from the discrete components in the msg
		header.

*/

static int totl_ov = 0;		/* override path msg total/highest */
static int high_ov = 0;

/* Kill a message, update the message count, etc. We only have to search
again if we delete the highest one. */

void killmsg(num)
int num;
{
char work[SF],name[SS];

	sprintf(work,0,"%d.MSG",num);
	makemname(name,work);
	delete(name);
	if (*msg_total() > 0) --*msg_total();		/* update count, */
	if (num >= *msg_highest()) {
		totlmsg[msgarea.number]= 0;		/* force a recount, */
		msgcount();				/* count them */
	}
}

/* Return a pointer to the highest message number in this area. */

int *msg_highest() {

	if (msg_or()) return(&high_ov);
	return(&highmsg[msgarea.number]);
}

/* Return a pointer to the total messages in this area. */

int *msg_total() {

	if (msg_or()) return(&totl_ov);
	return(&totlmsg[msgarea.number]);
}
/* Return true if the message area number is out of range or there is
an override path set. */

msg_or() {

	return(*ovpath || (msgarea.number < 0) || (msgarea.number > fido.marea_max));
}

/* Count the number of messages in this msg area if they are uncounted
(count is 0) or we are running with a taskID. */

msgcount() {
char spec[SS];
int nb,n;
struct _xfbuf xfbuf;

int *h,*t;
char *cp;

	if ((totlmsg[msgarea.number] == 0) || taskid || msg_or()) {
		if (msg_or()) {			/* if out of range, */
			h= &high_ov;		/* use override vars */
			t= &totl_ov;

		} else {			/* else the usual ones */
			t= &totlmsg[msgarea.number];
			h= &highmsg[msgarea.number];
		}
		*t= *h= 0;			/* zero both */

		xfbuf.s_attrib= 0;
		makemname(spec,"*.MSG");	/* must count */
		while (_find(spec,*t,&xfbuf)) {
			++*t; 			/* count another, */
			n= atoi(xfbuf.name);	/* change name to number */
			if (n > *h) *h= n;	/* pick highest one, */
		}
	} 
}

/* Zap the in-memory message. */

void msgzap() {
	*msg.from= NUL;				/* blank out the */
	*msg.to= NUL;				/* last msg so we cant */
	*msg.subj= NUL;				/* so reply to (PRIVATE) */
	msg.attr= 0;
}

/* Write out the open message. */

void wrtmsg() {
	if (msgfile == -1) return;

	lseek(msgfile,0L,0);			/* seek to start, */
	write(msgfile,&msg,sizeof(struct _msg)); /* write it out, */
	closemsg();
}

/* Close the message file if open. */

void closemsg() {

	if (msgfile != -1) close(msgfile);
	msgfile= -1;
}

/* Find a message by number. This will loop up or down, or not at all,
depending on the flag passed. The file, if found, is left open (global
'msgfile' so that it can be worked on. This returns "not found" or the 
message is skipped if it doesnt meet various criteria, such as privacy,
being forwarded, etc. best to look at the code. 

KLUDGE: This looks for the IFNA Kludge in the text immediately following 
the message header. If it finds it, it sets msg_dest to that. */

int findmsg(num,loop)
int num,loop;
{
char *cp,lastc,name[SS];
char work[256];			/* rummage for ^A lines */
int i;

	do {
		if ((num > *msg_highest()) || (num < 1)) return(0);

		sprintf(work,0,"%d.MSG",num);
		makemname(name,work);
/**/		if (msgfile != -1) {
/**/			clprintf(0,"msgfile is already open! (before open(%s))\r\n",name);
/**/			closemsg();
/**/		}
		msgfile= open(name,2);

		if (msgfile != -1) {
			read(msgfile,&msg,sizeof(struct _msg));

/* Generate the msg_orig and msg_dest structures, used globally, from the
piecemeal elements in the message header. If an "impure" network, then dont
use the zone field, its either Opus date or Seadog somethingorother. */

			msg_orig.number= msg.orig_node;
			msg_orig.net= msg.orig_net;

			msg_dest.number= msg.dest_node;
			msg_dest.net= msg.dest_net;

			msg_orig.zone= id.zone; 	/* in case no */
			msg_dest.zone= id.zone;		/* IFNA Kludge */

			msg_orig.point= 0;		/* assume no points */
			msg_dest.point= 0;

/* Check for the presence of an IFNA Kludge; if there is one, set the 
addresses to that. Also looks for FMPT and TOPT, and fills in the rest of
the _node structures. ^AWORD must be at the start of the line; either the
very first thing following the header, or following a CR/LF. */

			i= read(msgfile,work,sizeof(work));
			work[i]= NUL;
			lseek(msgfile,(0L + sizeof(struct _msg)),0);

			lastc= CR;				/* for first time */
			for (cp= work; *cp;) {
				if (*cp != SOH) {		/* look for SOH */
					lastc= *cp++ & 0x7f;	/* but remember prev. */
					continue;
				}
				++cp;
				if ((lastc != CR) && (lastc != LF)) {
					continue;		/* must be at start of line */
				}
				if (fcomp(cp,"INTL",4) == 0) {
					cp= next_arg(cp);
					set_nn(cp,&msg_dest);
					cp= next_arg(cp);
					set_nn(cp,&msg_orig);

				} else if (fcomp(cp,"FMPT",4) == 0) {
					msg_orig.point= atoi(next_arg(cp));

				} else if (fcomp(cp,"TOPT",4) == 0) {
					msg_dest.point= atoi(next_arg(cp));
				}
			}

/* The number-of-times-read counter is supposed to run 1 - N. If it is 0,
it was probably generated outside Fido. In order for the [NOTE: Modified..]
check to work, it must start at 1. Fix it. */

			if (! msg.times) ++msg.times;

			return(num);
		}
		num += loop;
	} while (loop);

/* If no msg found, clear things so that Fido wont get confused, and so
callers cant reply to private or non-existent messages. */

	msgzap();
	return(0);
}
