/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Author : Alexandre Parenteau <aubonbeurre@hotmail.com> --- December 1997
 */

/*
 * CvsPrefs.cpp --- class to handle CVS settings
 */

#include "stdafx.h"

#include <string.h>
#include <stdlib.h>
#include "CvsPrefs.h"
#include "Authen.h"
#include "AppConsole.h"
#include "CvsArgs.h"
#include "MultiString.h"
#include "FileTraversal.h"

#ifdef TARGET_OS_MAC
#	define PCVS "\pCVSROOT"
#	include <Resources.h>
#	include <Folders.h>
#	include <MacErrors.h>
#	include <TextUtils.h>
#	include "VolsPaths.h"
#	include "MacMisc.h"
#	include "AppGlue.h"
#endif /* TARGET_OS_MAC */

#ifdef HAVE_UNISTD_H
#	include <unistd.h>
#endif

#ifdef HAVE_PWD_H
#	include <pwd.h>
#endif

#ifdef WIN32
#	include "WinCvsBrowser.h"
#	include "wincvs.h"
#	include "wincvs_winutil.h"
#	ifdef _DEBUG
#	define new DEBUG_NEW
#	undef THIS_FILE
	static char THIS_FILE[] = __FILE__;
#	endif
#endif /* WIN32 */

#ifdef qMacCvsPP
#	include "GUSIInternal.h"
#	include "GUSIFileSpec.h"
#	include "MacCvsApp.h"
#	include <UProcess.h>
#endif

#if qUnix
#	include "UCvsApp.h"
#	include "UCvsFolders.h"
#endif

CvsPrefs gCvsPrefs;

static CPersistentInt gPersistentShema("P_PersistentShema", SCHEMA_0);

static CPersistentBool gCheckoutRO("P_CheckoutRO", true, kAddSettings);
static CPersistentBool gZ9Option("P_Z9Option", false, kAddSettings);
static CPersistentBool gPruneOption("P_PruneOption", true, kAddSettings);
static CPersistentBool gQuietOption("P_QuietOption", false);
static CPersistentInt gIsoConvert("P_NIsoConvert", ISO8559_none, kAddSettings);
static CPersistentBool gICTextOption("P_ICTextOption", false, kAddSettings);
static CPersistentBool gAddBinControl("P_AddBinControl", true);
static CPersistentBool gUseViewerAlways("P_UseViewerAlways", false, kAddSettings);
static CPersistentInt gMacBinEncoding("P_NMacBinEncoding", MAC_HQX, kAddSettings);
static CPersistentInt gUseShell("P_UseShell", SHELL_TCL);

static PCPStr gCvsroot("P_Cvsroot");
CMString gOldCvsroots(20, "P_OldCvsroots");

// migration
#ifndef MIGRATECVSROOTLIST
static PCPStr gCvsroot1("P_Cvsroot1");
static PCPStr gCvsroot2("P_Cvsroot2");
static PCPStr gCvsroot3("P_Cvsroot3");
static PCPStr gCvsroot4("P_Cvsroot4");
static PCPStr gCvsroot5("P_Cvsroot5");
static PCPStr gCvsroot6("P_Cvsroot6");
static PCPStr gCvsroot7("P_Cvsroot7");
static PCPStr gCvsroot8("P_Cvsroot8");
static PCPStr gCvsroot9("P_Cvsroot9");
static PCPStr gCvsroot10("P_Cvsroot10");
static PCPStr gCvsroot11("P_Cvsroot11");
static PCPStr gCvsroot12("P_Cvsroot12");
static PCPStr gCvsroot13("P_Cvsroot13");
static PCPStr gCvsroot14("P_Cvsroot14");
static PCPStr gCvsroot15("P_Cvsroot15");
static PCPStr gCvsroot16("P_Cvsroot16");
static PCPStr gCvsroot17("P_Cvsroot17");
static PCPStr gCvsroot18("P_Cvsroot18");
static PCPStr gCvsroot19("P_Cvsroot19");
static PCPStr gCvsroot20("P_Cvsroot20");
#endif 

static CPersistentInt gKserverPort("P_KserverPort", -1, kAddSettings);
static CPersistentInt gPserverPort("P_PserverPort", -1, kAddSettings);
static CPersistentInt gRhostPort("P_RhostPort", -1, kAddSettings);
static PCPStr gServerName("P_ServerName", 0L, kAddSettings);
static PCStr gRshName("P_RshName", 0L, kAddSettings);
static CPersistentBool gEncryptCommunication("P_EncryptCommunication", false, kAddSettings);

#ifndef qUnix
static PCStr gHome("P_Home", 0L, kAddSettings);
#endif /* !qUnix */
#ifdef qUnix
static PCStr gViewer("P_Viewer", "emacs"); // not vi ;-)
#else
static PCStr gViewer("P_Viewer", "Notepad");
#endif
static PCStr gHelper("P_Helper", "netscape");
static PCStr gBrowser("P_Browser", "gmc");
#ifdef qUnix
static PCStr gExtdiff("P_Extdiff", "emacs");
#elif TARGET_RT_MAC_MACHO
static PCStr gExtdiff("P_Extdiff", "opendiff");
#else
static PCStr gExtdiff("P_Extdiff", "");
#endif
static CPersistentBool gDirtySupport("P_DirtySupport", true, kAddSettings);
static CPersistentBool gAlwaysUseCvsroot("P_AlwaysUseCvsroot", false, kAddSettings);
static CPersistentInt gLogoutTimeOut("P_LogoutTimeOut", 0);
static PCStr gProxyHost("P_ProxyHost", "www.mydomain", kAddSettings);
static CPersistentInt gProxyPort("P_ProxyPort", 8888, kAddSettings);
static CPersistentBool gUseProxy("P_UseProxy", false, kAddSettings);
static CPersistentBool gUnixLF("P_UnixLF", false, kAddSettings);
static CPersistentBool gMacLF("P_MacLF", false, kAddSettings);
static CPersistentInt gZLevel("P_ZLevel", 9, kAddSettings);
static CPersistentInt gCvsVersion("P_CvsVersion", 0, kAddSettings);
static CPersistentBool gCvsConsole("P_CvsConsole", false, kAddSettings);
static CPersistentInt gWordWrapLogMsg("P_WordWrapLogMsg", 0, kAddSettings);
static PCStr gLastWorkingDir("P_LastWorkingDir", 0L, kAddSettings);

static CPersistentBool gDisableSplashScreen("P_DisableSplashScreen", false);
static CPersistentInt gStatusOutputType("P_StatusOutputType", STATUSOUTPUT_VERBOSE);

static CPersistentBool gHideCommandDlgUpdate("P_HideCommandDlgUpdate", false);
static CPersistentBool gHideCommandDlgDiff("P_HideCommandDlgDiff", false);
static CPersistentBool gHideCommandDlgLog("P_HideCommandDlgLog", false);
static CPersistentBool gHideCommandDlgGraph("P_HideCommandDlgGraph", false);
static CPersistentBool gHideCommandDlgAnnotate("P_HideCommandDlgAnnotate", false);
static CPersistentBool gHideCommandDlgStatus("P_HideCommandDlgStatus", false);
static CPersistentBool gHideCommandDlgUseShift("P_HideCommandDlgUseShift", true);

static CKeyString gWhichCvs(10, "P_WhichCvs" );
static CPersistentBool gUseAltCvs("P_UseAltCvs", false, kAddSettings);
static PCStr gSettingsFolder("P_SettingsFolder", 0L);

bool CvsPrefs::CheckoutRO(void) const {return gCheckoutRO;}
bool CvsPrefs::Z9Option(void) const
{
#if TARGET_RT_MAC_CFM
	// because of the problem with LSH...
	return true;
#endif
	return gZ9Option;
}
bool CvsPrefs::PruneOption(void) const {return gPruneOption;}
bool CvsPrefs::QuietOption(void) const {return gQuietOption;}
ISO8559 CvsPrefs::IsoConvert(void) const {return (ISO8559)(int)gIsoConvert;}
bool CvsPrefs::ICTextOption(void) const {return gICTextOption;}
bool CvsPrefs::AddControl(void) const {return gAddBinControl;}
bool CvsPrefs::UseViewerAlways(void) const {return gUseViewerAlways;}
MACENCODING CvsPrefs::MacBinEncoding(void) const {return (MACENCODING)(int)gMacBinEncoding;}
int CvsPrefs::KserverPort(void) const {return gKserverPort;}
int CvsPrefs::PserverPort(void) const {return gPserverPort;}
int CvsPrefs::RhostPort(void) const {return gRhostPort;}

const char* CvsPrefs::ServerName(void) const
{
	return gServerName.empty() ? 0L : (const char*)gServerName;
}
const char* CvsPrefs::RshName(void) const
{
	return gRshName.empty() ? 0L : (const char*)gRshName;
}
bool CvsPrefs::EncryptCommunication(void) const {return gEncryptCommunication;}

const char* CvsPrefs::Home(void) const
{
#if !qUnix && !TARGET_RT_MAC_MACHO
#	ifdef WIN32
	// Windows 98 doesn't like C:\/.cvspass
	if(!gHome.empty() && gHome.endsWith(kPathDelimiter))
	{
		gHome[gHome.length() - 1] = '\0';
	}
#	endif
	return gHome.empty() ? 0L : (const char*)gHome;
#else /* qUnix */
	static CStr home;
	if (!home.empty())
		return home;

	char *env = getenv ("HOME");
	struct passwd *pw;
	if (env)
		home = env;
	else if ((pw = (struct passwd *) getpwuid (getuid ()))
			 && pw->pw_dir)
		home = pw->pw_dir;
	else
		return 0L;

	return home;
#endif /* qUnix */
}
const char* CvsPrefs::Viewer(void) const
{
	return gViewer.empty() ? 0L : (const char*)gViewer;
}
const char* CvsPrefs::Helper(void) const
{
	return gHelper.empty() ? 0L : (const char*)gHelper;
}
const char* CvsPrefs::Browser(void) const
{
	return gBrowser.empty() ? 0L : (const char*)gBrowser;
}
const char* CvsPrefs::ExtDiff(void) const
{
	return gExtdiff.empty() ? 0L : (const char*)gExtdiff;
}
bool CvsPrefs::DirtySupport(void) const {return gDirtySupport;}
int CvsPrefs::LogoutTimeOut(void) const {return gLogoutTimeOut;}
bool CvsPrefs::AlwaysUseCvsroot(void) const {return gAlwaysUseCvsroot;}
const char* CvsPrefs::ProxyHost(void) const {return gProxyHost;}
int CvsPrefs::ProxyPort(void) const {return gProxyPort;}
bool CvsPrefs::UseProxy(void) const {return gUseProxy;}
bool CvsPrefs::UnixLF(void) const {return gUnixLF;}
bool CvsPrefs::MacLF(void) const {return gMacLF;}
int CvsPrefs::ZLevel(void) const {return gZLevel;}
int CvsPrefs::CvsVersion(void) const {return gCvsVersion;}
bool CvsPrefs::CvsConsole(void) const {return gCvsConsole;}
int CvsPrefs::WordWrapLogMsg(void) const {return gWordWrapLogMsg;}
SHELL_KIND CvsPrefs::GetUseShell(void) const {return (SHELL_KIND)(int)gUseShell;}
bool CvsPrefs::DisableSplashScreen(void) const {return gDisableSplashScreen;}
STATUSOUTPUT_TYPE CvsPrefs::StatusOutputType(void) const {return (STATUSOUTPUT_TYPE)(int)gStatusOutputType;}
const char* CvsPrefs::SettingsFolder(void) const {return gSettingsFolder.empty() ? 0L : (const char*)gSettingsFolder;};

/* Return the current working dir (last working dir).   */
/* This directory is automatically selected when WinCVS */
/* is opened the next time. */
const char* CvsPrefs::LastWorkingDir(void) const
{
	return gLastWorkingDir.empty() ? 0L : (const char*)gLastWorkingDir;
}

bool CvsPrefs::HideCommandDlgUpdate(void) const {return gHideCommandDlgUpdate;}
bool CvsPrefs::HideCommandDlgDiff(void) const {return gHideCommandDlgDiff;}
bool CvsPrefs::HideCommandDlgLog(void) const {return gHideCommandDlgLog;}
bool CvsPrefs::HideCommandDlgGraph(void) const {return gHideCommandDlgGraph;}
bool CvsPrefs::HideCommandDlgAnnotate(void) const {return gHideCommandDlgAnnotate;}
bool CvsPrefs::HideCommandDlgStatus(void) const {return gHideCommandDlgStatus;}
bool CvsPrefs::HideCommandDlgUseShift(void) const {return gHideCommandDlgUseShift;}

void CvsPrefs::SetCheckoutRO(bool newState) {gCheckoutRO = newState;}
void CvsPrefs::SetZ9Option(bool newState) {gZ9Option = newState;}
void CvsPrefs::SetPruneOption(bool newState) {gPruneOption = newState;}
void CvsPrefs::SetQuietOption(bool newState) {gQuietOption = newState;}
void CvsPrefs::SetIsoConvert(ISO8559 newState) {gIsoConvert = (int)newState;}
void CvsPrefs::SetICTextOption(bool newState) {gICTextOption = newState;}
void CvsPrefs::SetAddControl(bool newState) {gAddBinControl = newState;}
void CvsPrefs::SetUseViewerAlways(bool newState) {gUseViewerAlways = newState;}
void CvsPrefs::SetMacBinEncoding(MACENCODING newState) {gMacBinEncoding = (int)newState;}
void CvsPrefs::SetKserverPort(int newState) {gKserverPort = newState;}
void CvsPrefs::SetPserverPort(int newState) {gPserverPort = newState;}
void CvsPrefs::SetRhostPort(int newState) {gRhostPort = newState;}
void CvsPrefs::SetServerName(const char* newservername) {gServerName = newservername;}
void CvsPrefs::SetRshName(const char* newrshname) {gRshName = newrshname;}
void CvsPrefs::SetEncryptCommunication(bool newState) {gEncryptCommunication = newState;}

void CvsPrefs::SetHome(const char* newhome)
{
#ifndef qUnix
	gHome = newhome;
#	ifdef WIN32
	// Windows 98 doesn't like C:\/.cvspass
	if(!gHome.empty() && gHome.endsWith(kPathDelimiter))
	{
		gHome[gHome.length() - 1] = '\0';
	}
#	endif
#endif /* !qUnix */
}

void CvsPrefs::SetViewer(const char* newviewer) {gViewer = newviewer;}
void CvsPrefs::SetBrowser(const char* newviewer) {gBrowser = newviewer;}
void CvsPrefs::SetHelper(const char* newviewer) {gHelper = newviewer;}
void CvsPrefs::SetExtDiff(const char* newdiff) {gExtdiff = newdiff;}
void CvsPrefs::SetDirtySupport(bool newState) {gDirtySupport = newState;}
void CvsPrefs::SetLogoutTimeOut(int newTimeout) {gLogoutTimeOut = newTimeout;}
void CvsPrefs::SetAlwaysUseCvsroot(bool newState) {gAlwaysUseCvsroot = newState;}
void CvsPrefs::SetUseProxy(bool useit) {gUseProxy = useit;}
void CvsPrefs::SetUnixLF(bool useit) {gUnixLF = useit;}
void CvsPrefs::SetMacLF(bool useit) {gMacLF = useit;}
void CvsPrefs::SetZLevel(int level) {gZLevel = level;}
void CvsPrefs::SetProxyHost(const char* newhost) {gProxyHost = newhost;}
void CvsPrefs::SetProxyPort(int newport) {gProxyPort = newport;}
void CvsPrefs::SetCvsVersion(int vers) {gCvsVersion = vers;}
void CvsPrefs::SetCvsConsole(bool console) {gCvsConsole = console;}
void CvsPrefs::SetWordWrapLogMsg(int wordwrap) {gWordWrapLogMsg = wordwrap;}
void CvsPrefs::SetLastWorkingDir(const char* workdir) {gLastWorkingDir = workdir;}
void CvsPrefs::SetUseShell(SHELL_KIND shell) {gUseShell = shell;}
void CvsPrefs::SetDisableSplashScreen(bool newState) {gDisableSplashScreen = newState;}
void CvsPrefs::SetStatusOutputType(STATUSOUTPUT_TYPE outputType) {gStatusOutputType = outputType;}
void CvsPrefs::SetSettingsFolder(const char* settingsFolder) {gSettingsFolder = settingsFolder;};

void CvsPrefs::SetHideCommandDlgUpdate(bool newState) {gHideCommandDlgUpdate = newState;}
void CvsPrefs::SetHideCommandDlgDiff(bool newState) {gHideCommandDlgDiff = newState;}
void CvsPrefs::SetHideCommandDlgLog(bool newState) {gHideCommandDlgLog = newState;}
void CvsPrefs::SetHideCommandDlgGraph(bool newState) {gHideCommandDlgGraph = newState;}
void CvsPrefs::SetHideCommandDlgAnnotate(bool newState) {gHideCommandDlgAnnotate = newState;}
void CvsPrefs::SetHideCommandDlgStatus(bool newState) {gHideCommandDlgStatus = newState;}
void CvsPrefs::SetHideCommandDlgUseShift(bool newState) {gHideCommandDlgUseShift = newState;}

bool CvsPrefs::empty(void) const  {	return gCvsroot.empty();  }
int  CvsPrefs::length(void) const {	return gCvsroot.length(); }
CvsPrefs::operator const char*() const {	return (const char*)gCvsroot; }
CvsPrefs::operator const unsigned char *() const {return (const unsigned char *)gCvsroot;}
const char* CvsPrefs::operator=(const char*newstr) {	return gCvsroot = newstr; }
const unsigned char *CvsPrefs::operator=(const unsigned char *newstr) {	return gCvsroot = newstr; }

// migration
#ifndef MIGRATECVSROOTLIST
CPStr & CvsPrefs::get_cvsroot_list(int entry)
{
	switch(entry)	{
	case  0: return gCvsroot1;	break;
	case  1: return gCvsroot2;	break;
	case  2: return gCvsroot3;	break;
	case  3: return gCvsroot4;	break;
	case  4: return gCvsroot5;	break;
	case  5: return gCvsroot6;	break;
	case  6: return gCvsroot7;	break;
	case  7: return gCvsroot8;	break;
	case  8: return gCvsroot9;	break;
	case  9: return gCvsroot10;	break;
	case 10: return gCvsroot11;	break;
	case 11: return gCvsroot12;	break;
	case 12: return gCvsroot13;	break;
	case 13: return gCvsroot14;	break;
	case 14: return gCvsroot15;	break;
	case 15: return gCvsroot16;	break;
	case 16: return gCvsroot17;	break;
	case 17: return gCvsroot18;	break;
	case 18: return gCvsroot19;	break;
	case 19: return gCvsroot20;	break;
	}
	return gCvsroot1;
}

bool CvsPrefs::has_cvsroot_in_list(const char* cvsroot, int & entry)
{
	for(int i = 0; i < NUM_CVSROOT; i++)
	{
		CPStr & str = get_cvsroot_list(i);
		if(str.empty())
			continue;
		if(strcmp(str, cvsroot) == 0)
		{
			entry = i;
			return true;
		}
	}
	return false;
}

void CvsPrefs::insert_cvsroot_in_list(const char* cvsroot)
{
	int entry;
	
	if(has_cvsroot_in_list(cvsroot, entry))
	{
		// move to the first entry
		CPStr tmp;
		tmp = get_cvsroot_list(0);
		get_cvsroot_list(0) = get_cvsroot_list(entry);
		get_cvsroot_list(entry) = tmp;
	}
	else
	{
		// push back the entry
		for(int i = (NUM_CVSROOT - 1); i >= 1; i--)
		{
			get_cvsroot_list(i) = get_cvsroot_list(i - 1);
		}
		get_cvsroot_list(0) = cvsroot;
	}
}

void CvsPrefs::flush_list(void)
{
	for(int i = 0; i < NUM_CVSROOT; i++)
	{
		get_cvsroot_list(i) = "";
	}
}

#endif /* MIGRATECVSROOTLIST */


void CvsPrefs::save(void)
{
	if(empty())
		return;

	if( SCHEMA_1 != gPersistentShema )
	{
		gPersistentShema = SCHEMA_1;
	}

	bool needSave = CPersistent::NeedSave();
	bool needSaveSettings = CPersistent::NeedSave(true);
	if(!needSave)
		return;

// migration
#ifndef MIGRATECVSROOTLIST
	// update the CVSROOT list
	insert_cvsroot_in_list((const char*)*this);
#endif 
	
	CPersistent::SaveAll();

	if(!needSaveSettings)
		return;

#ifdef WIN32
	CWincvsApp* app = (CWincvsApp *)AfxGetApp();
	SavePersistentSettings(app->GetBrowserView()->GetRoot());
#endif
#ifdef qMacCvsPP
	CMacCvsApp::SavePersistentSettings();
#endif /* qMacCvsPP */
#if qUnix
	UCvsFolders *browser = UCvsApp::gApp->GetBrowserView();
	if(browser != 0L && browser->GetRoot() != 0L)
		SavePersistentSettings(browser->GetRoot());
#endif
}

void CvsPrefs::load(void)
{
// migration
#ifndef MIGRATECVSROOTLIST
	// flush the CVSROOT list, it will be filled later
	flush_list();
#endif 

	bool loaded = CPersistent::LoadAll();

	if( loaded )
	{
		if( SCHEMA_0 == gPersistentShema )
		{
			MigrateCvsrootList();
		}

		return;
	}

	// backward compatibility
#ifdef WIN32
	UINT value;

	CString cstr = AfxGetApp()->GetProfileString(PROFILE_NAME, "CVSROOT");
	if(!cstr.IsEmpty())
		*this = (const char*)cstr;

	if((value = AfxGetApp()->GetProfileInt(PROFILE_NAME, "CheckoutRO", -1)) != -1)
		SetCheckoutRO(value ? 1 : 0);
	if((value = AfxGetApp()->GetProfileInt(PROFILE_NAME, "Z9Option", -1)) != -1)
		SetZ9Option(value ? 1 : 0);
	if((value = AfxGetApp()->GetProfileInt(PROFILE_NAME, "QuietOption", -1)) != -1)
		SetQuietOption(value ? 1 : 0);
	if((value = AfxGetApp()->GetProfileInt(PROFILE_NAME, "PruneOption", -1)) != -1)
		SetPruneOption(value ? 1 : 0);
	if((value = AfxGetApp()->GetProfileInt(PROFILE_NAME, "Authentication", -1)) != -1)
		gAuthen.setkind((AuthenKind)value);
	if((value = AfxGetApp()->GetProfileInt(PROFILE_NAME, "AddControl", -1)) != -1)
		SetAddControl(value ? 1 : 0);

	char tmp[20];
	for(int i = 0; i < NUM_CVSROOT; i++)
	{
		sprintf(tmp, "CVSROOTLIST%d", i);
		cstr = AfxGetApp()->GetProfileString(PROFILE_NAME, tmp);
		if(!cstr.IsEmpty())
			gOldCvsroots.Insert((const char*)cstr);
	}

#endif /* WIN32 */

#if defined(TARGET_OS_MAC) && !TARGET_API_MAC_CARBON
	FSSpec theFolder;
	short FRef;
	Handle hdl;
	OSErr err;
	Str255 thePath;
	
	err = MacGetPrefsFolder(theFolder, thePath);
	if(err != noErr)
		return;

	err = HSetVol(NULL, theFolder.vRefNum, theFolder.parID);
	FRef = OpenResFile(PCVS);
	if(FRef < 0)
		return;

	hdl = GetResource('CVS ', 128);
	if(hdl != NULL)
	{
		Str255 str;
		HLock(hdl);
		BlockMove(*hdl, str, (*hdl)[0] + 1);
		str[str[0] + 1] = '\0';
		*this = (const char*)str + 1;
		HUnlock(hdl);
	}
	hdl = GetResource('CHRO', 128);
	if(hdl != NULL)
	{
		SetCheckoutRO(**hdl);
	}
	hdl = GetResource('Z9OP', 128);
	if(hdl != NULL)
	{
		SetZ9Option(**hdl);
	}
	hdl = GetResource('QUIE', 128);
	if(hdl != NULL)
	{
		SetQuietOption(**hdl);
	}
	hdl = GetResource('POPT', 128);
	if(hdl != NULL)
	{
		SetPruneOption(**hdl);
	}
	hdl = GetResource('AUTH', 128);
	if(hdl != NULL)
	{
		gAuthen.setkind((AuthenKind)**hdl);
	}
	hdl = GetResource('ISOC', 128);
	if(hdl != NULL)
	{
		SetIsoConvert((ISO8559)**hdl);
	}
	hdl = GetResource('ICTO', 128);
	if(hdl != NULL)
	{
		SetICTextOption(**hdl);
	}
	hdl = GetResource('ACTL', 128);
	if(hdl != NULL)
	{
		SetAddControl(**hdl);
	}

	for(int i = 0; i < NUM_CVSROOT; i++)
	{
		hdl = GetResource('CROL', 128 + i);
		if(hdl != NULL)
		{
			HLock(hdl);
			get_cvsroot_list(i) = (const char*)*hdl;
			HUnlock(hdl);
		}
	}
	CloseResFile (FRef);
#endif /* TARGET_OS_MAC && !TARGET_API_MAC_CARBON */
}

/// Helper method to migrate into a single CMString for cvsroot history
void MigrateCvsrootList()
{
	for(int nIndex = 0; nIndex <= NUM_CVSROOT; nIndex++)
	{
		CStr cvsroot;
#ifdef WIN32
		char tmp[20];
		sprintf(tmp, "P_Cvsroot%d", nIndex);
		BYTE* ppData;
		UINT pBytes = 0;

		if( !AfxGetApp()->GetProfileBinary(PROFILE_NAME, tmp, &ppData, &pBytes) )
		{
			continue;
		}

		cvsroot = (char*)ppData;
		delete ppData;
#endif /* WIN32 */
		
#if qUnix
#endif // qUnix
		
#if qMacCvsPP
#endif // qMacCvsPP
		
		if( !cvsroot.empty() )
		{
			gOldCvsroots.Insert(cvsroot);
		}
	}
}

#ifdef WIN32
kWinVersion CvsPrefs::WhichVersion()
{
	DWORD dwVersion = GetVersion(); // Get major and minor version numbers of Windows
	DWORD dwWindowsMajorVersion =  (DWORD)(LOBYTE(LOWORD(dwVersion)));
	DWORD dwWindowsMinorVersion =  (DWORD)(HIBYTE(LOWORD(dwVersion)));
	DWORD dwBuild;

	// Get build numbers for Windows NT or Win32s
	if (dwVersion < 0x80000000)                // Windows NT
	{
		dwBuild = (DWORD)(HIWORD(dwVersion));
		return dwWindowsMajorVersion == 3 ? kWinNT35 : kWinNT4;
	}
	else if (dwWindowsMajorVersion < 4)        // Win16s
	{
		dwBuild = (DWORD)(HIWORD(dwVersion));
		return kWin16;
	}
	
	// Windows 95 -- No build numbers provided    dwBuild =  0;
	return kWin32;
}
#endif /* WIN32 */


//
// TODO: If we sometimes implement multi-threaded CVS/TCL macro 
// execution then we have to implement thread synchronization in
// IsXXXRunning and SetXXXRunning methods.
//
// NOTE! IsCvsRunning and SetCvsRunning methods are not yet
// used in Mac/Unix/WinCVS. Each of these version have had
// their own app.gCvsRunning variable. I haven't cleaned up
// the code and changed them to use this "one and only" 
// CvsRunning methods. 
//
bool CvsPrefs::IsCvsRunning(void) const
{ 
	return(fCvsRunningCounter > 0); 
}

int CvsPrefs::SetCvsRunning(bool launched)  
{ 
	if(launched) 
		fCvsRunningCounter++;
	else if(fCvsRunningCounter > 0) 
		fCvsRunningCounter--;

	return fCvsRunningCounter;		
}

bool CvsPrefs::IsTclFileRunning(void) const
{ 
	return(fTclFileRunningCounter > 0); 
}

int CvsPrefs::SetTclFileRunning(bool launched)  
{ 
	if(launched) 
		fTclFileRunningCounter++;
	else if(fTclFileRunningCounter > 0) 
		fTclFileRunningCounter--;

	return fTclFileRunningCounter;		
}

bool CvsPrefs::UseAltCvs(void) const {return gUseAltCvs;}
void CvsPrefs::SetUseAltCvs(bool useit) {gUseAltCvs = useit;}

void CvsPrefs::SetWhichCvs(const char* cvsPath)
{
	UStr appPath;

#ifdef WIN32
	HINSTANCE hInst = ::AfxGetInstanceHandle();
	char apath[512];
	DWORD len;
	if(hInst != 0L && (len = ::GetModuleFileName(hInst, apath, 512)) > 0)
	{
		CString tmp(apath);
		tmp.MakeLower();
		appPath = tmp;
	}
#elif qUnix
	appPath << EXECLIB << "/" << "cvs";
#elif TARGET_RT_MAC_MACHO
	appPath = CMacCvsApp::gApp->GetAppPath();
#endif

	if(!appPath.empty()) {
		UStr value;
		gWhichCvs.Concatenate(value, appPath, cvsPath);
		gWhichCvs.Insert(value);
	} else {
		gWhichCvs.Insert( cvsPath );
	}
}

const char* CvsPrefs::WhichCvs(UStr & path, bool userOnly) const
{
	path = "";

	UStr appPath = "";

#ifdef WIN32
	HINSTANCE hInst = ::AfxGetInstanceHandle();
	char apath[512];
	DWORD len;
	if(hInst != 0L && (len = ::GetModuleFileName(hInst, apath, 512)) > 0)
	{
		CString tmp(apath);
		tmp.MakeLower();
		appPath = tmp;
	}
#elif qUnix
	appPath << EXECLIB << "/" << "cvs";
#elif TARGET_RT_MAC_MACHO
	appPath = CMacCvsApp::gApp->GetAppPath();
#endif

	// search if beside the default cvs, the user defined one to use
	// with this application only.
	UStr candidate;
	if(!appPath.empty())
	{
		UStr value;
		gWhichCvs.Concatenate(value, appPath, "");
		TMString<UStr>::list_t::const_iterator i = gWhichCvs.Find(value);
		if(i != gWhichCvs.end())
		{
			UStr key;
			gWhichCvs.Split(*i, key, candidate);
		}
	}

	// verify this cvs exe is still there
	struct stat sb;
	if(!candidate.empty() && stat(candidate, &sb) != -1 && S_ISREG(sb.st_mode))
	{
		path = candidate;
		return path.c_str();
	}

	// fallback to the default one.
	if(userOnly)
		return 0L;

#ifdef WIN32
	CWincvsApp* app = (CWincvsApp *)AfxGetApp();

	app->GetAppPath(path);
	if(!path.endsWith(kPathDelimiter))
		path << kPathDelimiter;
	path << (gCvsPrefs.WhichVersion() == kWin32 ? "cvs95.exe" : "cvs.exe");
#elif qUnix
	if( path.empty() )
		path = EXECLIB;

	if(!path.endsWith(kPathDelimiter))
		path << kPathDelimiter;

	path << "cvs";
#elif TARGET_RT_MAC_MACHO
	path = CMacCvsApp::gApp->GetAppResourcesPath();
	if(!path.endsWith(kPathDelimiter))
		path << kPathDelimiter;
	path << "cvsgui";
#endif

	return path.c_str();
}




