/* Little Usenet Reader */

#ifdef IBMPC
#include <stdlib.h>
#define READ_MODE	"rb"
#define WRITE_MODE	"wb"
#define SCREEN_ROWS	24
#define SCREEN_COLS	80
#endif

#ifdef AMIGA
#include <fcntl.h>
#define SEEK_SET 0
#define READ_MODE	"r"
#define WRITE_MODE	"w"
#define SCREEN_ROWS	22
#define SCREEN_COLS	78
char	*gets();
#endif

#include <stdio.h>

typedef unsigned char BOOL;
#define FALSE (0)
#define TRUE (!FALSE)
#define MAX_LINE_LEN 256
#define BACK_BUF	256
#define FF	(12)
#define BS  (8)
#ifdef MEDDLE
#define DPRT(x) x
#else
#define DPRT(x)
#endif

#define MIN(x,y) (x) > (y) ? (y) : (x)

long	start_msg;
long	end_msg;
int		start_col;
int		end_col;
int		start_row;
int		end_row;
FILE	*fpin;
FILE	*fpout;
int		msg_count;
char	msg_brk[MAX_LINE_LEN];
int		msg_brk_len;


long get_end_msg(begin)
long	begin;
{
	int		i;
	long	loc;
	char	s[MAX_LINE_LEN];

	fseek (fpin, begin, SEEK_SET);
	loc = begin;
	for (;;)
	{
		i = fgetc (fpin);
		if (i == msg_brk[0])
		{
			s[0] = i;
			if (msg_brk_len == 1)
				return (ftell(fpin) - 1L);
			i = fread (s+1, msg_brk_len - 1, 1, fpin);
			if (i == 0 || strncmp (msg_brk, s, msg_brk_len) == 0)
				return (ftell(fpin) - (long) msg_brk_len);
			fseek (fpin, ftell(fpin) - (long)msg_brk_len + 1L, SEEK_SET);
		}
	}
}

long get_prev_msg(begin)
long	begin;
{
	int		i;
	char	s[BACK_BUF];
	int		limit;
	int		last_ff;

	begin -= 1L;
	for (;;)
	{
		if (begin <= 0L)
			return(0L);
		begin -= (long) BACK_BUF;
		if (begin < 0L)
		{
			limit = (int) (BACK_BUF +  begin);
			begin = 0L;
		}
		else
			limit = BACK_BUF;

		fseek (fpin, begin, SEEK_SET);
		i = fread (s, 1, BACK_BUF, fpin);
		limit = limit > i ? i : limit;
		limit -= msg_brk_len;

		for (i = 0, last_ff = -1 ; i <= limit; i++)
		{
			if (s[i] == msg_brk[0])
				if (strncmp(&s[i], msg_brk, msg_brk_len) == 0)
					last_ff = i;
		}
		if (last_ff != -1)
			return (begin + (long) last_ff + 1L);
		if (begin <= 0L)
			return(0L);
		begin += ( (long)msg_brk_len - 1L);
	}
}


BOOL out_page(fp,lines)
FILE	*fp;
int		lines;
{
	int		i,j;
	char	s[MAX_LINE_LEN];

	if (ftell(fpin) >= end_msg)
		return(FALSE);

	for (i = 0, j = MIN((end_col - start_col), MAX_LINE_LEN); 
		i < lines || lines == 0; 
		i++)
	{
		fgets (s, j, fpin);
		fputs (s, fp);
		if (end_msg <= ftell(fpin))
			break;
	}
}


BOOL out_msg(fp,lines)
FILE	*fp;
int		lines;
{
	int		i,j;
	char	s[MAX_LINE_LEN];

	end_msg = get_end_msg(start_msg);
	fseek (fpin, start_msg > (long)msg_brk_len ? 
		start_msg - (long)msg_brk_len : 0L, 
		SEEK_SET);

	if (start_msg >= end_msg)
		return (FALSE);

	out_page (fp,lines);
}


BOOL next_page()
{
	int		i,j;
	char	s[MAX_LINE_LEN];

	fprintf(stdout,"===== Start of message %d\n", msg_count);
	start_msg = end_msg + 1L;
	return(out_msg(stdout,end_row - start_row));
}

BOOL write_page()
{
	int		ret;
	ret = out_msg(fpout,0);
	fputc ((int)FF, fpout);
	return(ret);
}

int close_all()
{
#ifdef AMIGA
	set_con();
#endif
	fclose (fpin);
	fclose (fpout);
	exit(0);
}

int get_one_char(fp)
FILE	*fp;
{
#ifdef IBMPC
	return(bdos(8));
#endif

#ifdef AMIGA
	unsigned char		c;
	struct FileHandle	*fh;

	fh = (struct FileHandle *) _devtab[fileno(fp)].fd;
	for (;;)
	{
		if (WaitForChar(fh, 1000L))
		{
			Read (fh, &c, 1L);
			return ((int) c);
		}
	}
#endif
}

help()
{
	printf ("ssur (small simple usenet reader)  version 1.1\n");
	printf ("Syntax: ssur [infile] [outfile] [message start string]\n\n");
	printf ("[message start string] defaults to a Form feed character\n");
	printf ("Key:      Use:\n");
	printf ("n         Print first page of next message\n");
	printf ("w         Write message to output file\n");
	printf ("BACKSPACE Display first page of previous message\n");
	printf ("b         Same as BACKSPACE\n");
	printf ("SPACE     Display next screen of current message\n");
	printf ("h         Display this help screen\n");
	printf ("q         Quit\n");
}

main (argc, argv)
int		argc;
char	**argv;
{
	int		c;

#ifdef AMIGA
	set_raw();
#endif
	start_msg = 0L;
	end_msg = -1L;
	start_row = 1;
	end_row = SCREEN_ROWS;
	start_col = 1;
	end_col = SCREEN_COLS;
	help();
	if (argc < 3)
		exit (3);
	fpin = fopen (argv[1], READ_MODE);
	if (fpin == NULL)
		exit(1);
	fpout = fopen (argv[2], WRITE_MODE);
	if (fpout == NULL)
		exit(2);
	if (argc == 4)
		strcpy(msg_brk, argv[3]);
	else
	{
		msg_brk[0] = FF;
		msg_brk[1] = NULL;
	}
	msg_brk_len = strlen(msg_brk);
	for (msg_count = 0;;)
	{
		c = get_one_char(stdin);
		switch (c & 0xff)
		{
		case (int)'w':
			msg_count++;
			write_page();
			next_page();
			break;
		case (int)'h':
			help();
			break;
		case (int)'b':
		case (int)BS:
			msg_count -= msg_count > 1 ? 1 : 0;
			end_msg = get_prev_msg(start_msg) - 1L;
			next_page();
			break;
		case (int)' ':
			if (! (out_page(stdout, end_row - start_row)))
				fprintf(stdout,"===== End of message %d\n",msg_count);
			break;
		case (int)'n':
			msg_count++;
			if (! (next_page()))
			{
				fprintf(stdout,"===== End of last message\n");
				msg_count--;
			}
			break;
		case (int)'q':
			close_all();
			break;
		}
	}
	close_all();
}
