/* 
** openurl.library - universal URL display and browser launcher library
** Written by Troels Walsted Hansen <troels@thule.no>
** Placed in the public domain.
**
** Module with all prefs related library support functions.
*/

#include "library_common.h"
#include "library_api.h"
#include "library_prefs.h"
#include "library_util.h"

/**************************************************************************
*
* Definitions.
*
*/

#define ID_BRWS MAKE_ID('B','R','W','S')
#define ID_MLRS MAKE_ID('M','L','R','S')
#define ID_FLGS MAKE_ID('F','L','G','S')
#define ID_DEFS MAKE_ID('D','E','F','S')

#define BRWS_SIZE (sizeof(struct URL_BrowserNode) - sizeof(struct MinNode))
#define MLRS_SIZE (sizeof(struct URL_MailerNode) - sizeof(struct MinNode))
#define FLGS_SIZE (sizeof(LONGBITS))
#define DEFS_SIZE (4 * sizeof(BOOL))

/**************************************************************************
*
* Externally visible functions.
*
*/

struct URL_Prefs *CopyPrefs(struct URL_Prefs *old_p)
{
	struct URL_Prefs *new_p;

	/* make a copy of a prefs structure */

	if(!(new_p = AllocMem(sizeof(struct URL_Prefs), MEMF_ANY)))
		return(NULL);

	memcpy(new_p, old_p, sizeof(struct URL_Prefs));
	NewList((struct List *)&new_p->up_BrowserList);
	NewList((struct List *)&new_p->up_MailerList);

	if(!CopyList((struct List *)&new_p->up_BrowserList, 
	             (struct List *)&old_p->up_BrowserList,
	             sizeof(struct URL_BrowserNode)))
	{
		LIB_URL_FreePrefs(new_p);
		return(NULL);
	}

	if(!CopyList((struct List *)&new_p->up_MailerList, 
	             (struct List *)&old_p->up_MailerList,
	             sizeof(struct URL_MailerNode)))
	{
		LIB_URL_FreePrefs(new_p);
		return(NULL);
	}

	return(new_p);
}

/**************************************************************************/

BOOL SavePrefs(STRPTR filename, struct URL_Prefs *up)
{
	BOOL retval = FALSE;
	struct IFFHandle *iffh;
	struct PrefHeader prhd;
	struct URL_BrowserNode *bn;
	struct URL_MailerNode *mn;

	/* init iff handle */

	if(!(iffh = AllocIFF()))
		goto done;

	if(!(iffh->iff_Stream = Open(filename, MODE_NEWFILE)))
		goto done;

	InitIFFasDOS(iffh);

	if(OpenIFF(iffh, IFFF_WRITE))
		goto done;

	/* init file as IFF PREF FORM */

	if(PushChunk(iffh, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN))
		goto done;

	/* write pref header */

	if(PushChunk(iffh, ID_PREF, ID_PRHD, sizeof(struct PrefHeader)))
		goto done;

	prhd.ph_Version = up->up_Version;
	prhd.ph_Type    = 0;
	prhd.ph_Flags   = 0;

	if(WriteChunkBytes(iffh, &prhd, sizeof(struct PrefHeader)) 
        != sizeof(struct PrefHeader))
		goto done;

	if(PopChunk(iffh))
		goto done;

	/* write browser nodes */

	for(bn = (struct URL_BrowserNode *)Prefs->up_BrowserList.mlh_Head;
	    bn->ubn_Node.mln_Succ;
	    bn = (struct URL_BrowserNode *)bn->ubn_Node.mln_Succ)
	{
		if(PushChunk(iffh, ID_PREF, ID_BRWS, BRWS_SIZE))
			goto done;

		if(WriteChunkBytes(iffh, &bn->ubn_Flags, BRWS_SIZE) != BRWS_SIZE)
			goto done;

		if(PopChunk(iffh))
			goto done;
	}

	/* write mailer nodes */

	for(mn = (struct URL_MailerNode *)Prefs->up_MailerList.mlh_Head;
	    mn->umn_Node.mln_Succ;
	    mn = (struct URL_MailerNode *)mn->umn_Node.mln_Succ)
	{
		if(PushChunk(iffh, ID_PREF, ID_MLRS, MLRS_SIZE))
			goto done;

		if(WriteChunkBytes(iffh, &mn->umn_Flags, MLRS_SIZE) != MLRS_SIZE)
			goto done;

		if(PopChunk(iffh))
			goto done;
	}

	/* write flags */

	if(PushChunk(iffh, ID_PREF, ID_FLGS, FLGS_SIZE))
		goto done;

	if(WriteChunkBytes(iffh, &Prefs->up_Flags, FLGS_SIZE) != FLGS_SIZE)
		goto done;

	if(PopChunk(iffh))
		goto done;

	/* write defaults */

	if(PushChunk(iffh, ID_PREF, ID_DEFS, DEFS_SIZE))
		goto done;

	if(WriteChunkBytes(iffh, &Prefs->up_DefShow, DEFS_SIZE) != DEFS_SIZE)
		goto done;

	if(PopChunk(iffh))
		goto done;

	/* pop the IFF PREF FORM chunk */

	if(PopChunk(iffh))
		goto done;

	retval = TRUE;
done:
	if(iffh)
	{
		CloseIFF(iffh);
		Close(iffh->iff_Stream);
		FreeIFF(iffh);
	}

	if(!retval) DeleteFile(filename);	

	return(retval);
}

/**************************************************************************/

BOOL LoadPrefs(STRPTR filename)
{
	BOOL retval = FALSE;
	struct IFFHandle *iffh = NULL;
	struct ContextNode *cn;
	struct PrefHeader prhd;

	ObtainSemaphore(&PrefsSemaphore);

	/* allocate main prefs structure */

	if(!(Prefs = AllocMem(sizeof(struct URL_Prefs), MEMF_CLEAR)))
		goto done;

	Prefs->up_Version = PREFS_VERSION;
	NewList((struct List *)&Prefs->up_BrowserList);
	NewList((struct List *)&Prefs->up_MailerList);

	/* init iff handle */

	if(!(iffh = AllocIFF()))
		goto done;

	if(!(iffh->iff_Stream = Open(filename, MODE_OLDFILE)))
		goto done;

	InitIFFasDOS(iffh);

	if(OpenIFF(iffh, IFFF_READ))
		goto done;

	/* stop at these chunks */

	if(StopChunk(iffh, ID_PREF, ID_PRHD))
		goto done;

	if(StopChunk(iffh, ID_PREF, ID_DEFS))
		goto done;

	if(StopChunk(iffh, ID_PREF, ID_FLGS))
		goto done;

	if(StopChunk(iffh, ID_PREF, ID_MLRS))
		goto done;

	if(StopChunk(iffh, ID_PREF, ID_BRWS))
		goto done;

	/* check that we got a prefheader of the right version */

	if(ParseIFF(iffh, IFFPARSE_SCAN))
		goto done;

	if(!(cn = CurrentChunk(iffh)))
		goto done;

	if((cn->cn_Type != ID_PREF) || (cn->cn_ID != ID_PRHD) || 
	   (cn->cn_Size != sizeof(struct PrefHeader)))
		goto done;

	if(ReadChunkBytes(iffh, &prhd, cn->cn_Size) != cn->cn_Size)
		goto done;

	if(prhd.ph_Version > PREFS_VERSION)
		goto done;

	if(prhd.ph_Version < 2)
		SetDefaultPrefsV2(Prefs);

	if(prhd.ph_Version < 3)
		SetDefaultPrefsV3(Prefs);

	/* read browser nodes */

	while(1)
	{
		ULONG error;

		error = ParseIFF(iffh, IFFPARSE_SCAN);
		if(error == IFFERR_EOF) break;
		else if(error) goto done;

		if(!(cn = CurrentChunk(iffh)))
			goto done;

		if(cn->cn_Type != ID_PREF)
			continue;

		if((cn->cn_ID == ID_BRWS) && (cn->cn_Size == BRWS_SIZE))
		{
			struct URL_BrowserNode *bn;

			if(!(bn = AllocMem(sizeof(struct URL_BrowserNode), MEMF_CLEAR)))
				goto done;

			if(ReadChunkBytes(iffh, &bn->ubn_Flags, cn->cn_Size) != cn->cn_Size)
			{
				FreeMem(bn, sizeof(struct URL_BrowserNode));
				goto done;
			}

			AddTail((struct List *)&Prefs->up_BrowserList, (struct Node *)bn);
		}
		else if((cn->cn_ID == ID_MLRS) && (cn->cn_Size == MLRS_SIZE))
		{
			struct URL_MailerNode *mn;

			if(!(mn = AllocMem(sizeof(struct URL_MailerNode), MEMF_CLEAR)))
				goto done;

			if(ReadChunkBytes(iffh, &mn->umn_Flags, cn->cn_Size) != cn->cn_Size)
			{
				FreeMem(mn, sizeof(struct URL_MailerNode));
				goto done;
			}

			AddTail((struct List *)&Prefs->up_MailerList, (struct Node *)mn);
		}
		else if((cn->cn_ID == ID_FLGS) && (cn->cn_Size == FLGS_SIZE))
		{
			if(ReadChunkBytes(iffh, &Prefs->up_Flags, cn->cn_Size) != cn->cn_Size)
				goto done;
		}
		else if((cn->cn_ID == ID_DEFS) && (cn->cn_Size == DEFS_SIZE))
		{
			if(ReadChunkBytes(iffh, &Prefs->up_DefShow, cn->cn_Size) != cn->cn_Size)
				goto done;
		}
	}

	Prefs->up_Flags &= ~UPF_ISDEFAULTS;

	if(prhd.ph_Version == 2)
		ConvertPrefsV2toV3(Prefs);

	retval = TRUE;
done:
	if(iffh)
	{
		CloseIFF(iffh);
		Close(iffh->iff_Stream);
		FreeIFF(iffh);
	}

	if(Prefs && !retval)
	{
		LIB_URL_FreePrefs(Prefs);
		Prefs = NULL;
	}

	ReleaseSemaphore(&PrefsSemaphore);

	return(retval);
}

/**************************************************************************/

BOOL SetDefaultPrefsV1(struct URL_Prefs *up)
{
	struct URL_BrowserNode *bn;

	NewList((struct List *)&up->up_BrowserList);

	if(!(bn = AllocMem(sizeof(struct URL_BrowserNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(bn->ubn_Name, "AMosaic");
	strcpy(bn->ubn_Path, "AMosaic \"%u\"");
	strcpy(bn->ubn_Port, "AMOSAIC");
	strcpy(bn->ubn_ShowCmd, "SHOW");
	strcpy(bn->ubn_ToFrontCmd, "SCREEN FRONT");
	strcpy(bn->ubn_OpenURLCmd, "JUMP URL \"%u\"");

	AddTail((struct List *)&up->up_BrowserList, (struct Node *)bn);

	if(!(bn = AllocMem(sizeof(struct URL_BrowserNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(bn->ubn_Name, "AWeb");
	strcpy(bn->ubn_Path, "AWeb-II:AWeb \"%u\"");
	strcpy(bn->ubn_Port, "AWEB");
	strcpy(bn->ubn_ShowCmd, "ICONIFY SHOW");
	strcpy(bn->ubn_ToFrontCmd, "SCREENTOFRONT");
	strcpy(bn->ubn_OpenURLCmd, "OPEN \"%u\"");
	strcpy(bn->ubn_OpenURLWCmd, "NEW \"%u\"");

	AddTail((struct List *)&up->up_BrowserList, (struct Node *)bn);

	if(!(bn = AllocMem(sizeof(struct URL_BrowserNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(bn->ubn_Name, "IBrowse");
	strcpy(bn->ubn_Path, "IBrowse \"%u\"");
	strcpy(bn->ubn_Port, "IBROWSE");
	strcpy(bn->ubn_ShowCmd, "SHOW");
	strcpy(bn->ubn_ToFrontCmd, "SCREENTOFRONT");
	strcpy(bn->ubn_OpenURLCmd, "GOTOURL \"%u\"");
	strcpy(bn->ubn_OpenURLWCmd, "NEWWINDOW \"%u\"");

	AddTail((struct List *)&up->up_BrowserList, (struct Node *)bn);

	if(!(bn = AllocMem(sizeof(struct URL_BrowserNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(bn->ubn_Name, "moreHTML");
	strcpy(bn->ubn_Port, "MOREHTML");
	strcpy(bn->ubn_ShowCmd, "SHOW");
	strcpy(bn->ubn_ToFrontCmd, "SCREENTOFRONT");
	strcpy(bn->ubn_OpenURLCmd, "OPEN URL \"%u\"");

	AddTail((struct List *)&up->up_BrowserList, (struct Node *)bn);

	if(!(bn = AllocMem(sizeof(struct URL_BrowserNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(bn->ubn_Name, "Voyager");

	if(GetVar("Vapor/Voyager_LASTUSEDDIR", bn->ubn_Path, 
	          UBN_PATH_LEN, GVF_GLOBAL_ONLY) != -1)
		AddPart(bn->ubn_Path, "V \"%u\"", UBN_PATH_LEN);

	strcpy(bn->ubn_Port, "VOYAGER");
	strcpy(bn->ubn_ShowCmd, "SHOW");
	strcpy(bn->ubn_ToFrontCmd, "SCREENTOFRONT");
	strcpy(bn->ubn_OpenURLCmd, "OPENURL \"%u\"");
	strcpy(bn->ubn_OpenURLWCmd, "OPENURL \"%u\" NEWWIN");

	AddTail((struct List *)&up->up_BrowserList, (struct Node *)bn);

	return(TRUE);
}

/**************************************************************************/

VOID SetDefaultPrefsV2(struct URL_Prefs *up)
{
	up->up_DefShow         = TRUE;
	up->up_DefBringToFront = TRUE;
	up->up_DefNewWindow    = FALSE;
	up->up_DefLaunch       = TRUE;
}

/**************************************************************************/

BOOL SetDefaultPrefsV3(struct URL_Prefs *up)
{
	struct URL_MailerNode *mn;

	up->up_Flags |= UPF_PREPENDHTTP;
	up->up_Flags |= UPF_DOMAILTO;

	NewList((struct List *)&up->up_MailerList);

	if(!(mn = AllocMem(sizeof(struct URL_MailerNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(mn->umn_Name, "MicroDot II");
	GetVar("Vapor/MD2_LASTUSEDDIR", mn->umn_Path, UMN_PATH_LEN, GVF_GLOBAL_ONLY);
	AddPart(mn->umn_Path, "MicroDot TO=\"%a\" SUBJECT=\"%s\" CONTENTS=\"%f\"", UMN_PATH_LEN);
	strcpy(mn->umn_Port, "MD");
	strcpy(mn->umn_ShowCmd, "SHOW");
	strcpy(mn->umn_WriteMailCmd, "NEWMSGWINDOW TO=\"%a\" SUBJECT=\"%s\" CONTENTS=\"%f\"");

	AddTail((struct List *)&up->up_MailerList, (struct Node *)mn);

	if(!(mn = AllocMem(sizeof(struct URL_MailerNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(mn->umn_Name, "THOR");
	strcpy(mn->umn_Path, "SYS:Rexxc/RX ");
	GetVar("THOR/THORPath", &mn->umn_Path[13], UMN_PATH_LEN - 13, GVF_GLOBAL_ONLY);
	AddPart(mn->umn_Path, "Rexx/SendThorMail.rexx ADDRESS=\"%a\" SUBJECT=\"%s\" TEXT=\"%f\"", UMN_PATH_LEN);

	AddTail((struct List *)&up->up_MailerList, (struct Node *)mn);

	if(!(mn = AllocMem(sizeof(struct URL_MailerNode), MEMF_CLEAR)))
		return(FALSE);

	strcpy(mn->umn_Name, "YAM 2.0");
	strcpy(mn->umn_Path, "YAM:YAM MAILTO=\"%a\" SUBJECT=\"%s\" LETTER=\"%f\"");
	strcpy(mn->umn_Port, "YAM");
	strcpy(mn->umn_ShowCmd, "SHOW");
	strcpy(mn->umn_ToFrontCmd, "SCREENTOFRONT");
	strcpy(mn->umn_WriteMailCmd, "\"MAILWRITE; WRITETO '%a'; WRITESUBJECT '%s'; WRITELETTER '%f'\"");

	AddTail((struct List *)&up->up_MailerList, (struct Node *)mn);
}

/**************************************************************************/

VOID ConvertPrefsV2toV3(struct URL_Prefs *up)
{
	struct URL_BrowserNode *bn;

	for(bn = (struct URL_BrowserNode *)Prefs->up_BrowserList.mlh_Head;
	    bn->ubn_Node.mln_Succ;
	    bn = (struct URL_BrowserNode *)bn->ubn_Node.mln_Succ)
	{
		STRPTR p;

		if(bn->ubn_Flags & UBNF_URLONCMDLINE)
		{
			int len = strlen(bn->ubn_Path);

			if(len && (len < (UBN_PATH_LEN - 5)))
				strcpy(&bn->ubn_Path[len], " \"%u\"");

			bn->ubn_Flags &= ~UBNF_URLONCMDLINE;
		}

		if((p = strstr(bn->ubn_OpenURLCmd, "%s")))
			*(p + 1) = 'u';

		if((p = strstr(bn->ubn_OpenURLWCmd, "%s")))
			*(p + 1) = 'u';
	}
}
