#define __USE_SYSBASE 1

#include <exec/memory.h>
#include <utility/tagitem.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/utility.h>
#include <dos/dostags.h>

#include <libraries/bbsread.h>
#include <proto/bbsread.h>
#include <libraries/utgui.h>
#include <proto/utgui.h>

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "packhippo_rev.h"

#define BUFLEN			26
#define BIGBUF			200

#define CURSOR_ON  "\x9b\x20\x70"
#define CURSOR_OFF "\x9b\x30\x20\x70"
#define LINE_UP    "\x9b\x41"
#define DEL_EOL    "\x9b\x4b"

static UBYTE *version_string = VERSTAG;

enum {
	BBSNAME,
	PUBSCREEN,
	USAGE,
	NUM_ARGS
};

UBYTE *template = "BBSNAME,PUBSCREEN/K,USAGE/S";
LONG arg_array[NUM_ARGS];

/* struct DosLibrary *DOSBase; */
struct Library *BBSReadBase;
struct Library *UtilityBase;
struct Library *UTGuiBase;

BPTR orig_lock;
BPTR lock;
BPTR msg_lock, fh, fh_msg;
char *message;
int msgsize;
struct List *bbslist;
struct TypeListItem *mytype;
BOOL *eventlist;
struct BBSListItem *mybbs;
struct RDArgs *rdargs;
struct GlobalConfig *global;
ULONG pb_win;

void read_msg(char *filename, void *msg, int size);
void save_reply(char *filename, void *header, void *msg, int size);
void quit(char *);
void pack(char *bbsname);
void dumpstring(char *string, UBYTE charset);
BOOL ctrl_msg(UBYTE charset, ULONG eventtype, struct TagItem *eventtags);
void nrml_msg(UBYTE charset, struct TagItem *eventtags);
extern APTR SPrintf(STRPTR dest, STRPTR fh_msgtstr, ...);
extern struct Library *OpenBRLibrary(char *library, struct ExecBase *SysBase, struct DosLibrary *DOSBase, LONG version);

void __stdargs __main(char *notused)
{
	struct ExecBase *SysBase = *(struct ExecBase **)4;

	setmem(arg_array, sizeof(LONG)*NUM_ARGS, 0);
	if(!(rdargs = ReadArgs(template, arg_array, NULL)))
		quit("Can't read arguments");

	if(!arg_array[BBSNAME] || arg_array[USAGE])
		quit("Usage: PackHippo <BBSNAME> [USAGE]\n"
			 "Copyright © Ultima Thule Software " DATE " Author: Kjell Irgens");

	if(!(UtilityBase = (struct Library *) OpenLibrary("utility.library", 37)))
		quit("No utility.library");

	if(!(BBSReadBase = OpenBRLibrary(BBSREADNAME, SysBase, DOSBase, 3L)))
		quit("Needs bbsread.library V3+");

	if(!(UTGuiBase = OpenBRLibrary("utgui.library", SysBase, DOSBase, 3L)))
		quit("Needs utgui.library V3+");

	pack((char *)arg_array[BBSNAME]);
}

void pack(char *bbsname)
{
	struct ArcConfigItem *arcitem;
	int eventc, eventnum, i;
	UBYTE charset;
	char arcbuf[BIGBUF];
	BOOL *travevent;

	ULONG eventtype, eventdate, eventflags;
	struct TagItem *eventtags;
	APTR eventobject = NULL;
	BPTR fh_arcout;

	if(!(bbslist = GetBBSList())) quit("Error getting bbslist.");

	if(!(mybbs = (struct BBSListItem *) ugFindiName(bbslist, bbsname)))
		quit("Unknown system");

	if(!(lock = Lock(mybbs->bl_BBSPath, ACCESS_READ)))
		quit("Can't find the directory for the bbs");
	orig_lock = CurrentDir(lock);

	if(!(mytype = TypeFromBBS(mybbs))) quit("Error getting bbstype");
	charset = ConfCharset(mybbs, NULL);

	if(!(eventlist = AllocMem((mybbs->bl_Internal->bi_LastEvent
										-mybbs->bl_Internal->bi_FirstEvent+2)*sizeof(BOOL),
										MEMF_CLEAR)))
		quit("Out of memory");
	travevent= eventlist;
	travevent--;

	eventnum = mybbs->bl_Internal->bi_LastEvent-mybbs->bl_Internal->bi_FirstEvent;

	if(!arg_array[PUBSCREEN]) PutStr(CURSOR_OFF);

	if(PGPBREventsTags(mybbs, PGP_PublicScreen, (char *)arg_array[PUBSCREEN],
		 TAG_DONE)){
		quit("PGP failed");
		// i != 0 => feil, i er eventen som feilet.
	}

	for(eventc=0;eventc<=eventnum;eventc++){
		travevent++;

		if(arg_array[PUBSCREEN]){
			if(!pb_win) pb_win = 
						ugOpenProgressBar("PackHippo",
												PB_ScreenName, (char *)arg_array[PUBSCREEN],
												PB_Total, eventnum+1,
												PB_ProgressText, "Making reply packet",
												PB_InactiveWin, TRUE,
												TAG_DONE);
			if(pb_win) ugUpdateProgressBar(pb_win, PB_Current, eventc+1, TAG_DONE);
		}

		if(!(eventobject = ReadBREventTags(mybbs,
				eventc+mybbs->bl_Internal->bi_FirstEvent,
				RBREV_EventTagsPtr,	&eventtags,
				RBREV_EventType,		&eventtype,
				RBREV_EventDate,		&eventdate,
				RBREV_Flags,			&eventflags,
			TAG_DONE))) continue;

		if(eventflags & (EDF_DELETED | EDF_FREEZE | EDF_DONE)
				|| (eventtype != EVE_ENTERMSG 
					 && eventtype != EVE_REPLYMSG
					 && eventtype != EVE_RESIGNCONF
					 && eventtype != EVE_JOINCONF)){
			FreeBRObject(eventobject);
			continue;
		}
		if(eventtype == EVE_RESIGNCONF
			|| eventtype == EVE_JOINCONF){
			if(ctrl_msg(charset, eventtype, eventtags))
				*travevent = TRUE;
			else quit("Missing some tags");
		}
		else if(eventtype == EVE_REPLYMSG
				  || eventtype == EVE_ENTERMSG){
			nrml_msg(charset, eventtags);
			*travevent = TRUE;
		}
		else continue;  // Kan ikke pakkes

		if(!arg_array[PUBSCREEN])
			Printf("Packing event #%4ld\n"LINE_UP, (LONG)eventc);

		if(message){
			FreeMem(message, msgsize);
			message = NULL;
		}
		FreeBRObject(eventobject);
	}


	strcpy(arcbuf, mybbs->bl_Data->bd_GrabName);
	strcat(arcbuf, ".HRA");
	if(!mybbs->bl_Data->bd_ReplyPacket || strcmp(arcbuf, mybbs->bl_Data->bd_ReplyPacket))
		ConfigBBSTags(mybbs, BC_ReplyPacket, arcbuf, TAG_DONE);

	if(!(global = GetGlobalConfig())) quit("GetGlobalConfig() failed!");
	if(mybbs->bl_Data->bd_UploadPath) stccpy(arcbuf, mybbs->bl_Data->bd_UploadPath, BIGBUF);
	else stccpy(arcbuf, global->gc_UploadPath, BIGBUF);
	AddPart(arcbuf, mybbs->bl_Data->bd_GrabName, BIGBUF-5);
	strcat(arcbuf, ".HRA");
	DeleteFile(arcbuf);  // Sletter eventuell gammel pakka fil.
	
	if(fh_msg){
		Close(fh_msg); fh_msg = NULL;

		if(!(arcitem = BBSEventArchiver(mybbs))){
			FreeBRObject(global);
			quit("No archiver defined");
		}

		if(pb_win) ugUpdateProgressBar(pb_win, PB_ProgressText, "Archiving...", TAG_DONE);

		if(fh_arcout = Open("T:packhippo.tmppk", MODE_NEWFILE)){
			if(ArchiveTags(arcitem, arcbuf, AR_AddFile, "REPLY.HR", SYS_Output, fh_arcout, TAG_END)){
				DeleteFile("REPLY.HR");
				FreeBRObject(global);
				FreeBRObject(arcitem);
				Seek(fh_arcout, 0, OFFSET_BEGINNING);
				while((i=FGetC(fh_arcout))!=-1)
					FPutC(Output(), i);

				Close(fh_arcout);
				DeleteFile("T:packhippo.tmppk");
				quit("Archiver failed, please check");
			}
			Close(fh_arcout);
			DeleteFile("T:packhippo.tmppk");
		} else quit("Couldn't archive");
		DeleteFile("REPLY.HR");
		FreeBRObject(arcitem);
	}
	FreeBRObject(global);
	quit(NULL);
}


BOOL ctrl_msg(UBYTE charset, ULONG eventtype, struct TagItem *eventtags)
{
	struct TagItem *tagitem;
	unsigned char medium[100], *buf=medium;

	if(tagitem = FindTagItem(BREV_Conference, eventtags)){

		if(!fh_msg) if(!(fh_msg = Open("REPLY.HR", MODE_NEWFILE)))
			quit("Couldn't open replyfile");

		strcpy(buf, "Command: ");
		strcat(buf, eventtype==EVE_JOINCONF ? "Join" : "Resign");
		dumpstring(buf, charset);

		SPrintf(buf, "Area: %s", (char *) tagitem->ti_Data);
		dumpstring(buf, charset);

		dumpstring("Lines: 0", charset);
	} else return(FALSE);
	return(TRUE);
}


void nrml_msg(UBYTE charset, struct TagItem *eventtags)
{
	struct TagItem *tagitem;
	unsigned char tiny[8], *smallbuf=tiny;
	unsigned char medium[100], *buf=medium;
	__aligned struct FileInfoBlock inf, *fileinfo = &inf;
	unsigned char *trav;
	int i, lines=0;

	if(tagitem = FindTagItem(BREV_MsgFile, eventtags)){  // Finn fillengde
		strcpy(buf, (char *)tagitem->ti_Data);
		if(FindTagItem(BREV_PGPSignID, eventtags) || FindTagItem(BREV_PGPEncryptID,
							eventtags))
			strncat(buf, ".asc", 30);
		if(!(msg_lock = Lock(buf, ACCESS_READ))
				|| !Examine(msg_lock, fileinfo))
			quit("Can't access message file");
		UnLock(msg_lock);
		msg_lock = NULL;
	}
	else quit("Missing some tags");

	msgsize = fileinfo->fib_Size;
	if(!(message = AllocMem(msgsize, 0)))
		quit("Out of memory");

	read_msg(buf, message, msgsize);

	if(charset != BRCS_ISO && !CharsetConvert(BRCS_ISO, charset, message,
															NULL, msgsize))
		quit("Not enough mem?");

	if(!fh_msg) if(!(fh_msg = Open("REPLY.HR", MODE_NEWFILE)))
		quit("Couldn't open replyfile");

	dumpstring("Command: Post", charset);

	if(tagitem = FindTagItem(BREV_Conference, eventtags)){ // Fixer konf.
		SPrintf(buf, "Area: %s", (char *) tagitem->ti_Data);
		if(charset != BRCS_ISO && !CharsetConvert(BRCS_ISO, charset, buf,
																NULL, 0L))
			quit("Not enough mem?");

		dumpstring(buf, charset);
	}
	else quit("Missing some tags");
		
	if(GetTagData(BREV_Private, FALSE, eventtags))  // Fixer private
		dumpstring("Status: Private", charset);

	if(tagitem = FindTagItem(BREV_RefOrginalNr, eventtags)){ // Fixer replynr
		if(tagitem->ti_Data){
			stcl_d(smallbuf, tagitem->ti_Data);
			SPrintf(buf, "Reply: %s", smallbuf);
			dumpstring(buf, charset);
		}
	}

	if(tagitem = FindTagItem(BREV_Subject, eventtags)){   // Fixer subject
		if(charset != BRCS_ISO) CharsetConvert(BRCS_ISO, charset, (void *)
				tagitem->ti_Data, NULL, strlen((char *)tagitem->ti_Data));
		SPrintf(buf, "Subject: %s", (char *)tagitem->ti_Data);
		dumpstring(buf, charset);
	}	

	if(tagitem = FindTagItem(BREV_ToName, eventtags)){   // Fixer mottaker
		if(charset != BRCS_ISO) CharsetConvert(BRCS_ISO, charset, (void *)
				tagitem->ti_Data, NULL, strlen((char *) tagitem->ti_Data));
		SPrintf(buf, "To: %s", (char *) tagitem->ti_Data);
		dumpstring(buf, charset);
	}

	for(i=0,trav=message; i<msgsize; i++,trav++){
		if(*trav=='\n') lines++;     // Traverserer for å finne antall linjer.
	}
	if(*(trav-1)!='\n') lines++;    // Må telle med siste linje.
	stcl_d(smallbuf, lines);
	SPrintf(buf, "Lines: %s", smallbuf);
	dumpstring(buf, charset);

	for(i=0,trav=message; i<msgsize; i++,trav++){
		if(*trav=='\n' && charset != BRCS_ISO) FPutC(fh_msg, '\r');  // Ekstra IBM CR
		FPutC(fh_msg, *trav);
	}
	if(*(trav-1)!='\n') FPutC(fh_msg, '\n');
}


void read_msg(char *filename, void *msg, int size) // Bruker fh
{
	if(!(fh = Open(filename, MODE_OLDFILE))) quit("Can't access message file");
	if(!FRead(fh, msg, size, 1))
		quit("Can't read from message file");

	Close(fh);
	fh = NULL;
}



void dumpstring(char *string, UBYTE charset)
{
	if(FPuts(fh_msg, string)==-1) quit("Error writing to file");
	if(charset==BRCS_IBN) FPutC(fh_msg, '\r');
	FPutC(fh_msg, '\n');
}

void quit(char *errmsg)
{
	BOOL *trav;
	int i=0;

	if(!arg_array[PUBSCREEN])
		PutStr(DEL_EOL CURSOR_ON);

	if(errmsg)
		Printf("%s\n", errmsg);

	Flush(Output());

	if(fh) Close(fh);
	if(fh_msg) Close(fh_msg);
	if(rdargs) FreeArgs(rdargs);

	if(mytype) FreeBRObject(mytype);
	if(eventlist){
	if(!errmsg)
			for(trav=eventlist, i=mybbs->bl_Internal->bi_FirstEvent;
				 i<=mybbs->bl_Internal->bi_LastEvent; trav++, i++){
				if(*trav)
					UpdateBREventTags(mybbs, i, UBRE_SetPacked, TRUE, TAG_DONE);
			}
		FreeMem(eventlist, (mybbs->bl_Internal->bi_LastEvent
				  -mybbs->bl_Internal->bi_FirstEvent+2)*sizeof(BOOL));
	}
	if(bbslist) FreeBRObject(bbslist);
	if(message) FreeMem(message, msgsize);
	if(msg_lock) UnLock(msg_lock);

	if(orig_lock){
		CurrentDir(orig_lock);
		UnLock(lock);
	}
	if(pb_win) ugCloseProgressBar(pb_win);

	CloseLibrary(BBSReadBase);
	CloseLibrary(UtilityBase);
	CloseLibrary(UTGuiBase);
	if(errmsg) exit(RETURN_ERROR);
	exit(0);
}
