/***************************************************************************
                          dcconfig.cpp  -  description
                             -------------------
    begin                : Fri Mar 1 2002
    copyright            : (C) 2002 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 "dcconfig.h"

#include <stdlib.h>

/*
 * Memset for crazy new user icon cache system.
 * It would be much easier to just load all the icons
 * but that would be 384 QPixmaps.
 */
#include <string.h>

#include <QPixmap>
#include <QProcess>
#include <qsound.h>
#include <QDir>
#include <QFile>
#include <QUrl>
#include <QVariant>
#include <QTextDocument>
#include <QDesktopServices>
#include <QApplication>

#include <dclib/core/cstring.h>
#include <dclib/core/cxml.h>

#include "dciconloader.h"

#include <dclib/dcos.h>

/* CMessageMyInfo for user list icon */
#include <dclib/dcobject.h>

// mac stuff
#if defined(Q_OS_MACX) 
#include <CoreFoundation/CoreFoundation.h> 
#endif 

#include "dcguiutils.h"

// config files
#define DCGUI_CONFIG		"dcgui.cfg"
#define DCGUI_HUBFILTER		"dchubfilter.cfg"
#define DCGUI_FRIENDLIST	"dcfriendlist.cfg"

#define XML_DCGUI_CONFIG	"dcgui"
#define XML_DCGUI_HUBFILTER	"dchubfilter"
#define XML_DCGUI_FRIENDLIST	"dcfriendlist"

#define XML_GUI				"gui"
#define XML_OPENPRIVATECHATWIN		"openprivatechatwindow"
#define XML_UNIT			"unit"
#define XML_THEME			"theme"
#define XML_THEME_QT4			"theme_qt4"
#define XML_LANGUAGEFILE		"languagefile"
#define XML_APP_FONT			"appfont"
#define XML_USE_CUSTOM_FONT		"use_custom_font"
#define XML_APP_WIDTH			"appwidth"
#define XML_APP_HEIGHT			"appheight"
#define XML_TABBAR			"tabbar"
#define XML_TOOLBAR			"toolbar"
#define XML_STATUSBAR			"statusbar"
#define XML_EXTERNAL_SOUND_PLAYER	"externalsoundplayer"
#define XML_EXTERNAL_PLAYER		"externalplayer"
#define XML_SOUND_FILE_CONNECT		"soundfileconnect"
#define XML_SOUND_FILE_DISCONNECT	"soundfiledisconnect"
#define XML_SOUND_FILE_SEND		"soundfilesend"
#define XML_SOUND_FILE_RECEIVE		"soundfilereceive"
#define XML_SOUND_FILE_FIRSTRECEIVE	"soundfilefirstreceive"
#define XML_SOUND_FILE_NICK_MENTIONED	"soundnickmentioned"
#define XML_SOUND_ENABLED_CONNECT	"soundenabledconnect"
#define XML_SOUND_ENABLED_DISCONNECT	"soundenableddisconnect"
#define XML_SOUND_ENABLED_SEND		"soundenabledsend"
#define XML_SOUND_ENABLED_RECEIVE	"soundenabledreceive"
#define XML_SOUND_ENABLED_FIRSTRECEIVE	"soundenabledfirstreceive"
#define XML_SOUND_ENABLED_NICK_MENTIONED	"soundenablednickmentioned"
#define XML_SOUND_DISABLED		"sounddisabled"
#define XML_SOUND_DISABLED_AWAY		"sounddisabledaway"
#define XML_TIMESTAMP_PRIVATECHAT	"timestampprivatechat"
#define XML_TIMESTAMP_HUBCHAT		"timestamphubchat"
#define XML_SHOW_STATUS_MESSAGE		"showstatusmessage"
#define XML_SHOW_TRANSFER_WIN		"showtransferwin"
#define XML_SEND_HIDE_PRIVATE_CHAT_TO_PUBLIC_CHAT "sendhideprivatechattopublicchat"
#define XML_CHAT_MESSAGE_MAX_LINES	"chatmessagemaxlines"
#define XML_DEFAULTDOWNLOADMODE		"defaultdownloadmode"
#define XML_EMOTICONS			"emoticons"
#define XML_SENDCHATINDEX		"sendchatindex"
#define XML_ENABLETRAY			"enabletray"
#define XML_QUERYONEXIT			"queryonexit"
#define XML_QUERYONFILEDELETE		"queryonfiledelete"
#define XML_SHOWCHATSENDBUTTON		"showchatsendbutton"
#define XML_CHATMAXPARAGRAPH		"chatmaxparagraph"
#define XML_VALKNUT_DATA_PATH		"valknutdatapath"
#define XML_QMAINWINDOW_STATE		"qmainwindowstate"

#define XML_APP_ICON_THEME		"appicontheme"
#define XML_EMOTICON_THEME		"emoticontheme"
#define XML_USER_ICON_THEME		"userlisticontheme"

#define XML_TV_CHUNKPERCENT		"tvchunkpercent"
#define XML_TV_FILEPERCENT		"tvfilepercent"
#define XML_TV_CHUNKSIZE		"tvchunksize"
#define XML_TV_FILESIZE			"tvfilesize"
#define XML_TV_DOWNLOADRATESINGLE	"tvdownloadratesingle"
#define XML_TV_ELAPSEDTIMESINGLE	"tvelapsedtimesingle"
#define XML_TV_DOWNLOADRATEMULTI	"tvdownloadratemulti"
#define XML_TV_ELAPSEDTIMEMULTI		"tvelapsedtimemulti"

#define XML_NAME			"name"
#define XML_ENTRY			"entry"
#define XML_SECTION			"section"
#define XML_SIZE			"size"
#define XML_POS				"pos"

#define XML_FILTER			"filter"
#define XML_FILTERNAME			"filtername"
#define XML_CONTAINS			"contains"
#define XML_USER			"user"
#define XML_SERVER			"server"
#define XML_DESCRIPTION			"description"
#define XML_USERLISTRIGHTALIGNMENT	"userlistrightalignment"
#define XML_BACKGROUNDPIXMAP		"backgroundpixmap"
#define XML_BROWSER			"browser"
#define XML_CUSTOM_BROWSER		"custom_browser"

#define XML_SHOWCHATINTAB		"showchatintab"
#define XML_OPENCLIENTWINDOWS		"openclientwindows"

#define XML_FLOODCOUNT			"floodcount"
#define XML_FLOODOPKICK			"floodopkick"
#define XML_FLOODKICKMESSAGE		"floodkickmessage"

#define XML_LCO_ENABLELOGGING			"LCO_ENABLELOGGING"
#define XML_LCO_APPENDDATE			"LCO_APPENDDATE"
#define XML_LCO_APPENDHUBNAME			"LCO_APPENDHUBNAME"
#define XML_LCO_APPENDHUBHOST			"LCO_APPENDHUBHOST"
#define XML_LCO_DISABLEPUBLICCHAT		"LCO_DISABLEPUBLICCHAT"
#define XML_LCO_ENABLENICKNAMEFILTER		"LCO_ENABLENICKNAMEFILTER"
#define XML_LCO_NICKNAMEFILTER_ENABLELOGGING	"LCO_NICKNAMEFILTER_ENABLELOGGING"

#define XML_CC_CHATTIMESTAMP			"CC_CHATTIMESTAMP"
#define XML_CC_CHATLOCALNICK			"CC_CHATLOCALNICK"
#define XML_CC_CHATLOCALTEXT			"CC_CHATLOCALTEXT"
#define XML_CC_CHATREMOTENICK			"CC_CHATREMOTENICK"
#define XML_CC_CHATREMOTETEXT			"CC_CHATREMOTETEXT"
#define XML_CC_CHATSTATUSNICK			"CC_CHATSTATUSNICK"
#define XML_CC_CHATSTATUSTEXT			"CC_CHATSTATUSTEXT"
#define XML_CC_PUBLICCHATTIMESTAMP		"CC_PUBLICCHATTIMESTAMP"
#define XML_CC_PUBLICCHATLOCALNICK		"CC_PUBLICCHATLOCALNICK"
#define XML_CC_PUBLICCHATLOCALTEXT		"CC_PUBLICCHATLOCALTEXT"
#define XML_CC_PUBLICCHATREMOTENICK		"CC_PUBLICCHATREMOTENICK"
#define XML_CC_PUBLICCHATREMOTETEXT		"CC_PUBLICCHATREMOTETEXT"
#define XML_CC_PUBLICCHATSTATUSNICK		"CC_PUBLICCHATSTATUSNICK"
#define XML_CC_PUBLICCHATSTATUSTEXT		"CC_PUBLICCHATSTATUSTEXT"
#define XML_CC_PUBLICPRIVATECHATNICK		"CC_PUBLICPRIVATECHATNICK"
#define XML_CC_PUBLICPRIVATECHATTEXT		"CC_PUBLICPRIVATECHATTEXT"
#define XML_CC_CHATSAY				"CC_CHATSAY"
#define XML_CC_PUBLICCHATMENICK			"CC_PUBLICCHATMENICK"
#define XML_CC_OPNICK				"CC_OPNICK"

#define XML_CHAT_BG_COLOR_ENABLED		"custom_chat_bg_enabled"
#define XML_CHAT_BG_COLOR			"chat_bg_color"

#define XML_AUTO_AWAY_MODE		"autoawaymode"
#define XML_AUTO_AWAY_TIME		"autoawaytime"
#define XML_CHAT_SHOW_JOINS_AND_PARTS	"chatshowjoinsandparts"
#define XML_CHAT_SHOW_JOINS_AND_PARTS_ONLY_FAV	"chatshowjoinsandpartsonlyfav"
#define XML_CHAT_SUPPRESSED_NICKS	"suppressednicks"
#define XML_DOUBLE_CLICK_ACTION		"doubleclickactionindex"

#define XML_FRIEND			"friend"
#define XML_IMAGE			"image"
#define XML_SEND_IMAGE			"sendimage"
#define XML_AUTO_SEC			"autosec"
#define XML_USER_PHOTO			"userphoto"
#define XML_PERM_SLOT			"permslot"
#define XML_IGNORE			"ignore"

#define XML_USERCHATCOMMAND		"userchatcommand"
#define XML_USERCHATCOMMAND_NAME	"command_name"
#define XML_USERCHATCOMMAND_ACT		"command_action"
#define XML_SHELL_COMMAND_THREADS	"shell_command_threads"
#define XML_SHELL_COMMAND_TIMEOUT	"shell_command_timeout"

#define XML_UNIT_AUTO	"auto"
#define XML_UNIT_BYTE	"byte"
#define XML_UNIT_KBYTE	"kbyte"
#define XML_UNIT_MBYTE	"mbyte"
#define XML_UNIT_GBYTE	"gbyte"

#define XML_USERMENUCOMMAND		"usermenucommand"
#define XML_USERMENUCOMMAND_NAME	"command_name"
#define XML_USERMENUCOMMAND_ACT		"command_action"
#define XML_USERMENUCOMMAND_CONTEXT	"command_context"
#define XML_USERMENUCOMMAND_TYPE	"command_type"
#define XML_USERMENUCOMMAND_HUBIP	"command_hub"
#define XML_USERMENUCOMMAND_POSITION	"command_position"

#define XML_AUTORESPONSE_ENABLED	"autoresponse_enabled"
#define XML_AUTORESPONSE_ENABLED_PM	"autoresponse_enabled_pm"
#define XML_AUTORESPONSE		"autoresponse"
#define XML_AUTORESPONSE_TRIGGER	"trigger"
#define XML_AUTORESPONSE_RESPONSE	"response"
#define XML_AUTORESPONSE_CASE_SENS	"case_sensitive"
#define XML_AUTORESPONSE_DELAY		"autoresponse_delay"
#define XML_AUTORESPONSE_IGNORES	"autoresponse_ignores"

#define XML_FILELIST_NAMING_SCHEME	"filelist_naming_scheme"

#define XML_FOLDERS_RIGHT_PANE		"folders_in_right_pane"
#define XML_SIZES_IN_LEFT_PANE		"sizes_in_left_pane"
#define XML_FOLDERS_RIGHT_PANE_ON_TOP	"folders_in_right_pane_on_top"
#define XML_OPEN_FOLDERS_RIGHT_PANE	"open_folders_in_right_pane"
#define XML_SEND_UNKNOWN_COMMANDS	"unknown_commands_as_chat"
#define XML_ALLOWED_UNKNOWN_COMMANDS	"allowed_unknown_commands"
#define XML_ADJUST_SR			"adjust_hub_details_in_sr"
#define XML_REMOVE_PUBLIC_HUB		"remove_public_hub"

#define XML_TAB_COMPLETE_MODE		"tab_complete_mode"
#define XML_TAB_COMPLETE_STRIP		"tab_complete_strip"

#define XML_USER_COMMAND_SUBMENU	"user_command_submenu"

/*
 * maybe different action for external magnet links
 * but they are not supported anyway
 */
#define XML_MAGNET_ACTION_CHAT		"magnet_action_chat"

/* these were removed from dclib cconfig.h */
#define XML_HUBNAME		"hubname"
#define XML_HUBHOST		"hubhost"

#define XML_ALTERNATING_ROW_COLORS	"alternating_row_colors"

DCConfig * g_pConfig = 0;

DCConfig::DCConfig( CString configpath ) : CConfig(configpath)
{
	// gui defaults
	bOpenPrivateChatWindow	= true;
	m_eUnit			= euAUTO;
#if defined(Q_OS_MACX)
	sTheme			= "Mac";
#else
	sTheme			= "";
#endif
	sThemeQT3		= "";
	sLanguageFile		= "";
	sAppFont		= DEFAULT_APP_FONT;
	
	/* The system default font is best */
	m_bUseCustomFont	= false;
	
	iAppHeight		= 480;
	iAppWidth		= 640;
	bTabBar			= true;
	bToolBar		= true;
	bStatusBar		= true;

	sSoundFileConnect	= "";
	sSoundFileDisconnect	= "";
	sSoundFileSend		= "";
	sSoundFileReceive	= "";
	sSoundFileFirstReceive	= "";
	sSoundFileNickMentioned = "";

	bSoundDisabled		= true;
	bSoundDisabledAway	= true;

	bSoundEnabledConnect	= true;
	bSoundEnabledDisconnect	= true;
	bSoundEnabledSend	= true;
	bSoundEnabledReceive	= true;
	bSoundEnabledFirstReceive = true;
	bSoundEnabledNickMentioned = true;

	bEnableEmoticons        = true;
	bTimeStampPrivateChat	= true;
	bTimeStampHubChat	= true;
	bShowStatusMessage      = true;
	bShowTransferWin        = false;
	m_nSendChat		= 1;

	bExternalSoundPlayer	= false;
	sExternalPlayer		= "";

	bTVChunkPercent         = false;
	bTVFilePercent          = true;
	bTVChunkSize            = false;
	bTVFileSize             = true;
	bTVDownloadRateSingle   = false;
	bTVElapsedTimeSingle    = false;
	bTVDownloadRateMulti    = true;
	bTVElapsedTimeMulti     = true;
	bThemeSupport           = true;
	bUserListRightAlignment = true;

	m_bAutoAwayMode         = false;
	m_nAutoAwayTime         = 300;

	m_bChatShowJoinsAndParts = false;
	m_bChatShowJoinsAndPartsOnlyFav = false;
	bSendHidePrivateChatToPublicChat = true;

	memset( m_UserIconCache, 0, sizeof(m_UserIconCache) );

	iChatMessageMaxLines = 0;
	
	iFloodCount    = 3;
	m_bFloodOpKick = false;
	
	pProcess = new QProcess();

	iDefaultDownloadMode = 0;

	m_bEnableTray = true;
	bQueryOnExit = false;
	bQueryOnFileDelete = true;
	bShowChatSendButton = true;
	sBackgroundPixmap = "";
#if defined(Q_OS_MACX)
	sBrowser = "open";
#elif defined(Q_WS_WIN)
	sBrowser = "start";
#else
	sBrowser = "xdg-open";
#endif
	/* false to use QDesktopServices */
	m_bCustomBrowser = false;
	bShowChatInTab = true;
	m_nChatMaxParagraph = 0;
	m_nOpenClientWindows = 1; // normal, not minimized nor maximized
	m_pEmoticons = 0;

	m_bLogChatOption_1 = false;
	m_bLogChatOption_2 = false;
	m_bLogChatOption_3 = false;
	m_bLogChatOption_4 = false;
	m_bLogChatOption_5 = false;
	m_bLogChatOption_6 = false;
	m_bLogChatOption_7 = false;

	m_sChatColor_1  = "#000000";
	m_sChatColor_2  = "#005500";
	m_sChatColor_3  = "#000000";
	m_sChatColor_4  = "#ac0000";
	m_sChatColor_5  = "#000000";
	m_sChatColor_6  = "#ff0000";
	m_sChatColor_7  = "#000000";
	m_sChatColor_8  = "#000000";
	m_sChatColor_9  = "#005500";
	m_sChatColor_10 = "#000000";
	m_sChatColor_11 = "#ac0000";
	m_sChatColor_12 = "#000000";
	m_sChatColor_13 = "#ff0000";
	m_sChatColor_14 = "#000000";
	m_sChatColor_15 = "#ffff00";
	m_sChatColor_16 = "#000000";
	m_sChatColor_17 = "#0000ff";
	m_sChatColor_18 = "#ff0c52";
	m_sChatColor_19 = "#000000";
	
	/* default false to use theme color */
	m_bChatBackgroundColorEnabled = false;
	/* white */
	m_sChatBackgroundColor = "#ffffff";

	/*
	 * The simple emoticon theme both looks nicer
	 * and the list has 35 entries while the list
	 * for default has 209 entries so simple will
	 * be faster.
	 */
	m_sApplicationIconTheme = "default";
	m_sEmoticonTheme        = "simple";
	m_sUserListIconTheme    = "default";
	
	m_sSuppressedNicks	= "";
	
	// auto responder defaults to disabled
	m_bAutoResponderEnabled = false;
	m_bAutoResponderEnabledForPM = false;
	m_nAutoResponseDelay = 5;
	m_sAutoResponseIgnores = "";
	
	m_nFilelistNamingSchemeVersion = 0;
	
	m_bFoldersInRightPane = false;
	m_bFolderSizesInLeftPane = true;
	m_bFoldersInRightPaneOnTop = false;
	m_bOpenFoldersInRightPane = true;
	m_bSendUnknownCommandsAsChat = true;
	m_sAllowedUnknownCommands = "/me,/ME";
	m_bAdjustSearchResultHubNames = false;
	m_bRemovePublicHubEnabled = false;

	m_baQMainWindowState = "";
	
	m_nTabCompleteMatchMode = 0;
	m_bTabCompleteStripTags = false;
	
	m_bThreadsForShellCommands = true;
	m_nShellCommandTimeout = 5;
	
	m_bUserCommandSubmenu = true;
	
	/*
	 * somehow the default for this was missing
	 * and would have been an empty CString/QString
	 */
	m_nDoubleClickAction = 0;
	
	m_eMagnetActionChat = eMagnetPrompt;
	
	m_bAlternatingRowColors = true;

#if defined(Q_OS_MACX) 
	CFURLRef pluginRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); 
	CFStringRef macPath = CFURLCopyFileSystemPath(pluginRef, kCFURLPOSIXPathStyle); 
	const char *pathPtr = CFStringGetCStringPtr(macPath, CFStringGetSystemEncoding()); 

	SetValknutDataPath(pathPtr); 
#endif 

	if ( m_sValknutDataPath.isEmpty() )
#ifdef WIN32
		m_sValknutDataPath = QApplication::applicationDirPath();
#else
		m_sValknutDataPath = VALKNUT_DATAPATH;
#endif
	g_pConfig = this;
}

DCConfig::~DCConfig()
{
	g_pConfig = NULL;
	
	delete pProcess;

	if ( m_pEmoticons )
	{
		for ( QList<DC_EmoticonObject*>::const_iterator it = m_pEmoticons->constBegin(); it != m_pEmoticons->constEnd(); ++it )
		{
			delete *it;
		}
		m_pEmoticons->clear();
		delete m_pEmoticons;
		m_pEmoticons = 0;
	}

	// delete the maps, fix memory leak on shutdown
	for ( SettingMap::const_iterator it = m_guiSettingMap.constBegin(); it != m_guiSettingMap.constEnd(); ++it )
	{
		delete it.value();
	}
	m_guiSettingMap.clear();

	for ( QMap<int, DC_UserMenuCommand*>::const_iterator it = m_UserMenuCommands.constBegin(); it != m_UserMenuCommands.constEnd(); ++it )
	{
		delete it.value();
	}
	m_UserMenuCommands.clear();
	
	for ( int x = 0; x < USERLIST_XPM_COLUMNS; ++x )
	{
		for ( int y = 0; y < USERLIST_XPM_ROWS; ++y )
		{
			if ( m_UserIconCache[x][y] )
			{
				delete m_UserIconCache[x][y];
				m_UserIconCache[x][y] = 0;
			}
		}
	}
	
	for ( QList<DC_UserChatCommand*>::const_iterator it = m_lUserChatCommands.constBegin(); it != m_lUserChatCommands.constEnd(); ++it )
	{
		delete *it;
	}
	m_lUserChatCommands.clear();
	
	for ( QList<DC_AutoResponseObject*>::const_iterator it = m_lAutoResponses.constBegin(); it != m_lAutoResponses.constEnd(); ++it )
	{
		delete *it;
	}
	m_lAutoResponses.clear();
}

/** */
void DCConfig::ParseDCGuiConfig( CXml * xml )
{
	CString xml_name, xml_tmp;

	do
	{
		/* gui entrys */
		if ( (xml->Name() == XML_GUI) && xml->FirstChild() )
		{
			do
			{
				xml_name = xml->Name();
				if ( xml_name == XML_OPENCLIENTWINDOWS )
					m_nOpenClientWindows = xml->Content().asINT();
				else if ( xml_name == XML_OPENPRIVATECHATWIN )
					bOpenPrivateChatWindow = xml->GetBoolChild();
				else if ( xml_name == XML_CHATMAXPARAGRAPH )
					m_nChatMaxParagraph = xml->Content().asLONG();
				else if ( xml_name == XML_EMOTICONS )
				        bEnableEmoticons = xml->GetBoolChild();
				else if ( xml_name == XML_USER_PHOTO )
				        m_sUserPhotoFileName = xml->Content().Data();
				else if ( xml_name == XML_TABBAR )
				        bTabBar = xml->GetBoolChild();
				else if ( xml_name == XML_TOOLBAR )
				        bToolBar = xml->GetBoolChild();
				else if ( xml_name == XML_STATUSBAR )
					bStatusBar = xml->GetBoolChild();
				else if ( xml_name == XML_USERLISTRIGHTALIGNMENT )
					bUserListRightAlignment = xml->GetBoolChild();
				else if ( xml_name == XML_SHOWCHATSENDBUTTON )
					bShowChatSendButton = xml->GetBoolChild();
				else if ( xml_name == XML_UNIT )
				{
					xml_tmp = xml->Content();
					if ( xml_tmp == XML_UNIT_AUTO )
						m_eUnit = euAUTO;
					else if ( xml_tmp == XML_UNIT_BYTE )
						m_eUnit = euBYTE;
					else if ( xml_tmp == XML_UNIT_KBYTE )
						m_eUnit = euKBYTE;
					else if ( xml_tmp == XML_UNIT_MBYTE )
						m_eUnit = euMBYTE;
					else if ( xml_tmp == XML_UNIT_GBYTE )
						m_eUnit = euGBYTE;
				}
				else if ( xml_name == XML_THEME_QT4 )
					sTheme = xml->Content().Data();
				else if ( xml_name == XML_THEME )
					sThemeQT3 = xml->Content().Data();
				else if ( xml_name == XML_BACKGROUNDPIXMAP )
					sBackgroundPixmap = xml->Content().Data();
				else if ( xml_name == XML_BROWSER )
					sBrowser = xml->Content().Data();
				else if ( xml_name == XML_CUSTOM_BROWSER )
					m_bCustomBrowser = xml->GetBoolChild();
				else if ( xml_name == XML_LANGUAGEFILE )
					sLanguageFile = xml->Content().Data();
				else if ( xml_name == XML_APP_FONT )
					sAppFont = xml->Content().Data();
				else if ( xml_name == XML_USE_CUSTOM_FONT )
					m_bUseCustomFont = xml->GetBoolChild();
				else if ( xml_name == XML_APP_WIDTH )
					iAppWidth = xml->Content().asINT();
				else if ( xml_name == XML_APP_HEIGHT )
					iAppHeight = xml->Content().asINT();
				else if ( xml_name == XML_SOUND_FILE_CONNECT )
					sSoundFileConnect = xml->Content().Data();
				else if ( xml_name == XML_SOUND_FILE_DISCONNECT )
					sSoundFileDisconnect = xml->Content().Data();
				else if ( xml_name == XML_SOUND_FILE_SEND )
					sSoundFileSend = xml->Content().Data();
				else if ( xml_name == XML_SOUND_FILE_RECEIVE )
					sSoundFileReceive = xml->Content().Data();
				else if ( xml_name == XML_SOUND_FILE_FIRSTRECEIVE )
					sSoundFileFirstReceive = xml->Content().Data();
				else if ( xml_name == XML_SOUND_FILE_NICK_MENTIONED )
					sSoundFileNickMentioned = xml->Content().Data();
				else if ( xml_name == XML_EXTERNAL_SOUND_PLAYER )
					bExternalSoundPlayer = xml->GetBoolChild();
				else if ( xml_name == XML_EXTERNAL_PLAYER )
					sExternalPlayer = xml->Content().Data();
				else if ( xml_name == XML_SOUND_DISABLED )
					bSoundDisabled = xml->GetBoolChild();
				else if ( xml_name == XML_SOUND_DISABLED_AWAY )
					bSoundDisabledAway = xml->GetBoolChild();
				else if ( xml_name == XML_SOUND_ENABLED_CONNECT )
					bSoundEnabledConnect = xml->GetBoolChild();
				else if ( xml_name == XML_SOUND_ENABLED_DISCONNECT )
					bSoundEnabledDisconnect = xml->GetBoolChild();
				else if ( xml_name == XML_SOUND_ENABLED_SEND )
					bSoundEnabledSend = xml->GetBoolChild();
				else if ( xml_name == XML_SOUND_ENABLED_RECEIVE )
					bSoundEnabledReceive = xml->GetBoolChild();
				else if ( xml_name == XML_SOUND_ENABLED_FIRSTRECEIVE )
					bSoundEnabledFirstReceive = xml->GetBoolChild();
				else if ( xml_name == XML_SOUND_ENABLED_NICK_MENTIONED )
					bSoundEnabledNickMentioned = xml->GetBoolChild();
				else if ( xml_name == XML_TIMESTAMP_PRIVATECHAT )
					bTimeStampPrivateChat = xml->GetBoolChild();
				else if ( xml_name == XML_TIMESTAMP_HUBCHAT )
					bTimeStampHubChat = xml->GetBoolChild();
				else if ( xml_name == XML_SHOW_STATUS_MESSAGE )
					bShowStatusMessage = xml->GetBoolChild();
				else if ( xml_name == XML_SENDCHATINDEX )
					m_nSendChat = xml->Content().asINT();
				else if ( xml_name == XML_SHOW_TRANSFER_WIN )
					bShowTransferWin = xml->GetBoolChild();
				else if ( xml_name == XML_TV_CHUNKPERCENT )
					bTVChunkPercent = xml->GetBoolChild();
				else if ( xml_name == XML_TV_FILEPERCENT )
					bTVFilePercent = xml->GetBoolChild();
				else if ( xml_name == XML_TV_CHUNKSIZE )
					bTVChunkSize = xml->GetBoolChild();
				else if ( xml_name == XML_TV_FILESIZE )
					bTVFileSize = xml->GetBoolChild();
				else if ( xml_name == XML_TV_DOWNLOADRATESINGLE )
					bTVDownloadRateSingle = xml->GetBoolChild();
				else if ( xml_name == XML_TV_ELAPSEDTIMESINGLE )
					bTVElapsedTimeSingle = xml->GetBoolChild();
				else if ( xml_name == XML_TV_DOWNLOADRATEMULTI )
					bTVDownloadRateMulti = xml->GetBoolChild();
				else if ( xml_name == XML_TV_ELAPSEDTIMEMULTI )
					bTVElapsedTimeMulti = xml->GetBoolChild();
				else if ( xml_name == XML_SEND_HIDE_PRIVATE_CHAT_TO_PUBLIC_CHAT )
					bSendHidePrivateChatToPublicChat = xml->GetBoolChild();
				else if ( xml_name == XML_CHAT_MESSAGE_MAX_LINES )
					iChatMessageMaxLines = xml->Content().asINT();
				else if ( xml_name == XML_FLOODCOUNT )
					iFloodCount = xml->Content().asINT();
				else if ( xml_name == XML_FLOODOPKICK )
					m_bFloodOpKick = xml->GetBoolChild();
				else if ( xml_name == XML_DEFAULTDOWNLOADMODE )
					iDefaultDownloadMode = xml->Content().asUINT();
				else if ( xml_name == XML_QUERYONEXIT )
					bQueryOnExit = xml->GetBoolChild();
				else if ( xml_name == XML_ENABLETRAY )
					m_bEnableTray = xml->GetBoolChild();
				else if ( xml_name == XML_QUERYONFILEDELETE )
					bQueryOnFileDelete = xml->GetBoolChild();
				else if ( xml_name == XML_SHOWCHATINTAB )
					bShowChatInTab = xml->GetBoolChild();
				else if ( xml_name == XML_AUTO_AWAY_MODE )
					m_bAutoAwayMode = xml->GetBoolChild();
				else if ( xml_name == XML_AUTO_AWAY_TIME )
					m_nAutoAwayTime = xml->Content().asUINT();
				else if ( xml_name == XML_CHAT_SHOW_JOINS_AND_PARTS )
					m_bChatShowJoinsAndParts = xml->GetBoolChild();
				else if ( xml_name == XML_CHAT_SHOW_JOINS_AND_PARTS_ONLY_FAV )
					m_bChatShowJoinsAndPartsOnlyFav = xml->GetBoolChild();
				else if ( xml_name == XML_CHAT_SUPPRESSED_NICKS )
					m_sSuppressedNicks = xml->Content().Data();
				else if ( xml_name == XML_SEND_UNKNOWN_COMMANDS )
					m_bSendUnknownCommandsAsChat = xml->GetBoolChild();
				else if ( xml_name == XML_ALLOWED_UNKNOWN_COMMANDS )
					m_sAllowedUnknownCommands = xml->Content().Data();
				else if ( xml_name == XML_DOUBLE_CLICK_ACTION )
					m_nDoubleClickAction = xml->Content().asINT();
				else if ( xml_name == XML_MAGNET_ACTION_CHAT )
					m_eMagnetActionChat = eMagnetAction( xml->Content().asINT() );
				else if ( xml_name == XML_VALKNUT_DATA_PATH )
					m_sValknutDataPath = xml->Content().Data();
				else if ( (xml_name == "MAP") && xml->FirstChild() )
				{
					StringMap * map = new StringMap();

					do
					{
						xml_tmp = xml->Name();
						if ( xml_tmp == "KEY" )
							m_guiSettingMap[xml->Content().Data()] = map;
						else if ( (xml_tmp == XML_ENTRY) && xml->FirstChild() )
						{
							CString key,name;
							
							do
							{
								xml_tmp = xml->Name();
								if ( xml_tmp == "KEY" )
									key = xml->Content();
								else if ( xml_tmp == "NAME" )
									name = xml->Content();
							}
							while ( xml->NextNode() );
							xml->Parent();
							
							(*map)[key.Data()]=name.Data();
						}
					}
					while ( xml->NextNode() );
					xml->Parent();
				}
				else if ( xml_name == XML_LCO_ENABLELOGGING )
					SetLogChatOption( elcoENABLELOGGING, xml->GetBoolChild() );
				else if ( xml_name == XML_LCO_APPENDDATE )
					SetLogChatOption( elcoAPPENDDATE, xml->GetBoolChild() );
				else if ( xml_name == XML_LCO_APPENDHUBNAME )
					SetLogChatOption( elcoAPPENDHUBNAME, xml->GetBoolChild() );
				else if ( xml_name == XML_LCO_APPENDHUBHOST )
					SetLogChatOption( elcoAPPENDHUBHOST, xml->GetBoolChild() );
				else if ( xml_name == XML_LCO_DISABLEPUBLICCHAT )
					SetLogChatOption( elcoDISABLEPUBLICCHAT, xml->GetBoolChild() );
				else if ( xml_name == XML_LCO_ENABLENICKNAMEFILTER )
					SetLogChatOption( elcoENABLENICKNAMEFILTER, xml->GetBoolChild() );
				else if ( xml_name == XML_LCO_NICKNAMEFILTER_ENABLELOGGING )
					SetLogChatOption( elcoNICKNAMEFILTER_ENABLELOGGING, xml->GetBoolChild() );
				else if ( xml_name == "NICKNAMEFILTER" )
				{
					xml_tmp = xml->Content();
					if ( xml_tmp.NotEmpty() )
						m_LogChatNickNameFilter << QString::fromAscii(xml_tmp.Data());
				}
				else if ( xml_name == XML_CC_CHATTIMESTAMP )
					SetChatColor( eccCHATTIMESTAMP, xml->Content().Data() );
				else if ( xml_name == XML_CC_CHATLOCALNICK )
					SetChatColor( eccCHATLOCALNICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_CHATLOCALTEXT )
					SetChatColor( eccCHATLOCALTEXT, xml->Content().Data() );
				else if ( xml_name == XML_CC_CHATREMOTENICK )
					SetChatColor( eccCHATREMOTENICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_CHATREMOTETEXT )
					SetChatColor( eccCHATREMOTETEXT, xml->Content().Data() );
				else if ( xml_name == XML_CC_CHATSTATUSNICK )
					SetChatColor( eccCHATSTATUSNICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_CHATSTATUSTEXT )
					SetChatColor( eccCHATSTATUSTEXT, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATTIMESTAMP )
					SetChatColor( eccPUBLICCHATTIMESTAMP, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATLOCALNICK )
					SetChatColor( eccPUBLICCHATLOCALNICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATLOCALTEXT )
					SetChatColor( eccPUBLICCHATLOCALTEXT, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATREMOTENICK )
					SetChatColor( eccPUBLICCHATREMOTENICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATREMOTETEXT )
					SetChatColor( eccPUBLICCHATREMOTETEXT, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATSTATUSNICK )
					SetChatColor( eccPUBLICCHATSTATUSNICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATSTATUSTEXT )
					SetChatColor( eccPUBLICCHATSTATUSTEXT, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICPRIVATECHATNICK )
					SetChatColor( eccPUBLICPRIVATECHATNICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICPRIVATECHATTEXT )
					SetChatColor( eccPUBLICPRIVATECHATTEXT, xml->Content().Data() );
				else if ( xml_name == XML_CC_CHATSAY )
					SetChatColor( eccCHATSAY, xml->Content().Data() );
				else if ( xml_name == XML_CC_PUBLICCHATMENICK )
					SetChatColor( eccPUBLICCHATMENICK, xml->Content().Data() );
				else if ( xml_name == XML_CC_OPNICK )
					SetChatColor( eccOPNICK, xml->Content().Data() );
				else if ( xml_name == XML_CHAT_BG_COLOR_ENABLED )
					m_bChatBackgroundColorEnabled = xml->GetBoolChild();
				else if ( xml_name == XML_CHAT_BG_COLOR )
					m_sChatBackgroundColor = QString::fromAscii(xml->Content().Data());
				else if ( xml_name == XML_USER_COMMAND_SUBMENU )
					m_bUserCommandSubmenu = xml->GetBoolChild();
				else if ( (xml_name == XML_USERMENUCOMMAND) && xml->FirstChild() )
				{
					DC_UserMenuCommand * umc = new DC_UserMenuCommand();
					
					do
					{
						xml_tmp = xml->Name();
						if ( xml_tmp == XML_USERMENUCOMMAND_NAME )
							umc->m_sName = QString::fromAscii(xml->Content().Data());
						else if ( xml_tmp == XML_USERMENUCOMMAND_ACT )
							umc->m_sCommand = QString::fromAscii(xml->Content().Data());
						else if ( xml_tmp == XML_USERMENUCOMMAND_CONTEXT )
							umc->m_nContext = xml->Content().asINT();
						else if ( xml_tmp == XML_USERMENUCOMMAND_TYPE )
							umc->m_nType = xml->Content().asINT();
						else if ( xml_tmp == XML_USERMENUCOMMAND_HUBIP )
							umc->m_sHubIP = QString::fromAscii(xml->Content().Data());
					}
					while ( xml->NextNode() );
					xml->Parent();
					
					if ( umc->m_nType == -1 )
					{
						umc->m_nType = euctRaw;
					}
					m_UserMenuCommands.insert( m_UserMenuCommands.size(), umc );
				}
				else if ( xml_name == XML_SHELL_COMMAND_THREADS )
					m_bThreadsForShellCommands = xml->GetBoolChild();
				else if ( xml_name == XML_SHELL_COMMAND_TIMEOUT )
					m_nShellCommandTimeout = xml->Content().asINT();
				else if ( (xml_name == XML_USERCHATCOMMAND) && xml->FirstChild() )
				{
					DC_UserChatCommand * ucc = new DC_UserChatCommand();
					
					do
					{
						xml_tmp = xml->Name();
						if ( xml_tmp == XML_USERCHATCOMMAND_NAME )
							ucc->m_sName = QString::fromAscii(xml->Content().Data());
						else if ( xml_tmp == XML_USERCHATCOMMAND_ACT )
							ucc->m_sCommand = QString::fromAscii(xml->Content().Data());
					}
					while ( xml->NextNode() );
					xml->Parent();
					
					if ( ucc->m_sName.isEmpty() || ucc->m_sCommand.isEmpty() )
						delete ucc;
					else
						m_lUserChatCommands.append( ucc );
				}
				else if ( xml_name == XML_AUTORESPONSE_ENABLED )
					SetAutoResponderEnabled( xml->GetBoolChild() );
				else if ( xml_name == XML_AUTORESPONSE_ENABLED_PM )
					SetAutoResponderEnabledForPM( xml->GetBoolChild() );
				else if ( (xml_name == XML_AUTORESPONSE) && xml->FirstChild() )
				{
					DC_AutoResponseObject * aro = new DC_AutoResponseObject();
					
					do
					{
						xml_tmp = xml->Name();
						if ( xml_tmp == XML_AUTORESPONSE_TRIGGER )
							aro->m_sTrigger = QString::fromAscii(xml->Content().Data());
						else if ( xml_tmp == XML_AUTORESPONSE_RESPONSE )
							aro->m_sResponse = QString::fromAscii(xml->Content().Data());
						else if ( xml_tmp == XML_AUTORESPONSE_CASE_SENS )
							aro->m_bCaseSensitive = xml->GetBoolChild();
					}
					while ( xml->NextNode() );
					xml->Parent();
					
					if ( aro->m_sTrigger.isEmpty() || aro->m_sResponse.isEmpty() )
					{
						delete aro;
					}
					else
					{
						m_lAutoResponses.append( aro );
					}
				}
				else if ( xml_name == XML_AUTORESPONSE_DELAY )
					SetAutoResponseDelay( xml->Content().asLONG() );
				else if ( xml_name == XML_AUTORESPONSE_IGNORES )
					m_sAutoResponseIgnores = xml->Content().Data();
				else if ( xml_name == XML_APP_ICON_THEME )
					m_sApplicationIconTheme = xml->Content().Data();
				else if ( xml_name == XML_EMOTICON_THEME )
					m_sEmoticonTheme = xml->Content().Data();
				else if ( xml_name == XML_USER_ICON_THEME )
					m_sUserListIconTheme = xml->Content().Data();
				else if ( xml_name == XML_FILELIST_NAMING_SCHEME )
					m_nFilelistNamingSchemeVersion = xml->Content().asINT();
				else if ( xml_name == XML_QMAINWINDOW_STATE )
					m_baQMainWindowState = QByteArray::fromBase64(xml->Content().Data());
				else if ( xml_name == XML_FOLDERS_RIGHT_PANE )
					SetFoldersInRightPane( xml->GetBoolChild() );
				else if ( xml_name == XML_SIZES_IN_LEFT_PANE )
					SetFolderSizesInLeftPane( xml->GetBoolChild() );
				else if ( xml_name == XML_FOLDERS_RIGHT_PANE_ON_TOP )
					SetFoldersInRightPaneOnTop( xml->GetBoolChild() );
				else if ( xml_name == XML_OPEN_FOLDERS_RIGHT_PANE )
					SetOpenFoldersInRightPane( xml->GetBoolChild() );
				else if ( xml_name == XML_ADJUST_SR )
					SetAdjustSearchResultHubNames( xml->GetBoolChild() );
				else if ( xml_name == XML_REMOVE_PUBLIC_HUB )
					SetRemovePublicHubEnabled( xml->GetBoolChild() );
				else if ( xml_name == XML_TAB_COMPLETE_MODE )
					SetTabCompleteMatchMode( xml->Content().asINT() );
				else if ( xml_name == XML_TAB_COMPLETE_STRIP )
					SetTabCompleteStripTags( xml->GetBoolChild() );
				else if ( xml_name == XML_ALTERNATING_ROW_COLORS )
					m_bAlternatingRowColors = xml->GetBoolChild();
			}
			while ( xml->NextNode() );
			xml->Parent();
		}
	}
	while ( xml->NextNode() );
}

/** */
int DCConfig::Load()
{
	LoadHubProfile();
	LoadDCLib();
	return LoadDCGui();
}

/** */
int DCConfig::Save()
{
	SaveDCLib();
	return SaveDCGui();
}

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

	s = sConfigPath + DCGUI_CONFIG;

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

	delete xml;

	if ( sTheme.isEmpty() )
	{
		sTheme = DCGuiUtils::DetectAppStyleKey();
	}

	// check datapath exists
	QDir dir( GetValknutDataPath() );
	if ( !dir.exists() )
	{
		printf("Data path specified does not exist, resetting.\n");
#if defined(Q_OS_MACX)
		CFURLRef pluginRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
		CFStringRef macPath = CFURLCopyFileSystemPath(pluginRef, kCFURLPOSIXPathStyle);
		const char *pathPtr = CFStringGetCStringPtr(macPath, CFStringGetSystemEncoding());
		
		SetValknutDataPath(pathPtr);
#elif defined(WIN32)
		SetValknutDataPath(QApplication::applicationDirPath());
#else
		SetValknutDataPath(VALKNUT_DATAPATH);
#endif
	}

	/* load user list icons, theme either from config file or default */
	QString actualtheme = m_sUserListIconTheme;
	m_sUserListIconTheme += "forceload";
	SetUserListIconTheme( actualtheme );

	InitMimeSourceFactory();

	return err;
}

/** */
int DCConfig::SaveDCGui()
{
	int err=0;
	CString s;
	CXml xml;

	xml.NewDoc( XML_DCGUI_CONFIG );

	// gui
	xml.StartNewChild( XML_GUI );

	xml.NewNumericChild( XML_OPENCLIENTWINDOWS, m_nOpenClientWindows );
	xml.NewBoolChild( XML_OPENPRIVATECHATWIN, bOpenPrivateChatWindow );
	xml.NewBoolChild( XML_EMOTICONS, bEnableEmoticons );
	xml.NewBoolChild( XML_TABBAR, bTabBar );
	xml.NewBoolChild( XML_TOOLBAR, bToolBar );
	xml.NewBoolChild( XML_STATUSBAR, bStatusBar );
	xml.NewBoolChild( XML_USERLISTRIGHTALIGNMENT, bUserListRightAlignment );
	xml.NewBoolChild( XML_SHOWCHATSENDBUTTON, bShowChatSendButton );
	xml.NewBoolChild( XML_SHOWCHATINTAB, bShowChatInTab );
	xml.NewNumericChild( XML_CHATMAXPARAGRAPH, m_nChatMaxParagraph );

	xml.NewStringChild( XML_USER_PHOTO, m_sUserPhotoFileName.toAscii().constData() );

	switch(m_eUnit)
	{
		case euBYTE:
			s = XML_UNIT_BYTE;
			break;
		case euKBYTE:
			s = XML_UNIT_KBYTE;
			break;
		case euMBYTE:
			s = XML_UNIT_MBYTE;
			break;
		case euGBYTE:
			s = XML_UNIT_GBYTE;
			break;
		default:
			s = XML_UNIT_AUTO;
			break;
	}

	xml.NewStringChild( XML_UNIT, s );
	xml.NewStringChild( XML_THEME, sThemeQT3.toAscii().constData() );
	xml.NewStringChild( XML_THEME_QT4, sTheme.toAscii().constData() );
	xml.NewStringChild( XML_BACKGROUNDPIXMAP, sBackgroundPixmap.toAscii().constData() );
	xml.NewStringChild( XML_BROWSER, sBrowser.toAscii().constData() );
	xml.NewBoolChild( XML_CUSTOM_BROWSER, m_bCustomBrowser );
	xml.NewNumericChild( XML_SENDCHATINDEX, m_nSendChat );
	xml.NewStringChild( XML_LANGUAGEFILE, sLanguageFile.toAscii().constData() );
	xml.NewStringChild( XML_APP_FONT, sAppFont.toAscii().constData() );
	xml.NewBoolChild( XML_USE_CUSTOM_FONT, m_bUseCustomFont );
	xml.NewNumericChild( XML_APP_WIDTH, iAppWidth );
	xml.NewNumericChild( XML_APP_HEIGHT, iAppHeight );
	xml.NewBoolChild( XML_ENABLETRAY, m_bEnableTray );
	xml.NewBoolChild( XML_QUERYONEXIT, bQueryOnExit );
	xml.NewBoolChild( XML_QUERYONFILEDELETE, bQueryOnFileDelete );
	xml.NewStringChild( XML_QMAINWINDOW_STATE, m_baQMainWindowState.toBase64().constData() );
	xml.NewBoolChild( XML_FOLDERS_RIGHT_PANE, m_bFoldersInRightPane );
	xml.NewBoolChild( XML_SIZES_IN_LEFT_PANE, m_bFolderSizesInLeftPane );
	xml.NewBoolChild( XML_FOLDERS_RIGHT_PANE_ON_TOP, m_bFoldersInRightPaneOnTop );
	xml.NewBoolChild( XML_OPEN_FOLDERS_RIGHT_PANE, m_bOpenFoldersInRightPane );
	xml.NewBoolChild( XML_ADJUST_SR, m_bAdjustSearchResultHubNames );
	xml.NewBoolChild( XML_REMOVE_PUBLIC_HUB, m_bRemovePublicHubEnabled );
	xml.NewNumericChild( XML_TAB_COMPLETE_MODE, m_nTabCompleteMatchMode );
	xml.NewBoolChild( XML_TAB_COMPLETE_STRIP, m_bTabCompleteStripTags );
	xml.NewBoolChild( XML_ALTERNATING_ROW_COLORS, m_bAlternatingRowColors );

	// sound settings
	xml.NewStringChild( XML_SOUND_FILE_CONNECT, sSoundFileConnect.toAscii().constData() );
	xml.NewStringChild( XML_SOUND_FILE_DISCONNECT, sSoundFileDisconnect.toAscii().constData() );
	xml.NewStringChild( XML_SOUND_FILE_SEND, sSoundFileSend.toAscii().constData() );
	xml.NewStringChild( XML_SOUND_FILE_RECEIVE, sSoundFileReceive.toAscii().constData() );
	xml.NewStringChild( XML_SOUND_FILE_FIRSTRECEIVE, sSoundFileFirstReceive.toAscii().constData() );
	xml.NewStringChild( XML_SOUND_FILE_NICK_MENTIONED, sSoundFileNickMentioned.toAscii().constData() );
	xml.NewStringChild( XML_EXTERNAL_PLAYER, sExternalPlayer.toAscii().constData() );
	xml.NewBoolChild( XML_SOUND_ENABLED_CONNECT, bSoundEnabledConnect );
	xml.NewBoolChild( XML_SOUND_ENABLED_DISCONNECT, bSoundEnabledDisconnect );
	xml.NewBoolChild( XML_SOUND_ENABLED_SEND, bSoundEnabledSend );
	xml.NewBoolChild( XML_SOUND_ENABLED_RECEIVE, bSoundEnabledReceive );
	xml.NewBoolChild( XML_SOUND_ENABLED_FIRSTRECEIVE, bSoundEnabledFirstReceive );
	xml.NewBoolChild( XML_SOUND_ENABLED_NICK_MENTIONED, bSoundEnabledNickMentioned );
	xml.NewBoolChild( XML_EXTERNAL_SOUND_PLAYER, bExternalSoundPlayer );
	xml.NewBoolChild( XML_SOUND_DISABLED, bSoundDisabled );
	xml.NewBoolChild( XML_SOUND_DISABLED_AWAY, bSoundDisabledAway );

	// log settings
	xml.NewBoolChild( XML_TIMESTAMP_PRIVATECHAT, bTimeStampPrivateChat );
	xml.NewBoolChild( XML_TIMESTAMP_HUBCHAT, bTimeStampHubChat );
	xml.NewBoolChild( XML_SHOW_STATUS_MESSAGE, bShowStatusMessage );

	xml.NewBoolChild( XML_LCO_ENABLELOGGING, GetLogChatOption( elcoENABLELOGGING ) );
	xml.NewBoolChild( XML_LCO_APPENDDATE, GetLogChatOption( elcoAPPENDDATE ) );
	xml.NewBoolChild( XML_LCO_APPENDHUBNAME, GetLogChatOption( elcoAPPENDHUBNAME ) );
	xml.NewBoolChild( XML_LCO_APPENDHUBHOST, GetLogChatOption( elcoAPPENDHUBHOST ) );
	xml.NewBoolChild( XML_LCO_DISABLEPUBLICCHAT, GetLogChatOption( elcoDISABLEPUBLICCHAT ) );
	xml.NewBoolChild( XML_LCO_ENABLENICKNAMEFILTER, GetLogChatOption( elcoENABLENICKNAMEFILTER ) );
	xml.NewBoolChild( XML_LCO_NICKNAMEFILTER_ENABLELOGGING, GetLogChatOption( elcoNICKNAMEFILTER_ENABLELOGGING ) );

	for ( QStringList::const_iterator slit = m_LogChatNickNameFilter.constBegin(); slit != m_LogChatNickNameFilter.constEnd(); ++slit )
	{
		xml.NewStringChild( "NICKNAMEFILTER", (*slit).toAscii().constData() );
	}

	// valknut data path
	xml.NewStringChild( XML_VALKNUT_DATA_PATH, m_sValknutDataPath.toAscii().constData() );

	xml.NewStringChild( XML_CC_CHATTIMESTAMP, GetChatColor(eccCHATTIMESTAMP).toAscii().constData() );
	xml.NewStringChild( XML_CC_CHATLOCALNICK, GetChatColor(eccCHATLOCALNICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_CHATLOCALTEXT, GetChatColor(eccCHATLOCALTEXT).toAscii().constData() );
	xml.NewStringChild( XML_CC_CHATREMOTENICK, GetChatColor(eccCHATREMOTENICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_CHATREMOTETEXT, GetChatColor(eccCHATREMOTETEXT).toAscii().constData() );
	xml.NewStringChild( XML_CC_CHATSTATUSNICK, GetChatColor(eccCHATSTATUSNICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_CHATSTATUSTEXT, GetChatColor(eccCHATSTATUSTEXT).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATTIMESTAMP, GetChatColor(eccPUBLICCHATTIMESTAMP).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATLOCALNICK, GetChatColor(eccPUBLICCHATLOCALNICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATLOCALTEXT, GetChatColor(eccPUBLICCHATLOCALTEXT).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATREMOTENICK, GetChatColor(eccPUBLICCHATREMOTENICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATREMOTETEXT, GetChatColor(eccPUBLICCHATREMOTETEXT).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATSTATUSNICK, GetChatColor(eccPUBLICCHATSTATUSNICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATSTATUSTEXT, GetChatColor(eccPUBLICCHATSTATUSTEXT).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICPRIVATECHATNICK, GetChatColor(eccPUBLICPRIVATECHATNICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICPRIVATECHATTEXT, GetChatColor(eccPUBLICPRIVATECHATTEXT).toAscii().constData() );
	xml.NewStringChild( XML_CC_CHATSAY, GetChatColor(eccCHATSAY).toAscii().constData() );
	xml.NewStringChild( XML_CC_PUBLICCHATMENICK, GetChatColor(eccPUBLICCHATMENICK).toAscii().constData() );
	xml.NewStringChild( XML_CC_OPNICK, GetChatColor(eccOPNICK).toAscii().constData() );
	
	xml.NewBoolChild( XML_CHAT_BG_COLOR_ENABLED, m_bChatBackgroundColorEnabled );
	xml.NewStringChild( XML_CHAT_BG_COLOR, m_sChatBackgroundColor.toAscii().constData() );

	// transfer view settings
	xml.NewBoolChild( XML_TV_CHUNKPERCENT, bTVChunkPercent );
	xml.NewBoolChild( XML_TV_FILEPERCENT, bTVFilePercent );
	xml.NewBoolChild( XML_TV_CHUNKSIZE, bTVChunkSize );
	xml.NewBoolChild( XML_TV_FILESIZE, bTVFileSize );
	xml.NewBoolChild( XML_TV_DOWNLOADRATESINGLE, bTVDownloadRateSingle );
	xml.NewBoolChild( XML_TV_ELAPSEDTIMESINGLE, bTVElapsedTimeSingle );
	xml.NewBoolChild( XML_TV_DOWNLOADRATEMULTI, bTVDownloadRateMulti );
	xml.NewBoolChild( XML_TV_ELAPSEDTIMEMULTI, bTVElapsedTimeMulti );
	xml.NewBoolChild( XML_SHOW_TRANSFER_WIN, bShowTransferWin );
	
	xml.NewNumericChild( XML_FLOODCOUNT, iFloodCount );
	xml.NewBoolChild( XML_FLOODOPKICK, m_bFloodOpKick );

	xml.NewBoolChild( XML_SEND_HIDE_PRIVATE_CHAT_TO_PUBLIC_CHAT, bSendHidePrivateChatToPublicChat );
	xml.NewNumericChild( XML_CHAT_MESSAGE_MAX_LINES, iChatMessageMaxLines );
	xml.NewNumericChild( XML_DEFAULTDOWNLOADMODE, iDefaultDownloadMode );

	xml.NewBoolChild( XML_AUTO_AWAY_MODE, m_bAutoAwayMode );
	xml.NewNumericChild( XML_AUTO_AWAY_TIME, m_nAutoAwayTime );
	xml.NewBoolChild( XML_CHAT_SHOW_JOINS_AND_PARTS, m_bChatShowJoinsAndParts );
	xml.NewBoolChild( XML_CHAT_SHOW_JOINS_AND_PARTS_ONLY_FAV, m_bChatShowJoinsAndPartsOnlyFav );
	xml.NewStringChild( XML_CHAT_SUPPRESSED_NICKS, m_sSuppressedNicks.toAscii().constData() );
	xml.NewBoolChild( XML_SEND_UNKNOWN_COMMANDS, m_bSendUnknownCommandsAsChat );
	xml.NewStringChild( XML_ALLOWED_UNKNOWN_COMMANDS, m_sAllowedUnknownCommands.toAscii().constData() );
	xml.NewNumericChild( XML_DOUBLE_CLICK_ACTION, m_nDoubleClickAction );
	xml.NewNumericChild( XML_MAGNET_ACTION_CHAT, m_eMagnetActionChat );

	xml.NewBoolChild( XML_USER_COMMAND_SUBMENU, m_bUserCommandSubmenu );
	// user menu commands
	DC_UserMenuCommand * umc = 0;
	for ( QMap<int, DC_UserMenuCommand*>::const_iterator umcit = m_UserMenuCommands.constBegin(); umcit != m_UserMenuCommands.constEnd(); ++umcit )
	{
		umc = umcit.value();
		xml.StartNewChild( XML_USERMENUCOMMAND );
		xml.NewStringChild( XML_USERMENUCOMMAND_NAME, umc->m_sName.toAscii().constData() );
		xml.NewStringChild( XML_USERMENUCOMMAND_ACT, umc->m_sCommand.toAscii().constData() );
		xml.NewNumericChild( XML_USERMENUCOMMAND_CONTEXT, umc->m_nContext );
		xml.NewNumericChild( XML_USERMENUCOMMAND_TYPE, umc->m_nType );
		xml.NewStringChild( XML_USERMENUCOMMAND_HUBIP, umc->m_sHubIP.toAscii().constData() );
		xml.NewNumericChild( XML_USERMENUCOMMAND_POSITION, umcit.key() ); /* ignored, position in file is used */
		xml.Parent();
	}
	
	// shell command settings
	xml.NewBoolChild( XML_SHELL_COMMAND_THREADS, m_bThreadsForShellCommands );
	xml.NewNumericChild( XML_SHELL_COMMAND_TIMEOUT, m_nShellCommandTimeout );
	
	// user chat commands
	for ( QList<DC_UserChatCommand*>::const_iterator uccit = m_lUserChatCommands.constBegin(); uccit != m_lUserChatCommands.constEnd(); ++uccit )
	{
		xml.StartNewChild( XML_USERCHATCOMMAND );
		xml.NewStringChild( XML_USERCHATCOMMAND_NAME, (*uccit)->m_sName.toAscii().constData() );
		xml.NewStringChild( XML_USERCHATCOMMAND_ACT, (*uccit)->m_sCommand.toAscii().constData() );
		xml.Parent();
	}
	
	// icon themes
	xml.NewStringChild( XML_APP_ICON_THEME, GetApplicationIconTheme().toAscii().constData() );
	xml.NewStringChild( XML_EMOTICON_THEME, GetEmoticonTheme().toAscii().constData() );
	xml.NewStringChild( XML_USER_ICON_THEME, GetUserListIconTheme().toAscii().constData() );
	
	// filelist naming scheme version
	xml.NewNumericChild( XML_FILELIST_NAMING_SCHEME, GetFilelistNamingSchemeVersion() );
	
	// auto responses
	xml.NewBoolChild( XML_AUTORESPONSE_ENABLED, GetAutoResponderEnabled() );
	xml.NewBoolChild( XML_AUTORESPONSE_ENABLED_PM, GetAutoResponderEnabledForPM() );
	for ( QList<DC_AutoResponseObject*>::const_iterator arit = m_lAutoResponses.constBegin(); arit != m_lAutoResponses.constEnd(); ++arit )
	{
		xml.StartNewChild( XML_AUTORESPONSE );
		xml.NewStringChild( XML_AUTORESPONSE_TRIGGER, (*arit)->m_sTrigger.toAscii().constData() );
		xml.NewStringChild( XML_AUTORESPONSE_RESPONSE, (*arit)->m_sResponse.toAscii().constData() );
		xml.NewBoolChild( XML_AUTORESPONSE_CASE_SENS, (*arit)->m_bCaseSensitive );
		xml.Parent();
	}
	xml.NewNumericChild( XML_AUTORESPONSE_DELAY, GetAutoResponseDelay() );
	xml.NewStringChild( XML_AUTORESPONSE_IGNORES, GetAutoResponseIgnores().toAscii().constData() );
	
	// save map settings
	SettingMap::Iterator it;
	StringMap::Iterator it1;

	for(it=m_guiSettingMap.begin();it!=m_guiSettingMap.end();++it)
	{
		xml.StartNewChild("MAP");
		xml.NewStringChild( "KEY", it.key().toAscii().constData() );
		for(it1=it.value()->begin();it1!=it.value()->end();++it1)
		{
			xml.StartNewChild( XML_ENTRY );
			xml.NewStringChild( "KEY", it1.key().toAscii().constData() );
			xml.NewStringChild( "NAME", it1.value().toAscii().constData() );
			xml.Parent();
		}
		xml.Parent();
	}

	// save file
	s = sConfigPath + DCGUI_CONFIG;

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

	return err;
}

/** */
int DCConfig::LoadDCHubFilter( QMap<QString, DC_HubFilterObject*> * map )
{
	CString s, xml_name;
	CXml xml;
	DC_HubFilterObject * HubFilterObject;

	s = sConfigPath + DCGUI_HUBFILTER;

	if ( xml.ParseFile(s) && xml.DocFirstChild() )
	{
		do
		{
			if ( (xml.Name() == XML_DCGUI_HUBFILTER) && xml.FirstChild() )
			{
				do
				{
					if ( (xml.Name() == XML_FILTER) && xml.FirstChild() )
					{
						HubFilterObject = new DC_HubFilterObject();

						do
						{
							xml_name = xml.Name();
							if ( xml_name == XML_FILTERNAME )
								HubFilterObject->m_sFilterName = QString::fromAscii(xml.Content().Data());
							else if ( xml_name == XML_CONTAINS )
								HubFilterObject->m_sContains = QString::fromAscii(xml.Content().Data());
							else if ( xml_name == XML_USER )
								HubFilterObject->m_nUser = xml.Content().asUINT();
							else if ( xml_name == XML_NAME )
								HubFilterObject->m_bName = xml.GetBoolChild();
							else if ( xml_name == XML_SERVER )
								HubFilterObject->m_bServer = xml.GetBoolChild();
							else if ( xml_name == XML_DESCRIPTION )
								HubFilterObject->m_bDescription = xml.GetBoolChild();
						}
						while ( xml.NextNode() );
						xml.Parent();

						if ( HubFilterObject->m_sFilterName.isEmpty() )
						{
							delete HubFilterObject;
						}
						else
						{
							if ( map->contains(HubFilterObject->m_sFilterName) )
							{
								delete HubFilterObject;
							}
							else
							{
								map->insert( HubFilterObject->m_sFilterName, HubFilterObject );
							}
						}
					}
				}
				while ( xml.NextNode() );
				xml.Parent();
			}
		}
		while ( xml.NextNode() );
	}

	return 0;
}

/** */
int DCConfig::SaveDCHubFilter( QMap<QString, DC_HubFilterObject*> * map )
{
	int err=0;
	CString s;
	DC_HubFilterObject * HubFilterObject;
	CXml xml;
	xml.NewDoc( XML_DCGUI_HUBFILTER );

	for ( QMap<QString, DC_HubFilterObject*>::const_iterator it = map->constBegin(); it != map->constEnd(); ++it )
	{
		HubFilterObject = it.value();
		
		xml.StartNewChild( XML_FILTER );
		xml.NewStringChild( XML_FILTERNAME, HubFilterObject->m_sFilterName.toAscii().constData() );
		xml.NewStringChild( XML_CONTAINS, HubFilterObject->m_sContains.toAscii().constData() );
		xml.NewNumericChild( XML_USER, HubFilterObject->m_nUser );
		xml.NewBoolChild( XML_NAME, HubFilterObject->m_bName );
		xml.NewBoolChild( XML_SERVER, HubFilterObject->m_bServer );
		xml.NewBoolChild( XML_DESCRIPTION, HubFilterObject->m_bDescription );
		xml.Parent();
	}

	// save file
	s = sConfigPath + DCGUI_HUBFILTER;

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

	return err;
}

/** */
int DCConfig::LoadDCFriendList( FriendMap * map )
{
	CString s, xml_name;
	CXml xml;
	DCFriendObject * FriendObject;

	s = sConfigPath + DCGUI_FRIENDLIST;

	if ( xml.ParseFile(s) && xml.DocFirstChild() )
	{
		do
		{
			if ( (xml.Name() == XML_DCGUI_FRIENDLIST) && xml.FirstChild() )
			{
				do
				{
					if ( (xml.Name() == XML_FRIEND) && xml.FirstChild() )
					{
						FriendObject = new DCFriendObject();

						do
						{
							xml_name = xml.Name();
							if ( xml_name == XML_NAME )
								FriendObject->m_sName = QString::fromAscii(xml.Content().Data());
							else if ( xml_name == XML_DESCRIPTION )
								FriendObject->m_sDescription = QString::fromAscii(xml.Content().Data());
							else if ( xml_name == XML_HUBNAME )
								FriendObject->m_sHubName = QString::fromAscii(xml.Content().Data());
							else if ( xml_name == XML_HUBHOST )
								FriendObject->m_sHubHost = QString::fromAscii(xml.Content().Data());
							else if ( xml_name == XML_IMAGE )
								FriendObject->m_sImageFileName = QString::fromAscii(xml.Content().Data());
							else if ( xml_name == XML_SEND_IMAGE )
								FriendObject->m_bSendImage = xml.GetBoolChild();
							else if ( xml_name == XML_AUTO_SEC )
								FriendObject->m_bAutoSec = xml.GetBoolChild();
							else if ( xml_name == XML_PERM_SLOT )
								FriendObject->m_bPermSlot = xml.GetBoolChild();
							else if ( xml_name == XML_IGNORE )
								FriendObject->m_bIgnore = xml.GetBoolChild();
						}
						while ( xml.NextNode() );
						xml.Parent();

						if ( FriendObject->m_sName.isEmpty() )
							delete FriendObject;
						else
							map->insert( FriendObject->m_sName, FriendObject );
					}
				}
				while ( xml.NextNode() );
				xml.Parent();
			}
		}
		while ( xml.NextNode() );
	}

	return 0;
}

/** */
int DCConfig::SaveDCFriendList( FriendMap * map )
{
	int err=0;
	CString s;
	DCFriendObject * FriendObject;
	CXml xml;
	xml.NewDoc( XML_DCGUI_FRIENDLIST );

	for ( FriendMap::const_iterator it = map->constBegin(); it != map->constEnd(); ++it )
	{
		FriendObject = it.value();
		
		xml.StartNewChild( XML_FRIEND );
		xml.NewStringChild( XML_NAME, FriendObject->m_sName.toAscii().constData() );
		xml.NewStringChild( XML_DESCRIPTION, FriendObject->m_sDescription.toAscii().constData() );
		xml.NewStringChild( XML_HUBNAME, FriendObject->m_sHubName.toAscii().constData() );
		xml.NewStringChild( XML_HUBHOST, FriendObject->m_sHubHost.toAscii().constData() );
		xml.NewStringChild( XML_IMAGE, FriendObject->m_sImageFileName.toAscii().constData() );
		xml.NewBoolChild( XML_SEND_IMAGE, FriendObject->m_bSendImage );
		xml.NewBoolChild( XML_AUTO_SEC, FriendObject->m_bAutoSec );
		xml.NewBoolChild( XML_PERM_SLOT, FriendObject->m_bPermSlot );
		xml.NewBoolChild( XML_IGNORE, FriendObject->m_bIgnore );
		xml.Parent();
	}

	// save file
	s = sConfigPath + DCGUI_FRIENDLIST;

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

	return err;
}

/** */
QPixmap * DCConfig::GetUserIcon( CMessageMyInfo * myinfo )
{
	int x,y;

	y = 0;

	if ( myinfo->m_bFireballFlag )
	{
		x = 7;
	}
	else if ( myinfo->m_bServerFlag )
	{
		x = 6;
	}
	else
	{	switch( myinfo->m_eUserSpeed )
		{
			case eusMODEM:
			case eus288KBPS:
			case eus336KBPS:
			case eus56KBPS:
			case eus0005:
			case eus001:
			case eus002:
			case eus005:
				x = 0;
				break;
			case eusISDN:
			case eus01:
				x = 1;
				break;
			case eusSATELLITE:
				x = 2;
				break;
			case eusDSL:
			case eus05:
			case eus1:
				x = 3;
				break;
			case eusCABLE:
			case eus02:
				x = 4;
				break;
			case eusLANT1:
			case eusLANT3:
			case eus2:
			case eus5:
			case eus10:
			case eus20:
			case eus50:
			case eus100:
				x = 5;
				break;
			case eus1000:
				x = 6;
				break;
			default:
				x = 8;
				break;
		}
	}

	if ( myinfo->m_eAwayMode == euamAWAY )
	{
		y += 1;
	}

	if ( myinfo->m_bTLSFlag )
	{
		y += 2;
	}
	
	if ( myinfo->m_eClientVersion == eucvDCGUI )
	{
		y += 4;
	}
	
	if ( myinfo->m_bOperator )
	{
		y += 8;
	}

	if ( myinfo->m_eClientMode == ecmPASSIVE )
	{
		y += 16;
	}
	
	if ( m_UserIconCache[x][y] == 0 )
	{
		m_UserIconCache[x][y] = new QPixmap(
			QPixmap::fromImage(
				m_UserIcons.copy(
					x * USERLIST_ICON_SIZE,
					y * USERLIST_ICON_SIZE,
					USERLIST_ICON_SIZE,
					USERLIST_ICON_SIZE
				)
			)
		);
	}
	
	return m_UserIconCache[x][y];
}

/** */
QString DCConfig::GetSoundFile( eUserSound usersound )
{
	QString s;

	switch (usersound)
	{
		case eusCONNECT:
			s = sSoundFileConnect;
			break;
		case eusDISCONNECT:
			s = sSoundFileDisconnect;
			break;
		case eusSEND:
			s = sSoundFileSend;
			break;
		case eusRECEIVE:
			s = sSoundFileReceive;
			break;
		case eusFIRSTRECEIVE:
			s = sSoundFileFirstReceive;
			break;
		case eusNICKMENTIONED:
			s = sSoundFileNickMentioned;
			break;
		default:
			break;
	}

	return s;
}

/** */
void DCConfig::SetSoundFile( eUserSound usersound, QString soundfile )
{
	switch (usersound)
	{
		case eusCONNECT:
			sSoundFileConnect = soundfile;
			break;
		case eusDISCONNECT:
			sSoundFileDisconnect = soundfile;
			break;
		case eusSEND:
			sSoundFileSend = soundfile;
			break;
		case eusRECEIVE:
			sSoundFileReceive = soundfile;
			break;
		case eusFIRSTRECEIVE:
			sSoundFileFirstReceive = soundfile;
			break;
		case eusNICKMENTIONED:
			sSoundFileNickMentioned = soundfile;
			break;
		default:
			break;
	}
}

/** */
bool DCConfig::GetSoundEnabled( eUserSound usersound )
{
	bool b;

	switch (usersound)
	{
		case eusCONNECT:
			b = bSoundEnabledConnect;
			break;
		case eusDISCONNECT:
			b = bSoundEnabledDisconnect;
			break;
		case eusSEND:
			b = bSoundEnabledSend;
			break;
		case eusRECEIVE:
			b = bSoundEnabledReceive;
			break;
		case eusFIRSTRECEIVE:
			b = bSoundEnabledFirstReceive;
			break;
		case eusNICKMENTIONED:
			b = bSoundEnabledNickMentioned;
			break;
		default:
			b = false;
			break;
	}

	return b;
}

/** */
void DCConfig::SetSoundEnabled( eUserSound usersound, bool enabled )
{
	switch (usersound)
	{
		case eusCONNECT:
			bSoundEnabledConnect = enabled;
			break;
		case eusDISCONNECT:
			bSoundEnabledDisconnect = enabled;
			break;
		case eusSEND:
			bSoundEnabledSend = enabled;
			break;
		case eusRECEIVE:
			bSoundEnabledReceive = enabled;
			break;
		case eusFIRSTRECEIVE:
			bSoundEnabledFirstReceive = enabled;
			break;
		case eusNICKMENTIONED:
			bSoundEnabledNickMentioned = enabled;
			break;
		default:
			break;
	}
}

/** */
void DCConfig::PlaySound( eUserSound usersound )
{
	QString s;

	if ( bSoundDisabled )
	{
		return;
	}

	if ( (GetAwayMode() == euamAWAY) && bSoundDisabledAway )
	{
		return;
	}

	switch(usersound)
	{
		case eusCONNECT:
			if ( bSoundEnabledConnect )
				s = sSoundFileConnect;
			break;
		case eusDISCONNECT:
			if ( bSoundEnabledDisconnect )
				s = sSoundFileDisconnect;
			break;
		case eusSEND:
			if ( bSoundEnabledSend )
				s = sSoundFileSend;
			break;
		case eusRECEIVE:
			if ( bSoundEnabledReceive )
				s = sSoundFileReceive;
			break;
		case eusFIRSTRECEIVE:
			if ( bSoundEnabledFirstReceive )
				s = sSoundFileFirstReceive;
			break;
		case eusNICKMENTIONED:
			if ( bSoundEnabledNickMentioned )
				s = sSoundFileNickMentioned;
			break;
		default:
			break;
	}

	PlaySound(s);
}

/** */
void DCConfig::PlaySound( QString file )
{
	if ( file.isEmpty() )
	{
		return;
	}

	if ( bExternalSoundPlayer == false )
	{
		QSound::play(file);
	}
	else
	{
		if ( pProcess->state() != QProcess::NotRunning )
		{
			pProcess->kill();
		}

		pProcess->start( sExternalPlayer + " " + file );
	}
}

/** */
void DCConfig::SetTimeStamp( eTimeStamp timestamp, bool enabled )
{
	switch(timestamp)
	{
		case etsPRIVATECHAT:
			bTimeStampPrivateChat = enabled;
			break;
		case etsHUBCHAT:
			bTimeStampHubChat = enabled;
			break;
		default:
			break;
	}
}

/** */
bool DCConfig::GetTimeStamp( eTimeStamp timestamp )
{
	bool res;

	switch(timestamp)
	{
		case etsPRIVATECHAT :
			res = bTimeStampPrivateChat;
			break;
		case etsHUBCHAT:
			res = bTimeStampHubChat;
			break;
		default:
			res = false;
			break;
	}

	return res;
}

/** */
bool DCConfig::GetTransferViewOptions( eTransferViewOptions e ) const
{
	switch(e)
	{
		case etvoCHUNKPERCENT:
			return bTVChunkPercent;
			break;
		case etvoFILEPERCENT:
			return bTVFilePercent;
			break;		
		case etvoCHUNKSIZE:
			return bTVChunkSize;
			break;		
		case etvoFILESIZE:
			return bTVFileSize;
			break;		
		case etvoDOWNLOADRATESINGLE:
			return bTVDownloadRateSingle;
			break;		
		case etvoELAPSEDTIMESINGLE:
			return bTVElapsedTimeSingle;
			break;		
		case etvoDOWNLOADRATEMULTI:
			return bTVDownloadRateMulti;
			break;		
		case etvoELAPSEDTIMEMULTI:
			return bTVElapsedTimeMulti;
			break;		
		default:
			return false;
			break;
	}
}

/** */
void DCConfig::SetTransferViewOptions( eTransferViewOptions e, bool b )
{
  	switch(e)
	{
		case etvoCHUNKPERCENT:
			bTVChunkPercent = b;
			break;
		case etvoFILEPERCENT:
			bTVFilePercent = b;
			break;		
		case etvoCHUNKSIZE:
			bTVChunkSize = b;
			break;		
		case etvoFILESIZE:
			bTVFileSize = b;
			break;		
		case etvoDOWNLOADRATESINGLE:
			bTVDownloadRateSingle = b;
			break;		
		case etvoELAPSEDTIMESINGLE:
			bTVElapsedTimeSingle = b;
			break;		
		case etvoDOWNLOADRATEMULTI:
			bTVDownloadRateMulti = b;
			break;		
		case etvoELAPSEDTIMEMULTI:
			bTVElapsedTimeMulti = b;
			break;		
		default:
			break;
	}
}

/** */
bool DCConfig::InitMimeSourceFactory()
{
	DC_EmoticonObject * EmoticonObject;
	CString s,imagename;
	CXml xml;
	int id = 0;
	bool res = false;

	QList<DC_EmoticonObject*> * newemotes = new QList<DC_EmoticonObject*>();

	// load emoticons
	
	// first we check if a local icon present
	s = GetConfigPath()+DIRSEPARATOR;
	
	if ( !(xml.ParseFile(s+"emoticons.xml") && xml.DocFirstChild()) )
	{
		// get global icons
		s  = GetValknutDataPath().toAscii().constData();
		s += DIRSEPARATOR;
		s += "icons";
		s += DIRSEPARATOR;
		s += "emot";
		s += DIRSEPARATOR;
		s += GetEmoticonTheme().toAscii().constData();
		s += DIRSEPARATOR;

		if ( !(xml.ParseFile(s+"emoticons.xml") && xml.DocFirstChild()) )
		{
			delete newemotes;
			return res;
		}
	}

	// parse the list
	do
	{
		if ( (xml.Name() == "emoticons") && xml.FirstChild() )
		{
			do
			{
				if ( xml.Name() == "emoticon" )
				{
					EmoticonObject = new DC_EmoticonObject();

					EmoticonObject->m_Text = QString::fromAscii(xml.Prop("text").Data());

					if ( xml.FirstChild() )
					{
						do
						{
							if ( xml.Name() == "source" )
							{
								EmoticonObject->left   = xml.Prop("left").asINT();
								EmoticonObject->top    = xml.Prop("top").asINT();
								EmoticonObject->right  = xml.Prop("right").asINT();
								EmoticonObject->bottom = xml.Prop("bottom").asINT();

								imagename = xml.Prop("name");
							}
						}
						while ( xml.NextNode() );
						xml.Parent();
					}

					if ( !(EmoticonObject->m_Text.isEmpty()) )
					{
							EmoticonObject->m_nID = id;
							++id;
							newemotes->append(EmoticonObject);

//							printf("%s\n",EmoticonObject->m_Text.toAscii().constData());
					}
					else
					{
						delete EmoticonObject;
					}
				}
			}
			while ( xml.NextNode() );
			xml.Parent();
		}
	}
	while ( xml.NextNode() );
	
	if ( m_EmoticonImage.load((s+imagename).Data()) ||
	     m_EmoticonImage.load((s+imagename+".png").Data()) ||
	     m_EmoticonImage.load((s+imagename+".xpm").Data())
	   )
	{
		res = true;
	}
	else
	{
		for ( QList<DC_EmoticonObject*>::const_iterator it = newemotes->constBegin(); it != newemotes->constEnd(); ++it )
		{
			delete *it;
		}
		newemotes->clear();
		delete newemotes;
	}

	if ( res )
	{
		if ( m_pEmoticons )
		{
			QList<DC_EmoticonObject*> * oldemotes = m_pEmoticons;
			m_pEmoticons = newemotes;
			
			for ( QList<DC_EmoticonObject*>::const_iterator it = oldemotes->constBegin(); it != oldemotes->constEnd(); ++it )
			{
				delete *it;
			}
			oldemotes->clear();
			delete oldemotes;
		}
		else
		{
			m_pEmoticons = newemotes;
		}
		emit emoticonThemeChanged();
	}

	return res;
}

/** */
QList<DC_EmoticonObject*> * DCConfig::EmoticonList()
{
	return m_pEmoticons;
}

/** */
QImage & DCConfig::GetEmoticonImage()
{
	return m_EmoticonImage;
}

/** */
bool DCConfig::AddEmoticons( QTextDocument * document )
{
	bool res = false;
	DC_EmoticonObject * EmoticonObject = 0;
	
	if ( m_pEmoticons )
	{
		for ( QList<DC_EmoticonObject*>::const_iterator it = m_pEmoticons->constBegin(); it != m_pEmoticons->constEnd(); ++it )
		{
			EmoticonObject = *it;
			document->addResource(
				QTextDocument::ImageResource,
				QUrl(GetEmoticonTheme() + QString("/emoticon") + QString().setNum(EmoticonObject->m_nID)),
				m_EmoticonImage.copy(
					EmoticonObject->left,
					EmoticonObject->top,
					EmoticonObject->right-EmoticonObject->left,
					EmoticonObject->bottom-EmoticonObject->top
				)
			);
		}
		res = true;
	}
	
	return res;
}

/** */
bool DCConfig::GetMap( QString name, StringMap *& map )
{
	bool res = true;

	if ( m_guiSettingMap.find(name) == m_guiSettingMap.end() )
	{
		m_guiSettingMap[name] = new StringMap();
		res = false;
	}

	map = m_guiSettingMap[name];

	return res;
}

/** */
QString DCConfig::GetChatColor( eChatColor type ) const
{
	switch (type)
	{
		case eccCHATTIMESTAMP:
			return m_sChatColor_1;
		case eccCHATLOCALNICK:
			return m_sChatColor_2;
		case eccCHATLOCALTEXT:
			return m_sChatColor_3;
		case eccCHATREMOTENICK:
			return m_sChatColor_4;
		case eccCHATREMOTETEXT:
			return m_sChatColor_5;
		case eccCHATSTATUSNICK:
			return m_sChatColor_6;
		case eccCHATSTATUSTEXT:
			return m_sChatColor_7;
		case eccPUBLICCHATTIMESTAMP:
			return m_sChatColor_8;
		case eccPUBLICCHATLOCALNICK:
			return m_sChatColor_9;
		case eccPUBLICCHATLOCALTEXT:
			return m_sChatColor_10;
		case eccPUBLICCHATREMOTENICK:
			return m_sChatColor_11;
		case eccPUBLICCHATREMOTETEXT:
			return m_sChatColor_12;
		case eccPUBLICCHATSTATUSNICK:
			return m_sChatColor_13;
		case eccPUBLICCHATSTATUSTEXT:
			return m_sChatColor_14;
		case eccPUBLICPRIVATECHATNICK:
			return m_sChatColor_15;
		case eccPUBLICPRIVATECHATTEXT:
			return m_sChatColor_16;
		case eccCHATSAY:
			return m_sChatColor_17;
		case eccPUBLICCHATMENICK:
			return m_sChatColor_18;
		case eccOPNICK:
			return m_sChatColor_19;
		default:
			break;
	}

	return QString();
}

/** */
void DCConfig::SetChatColor( eChatColor type, QString s )
{
	switch (type)
	{
		case eccCHATTIMESTAMP:
			m_sChatColor_1 = s;
			break;
		case eccCHATLOCALNICK:
			m_sChatColor_2 = s;
			break;
		case eccCHATLOCALTEXT:
			m_sChatColor_3 = s;
			break;
		case eccCHATREMOTENICK:
			m_sChatColor_4 = s;
			break;
		case eccCHATREMOTETEXT:
			m_sChatColor_5 = s;
			break;
		case eccCHATSTATUSNICK:
			m_sChatColor_6 = s;
			break;
		case eccCHATSTATUSTEXT:
			m_sChatColor_7 = s;
			break;
		case eccPUBLICCHATTIMESTAMP:
			m_sChatColor_8 = s;
			break;
		case eccPUBLICCHATLOCALNICK:
			m_sChatColor_9 = s;
			break;
		case eccPUBLICCHATLOCALTEXT:
			m_sChatColor_10 = s;
			break;
		case eccPUBLICCHATREMOTENICK:
			m_sChatColor_11 = s;
			break;
		case eccPUBLICCHATREMOTETEXT:
			m_sChatColor_12 = s;
			break;
		case eccPUBLICCHATSTATUSNICK:
			m_sChatColor_13 = s;
			break;
		case eccPUBLICCHATSTATUSTEXT:
			m_sChatColor_14 = s;
			break;
		case eccPUBLICPRIVATECHATNICK:
			m_sChatColor_15 = s;
			break;
		case eccPUBLICPRIVATECHATTEXT:
			m_sChatColor_16 = s;
			break;
		case eccCHATSAY:
			m_sChatColor_17 = s;
			break;
		case eccPUBLICCHATMENICK:
			m_sChatColor_18 = s;
			break;
		case eccOPNICK:
			m_sChatColor_19 = s;
			break;
		default:
			break;
	}
}

/** */
void DCConfig::SetLogChatOption( eLogChatOptions elco, bool enabled )
{
	switch(elco)
	{
		case elcoENABLELOGGING:
			m_bLogChatOption_1 = enabled;
			break;
		case elcoAPPENDDATE:
			m_bLogChatOption_2 = enabled;
			break;
		case elcoAPPENDHUBNAME:
			m_bLogChatOption_3 = enabled;
			break;
		case elcoDISABLEPUBLICCHAT:
			m_bLogChatOption_4 = enabled;
			break;
		case elcoENABLENICKNAMEFILTER:
			m_bLogChatOption_5 = enabled;
			break;
		case elcoNICKNAMEFILTER_ENABLELOGGING:
			m_bLogChatOption_6 = enabled;
			break;
		case elcoAPPENDHUBHOST:
			m_bLogChatOption_7 = enabled;
			break;
		default:
			break;
	}
}

/** */
bool DCConfig::GetLogChatOption( eLogChatOptions elco )
{
	switch(elco)
	{
		case elcoENABLELOGGING:
			return m_bLogChatOption_1;
			break;
		case elcoAPPENDDATE:
			return m_bLogChatOption_2;
			break;
		case elcoAPPENDHUBNAME:
			return m_bLogChatOption_3;
			break;
		case elcoDISABLEPUBLICCHAT:
			return m_bLogChatOption_4;
			break;
		case elcoENABLENICKNAMEFILTER:
			return m_bLogChatOption_5;
			break;
		case elcoNICKNAMEFILTER_ENABLELOGGING:
			return m_bLogChatOption_6;
			break;
		case elcoAPPENDHUBHOST:
			return m_bLogChatOption_7;
			break;
		default:
			break;
	}

	return false;
}

/** */
void DCConfig::SetLogChatNickNameFilter( QStringList list )
{
	/* due to QT's implicit sharing this is OK */
	m_LogChatNickNameFilter = list;
}

/** */
QStringList DCConfig::GetLogChatNickNameFilter()
{
	/* due to QT's implicit sharing this is OK */
	return m_LogChatNickNameFilter;
}

/** */
bool DCConfig::CheckLogChatNickNameFilter( QString nick )
{
	if ( GetLogChatOption(elcoENABLENICKNAMEFILTER) == false )
	{
		return true;
	}

	if ( m_LogChatNickNameFilter.contains(nick) )
	{
		if ( GetLogChatOption(elcoNICKNAMEFILTER_ENABLELOGGING) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	// nick not found
	if ( !GetLogChatOption(elcoNICKNAMEFILTER_ENABLELOGGING) )
		return true;

	return false;
}

/** */
void DCConfig::SetUserMenuCommands( QMap<int, DC_UserMenuCommand*> * list )
{
	if ( !list )
	{
		return;
	}
	
	/* clear map first delete objects second */
	QList<DC_UserMenuCommand*> tmp = m_UserMenuCommands.values();
	m_UserMenuCommands.clear();
	
	for ( QList<DC_UserMenuCommand*>::const_iterator it = tmp.constBegin(); it != tmp.constEnd(); ++it )
	{
		delete *it;
	}
	
	for ( QMap<int, DC_UserMenuCommand*>::const_iterator it = list->constBegin(); it != list->constEnd(); ++it )
	{
		m_UserMenuCommands.insert( it.key(), it.value() );
	}
	
	list->clear();
}

/** */
long DCConfig::GetUserMenuCommands( QMap<int, DC_UserMenuCommand*> * list )
{
	if ( !list )
	{
		return 0;
	}
	
	for ( QMap<int, DC_UserMenuCommand*>::const_iterator it = m_UserMenuCommands.constBegin(); it != m_UserMenuCommands.constEnd(); ++it )
	{
		/* default copy constructor does member by member copy */
		list->insert( it.key(), new DC_UserMenuCommand( *(it.value()) ) );
	}
	
	return list->size();
}

/** */
long DCConfig::GetUserMenuCommandsDirect( QMap<int, DC_UserMenuCommand*> * list )
{
	if ( !list )
	{
		return 0;
	}
	
	for ( QMap<int, DC_UserMenuCommand*>::const_iterator it = m_UserMenuCommands.constBegin(); it != m_UserMenuCommands.constEnd(); ++it )
	{
		list->insert( it.key(), it.value() );
	}
	
	return list->size();
}

/** */
void DCConfig::SetUserChatCommands( QList<DC_UserChatCommand*> * list )
{
	if ( !list )
	{
		return;
	}

	QList<DC_UserChatCommand*> tmp = m_lUserChatCommands;
	m_lUserChatCommands.clear();
	
	for ( QList<DC_UserChatCommand*>::const_iterator it = tmp.constBegin(); it != tmp.constEnd(); ++it )
	{
		delete *it;
	}

	for ( QList<DC_UserChatCommand*>::const_iterator it = list->constBegin(); it != list->constEnd(); ++it )
	{
		m_lUserChatCommands.append( *it );
	}
	
	list->clear();
}

/** */
long DCConfig::GetUserChatCommands( QList<DC_UserChatCommand*> * list )
{
	if ( !list )
	{
		return 0;
	}
	
	for ( QList<DC_UserChatCommand*>::const_iterator it = m_lUserChatCommands.constBegin(); it != m_lUserChatCommands.constEnd(); ++it )
	{
		/* default copy constructor does member by member copy */
		list->append( new DC_UserChatCommand( *(*it) ) );
	}
	
	return list->size();
}

/** */
QString DCConfig::ReplaceUserChatCommands( QString text )
{
	bool addedSpace = false;
	if ( text.right(1) != " " )
	{
		text += ' ';
		addedSpace = true;
	}
	
	for ( QList<DC_UserChatCommand*>::const_iterator it = m_lUserChatCommands.constBegin(); it != m_lUserChatCommands.constEnd(); ++it )
	{
		DC_UserChatCommand * ucc = *it;
		if ( text.startsWith(ucc->m_sName + " ") )
		{
			text.replace( 0, ucc->m_sName.length(), ucc->m_sCommand );
		}
	}
		
	if ( addedSpace )
	{
		text = text.left( text.length() - 1 );
	}
	
	return text;
}

/** */
void DCConfig::SetAutoResponses( QList<DC_AutoResponseObject*> * list )
{
	if ( !list )
	{
		return;
	}
	
	QList<DC_AutoResponseObject*> tmp = m_lAutoResponses;
	m_lAutoResponses.clear();
	
	for ( QList<DC_AutoResponseObject*>::const_iterator it = tmp.constBegin(); it != tmp.constEnd(); ++it )
	{
		delete *it;
	}
	
	for ( QList<DC_AutoResponseObject*>::const_iterator it = list->constBegin(); it != list->constEnd(); ++it )
	{
		m_lAutoResponses.append( *it );
	}
	
	list->clear();
}

/** */
long DCConfig::GetAutoResponses( QList<DC_AutoResponseObject*> * list )
{
	if ( !list )
	{
		return 0;
	}
	
	for ( QList<DC_AutoResponseObject*>::const_iterator it = m_lAutoResponses.constBegin(); it != m_lAutoResponses.constEnd(); ++it )
	{
		/* default copy constructor does member by member copy */
		list->append( new DC_AutoResponseObject( *(*it) ) );
	}
	
	return list->size();
}

void DCConfig::RenameStoredFilelists()
{
	QDir dir;
	QStringList listing;
	QByteArray buffer;
	buffer.resize(2048);
	
	printf("Renaming stored filelists ...\n");
	
	dir.setPath( g_pConfig->GetFileListPath().Data() );
	
	listing = dir.entryList();
	
	for (QStringList::Iterator it = listing.begin(); it != listing.end(); ++it)
	{
		QString filename = *it;
		
		if ( (filename == ".") || (filename == "..") )
		{
			// skip
		}
		else
		{
			QFile file;
			file.setFileName( QString(g_pConfig->GetFileListPath().Data()) + filename );
			if (file.open( QIODevice::ReadOnly ))
			{
				QString line, nick, hubhost;
				file.readLine( buffer.data(), buffer.size() );
				line = buffer.constData();
				
				if (line == "---HEADER START---\n")
				{
					while (line != "---HEADER END---\n")
					{
						file.readLine( buffer.data(), buffer.size() );
						line = buffer.constData();
						
						if (line.left(5) == "NICK=")
						{
							nick = line.mid(5);
							nick.remove("\n");
						}
						else if (line.left(8) == "HUBHOST=")
						{
							hubhost = line.mid(8);
							hubhost.remove("\n");
						}
					}
				}
				else
				{
					printf("%s is not a filelist from valknut <= 0.3.13\n", filename.toAscii().constData());
					file.close();
					continue;
				}
				
				file.close();
				
				QString newname = nick;
				newname += "@";
				newname += hubhost;
				newname += ".filelist";
				newname.replace('/', "_");
				newname.replace('\\', "_");
				newname.replace(':', "_");
				
				if ( filename == newname )
				{
					continue;
				}
				
				printf("Renaming %s to %s ...", filename.toAscii().constData(), newname.toAscii().constData());
				if ( dir.rename(filename, newname) )
				{
					printf(" OK\n");
				}
				else
				{
					printf(" renaming failed!\n");
				}
			}
			else
			{
				printf("Couldn't open %s!\n", filename.toAscii().constData());
			}
		}
	}
	
	// finished, set variable so renaming will not be done again
	SetFilelistNamingSchemeVersion(4);
}

/** */
void DCConfig::SetChatBackgroundColor( bool enabled, QString color )
{
	/* changing the color does not matter if it stays disabled */
	bool changed = ( (enabled != m_bChatBackgroundColorEnabled) || (enabled && (color != m_sChatBackgroundColor)) );
	
	m_bChatBackgroundColorEnabled = enabled;
	m_sChatBackgroundColor = color;
	
	if ( changed )
	{
		emit chatBackgroundColorChanged();
	}
}

/** */
void DCConfig::SetDefaultDownloadMode( unsigned int n, bool emitsig )
{
	if ( n != iDefaultDownloadMode )
	{
		iDefaultDownloadMode = n;
		if ( emitsig )
		{
			emit defaultDownloadModeChanged();
		}
	}
}

/** */
void DCConfig::OpenURL( QString url )
{
	if ( m_bCustomBrowser && !sBrowser.isEmpty() )
	{
		QProcess::startDetached( sBrowser + " " + url );
	}
	else
	{
		QDesktopServices::openUrl( url );
	}
}

/** */
void DCConfig::SetUserListIconTheme( QString theme )
{
	if ( theme != m_sUserListIconTheme )
	{
		/* delete cached pixmaps */
		for ( int x = 0; x < USERLIST_XPM_COLUMNS; ++x )
		{
			for ( int y = 0; y < USERLIST_XPM_ROWS; ++y )
			{
				if ( m_UserIconCache[x][y] )
				{
					delete m_UserIconCache[x][y];
					m_UserIconCache[x][y] = 0;
				}
			}
		}
		
		m_UserIcons.load( m_sValknutDataPath + "/icons/user/" + theme + "/" + "usericons.xpm" );
		
		m_sUserListIconTheme = theme;
	}
}

/** */
eMagnetAction DCConfig::GetMagnetAction( eMagnetSource source ) const
{
	if ( source == eChatMagnet )
	{
		return m_eMagnetActionChat;
	}
	else
	{
		return eMagnetPrompt;
	}
}

/** */
void DCConfig::SetMagnetAction( eMagnetAction action, eMagnetSource source )
{
	if ( source == eChatMagnet )
	{
		m_eMagnetActionChat = action;
	}
}

/** */
void DCConfig::SetAwayMode( eUserAwayMode mode )
{
	if ( mode != GetAwayMode() )
	{
		CConfig::SetAwayMode( mode );
		emit awayModeChanged( mode );
	}
}

/** */
void DCConfig::SetAlternatingRowColors( bool b )
{
	if ( m_bAlternatingRowColors != b )
	{
		m_bAlternatingRowColors = b;
		emit alternatingRowColorsChanged( b );
	}
}

/** */
void DCConfig::SetAutoAwayMode( bool b )
{
	if ( m_bAutoAwayMode != b )
	{
		m_bAutoAwayMode = b;
		emit autoAwayModeChanged( b );
	}
}
