/***************************************************************************
                          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>
#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 "dcgui.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 

#ifndef WIN32
#include <unistd.h>
#include <stdlib.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_DISABLE_MODE          "sounddisablemode"
#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_EISKALTDC_DATA_PATH		"eiskaltdcdatapath"
#define XML_QMAINWINDOW_STATE		"qmainwindowstate"
#define XML_QMAINWINDOW_INTRAY          "qmainwindowintray"
#define XML_TRANSFERVIEW_TYPE           "transferviewtype"
#define XML_CHATDBLCLICKACTION          "chatdoubleclickaction"
#define XML_TRAY_MSG_TYPE               "traymessagetype"
#define XML_INOTIFY_TYPE                "inotifytype"
#define XML_INOTIFY_ACTION              "inotifyaction"
#define XML_INOTIFY_RECURSIVE           "inotifyrecursive"
#define XML_INOTIFY_INTERVAL            "inotifyinterval"
#define XML_INOTIFY_ENABLED             "inotifyenabled"
#define XML_ANTISPAM_ENABLED            "antispamenabled"
#define XML_IPFILTER_ENABLED            "ipfilterenabled"

#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"

class DC_EmoticonObject {
public:
	/** construtor */
	DC_EmoticonObject() : left(-1),top(-1),right(-1),bottom(-1),m_nID(-1) {};
	/** destructor */
	~DC_EmoticonObject() {};

	/** */
	QStringList m_Text;
	/** */
	int left,top,right,bottom;
	/** */
	int m_nID;
};

DCConfig * g_pConfig = 0;

DCConfig::DCConfig( CString configpath ) : CConfig(configpath)
{
	// gui defaults
        bOpenPrivateChatWindow      = true;
        m_eUnit                     = euAUTO;
        m_eTransferViewType         = etvtDOCK;
        m_eChatDoubleClickAction    = ecdcaNONE;

        SET_TRAY_MSG_DISC(m_TrayMessageType);
        SET_TRAY_MSG_NICK(m_TrayMessageType);
        SET_TRAY_MSG_PRIV(m_TrayMessageType);
        USET_TRAY_MSG_NONE(m_TrayMessageType);

        SET_INOTIFY_CHG(m_InotifyMessageType);
        SET_INOTIFY_CRT(m_InotifyMessageType);
        SET_INOTIFY_DEL(m_InotifyMessageType);
        SET_INOTIFY_LOG(m_InotifyMessageType);

        m_eInotifyAction        = eInotifyAsk;
        m_bInotifyRecursive     = true;
        m_iInotifyInterval      = 60;
        m_bEnableInotify        = false;

        m_bAntiSpamEnabled      = false;

        m_bIPFilterEnabled      = false;

#ifndef WIN32
	if (GetNick() == "nick" && GetSearchNick() == "nick_search"){
	    QString nick(getenv("USER"));

	    if (nick != ""){
		SetSearchNick(nick.toAscii().data());
		SetNick(nick.toAscii().data());
	    }
	}
#endif

#if defined(Q_OS_MACX)
	sTheme			= "Mac";
#else
	sTheme			= "";
#endif
	sThemeQT3		= "";
	sLanguageFile		= "";
	sAppFont		= DEFAULT_APP_FONT;
	
        /* Default hub encoding */
        SetRemoteEncoding("WINDOWS-1251");

	/* The system default font is best */
	m_bUseCustomFont	= false;
	
	iAppHeight		= 480;
	iAppWidth		= 640;
	bTabBar			= true;
	bToolBar		= true;
	bStatusBar		= true;

        SET_SOUNDDISABLEWACTIVE(m_SoundDisableMode);
        SET_SOUNDDISABLEWSHOW(m_SoundDisableMode);
	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_eSendChat		= eEnter;

	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();

	m_eDefaultDownloadMode = eDownloadAsk;

	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

        SetMaxUpload( 8 );
        SetTransferAutoSearch( true );
        SetAutoSearchInterval( 60 );

        SetFoldersInRightPane( true );
        SetFoldersInRightPaneOnTop( true );
        SetFolderSizesInLeftPane( true );

	/* false to use QDesktopServices */
	m_bCustomBrowser = false;
	bShowChatInTab = true;
	m_nChatMaxParagraph = 0;
	m_eOpenClientWindows = eClientMaximized; // 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 looks nicer,
	 * and has fewer icons so 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_eTabCompleteMatchMode = eTabContains;
	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_eDoubleClickAction = eDownloadList;
	
	m_eMagnetActionChat = eMagnetPrompt;
	
	m_bAlternatingRowColors = true;

	/* dccmd:// removed, sounds like a terrible idea, was not handled anyway */
	m_lURLs.append("http://");
	m_lURLs.append("https://");
	m_lURLs.append("news://");
	m_lURLs.append("file://");
	m_lURLs.append("ftp://");
	m_lURLs.append("hkp://");
	m_lURLs.append("ldap://");
	m_lURLs.append("irc://");
	m_lURLs.append("dcfile://"); /* valknut specific, deprecated in favor of magnets */
	m_lURLs.append("dchub://");
	m_lURLs.append("dchubs://");
	m_lURLs.append("nmdc://");
	m_lURLs.append("nmdcs://");
	m_lURLs.append("www."); /* index 13 used in ChatToHTML */
	m_lURLs.append("ftp."); /* index 14 used in ChatToHTML */
	m_lURLs.append("magnet:"); /* index 15 used in ChatToHTML */

#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 = EISKALTDC_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_eOpenClientWindows = eOpenClientWindow( xml->Content().asINT() );
                                else if ( xml_name == XML_QMAINWINDOW_INTRAY )
                                        m_bInTray = xml->GetBoolChild();
                                else if (xml_name == XML_TRANSFERVIEW_TYPE)
                                        m_eTransferViewType = (eTransferViewType)xml->Content().asINT();
                                else if (xml_name == XML_CHATDBLCLICKACTION)
                                        m_eChatDoubleClickAction = (eChatDoubleClickAction)xml->Content().asINT();
                                else if (xml_name == XML_SOUND_DISABLE_MODE)
                                        m_SoundDisableMode = (SoundDisableMode)xml->Content().asINT();
                                else if (xml_name == XML_TRAY_MSG_TYPE)
                                        m_TrayMessageType = (TrayMessageType)xml->Content().asINT();
                                else if (xml_name == XML_INOTIFY_TYPE)
                                        m_InotifyMessageType = (InotifyMessageType)xml->Content().asINT();
                                else if (xml_name == XML_INOTIFY_ACTION)
                                        m_eInotifyAction = (eInotifyAction)xml->Content().asINT();
                                else if (xml_name == XML_INOTIFY_INTERVAL)
                                        SetInotifyInterval(xml->Content().asINT());
                                else if (xml_name == XML_INOTIFY_RECURSIVE)
                                        m_bInotifyRecursive = xml->GetBoolChild();
                                else if (xml_name == XML_INOTIFY_ENABLED )
                                        m_bEnableInotify = xml->GetBoolChild();
                                else if (xml_name == XML_ANTISPAM_ENABLED)
                                        m_bAntiSpamEnabled = xml->GetBoolChild();
                                else if (xml_name == XML_IPFILTER_ENABLED)
                                        m_bIPFilterEnabled = xml->GetBoolChild();
				else if ( xml_name == XML_OPENPRIVATECHATWIN )
					bOpenPrivateChatWindow = xml->GetBoolChild();
				else if ( xml_name == XML_CHATMAXPARAGRAPH )
					m_nChatMaxParagraph = xml->Content().asINT();
				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_eSendChat = eSendChatKey( 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 )
					m_eDefaultDownloadMode = eDownloadMode( xml->Content().asINT() );
				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_eDoubleClickAction = eDoubleClickUser( xml->Content().asINT() );
				else if ( xml_name == XML_MAGNET_ACTION_CHAT )
					m_eMagnetActionChat = eMagnetAction( xml->Content().asINT() );
                                else if ( xml_name == XML_EISKALTDC_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() );
                    SetChatForegroundColor( 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( eTabCompleteMode( 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(EISKALTDC_DATAPATH);
#endif
	}

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

	LoadEmoticons();

	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_eOpenClientWindows );
	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.NewBoolChild( XML_QMAINWINDOW_INTRAY, m_bInTray);
        xml.NewNumericChild( XML_TRANSFERVIEW_TYPE, (int)m_eTransferViewType );
        xml.NewNumericChild( XML_CHATDBLCLICKACTION, (int)m_eChatDoubleClickAction );
        xml.NewNumericChild( XML_TRAY_MSG_TYPE, (int)m_TrayMessageType );
        xml.NewNumericChild( XML_INOTIFY_TYPE, (int)m_InotifyMessageType );
        xml.NewNumericChild( XML_INOTIFY_ACTION, (int)m_eInotifyAction );
        xml.NewBoolChild( XML_INOTIFY_RECURSIVE, m_bInotifyRecursive );
        xml.NewNumericChild( XML_INOTIFY_INTERVAL, m_iInotifyInterval );
        xml.NewBoolChild( XML_INOTIFY_ENABLED, m_bEnableInotify );
        xml.NewBoolChild( XML_ANTISPAM_ENABLED, m_bAntiSpamEnabled );
        xml.NewBoolChild( XML_IPFILTER_ENABLED, m_bIPFilterEnabled );

	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_eSendChat );
	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_eTabCompleteMatchMode );
	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.NewNumericChild( XML_SOUND_DISABLE_MODE, m_SoundDisableMode );
	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_EISKALTDC_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, m_eDefaultDownloadMode );

	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_eDoubleClickAction );
	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;
	}

        if (g_pMainWin){
            if (IS_SOUNDDISABLEWACTIVE(m_SoundDisableMode) && g_pMainWin->isActiveWindow())
                return;
            if (IS_SOUNDDISABLEWSHOW(m_SoundDisableMode) && g_pMainWin->isVisible())
                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::LoadEmoticons()
{
	CString path,imagename;
	CXml xml;
	bool res = false;
	int id = 0;
	QList<DC_EmoticonObject*> * newemotes = 0;
	DC_EmoticonObject * emote = 0;
	QString pattern;
	
	// first we check if a local icon present
	path = GetConfigPath();
	
	if ( xml.ParseFile(path+"emoticons-v2.xml") && xml.DocFirstChild() )
	{
		res = true;
	}
	else
	{
		// get global icons
		path  = GetValknutDataPath().toAscii().constData();
		path += DIRSEPARATOR;
		path += "icons";
		path += DIRSEPARATOR;
		path += "emot";
		path += DIRSEPARATOR;
		path += GetEmoticonTheme().toAscii().constData();
		path += DIRSEPARATOR;

		if ( xml.ParseFile(path+"emoticons-v2.xml") && xml.DocFirstChild() )
		{
			res = true;
		}
	}

	if ( res ) /* load 0.4.10 format emoticons */
	{
		newemotes = new QList<DC_EmoticonObject*>();
		
		do
		{
			if ( (xml.Name() == "emoticons") && xml.FirstChild() )
			{
				do
				{
					if ( xml.Name() == "emoticon" )
					{
						emote = new DC_EmoticonObject();
					
						emote->left   = xml.Prop("left").asINT();
						emote->top    = xml.Prop("top").asINT();
						emote->right  = xml.Prop("right").asINT();
						emote->bottom = xml.Prop("bottom").asINT();
						
						if ( xml.FirstChild() )
						{
							do
							{
								if ( xml.Name() == "emotext" )
								{
									emote->m_Text.append( xml.Content().Replace("<","&lt;").Replace(">","&gt;").Data() );
								}
							}
							while ( xml.NextNode() );
							xml.Parent();
						}
						
						if ( emote->m_Text.isEmpty() )
						{
							delete emote;
						}
						else
						{
							newemotes->append(emote);
						}
					}
				}
				while ( xml.NextNode() );
				xml.Parent();
				
				imagename = xml.Prop("imagefile");
			}
		}
		while ( xml.NextNode() );
	}
	else /* load 0.4.9 and earlier format emoticons, and save new format file */
	{
		/* try local */
		path = GetConfigPath();
		
		if ( !(xml.ParseFile(path+"emoticons.xml") && xml.DocFirstChild()) )
		{
			/* try global */
			path  = GetValknutDataPath().toAscii().constData();
			path += DIRSEPARATOR;
			path += "icons";
			path += DIRSEPARATOR;
			path += "emot";
			path += DIRSEPARATOR;
			path += GetEmoticonTheme().toAscii().constData();
			path += DIRSEPARATOR;
			
			if ( !(xml.ParseFile(path+"emoticons.xml") && xml.DocFirstChild()) )
			{
				return false;
			}
		}
		
		/* The file likely had 'button="yes"', but this was ignored,
		 * the emoticon that appeared first in the xml file got used.
		 */
		
		QMap<QString, DC_EmoticonObject*> * emot_map = new QMap<QString, DC_EmoticonObject*>();
		int temp_left = -1, temp_top = -1, temp_right = -1, temp_bottom = -1;
		QString tempkey;
		int oldcount = 0;
		
		do
		{
			if ( (xml.Name() == "emoticons") && xml.FirstChild() )
			{
				do
				{
					if ( xml.Name() == "emoticon" )
					{
						pattern = QString::fromAscii( xml.Prop("text").Data() );
						
						if ( pattern.isEmpty() )
						{
							continue;
						}
						
						if ( xml.FirstChild() )
						{
							do
							{
								temp_left = xml.Prop("left").asINT();
								temp_top = xml.Prop("top").asINT();
								temp_right = xml.Prop("right").asINT();
								temp_bottom = xml.Prop("bottom").asINT();
								
								imagename = xml.Prop("name");
							}
							while ( xml.NextNode() );
							xml.Parent();
						}
						
						tempkey = QString::fromUtf8("%1;%2;%3;%4").arg(temp_left).arg(temp_top).arg(temp_right).arg(temp_bottom);
						emote = emot_map->value(tempkey);
						
						if ( emote )
						{
							emote->m_Text.append(pattern);
						}
						else
						{
							emote = new DC_EmoticonObject();
							
							emote->left   = temp_left;
							emote->top    = temp_top;
							emote->right  = temp_right;
							emote->bottom = temp_bottom;
							
							emote->m_Text.append(pattern);
							
							emot_map->insert(tempkey, emote);
						}
						
						++oldcount;
					}
				}
				while ( xml.NextNode() );
				xml.Parent();
			}
		}
		while ( xml.NextNode() );
		
		newemotes = new QList<DC_EmoticonObject*>();
		*newemotes = emot_map->values();
		delete emot_map;
		emot_map = 0;
		
		printf("Got %d new emoticons from %d old emoticons\n",newemotes->size(),oldcount);
		
		xml.NewDoc("emoticons");
		xml.NewStringProp("imagefile",imagename);
		
		for ( QList<DC_EmoticonObject*>::const_iterator it = newemotes->constBegin(); it != newemotes->constEnd(); ++it )
		{
			emote = *it;
			
			xml.StartNewChild("emoticon");
			
			xml.NewStringProp("left",CString::number(emote->left));
			xml.NewStringProp("top",CString::number(emote->top));
			xml.NewStringProp("right",CString::number(emote->right));
			xml.NewStringProp("bottom",CString::number(emote->bottom));
			
			for ( int j = 0; j < emote->m_Text.size(); ++j )
			{
				xml.NewStringChild("emotext",emote->m_Text[j].toAscii().constData());
			}
						
			xml.Parent();
		}
		
		if ( xml.SaveConfigXmlViaTemp(path+"emoticons-v2.xml") == -1 )
		{
			printf("Cannot save auto-converted emoticons to %semoticons-v2.xml\n",path.Data());
			
			CString localfile = GetConfigPath();
			localfile += "auto-converted-";
			localfile += GetEmoticonTheme().toAscii().constData();
			localfile += "-emoticons-v2.xml";
			
			if ( QFile::exists(localfile.Data()) )
			{
				printf("%s already exists\n",localfile.Data());
			}
			else
			{
				if ( xml.SaveConfigXmlViaTemp(localfile) == -1 )
				{
					printf("Could not save auto converted emoticons to %s\n",localfile.Data());
				}
				else
				{
					printf("Auto converted emoticons saved to %s\n",localfile.Data());
				}
			}
		}
		else
		{
			printf("Auto converted emoticons saved to %semoticons-v2.xml\n",path.Data());
		}
	}
	
	if ( m_EmoticonImage.load((path+imagename).Data()) ||
	     m_EmoticonImage.load((path+imagename+".png").Data()) ||
	     m_EmoticonImage.load((path+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;
		res = false;
	}

	if ( res )
	{
		/*
		 * assign IDs, forgot about generating some QRegExp patterns,
		 * using QString::indexOf, even about 1,000 times, appeared to
		 * be more efficient.
		 */
		for ( QList<DC_EmoticonObject*>::const_iterator it = newemotes->constBegin(); it != newemotes->constEnd(); ++it )
		{
			(*it)->m_nID = id++;
		}
		
		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;
}

/** */
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;
}

/** */
QString DCConfig::EmoticonTextForPos( int x, int y )
{
	QString emote;
	
	if ( m_pEmoticons )
	{
		DC_EmoticonObject * e = 0;
		for ( QList<DC_EmoticonObject*>::const_iterator it = m_pEmoticons->constBegin(); it != m_pEmoticons->constEnd(); ++it )
		{
			e = *it;
			if ( (e->left < x) &&
			     (e->right > x) &&
			     (e->top < y) &&
			     (e->bottom > y)
			   )
			{
				emote = e->m_Text.first();
				break;
			}
		}
	}
	
	return emote;
}

/** */
QString DCConfig::EmoticonTextForID( int id )
{
	QString emote;
	
	/* id should actually be the list index ... but anyway */
	if ( m_pEmoticons )
	{
		for ( QList<DC_EmoticonObject*>::const_iterator it = m_pEmoticons->constBegin(); it != m_pEmoticons->constEnd(); ++it )
		{
			if ( (*it)->m_nID == id )
			{
				emote = (*it)->m_Text.first();
			}
		}
	}
	
	return emote;
}

/** */
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::SetChatForegroundColor( QString color )
{
    bool changed = ( color != m_sChatForegroundColor);

    m_sChatForegroundColor = color;

    if ( changed )
    {
        emit chatForegroundColorChanged();
    }
}

/** */
void DCConfig::SetDefaultDownloadMode( eDownloadMode m, bool emitsig )
{
	if ( m != m_eDefaultDownloadMode )
	{
		m_eDefaultDownloadMode = m;
		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.png" );
		
		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 );
	}
}

/** */
QString DCConfig::ChatToHTML( QString chat )
{
	int pos = 0, firstafter = 0, len = 0;
	QString toshow, surl, html;
	QUrl url;
	
	//printf("DCConfig::ChatToHTML in ='%s'\n",chat.toAscii().constData());
	
	for ( int i = 0; i < m_lURLs.size(); ++i )
	{
		pos = 0;
		
		while ( (pos = chat.indexOf(m_lURLs.value(i),pos,Qt::CaseInsensitive)) != -1 )
		{
			/* find end */
			for ( firstafter = pos + 1; firstafter < chat.length(); ++firstafter )
			{
				if ( chat.at(firstafter).isSpace() )
				{
					break;
				}
			}
			
			/* not at start of string, no space before, so skip */
			if ( (pos > 0) && (chat.at(pos-1).isSpace() == false) )
			{
				if ( firstafter == chat.length() )
				{
					/* won't find any more for this url prefix */
					break;
				}
				else
				{
					/* resume search from next word */
					pos += firstafter;
					continue;
				}
			}
			
			len = firstafter - pos;
			
			surl = chat.mid(pos,len);
			
			if ( i == 13 ) /* www. */
			{
				//toshow = surl;
				surl.prepend("http://");

				QUrl url = QUrl::fromEncoded(surl.toAscii());
				toshow = url.toString().replace("http://","");
			}
			else if ( i == 14 ) /* ftp. */
			{
				surl.prepend("ftp://");

				QUrl url = QUrl::fromEncoded(surl.toAscii());
				toshow = url.toString();
			}
			else if ( i == 15 ) /* magnet: */
			{
				toshow = surl;
				toshow.replace("+","%20");
				url.setEncodedUrl(toshow.toAscii());
				if ( url.hasQueryItem("dn") )
				{
					toshow = url.queryItemValue("dn");
					if ( url.hasQueryItem("xl") )
					{
						toshow += " (";
						toshow += DCGuiUtils::GetSizeString(url.queryItemValue("xl").toULongLong());
						toshow += ")";
					}
				}
				else
				{
					toshow = surl;
				}
			}
			else
			{
				QUrl url = QUrl::fromEncoded(surl.toAscii());
				toshow = url.toString();
			}
			
			/* replace this url with HTML */
			html = "<a href=\"";
			html += surl;
			html +="\" title=\"";
			html += surl;
			html += "\">";
			html += toshow;
			html += "</a>";
			chat.replace(pos,len,html);
			
			/* resume search after the html just put in */
			pos += html.length();
		}
	}
	
	if ( bEnableEmoticons && m_pEmoticons )
	{
		html = "<img alt=\"%1\" title=\"%1\" align=\"center\" source=\"";
		html += m_sEmoticonTheme;
		html += "/emoticon%2\" />";
		QString filledform;
		for ( QList<DC_EmoticonObject*>::const_iterator it = m_pEmoticons->constBegin(); it != m_pEmoticons->constEnd(); ++it )
		{
			for ( QStringList::const_iterator slit = (*it)->m_Text.constBegin(); slit != (*it)->m_Text.constEnd(); ++slit )
			{
				pos = 0;
				while ( (pos = chat.indexOf(*slit,pos,Qt::CaseSensitive)) != -1 )
				{
					/* must have either space or start/end of string before and after the emoticon */
					if ( ( (pos == 0) || chat.at(pos-1).isSpace() ) &&
					     ( (pos + (*slit).length() == chat.length()) || chat.at(pos+(*slit).length()).isSpace() )
					   )
					{
						filledform = html.arg(*slit).arg((*it)->m_nID);
						chat.replace(pos,(*slit).length(),filledform);
						pos += filledform.length();
					}
					else
					{
						/* skip */
						++pos;
					}
				}
			}
		}
	}
	
	//printf("DCConfig::ChatToHTML out='%s'\n",chat.toAscii().constData());
	return chat;
}
