/***************************************************************************
                          cconfig.cpp  -  description
                             -------------------
    begin                : Tue May 14 2002
    copyright            : (C) 2002-2005 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "cconfig.h"

#define DCLIB_CONFIG		"dclib.cfg"
#define DCTRA_CONFIG		"dctra.cfg"
#define DCHUB_CONFIG		"dchub.cfg"
#define DCPROF_CONFIG		"dcprof.cfg"
#define DCBOOKHUB_CONFIG	"dcbookhub.cfg"

#define XML_DCLIB_CONFIG	"dclib"
#define XML_DCHUB_CONFIG	"dchub"
#define XML_DCBOOKHUB_CONFIG	"dcbookhub"
#define XML_DCTRA_CONFIG	"dctra"
#define XML_DCPROF_CONFIG	"dcprof"

#define XML_IDENTIFY		"identify"
#define XML_NICK		"nick"
#define XML_SEARCHNICK		"searchnick"
#define XML_AWAYMESSAGE		"awaymessage"
#define XML_EMAIL		"email"
#define XML_ANTISPAM		"antispam"
#define XML_SPEED		"speed"
#define XML_DESCRIPTION_TAG	"descriptiontag"
#define XML_EXTENDED_HUB_COUNT	"extendedhubcount"
#define XML_SUPPRESSED_NICKS	"suppressednicks"
#define XML_AWAY_PREFIX		"awayprefix"

#define XML_EMAIL_ENABLED	"emailenabled"
#define XML_DESCRIPTION_ENABLED	"descriptionenabled"

#define XML_LOGFILE		"logfile"
#define XML_LOGFILEON		"logfileon"
#define XML_LOGFILENAME		"logfilename"
#define XML_LOGDOWNLOADS	"logdownloads"
#define XML_LOGUPLOADS		"loguploads"
#define XML_LOGDETAILS		"logdetails"

#define XML_SECURITY		"security"
#define XML_FLOODOPKICKMESSAGE	"floodopkickmessage"

#define XML_TRANSFER		"transfer"
#define XML_DOWNLOADFOLDER	"downloadfolder"
#define XML_DOWNLOADFINISHEDFOLDER	"downloadfinishedfolder"
#define XML_MINSEGSIZE		"minsegsize"
#define XML_SHAREDFOLDER	"sharedfolder"
#define XML_MAXUPLOAD		"maxupload"
#define XML_MAXUPLOADRATE	"maxuploadrate"
#define XML_MAXDOWNLOADRATE	"maxdownloadrate"
#define XML_AUTORECREATESHARELIST	"autorecreatesharelist"
#define XML_SENDMESSAGEONACTIVEMODEREQUEST "sendmessageonactivemoderequest"
#define XML_EXTRA_SLOTS_RATE	"extra_slots_rate"
#define XML_MAX_EXTRA_SLOTS	"max_extra_slots"

#define XML_CONNECTION		"connection"
#define XML_MODE		"mode"
#define XML_TCPLISTENPORT	"tcplistenport"
#define XML_CRYPTOLISTENPORT	"cryptolistenport"
#define XML_UDPLISTENPORT	"udplistenport"
#define XML_IP			"ip"
#define XML_EXTERNALIP		"externalip"

#define XML_NAME		"name"
#define XML_HUBNAME		"hubname"
#define XML_HUBHOST		"hubhost"
#define XML_DESCRIPTION		"description"
#define XML_SERVER		"server"
#define XML_HOST		"host"
#define XML_PORT		"port"
#define XML_LISTENHOST		"listenhost"
#define XML_BOOKMARK		"bookmark"
#define XML_PUBLIC		"public"
#define XML_USERCOUNT		"usercount"
#define XML_COUNTRY		"country"
#define XML_EXTRA		"extra"
#define XML_SHARED		"shared"
#define XML_MINSHARE		"minshare"
#define XML_PROFILE_NAME	"profilename"
#define XML_PROFILE		"profile"
#define XML_PASSWORD		"password"
#define XML_AUTO_CONNECT	"autoconnect"
#define XML_SSL			"ssl"
#define XML_ID			"id"
#define XML_TIME		"time"
#define XML_FILE		"file"
#define XML_FILEENTRY		"fileentry"
#define XML_TYPE		"type"
#define XML_PATH		"path"
#define XML_ALIAS		"alias"
#define XML_LOCALFILE		"localfile"
#define XML_LOCALPATH		"localpath"
#define XML_LOCALFILENAME	"localfilename"
#define XML_SIZE		"size"
#define XML_STATE		"state"
#define XML_PRIORITY		"priority"
#define XML_REMOTEFILE		"remotefile"
#define XML_MEDIUM		"medium"
#define XML_MEDIUM_FILE		"file"
#define XML_MEDIUM_BUFFER	"buffer"
#define XML_HASH		"hash"
#define XML_JUMPTO		"jumpto"
#define XML_DL_FOLDERS		"dl_folders"

#define XML_FILECHUNK		"filechunk"
#define XML_REFCOUNT		"refcount"
#define XML_CHUNK		"chunk"
#define XML_TEMPHASH		"temphash"

#define XML_SIZEDONE		"sizedone"
#define XML_MULTI		"multi"

#define XML_START		"start"
#define XML_END			"end"

#define XML_HUB			"hub"
#define XML_ACTIVE		"active"

#define XML_HUBLISTURL		"hublisturl"
#define XML_URL			"url"
#define XML_ENABLED		"enabled"

#define XML_OTHER			"other"
#define XML_HUBLISTSTORELOCAL		"hubliststorelocal"
#define XML_RECONNECTCOUNT		"reconnectcount"
#define XML_RECONNECTTIMEOUT		"reconnecttimeout"
#define XML_TRANSFERRESPONSETIMEOUT 	"transferresponsetimeout"
#define XML_TRANSFERRESENDTIMEOUT 	"transferresendtimeout"
#define XML_FORCEMOVEENABLED		"forcemoveenabled"
#define XML_DOWNLOADQUEUETIME		"downloadqueuetime"
#define XML_CHECKPRIVATEADDRESSSPACE	"checkprivateaddressspace"
#define XML_PRIVATEADDRESSSPACEONLY	"privateaddressspaceonly"

#define XML_DCLIB_PLUGINPATH		"dclibpluginpath"
#define XML_DYNAMICUPLOADRATE		"dynamicuploadrate"

#define XML_CHATSENDTOOFFLINE		"chatsendtooffline"
#define XML_CHATRECVFROMOFFLINE		"chatrecvfromoffline"

#define XML_DC				"dc"
#define XML_VERSION			"version"
#define XML_RELEASE			"release"

#define XML_MODE_ACTIVE			"active"
#define XML_MODE_PASSIVE		"passive"

#define XML_USER_UPLOAD_SLOTS		"useruploadslots"
#define XML_TRANSFER_CERT		"transfercert"
#define XML_TRANSFER_KEY		"transferkey"
#define XML_OLD_SSL_SUPPORT		"old_ssl_support"

#define XML_HUBOFFLINE_TRANSFERCLOSE	"hubofflinetransferclose"
#define XML_TRANSFER_AUTOSEARCH		"transferautosearch"
#define XML_RELOAD_HUBLIST_TIME		"reloadhublisttime"
#define XML_RECREATE_SHARELIST_TIME	"recreatesharelisttime"

#define XML_DISABLEHASHLIST		"disablehashlist"
#define XML_COMPRESSEDTRANSFERS		"enablecompressedtransfers"
#define XML_ENABLE_ZPIPE		"enable_zpipe"

#define XML_TRAFFIC_RX			"trafficrx"
#define XML_TRAFFIC_TX			"traffictx"
#define XML_TRAFFIC_DATA_RX		"trafficdatarx"
#define XML_TRAFFIC_DATA_TX		"trafficdatatx"
#define XML_TRAFFIC_CONTROL_RX		"trafficcontrolrx"
#define XML_TRAFFIC_CONTROL_TX		"trafficcontroltx"

#define XML_AUTOSEARCHINTERVAL		"autosearchinterval"
#define XML_SMALLFILESIZE		"smallfilesize"

#define XML_DONTSHAREDOTFILES		"dontsharedotfiles"

#define XML_REMOTE_ENCODING		"remote_encoding"

#define XML_USERIP2_ENABLED		"userip2_enabled"

#define XML_READ_FILE_BUFFER_SIZE	"readfilebuffersize"
#define XML_NO_ADCGET_WITHOUT_TTH	"no_adcget_without_tth"
#define XML_NO_XMLLIST_WITHOUT_TTH	"no_xmllist_without_tth"
#define XML_OBSOLETE_EXT		"obsolete_ext"
#define XML_SHUFFLE_SUPPORTS		"shuffle_supports"
#define XML_ENABLE_USER_COMMAND		"enable_usercommand"

#ifdef WIN32
#define DCGUI_CONFIG_PATH	"\\dc"
#else
#define DCGUI_CONFIG_PATH	"/.dc"
#endif

#include <stdlib.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif

#include "core/cxml.h"
#include "core/cdir.h"
#include "core/csocket.h"
#include "core/cnetaddr.h"
#include "dcobject.h"
#include "cconnectionmanager.h"
#include "cdownloadmanager.h"
#include "cdownloadqueue.h"
#include "clistenmanager.h"

#include <stdio.h>

/**
 * default hub url list - see dcpp/SettingsManager.cpp in the DC++ sources for more
 * This has been removed, defaults are added only if the list is empty in LoadDCLib().
 * The first two XML lists are enabled and the .config lists are disabled.
 */
//const char * huburl_list[] = {
//	"http://hublist.hubtracker.com/hublist.xml.bz2",
//	"http://hublist.hubtracker.com/hublist.config.bz2",
//	"http://dchublist.com/hublist.xml.bz2",
//	"http://dchublist.com/hublist.config.bz2",
//	"http://dreamland.gotdns.org/PublicHubList.config.bz2",
//	"http://hublist.awenet.info/PublicHubList.config.bz2",
//	"http://www.hublist.org/PublicHubList.config.bz2",
//	"http://www.neo-modus.com/PublicHubList.config",
//	"http://dcplusplus.sourceforge.net/PublicHubList.config.bz2",
//	"http://axljab.homelinux.org:8080/PublicHubList.config.bz2",
//	"http://dreamland.gotdns.org/PublicHubList.config",
//	"http://dc-dreamland.dhs.org/PublicHubList.config",
//	"http://web.njit.edu/~cjm3//PublicHubList.config",
//	"http://ld.yi.org/dc/PublicHubList.config",
//	"http://www.p2pitalia.com/dclist/Publichublist.config",
//	"http://www.team-ppm.com/~dawson/PublicHubList.config",
//	"http://finhublist.no-ip.org/PublicHubList.config",
//	"http://freespace.morat.net/WUKY/PublicHubList.config",
//	"http://www.1stleg.com/PublicHubList.config",
//	0	   
//};

/** */
CConfig::CConfig( CString configpath )
{
	CDir d;

	if ( configpath.IsEmpty() )
	{
		sConfigPath = CDir::HomeDirPath();
	}
	else
	{
		sConfigPath = configpath;
	}

	// create the configpath
	d.SetPath(sConfigPath);
	d.CreatePath(DCGUI_CONFIG_PATH);
	sConfigPath += DCGUI_CONFIG_PATH;
	sConfigPath += DIRSEPARATOR;

	// create chatlog path
	d.SetPath(sConfigPath);
	d.CreatePath(DCGUI_CHATLOG_PATH);

	// create plugin config path
	d.CreatePath(DCGUI_PLUGINCONFIG_PATH);

	// create image path
	d.CreatePath(DCGUI_IMAGE_PATH);

	// create filellist path
	d.CreatePath(DCGUI_FILELIST_PATH);
	
	// default settings
	sNick       = "nick";
	sSearchNick = "nick_search";
	sSpeed      = "28.8Kbps";
	m_sHost     = "127.0.0.1";
	
	m_bExternalIP  = true;
	m_tHostTimeout = time(0);
	
	eMode     = ecmPASSIVE;
	eAwayMode = euamNORMAL;

	iTCPListenPort     = 9176;
	iCryptoListenPort  = 19176;
	iUDPListenPort     = 9176;
	iMaxUpload         = 3;
	lMaxUploadRate     = 0;
	iUserUploadSlots   = 1;
	lMaxDownloadRate   = 0;
	iDownloadQueueTime = 0;
	iReconnectCount    = 3;
	iReconnectTimeout  = 60;

	bSendMessageOnActiveModeRequest = false;
	bHubListStoreLocal              = true;
	bForceMoveEnabled               = true;
	bAntiSpam                       = true;
	bDescriptionTag                 = true;
	m_bUseExtendedHubCount          = true;
	bCheckPrivateAddressSpace       = false;
	bPrivateAddressSpaceOnly	= false;
	bDynamicUploadRate              = false;
	bChatSendToOffline		= false;
	bChatRecvFromOffline		= true;
	bTransferAutoSearch             = false;

	iTransferResendTimeout   = 100;
	iTransferResponseTimeout = 60;
	eHubOfflineTransferClose = ectNONE;
	
	bAutoRecreateShareList = false;

	bLogFile = false;
	bLogFinishedDownloads = true;
	bLogFinishedUploads = true;
	bLogDetails = false;

	pBookmarkHubList = new CStringList<DCConfigHubItem>();
	pPublicHubList   = new CStringList<DCConfigHubItem>();
	pHubProfileMap   = new HubProfileMap();
	pOrderedBookmarks = new OrderedBookmarkMap();

	pPublicHubList_HostIndex   = new CStringList<CString>();
	pBookmarkHubList_HostIndex = new CStringList<CString>();

	sFloodOpKickMessage = "Flooding";

	m_nPublicHubID = 0;
	m_nBookHubID   = 0;

	/* plugins disabled by default - leave string empty */
	/* m_sDCLibPluginPath = DCLIB_PLUGINDIR; */

	m_nReloadHubListTime = 0;
	m_nRecreateShareListTime = 0;
	m_bCreateFile = false;
	m_bDisableHashList = false;
	
	/* not a good idea since almost everything
	 * in dclib runs on the same thread! (CManager)
	 */
	m_bCompressedTransfers = false;

	/* The previous hard coded interval was 10 minutes */
	m_nAutoSearchInterval = 600;
	/* Previous valknut value was 16KiB, DC++ increased it to 64KiB */
	m_nSmallFileSize = 65536;
	
	/** Default to false, share dot files (previous behaviour) */
	m_bDontShareDotFiles = false;
	
	/* Default to CP1252 (DC++ NMDC English default) */
	m_sRemoteEncoding = "WINDOWS-1252";
	
#if defined(__APPLE__)
	m_sLocalEncoding = "UTF-8";
#elif defined(WIN32)
	m_sLocalEncoding = "WINDOWS-1252";
#elif defined(HAVE_NL_LANGINFO)
	m_sLocalEncoding = nl_langinfo(CODESET);
	if ( m_sLocalEncoding.IsEmpty() )
	{
		m_sLocalEncoding = "UTF-8";
	}
#else
	/** Read local encoding from $LANG */
	m_sLocalEncoding = getenv("LANG");
	int pos = m_sLocalEncoding.Find('.');
	if ( pos == -1 )
	{
		m_sLocalEncoding = "UTF-8";
	}
	else
	{
		m_sLocalEncoding = m_sLocalEncoding.Mid(pos + 1);
	}
#endif
	
	/** Default to UserIP2 support enabled because it's good */
	m_bUserIP2Enabled = true;
	
	/** ZPipe support default disabled - it is a useless disaster */
	m_bEnableZPipe = false;
	
	/** Used for calculating session transfer stats */
	m_nStartDownloaded = 0;
	m_nStartUploaded = 0;
	
	/** Default to 40KiB */
	m_nReadFileBufferSize = 40960;
	
	/* work around bugs in old clients */
	m_bDisableADCGetWithoutTTH = false;
	m_bDisableXMLListWithoutTTH = false;
	
	/* obsolete peer extensions, original protocol unaffected */
	m_bEnableObsoleteExt = true;
	
	/* UserCommand on by default */
	m_bEnableUserCommand = true;
	
	/* Disabled by default since it cannot encrypt data before Supports including nick */
	m_bOldSSLSupport = false;
	
	/* All previous versions used fixed 1MiB segments */
	m_nMinSegSize = 1048576;
	
	/* Disabled, I have no idea how fast you expect to upload */
	m_nExtraSlotsRate = 0;
	
	/* Not used when rate limit is 0, but set to same as default upload slots */
	m_nMaxExtraSlots = 3;
	
	/* Enable randomizing of $Supports strings order */
	m_bShuffleSupports = true;
}

/** */
CConfig::~CConfig()
{
	SetInstance(0);
	
	delete pPublicHubList;
	pPublicHubList = 0;

	delete pOrderedBookmarks;
	pOrderedBookmarks = 0;

	delete pBookmarkHubList;
	pBookmarkHubList = 0;

	if ( pHubProfileMap )
	{
		for ( HubProfileMap::const_iterator profile_it = pHubProfileMap->begin(); profile_it != pHubProfileMap->end(); ++profile_it )
		{
			delete profile_it->second;
		}
		pHubProfileMap->clear();
		delete pHubProfileMap;
		pHubProfileMap = 0;
	}

	delete pPublicHubList_HostIndex;
	pPublicHubList_HostIndex = 0;

	delete pBookmarkHubList_HostIndex;
	pBookmarkHubList_HostIndex = 0;
}

/** */
int CConfig::LoadDCLib()
{
	int err = 0;

	CString s = sConfigPath + DCLIB_CONFIG;

	CXml * xml = new CXml();

	if ( xml->ParseFile(s) && xml->DocFirstChild() )
	{
		do
		{
			if ( (xml->Name() == XML_DCLIB_CONFIG) && xml->FirstChild() )
			{
				ParseDCLibConfig(xml);
				xml->Parent();
			}
		}
		while ( xml->NextNode() );
	}
	else
	{
		err = -1;
	}

	// add default urls only if the list is empty
	if ( pHubListUrlList.Count() == 0 )
	{
		/* adc:// or adcs:// hubs will not be shown */
		DCConfigHubListUrl * hublisturl = new DCConfigHubListUrl();
		hublisturl->sUrl = "http://hublist.openhublist.org/hublist.xml.bz2";
		hublisturl->bEnabled = true;
		pHubListUrlList.Add(hublisturl);
		
		hublisturl = new DCConfigHubListUrl();
		hublisturl->sUrl = "http://hublist.openhublist.org/hublist.config.bz2";
		hublisturl->bEnabled = false;
		pHubListUrlList.Add(hublisturl);
		
		hublisturl = new DCConfigHubListUrl();
		hublisturl->sUrl = "http://dchublist.com/hublist.xml.bz2";
		hublisturl->bEnabled = true;
		pHubListUrlList.Add(hublisturl);
		
		hublisturl = new DCConfigHubListUrl();
		hublisturl->sUrl = "http://dchublist.com/hublist.config.bz2";
		hublisturl->bEnabled = false;
		pHubListUrlList.Add(hublisturl);
	}

	delete xml;

	return err;
}

/** */
int CConfig::SaveDCLib()
{
	int err=0;
	CString s;
	CXml * xml = new CXml();

	xml->NewDoc(XML_DCLIB_CONFIG);

	// identify
	xml->StartNewChild( XML_IDENTIFY );
	xml->NewStringChild( XML_NICK,        sNick );
	xml->NewStringChild( XML_SEARCHNICK,  sSearchNick );
	xml->NewStringChild( XML_AWAYMESSAGE, sAwayMessage );
	xml->NewStringChild( XML_EMAIL,       sEMail );
	xml->NewStringChild( XML_DESCRIPTION, sDescription );
	xml->NewStringChild( XML_AWAY_PREFIX, sAwayPrefix );
	xml->NewStringChild( XML_SPEED,       sSpeed );
	xml->NewBoolChild( XML_ANTISPAM, bAntiSpam );
	xml->NewBoolChild( XML_DESCRIPTION_TAG, bDescriptionTag );
	xml->NewBoolChild( XML_EXTENDED_HUB_COUNT, m_bUseExtendedHubCount );
	xml->Parent();

	// logfile
	xml->StartNewChild( XML_LOGFILE );
	xml->NewBoolChild( XML_LOGFILEON, bLogFile );
	xml->NewStringChild( XML_LOGFILENAME, sLogFile );
	xml->NewBoolChild( XML_LOGDOWNLOADS, bLogFinishedDownloads );
	xml->NewBoolChild( XML_LOGUPLOADS, bLogFinishedUploads );
	xml->NewBoolChild( XML_LOGDETAILS, bLogDetails );
	xml->NewStringChild( XML_FLOODOPKICKMESSAGE, sFloodOpKickMessage );
	xml->Parent();
	
	// transfer
	xml->StartNewChild( XML_TRANSFER );
	xml->NewStringChild( XML_DOWNLOADFOLDER, sDownloadFolder );
	xml->NewStringChild( XML_DOWNLOADFINISHEDFOLDER, sDownloadFinishedFolder );
	xml->NewBoolChild( XML_TRANSFER_AUTOSEARCH, bTransferAutoSearch );
	xml->NewNumericChild( XML_MINSEGSIZE, m_nMinSegSize );

	DCConfigShareFolder * csf = 0;

	while( (csf=SharedFolders.Next(csf)) != 0 )
	{
		xml->StartNewChild( XML_SHAREDFOLDER );
		xml->NewStringChild( XML_PATH, csf->m_sPath );
		xml->NewStringChild( XML_ALIAS, csf->m_sAlias );
		xml->Parent();
	}

	xml->NewBoolChild( XML_AUTORECREATESHARELIST, bAutoRecreateShareList );
	xml->NewNumericChild( XML_RECREATE_SHARELIST_TIME, m_nRecreateShareListTime );

	xml->NewNumericChild( XML_MAXUPLOAD, iMaxUpload );
	xml->NewNumericChild( XML_USER_UPLOAD_SLOTS, iUserUploadSlots );
	xml->NewNumericChild( XML_MAXUPLOADRATE, lMaxUploadRate );
	xml->NewNumericChild( XML_MAXDOWNLOADRATE, lMaxDownloadRate );
	xml->NewNumericChild( XML_EXTRA_SLOTS_RATE, m_nExtraSlotsRate );
	xml->NewNumericChild( XML_MAX_EXTRA_SLOTS, m_nMaxExtraSlots );
	xml->NewNumericChild( XML_DOWNLOADQUEUETIME, iDownloadQueueTime );
	xml->NewBoolChild( XML_DYNAMICUPLOADRATE, bDynamicUploadRate );
	xml->NewStringChild( XML_TRANSFER_CERT, m_sTransferCert );
	xml->NewStringChild( XML_TRANSFER_KEY, m_sTransferKey );
	xml->NewBoolChild( XML_OLD_SSL_SUPPORT, m_bOldSSLSupport );
	xml->NewNumericChild( XML_HUBOFFLINE_TRANSFERCLOSE, eHubOfflineTransferClose );
	
	xml->NewNumericChild( XML_TRAFFIC_RX, CSocket::m_Traffic.GetTraffic(ettRX) );
	xml->NewNumericChild( XML_TRAFFIC_TX, CSocket::m_Traffic.GetTraffic(ettTX) );
	xml->NewNumericChild( XML_TRAFFIC_DATA_RX, CSocket::m_Traffic.GetTraffic(ettDATARX) );
	xml->NewNumericChild( XML_TRAFFIC_DATA_TX, CSocket::m_Traffic.GetTraffic(ettDATATX) );
	xml->NewNumericChild( XML_TRAFFIC_CONTROL_RX, CSocket::m_Traffic.GetTraffic(ettCONTROLRX) );
	xml->NewNumericChild( XML_TRAFFIC_CONTROL_TX, CSocket::m_Traffic.GetTraffic(ettCONTROLTX) );
	xml->Parent();

	// connection
	xml->StartNewChild( XML_CONNECTION );

	if ( eMode == ecmPASSIVE )
		s = XML_MODE_PASSIVE;
	else
		s = XML_MODE_ACTIVE;
	xml->NewStringChild( XML_MODE, s );
	xml->NewNumericChild( XML_TCPLISTENPORT, iTCPListenPort );
	xml->NewNumericChild( XML_CRYPTOLISTENPORT, iCryptoListenPort );
	xml->NewNumericChild( XML_UDPLISTENPORT, iUDPListenPort );
	xml->NewBoolChild( XML_EXTERNALIP, m_bExternalIP );
	xml->NewStringChild( XML_IP, m_sHost );
	xml->NewStringChild( XML_LISTENHOST, m_sListenHost );	
	xml->NewBoolChild( XML_SENDMESSAGEONACTIVEMODEREQUEST, bSendMessageOnActiveModeRequest );
	xml->NewBoolChild( XML_CHECKPRIVATEADDRESSSPACE, bCheckPrivateAddressSpace );
	xml->NewBoolChild( XML_PRIVATEADDRESSSPACEONLY, bPrivateAddressSpaceOnly );
	xml->NewBoolChild( XML_USERIP2_ENABLED, m_bUserIP2Enabled );
	xml->Parent();

	// hublisturl
	xml->StartNewChild( XML_HUBLISTURL );

	DCConfigHubListUrl *hublisturl = 0;

	while( (hublisturl=pHubListUrlList.Next(hublisturl)) != 0 )
	{
		xml->StartNewChild( XML_URL );
		xml->NewStringChild( XML_NAME, hublisturl->sUrl );
		xml->NewBoolChild( XML_ENABLED, hublisturl->bEnabled );
		xml->Parent();
	}
	xml->Parent();

	// other
	xml->StartNewChild( XML_OTHER );

	xml->NewNumericChild( XML_RECONNECTCOUNT, iReconnectCount );
	xml->NewNumericChild( XML_RECONNECTTIMEOUT, iReconnectTimeout );
	xml->NewNumericChild( XML_TRANSFERRESPONSETIMEOUT, iTransferResponseTimeout );
	xml->NewNumericChild( XML_TRANSFERRESENDTIMEOUT, iTransferResendTimeout );
	xml->NewStringChild( XML_DCLIB_PLUGINPATH, m_sDCLibPluginPath );
	xml->NewBoolChild( XML_CHATSENDTOOFFLINE, bChatSendToOffline );
	xml->NewBoolChild( XML_CHATRECVFROMOFFLINE, bChatRecvFromOffline );
	xml->NewBoolChild( XML_HUBLISTSTORELOCAL, bHubListStoreLocal );
	xml->NewNumericChild( XML_RELOAD_HUBLIST_TIME, m_nReloadHubListTime );
	xml->NewBoolChild( XML_FORCEMOVEENABLED, bForceMoveEnabled );
	xml->NewBoolChild( XML_DISABLEHASHLIST, m_bDisableHashList );
	xml->NewBoolChild( XML_COMPRESSEDTRANSFERS, m_bCompressedTransfers );
	xml->NewBoolChild( XML_ENABLE_ZPIPE, m_bEnableZPipe );
	xml->NewNumericChild( XML_AUTOSEARCHINTERVAL, m_nAutoSearchInterval );
	xml->NewNumericChild( XML_SMALLFILESIZE, m_nSmallFileSize );
	xml->NewBoolChild( XML_DONTSHAREDOTFILES, m_bDontShareDotFiles );
	xml->NewStringChild( XML_REMOTE_ENCODING, m_sRemoteEncoding );
	xml->NewNumericChild( XML_READ_FILE_BUFFER_SIZE, m_nReadFileBufferSize );
	xml->NewBoolChild( XML_NO_ADCGET_WITHOUT_TTH, m_bDisableADCGetWithoutTTH );
	xml->NewBoolChild( XML_NO_XMLLIST_WITHOUT_TTH, m_bDisableXMLListWithoutTTH );
	xml->NewBoolChild( XML_OBSOLETE_EXT, m_bEnableObsoleteExt );
	xml->NewBoolChild( XML_SHUFFLE_SUPPORTS, m_bShuffleSupports );
	xml->NewBoolChild( XML_ENABLE_USER_COMMAND, m_bEnableUserCommand );
	
	xml->Parent();

	// save file
	s = sConfigPath + DCLIB_CONFIG;

	if ( xml->SaveConfigXmlViaTemp(s) == -1 )
	{
		err = -1;
	}

	delete xml;

	return err;
}

/** */
int CConfig::LoadDCHub()
{
	// load public hub list
	CString s = sConfigPath + DCHUB_CONFIG;
	CXml * xml = new CXml();

	if ( xml->ParseFile(s) && xml->DocFirstChild() )
	{
		do
		{
			if ( (xml->Name() == XML_DCHUB_CONFIG) && xml->FirstChild() )
			{
				ParseDCHubConfig(xml);
				xml->Parent();
			}
		}
		while ( xml->NextNode() );
	}

	// load bookmark hub list
	s = sConfigPath + DCBOOKHUB_CONFIG;

	if ( xml->ParseFile(s) && xml->DocFirstChild() )
	{
		do
		{
			if ( (xml->Name() == XML_DCBOOKHUB_CONFIG) && xml->FirstChild() )
			{
				ParseDCBookHubConfig(xml);
				xml->Parent();
			}
		}
		while ( xml->NextNode() );
	}

	delete xml;

	// add default hub entry
	if ( pBookmarkHubList->Count() == 0 )
	{
		DCConfigHubItem *hubitem = new DCConfigHubItem();

		hubitem->m_nID          = 1;
		hubitem->m_sName        = "Valknut/DCLib Chat";
		hubitem->m_sHost        = "valknut.dyndns.info:59176";
		hubitem->m_sDescription = "Valknut/DCLib Chat";

		pBookmarkHubList->Add(hubitem->m_sName,hubitem);
		pBookmarkHubList_HostIndex->Add(hubitem->m_sHost.ToUpper(),new CString(hubitem->m_sName));

		(*pOrderedBookmarks)[0] = hubitem;
		hubitem->m_nPosition = 0;

		// save bookmark list
		SaveDCBookHub();
	}

	return 0;
}

/** */
int CConfig::SaveDCHub()
{
	int err=0;

	SaveDCPublicHub();

	SaveDCBookHub();

	return err;
}

/** */
int CConfig::SaveDCPublicHub()
{
	int err=0;
	CString s;
	CXml * xml = new CXml();
	DCConfigHubItem *hubitem;

	xml->NewDoc( XML_DCHUB_CONFIG );

	// bookmarks
	xml->StartNewChild( XML_SERVER );

	// store public hub list
	if ( bHubListStoreLocal )
	{
		hubitem = 0;

		while( pPublicHubList->Next(&hubitem) != 0 )
		{
			xml->StartNewChild( XML_PUBLIC );
			xml->NewNumericChild( XML_ID,	       hubitem->m_nID );
			xml->NewStringChild(  XML_NAME,        hubitem->m_sName );
			xml->NewStringChild(  XML_HOST,        hubitem->m_sHost );
			xml->NewStringChild(  XML_DESCRIPTION, hubitem->m_sDescription );
			xml->NewNumericChild( XML_USERCOUNT,   hubitem->m_nUserCount );
			xml->NewStringChild(  XML_COUNTRY,     hubitem->m_sCountry );
			xml->NewStringChild(  XML_EXTRA,       hubitem->m_sExtra );
			xml->NewNumericChild( XML_SHARED,      hubitem->m_nShared );
			xml->NewNumericChild( XML_MINSHARE,    hubitem->m_nMinShare );
			xml->Parent();
		}
	}

	xml->Parent();

	// save file
	s = sConfigPath + DCHUB_CONFIG;

	if ( xml->SaveConfigXmlViaTemp(s) == -1 )
	{
		err = -1;
	}

	delete xml;

	return err;
}

/** */
int CConfig::SaveDCBookHub()
{
	int err=0;
	CString s;
	CXml * xml = new CXml();
	DCConfigHubItem *hubitem;

	xml->NewDoc( XML_DCBOOKHUB_CONFIG );

	// bookmarks
	xml->StartNewChild( XML_SERVER );

	hubitem = 0;

	for ( OrderedBookmarkMap::const_iterator it = pOrderedBookmarks->begin(); it != pOrderedBookmarks->end(); ++it )
	{
		hubitem = it->second;
		
		/* of course if should have been XML_BOOKMARK but changing it would cause more problems */
		xml->StartNewChild( XML_PUBLIC );
		xml->NewNumericChild( XML_ID,	        hubitem->m_nID );
		xml->NewStringChild(  XML_NAME,         hubitem->m_sName );
		xml->NewStringChild(  XML_HOST,         hubitem->m_sHost );
		xml->NewStringChild(  XML_DESCRIPTION,  hubitem->m_sDescription );
		xml->NewStringChild(  XML_PROFILE_NAME, hubitem->m_sProfile );
		xml->Parent();
	}

	xml->Parent();

	// save file
	s = sConfigPath + DCBOOKHUB_CONFIG;

	if ( xml->SaveConfigXmlViaTemp(s) == -1 )
	{
		err = -1;
	}

	delete xml;

	return err;
}

/** */
int CConfig::LoadDCTra( CStringList<CStringList<DCTransferQueueObject> > * queue, CStringList<DCFileChunkObject> * chunks )
{
	CXml * xml = new CXml();
	CString s, xml_name1, xml_name2;
	CStringList<DCTransferQueueObject> * sl1;
	DCTransferQueueObject * tqo2;
	DCHubObject * HubObject;

	s = sConfigPath + DCTRA_CONFIG;

	if ( !(xml->ParseFile(s) && xml->DocFirstChild()) )
	{
		delete xml;
		return -1;
	}

	do
	{
		if ( (xml->Name() == XML_DCTRA_CONFIG) && xml->FirstChild() )
		{
			do
			{
				if ( (xml->Name() == XML_TRANSFER) && xml->FirstChild() )
				{
					DCTransferQueueObject * TransferObject = new DCTransferQueueObject();
					TransferObject->eState = etwsIDLE;
					TransferObject->iConnections = 0;

					do
					{
						xml_name1 = xml->Name();
						if ( xml_name1 == XML_NICK )
							TransferObject->sNick = xml->Content();
						else if ( xml_name1 == XML_HUBNAME )
							TransferObject->sHubName = xml->Content();
						else if ( xml_name1 == XML_HUBHOST )
							TransferObject->sHubHost = xml->Content();
						else if ( (xml_name1 == XML_HUB) && xml->FirstChild() )
						{
							HubObject = new DCHubObject();

							do
							{
								xml_name2 = xml->Name();
								if ( xml_name2 == XML_HUBNAME )
									HubObject->m_sHubName = xml->Content();
								else if ( xml_name2 == XML_HUBHOST )
									HubObject->m_sHubHost = xml->Content();
								else if ( xml_name2 == XML_ACTIVE )
									HubObject->m_bActive = xml->GetBoolChild();
							}
							while ( xml->NextNode() );
							xml->Parent();

							TransferObject->pHubList.Add(HubObject);
						}
						else if ( (xml_name1 == XML_FILE) && xml->FirstChild() )
						{
							DCTransferFileObject * TransferFileObject = new DCTransferFileObject();

							do
							{
								xml_name2 = xml->Name();
								if ( xml_name2 == XML_REMOTEFILE )
									TransferFileObject->m_sRemoteFile = xml->Content();
								else if ( xml_name2 == XML_LOCALFILENAME )
									TransferFileObject->m_sLocalFileName = xml->Content();
								else if ( xml_name2 == XML_SIZE )
									TransferFileObject->m_nSize = xml->Content().asULL();
								else if ( xml_name2 == XML_PRIORITY )
									TransferFileObject->m_nPriority = xml->Content().asINT();
								else if ( xml_name2 == XML_STATE )
									TransferFileObject->m_eState = (eTransferFileState)xml->Content().asINT();
								else if ( xml_name2 == XML_LOCALPATH )
									TransferFileObject->m_sLocalPath = xml->Content();
								else if ( xml_name2 == XML_LOCALFILE )
									TransferFileObject->m_sLocalFile = xml->Content();
								else if ( xml_name2 == XML_TEMPHASH )
									TransferFileObject->m_stHash = xml->Content();
								else if ( xml_name2 == XML_HASH )
									TransferFileObject->m_sHash = xml->Content();
								else if ( xml_name2 == XML_MEDIUM )
								{
									if ( xml->Content() == XML_MEDIUM_BUFFER )
										TransferFileObject->m_eMedium = eltBUFFER;
									else
										TransferFileObject->m_eMedium = eltFILE;
								}
								else if ( xml_name2 == XML_MULTI )
									TransferFileObject->m_bMulti = xml->GetBoolChild();
								else if ( xml_name2 == XML_JUMPTO )
									TransferFileObject->m_sJumpTo = xml->Content();
								else if ( xml_name2 == XML_DL_FOLDERS && xml->FirstChild() )
								{
									TransferFileObject->m_pDirList = new std::list<CString>();
									
									do
									{
										if ( xml->Name() == XML_PATH )
										{
											TransferFileObject->m_pDirList->push_back( xml->Content() );
										}
									}
									while ( xml->NextNode() );
									xml->Parent();
								}
							}
							while ( xml->NextNode() );
							xml->Parent();

							// fix state
							if ( TransferFileObject->m_eState == etfsTRANSFER )
								TransferFileObject->m_eState = etfsNONE;
							TransferObject->pTransferFileList.Add( TransferFileObject->m_sRemoteFile, TransferFileObject );
						}
					}
					while ( xml->NextNode() );
					xml->Parent();

					if ( TransferObject->pTransferFileList.Count() == 0 )
					{
						delete TransferObject;
					}
					else
					{
						if ( queue->Get( TransferObject->sNick, &sl1 ) == 0 )
						{
							if ( sl1->Get( TransferObject->sHubName, &tqo2 ) == 0 )
							{
								printf("load queue: error double entrys !!!!\n");
							}
							else
							{
								sl1->Add( TransferObject->sHubName, TransferObject );
							}
						}
						else
						{
							sl1 = new CStringList<DCTransferQueueObject>();
							sl1->Add( TransferObject->sHubName, TransferObject );
							queue->Add( TransferObject->sNick, sl1 );
						}
					}
				}
				else if ( (xml->Name() == XML_FILECHUNK) && xml->FirstChild() )
				{
					DCFileChunkObject * FileChunkObject = new DCFileChunkObject();

					do
					{
						xml_name2 = xml->Name();
						if ( xml_name2 == XML_LOCALFILE )
							FileChunkObject->m_sLocalFile = xml->Content();
						else if ( xml_name2 == XML_TEMPHASH )
							FileChunkObject->m_stHash = xml->Content();
						else if ( xml_name2 == XML_HASH )
							FileChunkObject->m_sHash = xml->Content();
						else if ( xml_name2 == XML_SIZE )
							FileChunkObject->m_nSize = xml->Content().asULL();
						else if ( xml_name2 == XML_SIZEDONE )
							FileChunkObject->m_nSizeDone = xml->Content().asULL();
						else if ( xml_name2 == XML_REFCOUNT )
							FileChunkObject->m_nReferenceCount = xml->Content().asINT();
						else if ( xml_name2 == XML_MULTI )
							FileChunkObject->m_bMulti = xml->GetBoolChild();
						else if ( (xml_name2 == XML_CHUNK) && xml->FirstChild() )
						{
							DCChunkObject * ChunkObject = new DCChunkObject();

							do
							{
								if ( xml->Name() == XML_START )
									ChunkObject->m_nStart = xml->Content().asULL();
								else if ( xml->Name() == XML_END )
									ChunkObject->m_nEnd = xml->Content().asULL();
							}
							while ( xml->NextNode() );
							xml->Parent();

							FileChunkObject->m_Chunks.Add(ChunkObject);
						}
					}
					while ( xml->NextNode() );
					xml->Parent();

					chunks->Add( FileChunkObject->m_sLocalFile, FileChunkObject );
				}
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
	}
	while ( xml->NextNode() );

	delete xml;

	return 0;
}

/** */
int CConfig::SaveDCTra( CStringList<CStringList<DCTransferQueueObject> > * queue, CStringList<DCFileChunkObject> * chunks )
{
	int err = 0;
	CString s;
	DCTransferQueueObject * TransferObject;
	DCFileChunkObject * FileChunkObject;
	DCChunkObject * ChunkObject;
	DCHubObject * HubObject;

	CStringList<DCTransferQueueObject> * sl1;

	CXml * xml = new CXml();
	xml->NewDoc( XML_DCTRA_CONFIG );

	// nick,stringlist
	sl1 = 0;
	while(queue->Next(&sl1))
	{
		// hubname,transferobject
		TransferObject = 0;
		while(sl1->Next(&TransferObject))
		{
			if ( TransferObject->pTransferFileList.Count() == 0 )
			{
				continue;
			}

			xml->StartNewChild( XML_TRANSFER );

			// store nick,hubhost and hubname
			xml->NewStringChild( XML_NICK,      TransferObject->sNick);
			xml->NewStringChild( XML_HUBNAME,   TransferObject->sHubName);
			xml->NewStringChild( XML_HUBHOST,   TransferObject->sHubHost);

			HubObject = 0;

			while( (HubObject=TransferObject->pHubList.Next(HubObject)) != 0 )
			{
				xml->StartNewChild( XML_HUB );

				xml->NewStringChild( XML_HUBNAME, HubObject->m_sHubName );
				xml->NewStringChild( XML_HUBHOST, HubObject->m_sHubHost );
				xml->NewBoolChild( XML_ACTIVE, HubObject->m_bActive );
				
				xml->Parent();
			}

			// save files
			DCTransferFileObject * TransferFileObject = 0;
			while(TransferObject->pTransferFileList.Next(&TransferFileObject))
			{
				xml->StartNewChild( XML_FILE );

				xml->NewStringChild( XML_REMOTEFILE, TransferFileObject->m_sRemoteFile );
				xml->NewStringChild( XML_LOCALFILENAME, TransferFileObject->m_sLocalFileName );
				xml->NewNumericChild( XML_SIZE, TransferFileObject->m_nSize );
				xml->NewNumericChild( XML_PRIORITY, TransferFileObject->m_nPriority );
				xml->NewNumericChild( XML_STATE, TransferFileObject->m_eState );
				xml->NewStringChild( XML_LOCALFILE, TransferFileObject->m_sLocalFile );
				xml->NewStringChild( XML_LOCALPATH, TransferFileObject->m_sLocalPath );

				if ( TransferFileObject->m_stHash.NotEmpty() )
				{
					xml->NewStringChild( XML_TEMPHASH, TransferFileObject->m_stHash );
				}
				
				if ( TransferFileObject->m_sHash.NotEmpty() )
				{
					xml->NewStringChild( XML_HASH, TransferFileObject->m_sHash );
				}
				
				if(TransferFileObject->m_eMedium==eltBUFFER)
					s = XML_MEDIUM_BUFFER;
				else
					s = XML_MEDIUM_FILE;			
				xml->NewStringChild( XML_MEDIUM, s );

				xml->NewBoolChild( XML_MULTI, TransferFileObject->m_bMulti );
				
				if ( TransferFileObject->m_sJumpTo.NotEmpty() )
				{
					xml->NewStringChild( XML_JUMPTO, TransferFileObject->m_sJumpTo );
				}
				
				if ( TransferFileObject->m_pDirList )
				{
					xml->StartNewChild( XML_DL_FOLDERS );
					
					for ( std::list<CString>::const_iterator it = TransferFileObject->m_pDirList->begin(); it != TransferFileObject->m_pDirList->end(); ++it )
					{
						xml->NewStringChild( XML_PATH, *it );
					}
					
					xml->Parent();
				}
				
				xml->Parent();
			}
			
			xml->Parent();
		}
	}

	FileChunkObject = 0;
	while( chunks->Next(&FileChunkObject) )
	{
		xml->StartNewChild( XML_FILECHUNK );

		xml->NewStringChild( XML_LOCALFILE, FileChunkObject->m_sLocalFile );
		xml->NewStringChild( XML_TEMPHASH, FileChunkObject->m_stHash );
		xml->NewStringChild( XML_HASH, FileChunkObject->m_sHash );
		xml->NewNumericChild( XML_SIZE, FileChunkObject->m_nSize );
		xml->NewNumericChild( XML_SIZEDONE, FileChunkObject->m_nSizeDone );
		xml->NewNumericChild( XML_REFCOUNT, FileChunkObject->m_nReferenceCount );
		xml->NewBoolChild( XML_MULTI, FileChunkObject->m_bMulti );

		ChunkObject = 0;

		while( (ChunkObject=FileChunkObject->m_Chunks.Next(ChunkObject)) != 0 )
		{
			xml->StartNewChild( XML_CHUNK );
			xml->NewNumericChild( XML_START, ChunkObject->m_nStart );
			xml->NewNumericChild( XML_END, ChunkObject->m_nEnd );
			xml->Parent();
		}
		
		xml->Parent();
	}

	s = sConfigPath + DCTRA_CONFIG;

	if ( xml->SaveConfigXmlViaTemp(s) == -1 )
	{
		err = -1;
	}

	delete xml;

	return err;
}

/** */
CString CConfig::ParseVersion( CString s )
{
	CString release;
	CXml * xml = new CXml();

	if ( xml->ParseMemory( s.Data(), s.Length() ) && xml->DocFirstChild() )
	{
		do
		{
			if ( (xml->Name() == XML_DC) && xml->FirstChild() )
			{
				do
				{
					if ( (xml->Name() == XML_VERSION) && xml->FirstChild() )
					{
						do
						{
							if ( xml->Name() == XML_RELEASE )
							{
								release = xml->Content();
							}
						}
						while ( xml->NextNode() );
						xml->Parent();
					}
				}
				while ( xml->NextNode() );
				xml->Parent();
			}
		}
		while ( xml->NextNode() );
	}

	delete xml;
	return release;
}

/** */
void CConfig::ParseDCHubConfig( CXml * xml )
{
	DCConfigHubItem * hubitem;
	CString xml_name;

	do
	{
		/* parse server entrys */
		if ( (xml->Name() == XML_SERVER) && xml->FirstChild() )
		{
			do
			{
				// public hub list
				if ( (xml->Name() == XML_PUBLIC) && xml->FirstChild() )
				{
					hubitem = new DCConfigHubItem();

					do
					{
						xml_name = xml->Name();

						if ( xml_name == XML_NAME )
							hubitem->m_sName = xml->Content();
						else if ( xml_name == XML_HOST )
							hubitem->m_sHost = xml->Content();
						else if ( xml_name == XML_DESCRIPTION )
							hubitem->m_sDescription = xml->Content();
						else if ( xml_name == XML_USERCOUNT )
							hubitem->m_nUserCount = xml->Content().asULL();
						else if ( xml_name == XML_COUNTRY )
							hubitem->m_sCountry = xml->Content();
						else if ( xml_name == XML_EXTRA )
							hubitem->m_sExtra = xml->Content();
						else if ( xml_name == XML_SHARED )
							hubitem->m_nShared = xml->Content().asULL();
						else if ( xml_name == XML_MINSHARE )
							hubitem->m_nMinShare = xml->Content().asULL();
					}
					while ( xml->NextNode() );
					xml->Parent();

					// remove spaces
					hubitem->m_sHost = hubitem->m_sHost.Replace(" ","");
					
					// no port found
					if ( hubitem->m_sHost.Find(':') == -1 )
					{
						// add default port
						hubitem->m_sHost += ":411";
					}
					
					hubitem->m_nID = ++m_nPublicHubID;
					pPublicHubList->Add(hubitem->m_sName.ToUpper(),hubitem);
					pPublicHubList_HostIndex->Add(hubitem->m_sHost.ToUpper(),new CString(hubitem->m_sName));
				}
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
	}
	while ( xml->NextNode() );
}

/** */
void CConfig::ParseDCBookHubConfig( CXml * xml )
{
	DCConfigHubItem * hubitem;
	CString xml_name;

	do
	{
		/* parse server entrys */
		if ( (xml->Name() == XML_SERVER) && xml->FirstChild() )
		{
			do
			{
				// bookmark hub list
				if ( (xml->Name() == XML_PUBLIC) && xml->FirstChild() )
				{
					hubitem = new DCConfigHubItem();

					do
					{
						xml_name = xml->Name();

						if ( xml_name == XML_NAME )
							hubitem->m_sName = xml->Content();
						else if ( xml_name == XML_HOST )
							hubitem->m_sHost = xml->Content();
						else if ( xml_name == XML_DESCRIPTION )
							hubitem->m_sDescription = xml->Content();
						else if ( xml_name == XML_PROFILE_NAME )
							hubitem->m_sProfile = xml->Content();
					}
					while ( xml->NextNode() );
					xml->Parent();

					// remove spaces
					hubitem->m_sHost = hubitem->m_sHost.Replace(" ","");
					
					// no port found
					if ( hubitem->m_sHost.Find(':') == -1 )
					{
						// add default port
						hubitem->m_sHost += ":411";
					}
					
					hubitem->m_nID = ++m_nBookHubID;
					pBookmarkHubList->Add(hubitem->m_sName,hubitem);
					pBookmarkHubList_HostIndex->Add(hubitem->m_sHost.ToUpper(),new CString(hubitem->m_sName));
					
					hubitem->m_nPosition = pOrderedBookmarks->size();
					(*pOrderedBookmarks)[hubitem->m_nPosition] = hubitem;
				}
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
	}
	while ( xml->NextNode() );
}

/** */
void CConfig::ParseDCLibConfig( CXml * xml )
{
	CString xml_name1, xml_name2;

	do
	{
		xml_name1 = xml->Name();
		/* parse identify entrys */
		if ( (xml_name1 == XML_IDENTIFY) && xml->FirstChild() )
		{
			do
			{
				xml_name2 = xml->Name();

				if ( xml_name2 == XML_NICK )
					sNick = xml->Content();
				else if ( xml_name2 == XML_SEARCHNICK )
					sSearchNick = xml->Content();
				else if ( xml_name2 == XML_AWAYMESSAGE )
					sAwayMessage = xml->Content();
				else if ( xml_name2 == XML_EMAIL )
					sEMail = xml->Content();
				else if ( xml_name2 == XML_ANTISPAM )
					bAntiSpam = xml->GetBoolChild();
				else if ( xml_name2 == XML_DESCRIPTION )
					sDescription = xml->Content();
				else if ( xml_name2 == XML_AWAY_PREFIX )
					sAwayPrefix = xml->Content();
				else if ( xml_name2 == XML_DESCRIPTION_TAG )
					bDescriptionTag = xml->GetBoolChild();
				else if ( xml_name2 == XML_SPEED )
					sSpeed = xml->Content();
				else if ( xml_name2 == XML_EXTENDED_HUB_COUNT )
					m_bUseExtendedHubCount = xml->GetBoolChild();
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
		/* parse logfile entry */
		else if ( (xml_name1 == XML_LOGFILE) && xml->FirstChild() )
		{
			do
			{
				xml_name2 = xml->Name();

				if ( xml_name2 == XML_LOGFILENAME )
					sLogFile = xml->Content();
				else if ( xml_name2 == XML_LOGFILEON )
					bLogFile = xml->GetBoolChild();
				else if ( xml_name2 == XML_LOGDOWNLOADS )
					bLogFinishedDownloads = xml->GetBoolChild();
				else if ( xml_name2 == XML_LOGUPLOADS )
					bLogFinishedUploads = xml->GetBoolChild();
				else if ( xml_name2 == XML_LOGDETAILS )
					bLogDetails = xml->GetBoolChild();
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
		else if ( (xml_name1 == XML_SECURITY) && xml->FirstChild() )
		{
			do
			{
				if ( xml->Name() == XML_FLOODOPKICKMESSAGE )
					sFloodOpKickMessage = xml->Content();
			}
			while ( xml->NextNode() );
			xml->Parent();
		
		}
		/* parse transfer entrys */
		else if ( (xml_name1 == XML_TRANSFER) && xml->FirstChild() )
		{
			do
			{
				xml_name2 = xml->Name();

				if ( xml_name2 == XML_DOWNLOADFOLDER )
					sDownloadFolder = xml->Content();
				else if ( xml_name2 == XML_DOWNLOADFINISHEDFOLDER )
					sDownloadFinishedFolder = xml->Content();
				else if ( xml_name2 == XML_TRANSFER_AUTOSEARCH )
					bTransferAutoSearch = xml->GetBoolChild();
				else if ( xml_name2 == XML_MINSEGSIZE )
					m_nMinSegSize = xml->Content().asULL();
				else if ( (xml_name2 == XML_SHAREDFOLDER) && xml->FirstChild() )
				{
					DCConfigShareFolder * csf = new DCConfigShareFolder();

					do
					{
						if ( xml->Name() == XML_PATH )
						 	csf->m_sPath = xml->Content();
						else if ( xml->Name() == XML_ALIAS )
							csf->m_sAlias = xml->Content();
					}
					while ( xml->NextNode() );
					xml->Parent();

					if ( csf->m_sPath.IsEmpty() || csf->m_sAlias.IsEmpty() )
						delete csf;
					else
						SharedFolders.Add( csf );
				}
				else if ( xml_name2 == XML_AUTORECREATESHARELIST )
					bAutoRecreateShareList = xml->GetBoolChild();
				else if ( xml_name2 == XML_RECREATE_SHARELIST_TIME )
					m_nRecreateShareListTime = xml->Content().asINT();
				else if ( xml_name2 == XML_MAXUPLOAD )
					iMaxUpload = xml->Content().asINT();
				else if ( xml_name2 == XML_USER_UPLOAD_SLOTS )
					iUserUploadSlots = xml->Content().asINT();
				else if ( xml_name2 == XML_MAXUPLOADRATE )
					lMaxUploadRate = xml->Content().asULL();
				else if ( xml_name2 == XML_MAXDOWNLOADRATE )
					lMaxDownloadRate = xml->Content().asULL();
				else if ( xml_name2 == XML_EXTRA_SLOTS_RATE )
					m_nExtraSlotsRate = xml->Content().asULL();
				else if ( xml_name2 == XML_MAX_EXTRA_SLOTS )
					m_nMaxExtraSlots = xml->Content().asINT();
				else if ( xml_name2 == XML_DOWNLOADQUEUETIME )
					iDownloadQueueTime = xml->Content().asINT();
				else if ( xml_name2 == XML_DYNAMICUPLOADRATE )
					bDynamicUploadRate = xml->GetBoolChild();
				else if ( xml_name2 == XML_TRANSFER_CERT )
					m_sTransferCert = xml->Content();
				else if ( xml_name2 == XML_TRANSFER_KEY )
					m_sTransferKey = xml->Content();
				else if ( xml_name2 == XML_OLD_SSL_SUPPORT )
					m_bOldSSLSupport = xml->GetBoolChild();
				else if ( xml_name2 == XML_HUBOFFLINE_TRANSFERCLOSE )
					eHubOfflineTransferClose = (eCloseType)xml->Content().asINT();
				else if ( xml_name2 == XML_TRAFFIC_RX )
				{
					m_nStartDownloaded = xml->Content().asULL();
					CSocket::m_Traffic.AddTraffic( ettRX, m_nStartDownloaded );
				}
				else if ( xml_name2 == XML_TRAFFIC_TX )
				{
					m_nStartUploaded = xml->Content().asULL();
					CSocket::m_Traffic.AddTraffic( ettTX, m_nStartUploaded );
				}
				else if ( xml_name2 == XML_TRAFFIC_DATA_RX )
					CSocket::m_Traffic.AddTraffic( ettDATARX, xml->Content().asULL() );
				else if ( xml_name2 == XML_TRAFFIC_DATA_TX )
					CSocket::m_Traffic.AddTraffic( ettDATATX, xml->Content().asULL() );
				else if ( xml_name2 == XML_TRAFFIC_CONTROL_RX )
					CSocket::m_Traffic.AddTraffic( ettCONTROLRX, xml->Content().asULL() );
				else if ( xml_name2 == XML_TRAFFIC_CONTROL_TX )
					CSocket::m_Traffic.AddTraffic( ettCONTROLTX, xml->Content().asULL() );
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
		/* parse connection entrys */
		else if ( (xml_name1 == XML_CONNECTION) && xml->FirstChild() )
		{
			do
			{
				xml_name2 = xml->Name();

				if ( xml_name2 == XML_MODE )
				{
					if ( xml->Content() == XML_MODE_PASSIVE )
						eMode = ecmPASSIVE;
					else
						eMode = ecmACTIVE;
				}
				else if ( xml_name2 == XML_TCPLISTENPORT )
					iTCPListenPort = xml->Content().asINT();
				else if ( xml_name2 == XML_CRYPTOLISTENPORT )
					iCryptoListenPort = xml->Content().asINT();
				else if ( xml_name2 == XML_UDPLISTENPORT )
					iUDPListenPort = xml->Content().asINT();
				else if ( xml_name2 == XML_IP )
					m_sHost = xml->Content();
				else if ( xml_name2 == XML_LISTENHOST )
					m_sListenHost = xml->Content();
				else if ( xml_name2 == XML_EXTERNALIP )
					m_bExternalIP = xml->GetBoolChild();
				else if ( xml_name2 == XML_SENDMESSAGEONACTIVEMODEREQUEST )
					bSendMessageOnActiveModeRequest = xml->GetBoolChild();
				else if ( xml_name2 == XML_CHECKPRIVATEADDRESSSPACE )
					bCheckPrivateAddressSpace = xml->GetBoolChild();
				else if ( xml_name2 == XML_PRIVATEADDRESSSPACEONLY )
					bPrivateAddressSpaceOnly = xml->GetBoolChild();
				else if ( xml_name2 == XML_USERIP2_ENABLED )
					m_bUserIP2Enabled = xml->GetBoolChild();
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
		/* other entrys */
		else if ( (xml_name1 == XML_OTHER) && xml->FirstChild() )
		{
			do
			{
				xml_name2 = xml->Name();

				if ( xml_name2 == XML_HUBLISTSTORELOCAL )
					bHubListStoreLocal = xml->GetBoolChild();
				else if ( xml_name2 == XML_RECONNECTCOUNT )
					iReconnectCount = xml->Content().asINT();
				else if ( xml_name2 == XML_RECONNECTTIMEOUT )
					iReconnectTimeout = xml->Content().asINT();
				else if ( xml_name2 == XML_TRANSFERRESPONSETIMEOUT )
					iTransferResponseTimeout = xml->Content().asINT();
				else if ( xml_name2 == XML_TRANSFERRESENDTIMEOUT )
					iTransferResendTimeout = xml->Content().asINT();
				else if ( xml_name2 == XML_FORCEMOVEENABLED )
					bForceMoveEnabled = xml->GetBoolChild();
				else if ( xml_name2 == XML_DCLIB_PLUGINPATH )
					m_sDCLibPluginPath = xml->Content();
				else if ( xml_name2 == XML_CHATSENDTOOFFLINE )
					bChatSendToOffline = xml->GetBoolChild();
				else if ( xml_name2 == XML_CHATRECVFROMOFFLINE )
					bChatRecvFromOffline = xml->GetBoolChild();
				else if ( xml_name2 == XML_RELOAD_HUBLIST_TIME )
					m_nReloadHubListTime = xml->Content().asINT();
				else if ( xml_name2 == XML_DISABLEHASHLIST )
					m_bDisableHashList = xml->GetBoolChild();
				else if ( xml_name2 == XML_COMPRESSEDTRANSFERS )
					m_bCompressedTransfers = xml->GetBoolChild();
				else if ( xml_name2 == XML_ENABLE_ZPIPE )
					m_bEnableZPipe = xml->GetBoolChild();
				else if ( xml_name2 == XML_AUTOSEARCHINTERVAL )
					m_nAutoSearchInterval = xml->Content().asLONG();
				else if ( xml_name2 == XML_SMALLFILESIZE )
					m_nSmallFileSize = xml->Content().asULL();
				else if ( xml_name2 == XML_DONTSHAREDOTFILES )
					m_bDontShareDotFiles = xml->GetBoolChild();
				else if ( xml_name2 == XML_REMOTE_ENCODING )
					m_sRemoteEncoding = xml->Content();
				else if ( xml_name2 == XML_READ_FILE_BUFFER_SIZE )
					m_nReadFileBufferSize = xml->Content().asLONG();
				else if ( xml_name2 == XML_NO_ADCGET_WITHOUT_TTH )
					m_bDisableADCGetWithoutTTH = xml->GetBoolChild();
				else if ( xml_name2 == XML_NO_XMLLIST_WITHOUT_TTH )
					m_bDisableXMLListWithoutTTH = xml->GetBoolChild();
				else if ( xml_name2 == XML_OBSOLETE_EXT )
					m_bEnableObsoleteExt = xml->GetBoolChild();
				else if ( xml_name2 == XML_SHUFFLE_SUPPORTS )
					m_bShuffleSupports = xml->GetBoolChild();
				else if ( xml_name2 == XML_ENABLE_USER_COMMAND )
					m_bEnableUserCommand = xml->GetBoolChild();
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
		/* parse server entrys */
		else if ( (xml_name1 == XML_HUBLISTURL) && xml->FirstChild() )
		{
			do
			{
				if ( (xml->Name() == XML_URL) && xml->FirstChild() )
				{
					DCConfigHubListUrl * hublisturl = new DCConfigHubListUrl();

					do
					{
						xml_name2 = xml->Name();
						if ( xml_name2 == XML_NAME )
							hublisturl->sUrl = xml->Content();
						else if ( xml_name2 == XML_ENABLED )
							hublisturl->bEnabled = xml->GetBoolChild();
					}
					while ( xml->NextNode() );
					xml->Parent();

					if ( hublisturl->sUrl.IsEmpty() )
					{
						delete hublisturl;
					}
					else
					{
						pHubListUrlList.Add(hublisturl);
					}
				}
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
	}
	while ( xml->NextNode() );
}

/** */
CString CConfig::GetEMail( bool raw )
{
	m_Mutex.Lock();

	CString s = sEMail;

	if ( (raw == false) && bAntiSpam )
	{
		s = s.Replace( '@', " [at] " );
		s = s.Replace( '.', " [dot] " );
	}

	m_Mutex.UnLock();

	return s;
}

/** */
CString CConfig::GetDescription( bool raw, CString hubname, CString hubhost )
{
	DCConfigHubProfile pConfigHubProfile;	
	CString s;
	bool tag = false;
	bool prof = false;
	bool extHubCount = true;
	enum eClientMode mode;
	long normalHubs = 0;
	long regHubs = 0;
	long opHubs = 0;
	long totalHubs = 0;
	
	// check profile
	if ( (hubname.NotEmpty()) || (hubhost.NotEmpty()) )
	{
		if ( GetBookmarkHubProfile( hubname, hubhost, &pConfigHubProfile ) )
		{
			prof = true;
		}
	}

	mode = GetMode();
	
	m_Mutex.Lock();
	
	if ( (GetAwayMode() == euamAWAY) && (raw == false) )
	{
		s += sAwayPrefix;
	}

	// set tag
	if ( prof )
	{
		tag = pConfigHubProfile.m_bTag;
		extHubCount = pConfigHubProfile.m_bExtHubCount;
	}
	else
	{
		tag = bDescriptionTag;
		extHubCount = m_bUseExtendedHubCount;
	}
	
	// set description
	if ( prof && pConfigHubProfile.m_bComment )
	{
		s += pConfigHubProfile.m_sComment;
	}
	else
	{
		s += sDescription;
	}
	
	// Fake share bug fix :)
	s.Swap( '$', '_' );
	s.Swap( '|', '_' );

	// all bots need to check start AND end tag
	if ( (s.Find('<') != -1) && (s.Find('>') != -1) )
	{
		s.Swap( '<', '_' );
		s.Swap( '>', '_' );
	}

	if ( tag && (raw == false) )
	{
		s += "<DCGUI V:";
		s += DCLIB_VERSION_STRING;
		s += ",M:";

		switch (mode)
		{
			case ecmACTIVE:
				s += 'A';
				break;
			case ecmPASSIVE:
				s += 'P';
				break;
			default:
				s += 'U';
				break;
		}

		s += ",H:";
		
		if ( extHubCount ) // long H:3/2/1 DC++ format
		{
			if ( CConnectionManager::Instance() && ((totalHubs = CConnectionManager::Instance()->GetConnectedHubCount(false)) > 0))
			{
				opHubs = totalHubs - CConnectionManager::Instance()->GetConnectedHubCount(true);
				regHubs = CConnectionManager::Instance()->GetConnectedHubPasswordCount() - opHubs;
				normalHubs = totalHubs - (opHubs + regHubs);
				
				/* printf("Debug GetConnectedHubCount(false): %d\n", CConnectionManager::Instance()->GetConnectedHubCount(false));
				 * printf("Debug GetConnectedHubCount(true): %d\n", CConnectionManager::Instance()->GetConnectedHubCount(true));
				 * printf("Debug GetConnectedHubPasswordCount(): %d\n", CConnectionManager::Instance()->GetConnectedHubPasswordCount());
			 	* printf("Debug total hub count: %d\n", totalHubs);
			 	* printf("Debug OP hub count: %d\n", opHubs);
			 	* printf("Debug reg hub count: %d\n", regHubs);
			 	* printf("Debug normal hub count: %d\n", normalHubs);
			 	*/
				
				// extra sanity check
				if (normalHubs < 0)
				{
					printf("Warning! normal user hub count < 0, setting to 0\n");
					normalHubs = 0;
				}
				
				if (regHubs < 0)
				{
					printf("Warning! registered user hub count < 0, setting to 0\n");
					regHubs = 0;
				}
				
				if (opHubs < 0)
				{
					printf("Warning! operator hub count < 0, setting to 0\n");
					opHubs = 0;
				}
				
				// cannot be on zero hubs!
				// this sometimes happens when logging on to a hub
				// and the tag hasn't updated yet)
				if ( (normalHubs == 0) && (regHubs == 0) && (opHubs == 0) )
				{
					normalHubs = 1;
				}
				
				s += CString::number(normalHubs);
				s += '/';
				s += CString::number(regHubs);
				s += '/';
				s += CString::number(opHubs);
			}
			else
			{
				s += "1/0/0";
			}
		}
		else // short H:6 original valknut format
		{
			if ( CConnectionManager::Instance() && ((totalHubs = CConnectionManager::Instance()->GetConnectedHubCount(true)) > 0) )
			{
				s += CString::number(totalHubs);
			}
			else
			{
				s += '1';
			}
		}

		s += ",S:";

		if ( (iMaxUpload == 0) || (!CDownloadManager::Instance()) )
		{
			s += '*';
		}
		else
		{
			/* total # of slots open
			   more Hub Script DC++ Tag Checking friendly */
			s += CString::number(iMaxUpload);
		}

		if ( (m_nExtraSlotsRate > 0) && (m_nMaxExtraSlots > 0) )
		{
			s += ",O:";
			s += CString::number( m_nExtraSlotsRate/1024 );
		}

		if ( lMaxUploadRate > 0 )
		{
			s += ",L:";
			
			CString ratelimit = CString::number(lMaxUploadRate*1.0/1024,1);
			
			// remove trailing zero
			// in case decimal separator is ","
			if (ratelimit.Right(1) == "0")
			{
				ratelimit = ratelimit.Left(ratelimit.Length() - 2);
			}
			
			s += ratelimit;
		}

		if ( m_bDisableHashList )
		{
			s += ",NOTTH";
		}

		s += '>';
	}

	m_Mutex.UnLock();

	return s;
}

/** */
void CConfig::SetSharedFolders( CList<DCConfigShareFolder> * list )
{
	DCConfigShareFolder * csf = 0, *csf1;

	if (!list)
	{
		return;
	}

	SharedFolders.Clear();

	while ( (csf=list->Next(csf)) != 0 )
	{
		csf1 = new DCConfigShareFolder();
		csf1->m_sPath  = csf->m_sPath;
		csf1->m_sAlias = csf->m_sAlias;
		SharedFolders.Add( csf1 );
	}

	return;
}

/** */
long CConfig::GetSharedFolders( CList<DCConfigShareFolder> * list )
{
	DCConfigShareFolder * csf = 0, *csf1;

	if (!list)
	{
		return 0;
	}

	list->Clear();

	while ( (csf=SharedFolders.Next(csf)) != 0 )
	{
		csf1 = new DCConfigShareFolder();
		csf1->m_sPath  = csf->m_sPath;
		csf1->m_sAlias = csf->m_sAlias;

		list->Add( csf1 );
	}

	return list->Count();
}

/** */
bool CConfig::RemoveBookmarkHub( CString name, CString /*host*/, CString /*description*/ )
{
	m_Mutex.Lock();

	bool err = false;
	DCConfigHubItem * hubitem = 0;

	if ( pBookmarkHubList->Get(name,&hubitem) == 0 )
	{
		int oldkey = hubitem->m_nPosition;
		
		pBookmarkHubList_HostIndex->Del(hubitem->m_sHost.ToUpper());
		pBookmarkHubList->Del(hubitem->m_sName);
		
		// fix ordered bookmark map
		pOrderedBookmarks->clear();
		hubitem = 0;
		while ( (pBookmarkHubList->Next( &hubitem )) != 0 )
		{
			if ( hubitem->m_nPosition > oldkey )
			{
				hubitem->m_nPosition--;
			}
			(*pOrderedBookmarks)[hubitem->m_nPosition] = hubitem;
		}
		
		err = true;
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::AddBookmarkHub( CString name, CString host, CString description )
{
	m_Mutex.Lock();

	bool err = true;
	DCConfigHubItem * hubitem;

	hubitem = 0;

	// remove spaces
	host = host.Replace(" ","");
					
	// no port found
	if ( host.Find(':') == -1 )
	{
		// add default port
		host += ":411";
	}
					
	if ( pBookmarkHubList->Get(name,&hubitem) == 0 )
	{
		// update
		hubitem->m_sHost        = host;
		hubitem->m_sDescription = description;
		hubitem->m_sDescription = description;
		err = false;
	}

	if ( err )
	{
		hubitem = new DCConfigHubItem();

		hubitem->m_nID = (++m_nBookHubID);
		hubitem->m_sName = name;
		hubitem->m_sHost = host;
		hubitem->m_sDescription = description;
		pBookmarkHubList->Add(name,hubitem);
		pBookmarkHubList_HostIndex->Add(hubitem->m_sHost.ToUpper(),new CString(hubitem->m_sName));
		
		hubitem->m_nPosition = pOrderedBookmarks->size();
		(*pOrderedBookmarks)[hubitem->m_nPosition] = hubitem;
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::UpdateBookmarkHub( CString name, CString host, CString description )
{
	m_Mutex.Lock();

	bool err = false;
	DCConfigHubItem * hubitem;

	hubitem = 0;

	if ( pBookmarkHubList->Get(name,&hubitem) == 0 )
	{
		// remove spaces
		host = host.Replace(" ","");
					
		// no port found
		if ( host.Find(':') == -1 )
		{
			// add default port
			host += ":411";
		}

		// update
		hubitem->m_sHost        = host;
		hubitem->m_sDescription = description;
		err = true;
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::MoveBookmarkHub( int oldpos, int newpos )
{
	if ( oldpos == newpos )
	{
		return true;
	}
	
	if ( ((oldpos - newpos) != 1) && ((newpos - oldpos) != 1) )
	{
		printf("MoveBookmarkHub: can only move adjacent bookmarks\n");
		return false;
	}
	
	bool suceeded = false;
	
	m_Mutex.Lock();
	
	OrderedBookmarkMap::const_iterator it1 = pOrderedBookmarks->find( oldpos );
	
	if ( it1 != pOrderedBookmarks->end() )
	{
		OrderedBookmarkMap::const_iterator it2= pOrderedBookmarks->find( newpos );
		if ( it2 != pOrderedBookmarks->end() )
		{
			DCConfigHubItem * item1 = it1->second;
			DCConfigHubItem * item2 = it2->second;
			
			pOrderedBookmarks->erase( oldpos );
			pOrderedBookmarks->erase( newpos );
			
			item1->m_nPosition = newpos;
			item2->m_nPosition = oldpos;
			
			(*pOrderedBookmarks)[newpos] = item1;
			(*pOrderedBookmarks)[oldpos] = item2;
			
			suceeded = true;
		}
		else
		{
			printf("MoveBookmarkHub: new position not valid\n");
		}
		
	}
	else
	{
		printf("MoveBookmarkHub: old position not valid\n");
	}
	
	m_Mutex.UnLock();
	
	return suceeded;
}

/** */
bool CConfig::ReorderBookmarkHubs( const std::vector<int> & newpositions )
{
	if ( pOrderedBookmarks->size() != newpositions.size() )
	{
		printf("ReorderBookmarkHubs: container size mismatch\n");
		return false;
	}
	
	/* safety check everything first */
	DCConfigHubItem * hubitem = 0;
	while( pBookmarkHubList->Next( &hubitem ) != 0 )
	{
		if ( (hubitem->m_nPosition < 0) || (hubitem->m_nPosition > newpositions.size()) )
		{
			printf("ReorderBookmarkHubs: Existing key for %s out of range at %d\n", hubitem->m_sName.Data(), hubitem->m_nPosition);
			return false;
		}
	}
	
	pOrderedBookmarks->clear();
	
	hubitem = 0;
	
	while ( pBookmarkHubList->Next( &hubitem ) != 0 )
	{
		//printf("%d goes to %d\n",hubitem->m_nPosition,newpositions[hubitem->m_nPosition]);
		hubitem->m_nPosition = newpositions[hubitem->m_nPosition];
		(*pOrderedBookmarks)[hubitem->m_nPosition] = hubitem;
	}
	
	return true;
}

/** */
void CConfig::ClearPublicHubList()
{
	m_Mutex.Lock();
	m_nPublicHubID = 0;
	pPublicHubList->Clear();
	pPublicHubList_HostIndex->Clear();
	m_Mutex.UnLock();
}

/** */
bool CConfig::RemovePublicHub( CString name, CString /*host*/, CString /*description*/ )
{
	m_Mutex.Lock();

	bool err = false;
	DCConfigHubItem * hubitem;

	hubitem = 0;

	if ( pPublicHubList->Get(name.ToUpper(),&hubitem) == 0 )
	{
		pPublicHubList_HostIndex->Del(hubitem->m_sHost);
		pPublicHubList->Del(hubitem->m_sName.ToUpper());
		err = true;
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::AddPublicHub( const CString & name, const CString & host, const CString & description, const ulonglong usercount, const CString country, const ulonglong shared, const ulonglong minshare, const CString extra )
{
	if ( name.IsEmpty() || host.IsEmpty() )
	{
		return false;
	}

	bool badd = true;
	DCConfigHubItem * hubitem = 0;
	CString *ps;
	CString sname,shost,thost,fixedname;
	ulonglong ucount = usercount;

	// remove spaces
	thost = host.Replace(" ","");
	
	// remove dchub://
	if ( thost.Left(8).ToLower() == "dchub://" )
	{
		thost = thost.Mid(8);
	}
	
	// no port found
	if ( thost.Find(':') == -1 )
	{
		// add default port
		thost += ":411";
	}
	
	shost = thost.ToUpper();

	/* FIXME ADC protocol hubs not supported, so do not put into list */
	if ( shost.StartsWith("ADC://",6) || shost.StartsWith("ADCS://",7) )
	{
		return false;
	}

	fixedname = name;
	sname = name.ToUpper();

	// check for negative user count
	if ( ((long long) ucount) < 0 )
	{
		ucount = 0;
	}

	m_Mutex.Lock();

	if ( pPublicHubList->Get(sname,&hubitem) == 0 )
	{
		// hub found by name

		CString uppercurhost = hubitem->m_sHost.ToUpper();
		
		if ( shost == uppercurhost )
		{
			// remove from host index
			pPublicHubList_HostIndex->Del(uppercurhost);

			// if another hub with the new ip present ?
			if ( pPublicHubList_HostIndex->Get(shost,&ps) == 0 )
			{
				printf("double found: '%s'\n",shost.Data());

				if ( ps->ToUpper() != sname )
					pPublicHubList->Del(ps->ToUpper());

				pPublicHubList_HostIndex->Del(shost);
			}

			// remove hub from hublist
			pPublicHubList->Del(sname);
		}
		else
		{
			// same name but different host - append (2) etc. to name
			int n = 2;
			CString tempkey = sname;
			tempkey += " (";
			tempkey += CString::number(n);
			tempkey += ')';
			while ( pPublicHubList->Get(tempkey,&hubitem) == 0 )
			{
				if ( thost == hubitem->m_sHost )
				{
					badd = false;
					break;
				}
				n++;
				tempkey = sname;
				tempkey += " (";
				tempkey += CString::number(n);
				tempkey += ')';
			}
			sname = tempkey;
			fixedname += " (";
			fixedname += CString::number(n);
			fixedname += ')';
		}
	}
	else
	{
		// hub not found, check if hub exists in the host index
		if ( pPublicHubList_HostIndex->Get(shost,&ps) == 0 )
		{
			// hub by host found
			if ( pPublicHubList->Get(ps->ToUpper(),&hubitem) == 0 )
			{
				printf("double found: '%s'\n",shost.Data());

				pPublicHubList->Del(ps->ToUpper());
				pPublicHubList_HostIndex->Del(shost);
			}
			else
			{
				printf("warning public hub list inconsistent !\n");
			}
		}
	}

	if ( badd )
	{
		hubitem = new DCConfigHubItem();

		hubitem->m_nID	        = (++m_nPublicHubID);
		hubitem->m_sName        = fixedname;
		hubitem->m_sHost        = thost;
		hubitem->m_sDescription = description;
		hubitem->m_nUserCount   = ucount;
		hubitem->m_sCountry     = country;
		hubitem->m_sExtra       = extra;
		hubitem->m_nShared      = shared;
		hubitem->m_nMinShare    = minshare;

		pPublicHubList->Add(sname,hubitem);
		pPublicHubList_HostIndex->Add(shost,new CString(fixedname));
		
	}

	m_Mutex.UnLock();

	return badd;
}

/** */
CString CConfig::GetListenHostString()
{
	m_Mutex.Lock();

	CString s;

	if ( m_sListenHost.NotEmpty() )
	{
		s = CNetAddr::GetHostI4(m_sListenHost.Replace(' ',""));
	}

	m_Mutex.UnLock();

	return s;
}

/** */
CString CConfig::GetTCPHostString( bool addport, bool crypto )
{
	CString s;
	unsigned int n = 0;
	
	// get current port from listenmanager
	if ( crypto )
	{
		if ( CCryptoListenManager::Instance() )
		{
			n = CCryptoListenManager::Instance()->GetListenPort();
		}
	}
	else
	{
		if ( CListenManager::Instance() )
		{
			n = CListenManager::Instance()->GetListenPort();
		}
	}

	m_Mutex.Lock();
	
	if ( m_sHost.NotEmpty() )
	{
		if ( m_bExternalIP )
		{
			// first we check for a cache update
			if ( (m_sHostCache.IsEmpty()) ||
		     	     ((time(0)-m_tHostTimeout) > 60) )
			{
				m_sHostCache   = CNetAddr::GetHostI4(m_sHost.Replace(' ',""));
				m_tHostTimeout = time(0);
			}

			s = m_sHostCache;
		}
		else
		{
			s = CNetAddr::GetInterfaceI4( m_sHost );
		}
	}
	
	if ( s.NotEmpty() && addport )
	{
		if ( n != 0 )
		{
			s += ':';
			s += CString::number(n);
		}
		else
		{
			s.Empty();
		}
	}

	m_Mutex.UnLock();

	return s;
}

/** */
CString CConfig::GetUDPHostString( bool addport )
{
	m_Mutex.Lock();

	CString s;

	if ( m_sHost.NotEmpty() )
	{
		if ( m_bExternalIP )
		{
			// first we check for a cache update
			if ( (m_sHostCache.IsEmpty()) ||
		     	     ((time(0)-m_tHostTimeout) > 60) )
			{
				m_sHostCache   = CNetAddr::GetHostI4(m_sHost.Replace(' ',""));
				m_tHostTimeout = time(0);
			}

			s = m_sHostCache;
		}
		else
		{
			s = CNetAddr::GetInterfaceI4( m_sHost );
		}
	}

	if ( s.NotEmpty() && addport )
	{
		s += ':';
		s += CString::number(iUDPListenPort);
	}

	m_Mutex.UnLock();

	return s;
}

/**
 * check if we can resolve the ip in active mode
*/
eClientMode CConfig::GetMode( bool setting )
{
	if ( !setting && (eMode == ecmACTIVE) )
	{
		if ( GetTCPHostString().IsEmpty() )
		{
			return ecmPASSIVE;
		}
	}

	return eMode;
}

/** */
long CConfig::GetBookmarkHubList( CList<DCConfigHubItem> * list )
{
	DCConfigHubItem * newitem;

	if (!list)
	{
		return 0;
	}

	list->Clear();

	m_Mutex.Lock();

	for ( OrderedBookmarkMap::const_iterator it = pOrderedBookmarks->begin(); it != pOrderedBookmarks->end(); ++it )
	{
		newitem = new DCConfigHubItem( it->second );
		list->Add(newitem);
	}

	m_Mutex.UnLock();

	return list->Count();
}

/** */
long CConfig::GetPublicHubList( CList<DCConfigHubItem> * list )
{
	DCConfigHubItem * item = 0, *newitem;

	if (!list)
	{
		return 0;
	}

	list->Clear();

	m_Mutex.Lock();

	while ( pPublicHubList->Next(&item) != 0 )
	{
		newitem = new DCConfigHubItem( item );
		list->Add(newitem);
	}

	m_Mutex.UnLock();

	return list->Count();
}

/** */
long CConfig::GetPublicHubListSize() const
{
	return pPublicHubList->Count();
}

/** */
CStringList<CString> * CConfig::GetPublicHubServerList()
{
	DCConfigHubItem * item = 0;
	CStringList<CString> * StringList = 0;
	CString * string;

	m_Mutex.Lock();

	if ( pPublicHubList->Count() > 0 )
	{
		StringList = new CStringList<CString>();
		
		while ( pPublicHubList->Next(&item) != 0 )
		{
			if ( StringList->Get( item->m_sHost, &string ) != 0 )
			{
				StringList->Add(item->m_sHost, new CString(item->m_sHost));
			}
		}
	}
	
	m_Mutex.UnLock();

	return StringList;
}

/** */
CStringList<CString> * CConfig::GetBookmarkHubServerList()
{
	DCConfigHubItem * item = 0;
	CStringList<CString> * StringList = 0;
	CString * string;

	m_Mutex.Lock();

	if ( pBookmarkHubList->Count() > 0 )
	{
		StringList = new CStringList<CString>();
		
		while ( pBookmarkHubList->Next(&item) != 0 )
		{
			if ( StringList->Get( item->m_sHost, &string ) != 0 )
			{
				StringList->Add(item->m_sHost, new CString(item->m_sHost));
			}
		}
	}
	
	m_Mutex.UnLock();

	return StringList;
}

/** */
bool CConfig::GetBookmarkHub( CString name, DCConfigHubItem * hubitem )
{
	bool err = false;
	DCConfigHubItem * hubitem1;

	if ( !hubitem )
	{
		return err;
	}

	hubitem1 = 0;

	m_Mutex.Lock();

	if ( pBookmarkHubList->Get(name,&hubitem1) == 0 )
	{
		// update
		hubitem->m_sName        = hubitem1->m_sName;
		hubitem->m_sHost        = hubitem1->m_sHost;
		hubitem->m_sDescription = hubitem1->m_sDescription;
		hubitem->m_nUserCount   = hubitem1->m_nUserCount;
		hubitem->m_sProfile     = hubitem1->m_sProfile;
		hubitem->m_sCountry     = hubitem1->m_sCountry;
		hubitem->m_sExtra       = hubitem1->m_sExtra;
		hubitem->m_nShared      = hubitem1->m_nShared;
		hubitem->m_nMinShare    = hubitem1->m_nMinShare;
		hubitem->m_nPosition    = hubitem1->m_nPosition;
		err = true;
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::GetBookmarkHub( unsigned long id, DCConfigHubItem * hubitem )
{
	bool err = false;
	DCConfigHubItem * hubitem1;

	if ( !hubitem )
	{
		return err;
	}

	hubitem1 = 0;

	m_Mutex.Lock();

	while ( (pBookmarkHubList->Next(&hubitem1)) == 1 )
	{
		if ( hubitem1->m_nID == id )
		{
			hubitem->m_sName        = hubitem1->m_sName;
			hubitem->m_sHost        = hubitem1->m_sHost;
			hubitem->m_sDescription = hubitem1->m_sDescription;
			hubitem->m_nUserCount   = hubitem1->m_nUserCount;
			hubitem->m_sProfile     = hubitem1->m_sProfile;
			hubitem->m_sCountry     = hubitem1->m_sCountry;
			hubitem->m_sExtra       = hubitem1->m_sExtra;
			hubitem->m_nShared      = hubitem1->m_nShared;
			hubitem->m_nMinShare    = hubitem1->m_nMinShare;
			hubitem->m_nPosition    = hubitem1->m_nPosition;
			err = true;
			break;
		}
	}

	m_Mutex.UnLock();

	return err;
}

/** */
CString CConfig::GetNick( CString hubname, CString hubhost )
{
	DCConfigHubItem * hubitem;
	DCConfigHubProfile * profile;
	CString * ps = 0;
	CString s;

	hubitem = 0;

	m_Mutex.Lock();

	if ( pBookmarkHubList_HostIndex->Get( hubhost.ToUpper(), &ps ) == 0 )
	{
		hubname = *ps;
	}

	if ( pBookmarkHubList->Get(hubname,&hubitem) == 0 )
	{
		if ( hubitem->m_sProfile.NotEmpty() )
		{
			HubProfileMap::const_iterator profile_it = pHubProfileMap->find( hubitem->m_sProfile );
			if ( profile_it != pHubProfileMap->end() )
			{
				profile = profile_it->second;
				
				if ( profile->m_sNick.NotEmpty() )
				{
					m_Mutex.UnLock();
					return profile->m_sNick.Replace(' ',"\xa0");
				}
			}
		}
	}

	s = CConnectionManager::Instance()->GetNick(hubname,hubhost);
	
	if ( s.NotEmpty() )
	{
		m_Mutex.UnLock();
		return s;
	}

	m_Mutex.UnLock();

	return GetNick();
}

/** */
CString CConfig::GetRemoteEncoding( CString hubname, CString hubhost )
{
	DCConfigHubProfile profile;
	
	if ( GetBookmarkHubProfile( hubname, hubhost, &profile ) )
	{
		if ( profile.m_sRemoteEncoding.NotEmpty() )
		{
			return profile.m_sRemoteEncoding;
		}
	}
	
	return m_sRemoteEncoding;
}

/** */
bool CConfig::SetBookmarkHubProfile( CString name, CString profile )
{
	bool err = false;
	DCConfigHubItem * hubitem;

	m_Mutex.Lock();

	if ( pBookmarkHubList->Get(name,&hubitem) == 0 )
	{
		// update
		hubitem->m_sProfile = profile;

		err = true;
	}

	m_Mutex.UnLock();

	// save bookmark list
	if ( err )
	{
		SaveDCBookHub();
	}

	return err;
}

/** */
bool CConfig::GetBookmarkHubProfile( CString name, CString host, DCConfigHubProfile * p )
{
	bool err = false;
	DCConfigHubItem * hubitem;

	m_Mutex.Lock();

	if ( host.NotEmpty() )
	{
		// remove spaces
		host = host.Replace(" ","");
					
		// no port found
		if ( host.Find(':') == -1 )
		{
			// add default port
			host += ":411";
		}
	
		if ( pBookmarkHubList->Get(name,&hubitem) != 0 )
		{
			CString * ps;
			if ( pBookmarkHubList_HostIndex->Get(host.ToUpper(),&ps) == 0 )
			{
				name = *ps;
			}
		}
	}

	if ( pBookmarkHubList->Get(name,&hubitem) == 0 )
	{
		if ( hubitem->m_sProfile.NotEmpty() )
		{
			HubProfileMap::const_iterator profile_it = pHubProfileMap->find( hubitem->m_sProfile );
			if ( profile_it != pHubProfileMap->end() )
			{
				*p = profile_it->second;
				err = true;
			}
		}
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::GetPublicHub( CString name, DCConfigHubItem * hubitem )
{
	bool err = false;
	DCConfigHubItem * hubitem1;

	if ( !hubitem )
	{
		return err;
	}

	hubitem1 = 0;

	m_Mutex.Lock();

	if ( pPublicHubList->Get(name.ToUpper(),&hubitem1) == 0 )
	{
		// update
		hubitem->m_sName        = hubitem1->m_sName;
		hubitem->m_sHost        = hubitem1->m_sHost;
		hubitem->m_sDescription = hubitem1->m_sDescription;
		hubitem->m_nUserCount   = hubitem1->m_nUserCount;
		hubitem->m_sProfile     = hubitem1->m_sProfile;
		hubitem->m_sCountry     = hubitem1->m_sCountry;
		hubitem->m_sExtra       = hubitem1->m_sExtra;
		hubitem->m_nShared      = hubitem1->m_nShared;
		hubitem->m_nMinShare    = hubitem1->m_nMinShare;
		err = true;
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::GetPublicHub( unsigned long id, DCConfigHubItem * hubitem )
{
	bool err = false;
	DCConfigHubItem * hubitem1;

	if ( !hubitem )
	{
		return err;
	}

	hubitem1 = 0;

	m_Mutex.Lock();

	while ( (pPublicHubList->Next(&hubitem1)) == 1 )
	{
		if ( hubitem1->m_nID == id )
		{
			hubitem->m_sName        = hubitem1->m_sName;
			hubitem->m_sHost        = hubitem1->m_sHost;
			hubitem->m_sDescription = hubitem1->m_sDescription;
			hubitem->m_nUserCount   = hubitem1->m_nUserCount;
			hubitem->m_sProfile     = hubitem1->m_sProfile;
			hubitem->m_sCountry     = hubitem1->m_sCountry;
			hubitem->m_sExtra       = hubitem1->m_sExtra;
			hubitem->m_nShared      = hubitem1->m_nShared;
			hubitem->m_nMinShare    = hubitem1->m_nMinShare;
			err = true;
			break;
		}
	}

	m_Mutex.UnLock();

	return err;
}

/** */
long CConfig::GetHubListUrlList( CList<DCConfigHubListUrl> * list )
{
	DCConfigHubListUrl * item = 0, *newitem;

	if (!list)
	{
		return 0;
	}

	list->Clear();

	m_Mutex.Lock();

	while ( (item=pHubListUrlList.Next(item)) != 0 )
	{
		newitem = new DCConfigHubListUrl();

		newitem->bEnabled = item->bEnabled;
		newitem->sUrl     = item->sUrl;

		list->Add(newitem);
	}

	m_Mutex.UnLock();

	return list->Count();
}

/** */
void CConfig::SetHubListUrlList( CList<DCConfigHubListUrl> * list )
{
	DCConfigHubListUrl * item = 0, *newitem;

	pHubListUrlList.Clear();

	if (!list)
	{
		return;
	}

	m_Mutex.Lock();

	while ( (item=list->Next(item)) != 0 )
	{
		newitem = new DCConfigHubListUrl();

		newitem->bEnabled = item->bEnabled;
		newitem->sUrl     = item->sUrl;

		pHubListUrlList.Add(newitem);
	}

	m_Mutex.UnLock();

	return;
}

/** */
bool CConfig::AddHubProfile( DCConfigHubProfile * p )
{
	bool err = false;

	if ( !p )
	{
		return err;
	}

	m_Mutex.Lock();

	HubProfileMap::const_iterator profile_it = pHubProfileMap->find( p->m_sName );
	if ( profile_it == pHubProfileMap->end() )
	{
		// create new entry
		(*pHubProfileMap)[p->m_sName] = new DCConfigHubProfile(p);
		err = true;
	}
	else
	{
		// update
		*(profile_it->second) = *p;
		err = true;
	}

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::DelHubProfile( CString name )
{
	bool res = false;
	
	m_Mutex.Lock();

	HubProfileMap::iterator profile_it = pHubProfileMap->find( name );
	if ( profile_it != pHubProfileMap->end() )
	{
		delete profile_it->second;
		pHubProfileMap->erase( profile_it );
		res = true;
	}

	m_Mutex.UnLock();

	return res;
}

/** */
bool CConfig::GetHubProfile( CString name, DCConfigHubProfile * p )
{
	bool res = false;

	m_Mutex.Lock();

	HubProfileMap::const_iterator profile_it = pHubProfileMap->find( name );
	if ( profile_it != pHubProfileMap->end() )
	{
		*p = *(profile_it->second);
		res = true;
	}

	m_Mutex.UnLock();

	return res;
}

/** */
std::list<CString> * CConfig::GetHubProfileNames()
{
	m_Mutex.Lock();

	std::list<CString> * nameslist = new std::list<CString>();

	for ( HubProfileMap::const_iterator profile_it = pHubProfileMap->begin(); profile_it != pHubProfileMap->end(); ++profile_it )
	{
		nameslist->push_back(profile_it->second->m_sName);
	}

	m_Mutex.UnLock();
	
	return nameslist;
}

/** */
bool CConfig::SaveHubProfile()
{
	bool err = false;
	CString s;
	DCConfigHubProfile * pConfigHubProfile = 0;
	CXml * xml;

	m_Mutex.Lock();

	xml = new CXml();
	xml->NewDoc( XML_DCPROF_CONFIG );

	for ( HubProfileMap::const_iterator profile_it = pHubProfileMap->begin(); profile_it != pHubProfileMap->end(); ++profile_it )
	{
		pConfigHubProfile = profile_it->second;

		xml->StartNewChild( XML_PROFILE );

		xml->NewStringChild( XML_NAME, pConfigHubProfile->m_sName);
		xml->NewStringChild( XML_NICK, pConfigHubProfile->m_sNick);
		xml->NewStringChild( XML_PASSWORD, pConfigHubProfile->m_sPassword);
		xml->NewStringChild( XML_EMAIL, pConfigHubProfile->m_sEMail);
		xml->NewBoolChild( XML_EMAIL_ENABLED, pConfigHubProfile->m_bEMail );
		xml->NewStringChild( XML_DESCRIPTION, pConfigHubProfile->m_sComment);	
		xml->NewBoolChild( XML_DESCRIPTION_ENABLED, pConfigHubProfile->m_bComment );
		xml->NewBoolChild( XML_AUTO_CONNECT, pConfigHubProfile->m_bAutoConnect );
		xml->NewBoolChild( XML_SSL, pConfigHubProfile->m_bSSL );
		xml->NewBoolChild( XML_DESCRIPTION_TAG, pConfigHubProfile->m_bTag );
		xml->NewBoolChild( XML_EXTENDED_HUB_COUNT, pConfigHubProfile->m_bExtHubCount );
		xml->NewStringChild( XML_SUPPRESSED_NICKS, pConfigHubProfile->m_sSuppressedNicks );
		xml->NewStringChild( XML_REMOTE_ENCODING, pConfigHubProfile->m_sRemoteEncoding );
		
		xml->Parent();
	}

	s = sConfigPath + DCPROF_CONFIG;

	if ( xml->SaveConfigXmlViaTemp(s) != -1 )
	{
		err = true;
	}

	delete xml;

	m_Mutex.UnLock();

	return err;
}

/** */
bool CConfig::LoadHubProfile()
{
	bool err = true;
	CString s, xml_name;
	DCConfigHubProfile * pConfigHubProfile;
	CXml *xml;

	m_Mutex.Lock();

	xml = new CXml();

	s = sConfigPath + DCPROF_CONFIG;

	if ( xml->ParseFile(s) && xml->DocFirstChild() )
	{
		do
		{
			if ( (xml->Name() == XML_DCPROF_CONFIG) && xml->FirstChild() )
			{
				do
				{
					if ( (xml->Name() == XML_PROFILE) && xml->FirstChild() )
					{
						pConfigHubProfile = new DCConfigHubProfile();

						do
						{
							xml_name = xml->Name();
							if ( xml_name == XML_NAME )
								pConfigHubProfile->m_sName = xml->Content();
							else if ( xml_name == XML_NICK )
								pConfigHubProfile->m_sNick = xml->Content();
							else if ( xml_name == XML_PASSWORD )
								pConfigHubProfile->m_sPassword = xml->Content();
							else if ( xml_name == XML_EMAIL )
								pConfigHubProfile->m_sEMail = xml->Content();
							else if ( xml_name == XML_DESCRIPTION )
								pConfigHubProfile->m_sComment = xml->Content();
							else if ( xml_name == XML_AUTO_CONNECT )
								pConfigHubProfile->m_bAutoConnect = xml->GetBoolChild();
							else if ( xml_name == XML_SSL )
								pConfigHubProfile->m_bSSL = xml->GetBoolChild();
							else if ( xml_name == XML_DESCRIPTION_TAG )
								pConfigHubProfile->m_bTag = xml->GetBoolChild();
							else if ( xml_name == XML_DESCRIPTION_ENABLED )
								pConfigHubProfile->m_bComment = xml->GetBoolChild();
							else if ( xml_name == XML_EMAIL_ENABLED )
								pConfigHubProfile->m_bEMail = xml->GetBoolChild();
							else if ( xml_name == XML_EXTENDED_HUB_COUNT )
								pConfigHubProfile->m_bExtHubCount = xml->GetBoolChild();
							else if ( xml_name == XML_SUPPRESSED_NICKS )
								pConfigHubProfile->m_sSuppressedNicks = xml->Content();
							else if ( xml_name == XML_REMOTE_ENCODING )
								pConfigHubProfile->m_sRemoteEncoding = xml->Content();
						}
						while ( xml->NextNode() );
						xml->Parent();

						if ( pConfigHubProfile->m_sName.IsEmpty() )
						{
							delete pConfigHubProfile;
						}
						else
						{
							HubProfileMap::const_iterator profile_it = pHubProfileMap->find( pConfigHubProfile->m_sName );
							if ( profile_it == pHubProfileMap->end() )
							{
								(*pHubProfileMap)[pConfigHubProfile->m_sName] = pConfigHubProfile;
							}
							else
							{
								// duplicate profile name in config file, rename profile
								CString key;
								int i = 0;
								do
								{
									key = pConfigHubProfile->m_sName;
									key += " (";
									key += CString::number(i);
									key += ")";
									profile_it = pHubProfileMap->find( key );
								}
								while ( (profile_it != pHubProfileMap->end()) && (i < 20) );
								
								if ( profile_it == pHubProfileMap->end() )
								{
									pConfigHubProfile->m_sName = key;
									(*pHubProfileMap)[pConfigHubProfile->m_sName] = pConfigHubProfile;
								}
								else
								{
									delete pConfigHubProfile;
								}
							}
						}
					}
				}
				while ( xml->NextNode() );
				xml->Parent();
			}
		}
		while ( xml->NextNode() );
	}

	delete xml;

	m_Mutex.UnLock();

	return err;
}

/** */
CString CConfig::AliasToPath( CString file )
{
	int i;
	CString s,s1,sfile,sdir;
	DCConfigShareFolder * csf;

	m_Mutex.Lock();

	if ( SharedFolders.Count() <= 0 )
	{
		m_Mutex.UnLock();
		return s;
	}

	// simple filename
	sfile = CDir::SimplePath(file);

	if ( sfile.IsEmpty() )
	{
		m_Mutex.UnLock();
		return sfile;
	}

	// get the first directory
	i = sfile.Find(DIRSEPARATOR);

	if ( i <= 0 )
	{
		// must be a top level directory, find it!
		csf = 0;
		while( (csf=SharedFolders.Next(csf)) != 0 )
		{
			if ( sfile == CDir::SimplePath(csf->m_sAlias) )
			{
				m_Mutex.UnLock();
				return CDir::SimplePath(csf->m_sPath);
			}
		}
	}
	else
	{
		sdir  = sfile.Left(i);
		sfile = sfile.Mid(i+1,sfile.Length()-1-i);
	}

	// this test remove because directories are indexed in 0.3.14 - ejs
	/* if ( sfile.IsEmpty() )
	{
		// get directory ...
		m_Mutex.UnLock();
		return sfile;
	} */

	CDir dir;
	csf = 0;
	while( (csf=SharedFolders.Next(csf)) != 0 )
	{
		// check for correct alias
		if ( csf->m_sAlias != sdir )
		{
			continue;
		}

		// set correct path
		s = csf->m_sPath;
		
		// is valid ?
		if ( dir.cd(s) )
		{
			if ( sfile.IsEmpty() )
			{
				s1 = DIRSEPARATOR + sdir;
			}
			else
			{
				s1 = DIRSEPARATOR + sfile;
			}
			
			if ( dir.IsFile(s1) )
			{
				s += DIRSEPARATOR;
				s += sfile;
				s = CDir::SimplePath(s);
				m_Mutex.UnLock();
				return s;
			}
			else if ( dir.IsDir(s1) )
			{
				if ( sfile.IsEmpty() )
				{
					s += DIRSEPARATOR;
					s += sdir;
				}
				else
				{
					s += DIRSEPARATOR;
					s += sfile;
				}
				s = CDir::SimplePath(s);
				m_Mutex.UnLock();
				return s;
			}
		}
	}

	m_Mutex.UnLock();

	return CString();
}

/** */
void CConfig::SetHost( CString newhost )
{
	if ( newhost != m_sHost )
	{
		m_Mutex.Lock();
		
		m_sHost = newhost;
		m_sHostCache.Empty();
		
		m_Mutex.UnLock();
	}
}

/** */
void CConfig::SetAwayMode( eUserAwayMode mode )
{
	m_Mutex.Lock();
	eAwayMode = mode;
	m_Mutex.UnLock();
}

