diff options
Diffstat (limited to 'src/kvilib')
219 files changed, 41306 insertions, 0 deletions
diff --git a/src/kvilib/Makefile.am b/src/kvilib/Makefile.am new file mode 100644 index 00000000..1268e5e0 --- /dev/null +++ b/src/kvilib/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +SUBDIRS = build config core ext file include irc net system tal diff --git a/src/kvilib/build/Makefile.am b/src/kvilib/build/Makefile.am new file mode 100644 index 00000000..51e9333a --- /dev/null +++ b/src/kvilib/build/Makefile.am @@ -0,0 +1,339 @@ +######################################################################################################################## +# +# KVILIB Makefile : KVIrc utility library +# Szymon Stefanek 21.09.2001 +# +######################################################################################################################## + +AM_CPPFLAGS = -I$(SS_TOPSRCDIR)/src/kvilib/include/ $(SS_INCDIRS) $(SS_CPPFLAGS) + +lib_LTLIBRARIES = libkvilib.la +libkvilib_la_LDFLAGS = $(SS_LDFLAGS) -version-info 3:0:0 $(SS_LIBDIRS) +libkvilib_la_LIBADD = $(SS_LIBLINK) + +# +# Command useful to find out all the sources +# SRC=`find ../ -name *.cpp | sort` +# echo $SRC +# + +nodist_libkvilib_la_SOURCES = \ + ../ext/moc_kvi_crypt.cpp \ + ../ext/moc_kvi_garbage.cpp \ + ../ext/moc_kvi_regusersdb.cpp \ + ../ext/moc_kvi_sharedfiles.cpp \ + ../irc/moc_kvi_ircuserdb.cpp \ + ../net/moc_kvi_dns.cpp \ + ../net/moc_kvi_http.cpp \ + ../system/moc_kvi_locale.cpp \ + ../system/moc_kvi_thread.cpp \ + ../tal/moc_kvi_tal_wizard.cpp + +libkvilib_la_SOURCES = \ + ../core/kvi_error.cpp \ + ../core/kvi_heapobject.cpp \ + ../core/kvi_malloc.cpp \ + ../core/kvi_memmove.cpp \ + ../core/kvi_qstring.cpp \ + ../core/kvi_string.cpp \ + ../core/kvi_stringarray.cpp \ + ../ext/kvi_cmdformatter.cpp \ + ../ext/kvi_config.cpp \ + ../ext/kvi_crypt.cpp \ + ../ext/kvi_databuffer.cpp \ + ../ext/kvi_dcophelper.cpp \ + ../ext/kvi_doublebuffer.cpp \ + ../ext/kvi_garbage.cpp \ + ../ext/kvi_osinfo.cpp \ + ../ext/kvi_imagelib.cpp \ + ../ext/kvi_md5.cpp \ + ../ext/kvi_mediatype.cpp \ + ../ext/kvi_miscutils.cpp \ + ../ext/kvi_msgtype.cpp \ + ../ext/kvi_parameterlist.cpp \ + ../ext/kvi_pixmap.cpp \ + ../ext/kvi_proxydb.cpp \ + ../ext/kvi_regchan.cpp \ + ../ext/kvi_regusersdb.cpp \ + ../ext/kvi_sharedfiles.cpp \ + ../ext/kvi_stringconversion.cpp \ + ../file/kvi_file.cpp \ + ../file/kvi_fileutils.cpp \ + ../file/kvi_packagefile.cpp \ + ../irc/kvi_avatar.cpp \ + ../irc/kvi_avatarcache.cpp \ + ../irc/kvi_ircmask.cpp \ + ../irc/kvi_ircserver.cpp \ + ../irc/kvi_ircserverdb.cpp \ + ../irc/kvi_ircuserdb.cpp \ + ../irc/kvi_mirccntrl.cpp \ + ../irc/kvi_nickserv.cpp \ + ../irc/kvi_useridentity.cpp \ + ../net/kvi_dns.cpp \ + ../net/kvi_http.cpp \ + ../net/kvi_netutils.cpp \ + ../net/kvi_socket.cpp \ + ../net/kvi_ssl.cpp \ + ../net/kvi_url.cpp \ + ../system/kvi_env.cpp \ + ../system/kvi_locale.cpp \ + ../system/kvi_thread.cpp \ + ../system/kvi_time.cpp \ + ../tal/kvi_tal_application.cpp \ + ../tal/kvi_tal_filedialog.cpp \ + ../tal/kvi_tal_grid.cpp \ + ../tal/kvi_tal_groupbox.cpp \ + ../tal/kvi_tal_hbox.cpp \ + ../tal/kvi_tal_iconview.cpp \ + ../tal/kvi_tal_listbox.cpp \ + ../tal/kvi_tal_listview.cpp \ + ../tal/kvi_tal_mainwindow.cpp \ + ../tal/kvi_tal_menubar.cpp \ + ../tal/kvi_tal_popupmenu.cpp \ + ../tal/kvi_tal_scrollview.cpp \ + ../tal/kvi_tal_tabdialog.cpp \ + ../tal/kvi_tal_textedit.cpp \ + ../tal/kvi_tal_toolbar.cpp \ + ../tal/kvi_tal_tooltip.cpp \ + ../tal/kvi_tal_vbox.cpp \ + ../tal/kvi_tal_widgetstack.cpp \ + ../tal/kvi_tal_wizard.cpp + +# +# Command useful to find out all the headers +# rm -f ../include/*.h +# SRC=`find ../ -name *.h | sort` +# echo $SRC +# + + +headers_HEADERS = \ + ../config/kvi_confignames.h \ + ../config/kvi_debug.h \ + ../config/kvi_defaults.h \ + ../config/kvi_fileextensions.h \ + ../config/kvi_settings.h \ + ../config/kvi_sourcesdate.h \ + ../config/kvi_wincfg.h \ + ../core/kvi_bswap.h \ + ../core/kvi_error.h \ + ../core/kvi_heapobject.h \ + ../core/kvi_inttypes.h \ + ../core/kvi_malloc.h \ + ../core/kvi_memmove.h \ + ../core/kvi_pointerlist.h \ + ../core/kvi_pointerhashtable.h \ + ../core/kvi_qcstring.h \ + ../core/kvi_qstring.h \ + ../core/kvi_strasm.h \ + ../core/kvi_string.h \ + ../core/kvi_stringarray.h \ + ../core/kvi_valuelist.h \ + ../ext/kvi_accel.h \ + ../ext/kvi_cmdformatter.h \ + ../ext/kvi_config.h \ + ../ext/kvi_crypt.h \ + ../ext/kvi_databuffer.h \ + ../ext/kvi_doublebuffer.h \ + ../ext/kvi_draganddrop.h \ + ../ext/kvi_osinfo.h \ + ../ext/kvi_garbage.h \ + ../ext/kvi_imagelib.h \ + ../ext/kvi_md5.h \ + ../ext/kvi_mediatype.h \ + ../ext/kvi_miscutils.h \ + ../ext/kvi_msgtype.h \ + ../ext/kvi_parameterlist.h \ + ../ext/kvi_pixmap.h \ + ../ext/kvi_proxydb.h \ + ../ext/kvi_regchan.h \ + ../ext/kvi_regusersdb.h \ + ../ext/kvi_sharedfiles.h \ + ../ext/kvi_stringconversion.h \ + ../ext/kvi_xlib.h \ + ../file/kvi_file.h \ + ../file/kvi_fileutils.h \ + ../file/kvi_packagefile.h \ + ../irc/kvi_avatar.h \ + ../irc/kvi_avatarcache.h \ + ../irc/kvi_ircmask.h \ + ../irc/kvi_ircserverdb.h \ + ../irc/kvi_ircserver.h \ + ../irc/kvi_ircuserdb.h \ + ../irc/kvi_mirccntrl.h \ + ../irc/kvi_nickserv.h \ + ../irc/kvi_useridentity.h \ + ../net/kvi_dns.h \ + ../net/kvi_http.h \ + ../net/kvi_netutils.h \ + ../net/kvi_socket.h \ + ../net/kvi_sockettype.h \ + ../net/kvi_ssl.h \ + ../net/kvi_url.h \ + ../system/kvi_env.h \ + ../system/kvi_library.h \ + ../system/kvi_locale.h \ + ../system/kvi_process.h \ + ../system/kvi_stdarg.h \ + ../system/kvi_thread.h \ + ../system/kvi_time.h \ + ../tal/kvi_tal_application.h \ + ../tal/kvi_tal_application_kde.h \ + ../tal/kvi_tal_application_qt.h \ + ../tal/kvi_tal_filedialog.h \ + ../tal/kvi_tal_filedialog_kde.h \ + ../tal/kvi_tal_filedialog_qt.h \ + ../tal/kvi_tal_filedialog_qt4.h \ + ../tal/kvi_tal_grid.h \ + ../tal/kvi_tal_grid_qt3.h \ + ../tal/kvi_tal_grid_qt4.h \ + ../tal/kvi_tal_groupbox.h \ + ../tal/kvi_tal_groupbox_qt3.h \ + ../tal/kvi_tal_groupbox_qt4.h \ + ../tal/kvi_tal_hbox.h \ + ../tal/kvi_tal_hbox_qt3.h \ + ../tal/kvi_tal_hbox_qt4.h \ + ../tal/kvi_tal_iconview.h \ + ../tal/kvi_tal_iconview_qt3.h \ + ../tal/kvi_tal_iconview_qt4.h \ + ../tal/kvi_tal_listbox.h \ + ../tal/kvi_tal_listbox_qt3.h \ + ../tal/kvi_tal_listbox_qt4.h \ + ../tal/kvi_tal_listview.h \ + ../tal/kvi_tal_listview_qt3.h \ + ../tal/kvi_tal_listview_qt4.h \ + ../tal/kvi_tal_mainwindow.h \ + ../tal/kvi_tal_mainwindow_kde.h \ + ../tal/kvi_tal_mainwindow_qt3.h \ + ../tal/kvi_tal_mainwindow_qt4.h \ + ../tal/kvi_tal_menubar.h \ + ../tal/kvi_tal_menubar_kde.h \ + ../tal/kvi_tal_menubar_qt.h \ + ../tal/kvi_tal_popupmenu.h \ + ../tal/kvi_tal_popupmenu_qt3.h \ + ../tal/kvi_tal_popupmenu_qt4.h \ + ../tal/kvi_tal_scrollview.h \ + ../tal/kvi_tal_scrollview_qt3.h \ + ../tal/kvi_tal_scrollview_qt4.h \ + ../tal/kvi_tal_tabdialog.h \ + ../tal/kvi_tal_tabdialog_qt3.h \ + ../tal/kvi_tal_tabdialog_qt4.h \ + ../tal/kvi_tal_textedit.h \ + ../tal/kvi_tal_textedit_qt3.h \ + ../tal/kvi_tal_textedit_qt4.h \ + ../tal/kvi_tal_toolbar.h \ + ../tal/kvi_tal_toolbar_kde.h \ + ../tal/kvi_tal_toolbar_qt3.h \ + ../tal/kvi_tal_toolbar_qt4.h \ + ../tal/kvi_tal_toolbardocktype.h \ + ../tal/kvi_tal_tooltip.h \ + ../tal/kvi_tal_vbox.h \ + ../tal/kvi_tal_vbox_qt3.h \ + ../tal/kvi_tal_vbox_qt4.h \ + ../tal/kvi_tal_widgetstack.h \ + ../tal/kvi_tal_widgetstack_qt3.h \ + ../tal/kvi_tal_widgetstack_qt4.h \ + ../tal/kvi_tal_wizard.h \ + ../tal/kvi_tal_windowstate.h + + +../ext/moc_%.cpp: ../ext/%.h + $(SS_QT_MOC) $(SS_QT_MOC_FLAGS) $< -o $@ + +../file/moc_%.cpp: ../file/%.h + $(SS_QT_MOC) $(SS_QT_MOC_FLAGS) $< -o $@ + +../irc/moc_%.cpp: ../irc/%.h + $(SS_QT_MOC) $(SS_QT_MOC_FLAGS) $< -o $@ + +../net/moc_%.cpp: ../net/%.h + $(SS_QT_MOC) $(SS_QT_MOC_FLAGS) $< -o $@ + +../system/moc_%.cpp: ../system/%.h + $(SS_QT_MOC) $(SS_QT_MOC_FLAGS) $< -o $@ + +../tal/moc_%.cpp: ../tal/%.h + $(SS_QT_MOC) $(SS_QT_MOC_FLAGS) $< -o $@ + + +%.moc: %.h + $(SS_QT_MOC) $(SS_QT_MOC_FLAGS) $< -o $@ + +#%.h.gch: %.h +# $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c $< -o $@ + +#PRECOMPILED_HDRS = \ +# ../config/kvi_confignames.h.gch \ +# ... + +# +# Command useful to find the moc dependancies +# grep "\.moc" ../*/*.cpp | sort | sed -e 's/[[:space:]]*#include//' | sed -e 's/\"//g' +# needs to be modified by hand then to add the moc file path... :) +# + +../tal/kvi_tal_application.cpp: ../tal/kvi_tal_application_kde.moc +../tal/kvi_tal_application.cpp: ../tal/kvi_tal_application_qt.moc +../tal/kvi_tal_mainwindow.cpp: ../tal/kvi_tal_mainwindow_kde.moc +../tal/kvi_tal_mainwindow.cpp: ../tal/kvi_tal_mainwindow_qt3.moc +../tal/kvi_tal_mainwindow.cpp: ../tal/kvi_tal_mainwindow_qt4.moc +../tal/kvi_tal_menubar.cpp: ../tal/kvi_tal_menubar_kde.moc +../tal/kvi_tal_menubar.cpp: ../tal/kvi_tal_menubar_qt.moc +../tal/kvi_tal_filedialog.cpp: ../tal/kvi_tal_filedialog_kde.moc +../tal/kvi_tal_filedialog.cpp: ../tal/kvi_tal_filedialog_qt.moc +../tal/kvi_tal_filedialog.cpp: ../tal/kvi_tal_filedialog_qt4.moc +../tal/kvi_tal_grid.cpp: ../tal/kvi_tal_grid_qt3.moc +../tal/kvi_tal_grid.cpp: ../tal/kvi_tal_grid_qt4.moc +../tal/kvi_tal_groupbox.cpp: ../tal/kvi_tal_groupbox_qt3.moc +../tal/kvi_tal_groupbox.cpp: ../tal/kvi_tal_groupbox_qt4.moc +../tal/kvi_tal_hbox.cpp: ../tal/kvi_tal_hbox_qt3.moc +../tal/kvi_tal_hbox.cpp: ../tal/kvi_tal_hbox_qt4.moc +../tal/kvi_tal_vbox.cpp: ../tal/kvi_tal_vbox_qt3.moc +../tal/kvi_tal_vbox.cpp: ../tal/kvi_tal_vbox_qt4.moc +../tal/kvi_tal_popupmenu.cpp: ../tal/kvi_tal_popupmenu_qt3.moc +../tal/kvi_tal_popupmenu.cpp: ../tal/kvi_tal_popupmenu_qt4.moc +../tal/kvi_tal_listview.cpp: ../tal/kvi_tal_listview_qt3.moc +../tal/kvi_tal_listview.cpp: ../tal/kvi_tal_listview_qt4.moc +../tal/kvi_tal_listbox.cpp: ../tal/kvi_tal_listbox_qt3.moc +../tal/kvi_tal_listbox.cpp: ../tal/kvi_tal_listbox_qt4.moc +../tal/kvi_tal_iconview.cpp: ../tal/kvi_tal_iconview_qt3.moc +../tal/kvi_tal_iconview.cpp: ../tal/kvi_tal_iconview_qt4.moc +../tal/kvi_tal_scrollview.cpp: ../tal/kvi_tal_scrollview_qt3.moc +../tal/kvi_tal_scrollview.cpp: ../tal/kvi_tal_scrollview_qt4.moc +../tal/kvi_tal_tabdialog.cpp: ../tal/kvi_tal_tabdialog_qt3.moc +../tal/kvi_tal_tabdialog.cpp: ../tal/kvi_tal_tabdialog_qt4.moc +../tal/kvi_tal_textedit.cpp: ../tal/kvi_tal_textedit_qt3.moc +../tal/kvi_tal_textedit.cpp: ../tal/kvi_tal_textedit_qt4.moc +../tal/kvi_tal_toolbar.cpp: ../tal/kvi_tal_toolbar_qt3.moc +../tal/kvi_tal_toolbar.cpp: ../tal/kvi_tal_toolbar_qt4.moc +../tal/kvi_tal_toolbar.cpp: ../tal/kvi_tal_toolbar_kde.moc +../tal/kvi_tal_tooltip.cpp: ../tal/kvi_tal_tooltip.moc +../tal/kvi_tal_widgetstack.cpp: ../tal/kvi_tal_widgetstack_qt3.moc +../tal/kvi_tal_widgetstack.cpp: ../tal/kvi_tal_widgetstack_qt4.moc + +# +# All the cpp files depend on the precompiled headers being up-to-date +# + +#../*/*.cpp: symlinks $(PRECOMPILED_HDRS) gchsymlinks + +../*/*.cpp: symlinks + +# +# Symlinks depend on all the header files: symlink is rebuilt whenewer an *.h file changes +# + +symlinks: ../config/*.h ../core/*.h ../ext/*.h ../file/*.h ../irc/*.h ../net/*.h ../system/*.h ../tal/*.h + cd ../include; for i in kvi_*.h; do if [ ! -f $$i ]; then rm -f $$i; fi; done; for i in $(SS_TOPSRCDIR)/src/kvilib/*/kvi_*.h; do $(LN_S) $$i . >/dev/null 2>&1; echo "Created link to $$i"; done; + touch symlinks + +# gchsymlinks: ../config/*.h ../core/*.h ../ext/*.h ../file/*.h ../irc/*.h ../net/*.h ../system/*.h ../tal/*.h +# cd ../include; for i in kvi_*.gch; do if [ ! -f $$i ]; then rm -f $$i; fi; done; for i in $(SS_TOPSRCDIR)/src/kvilib/*/kvi_*.h.gch; do $(LN_S) $$i . >/dev/null 2>&1; echo "Created link to $$i"; done; +# touch gchsymlinks + +# +# When cleaning...remove also the symlinks, gchsymlinks and gch headers +# + +#CLEANFILES = ../include/*.h ../include/*.gch symlinks gchsymlinks ../*/*.moc ../*/moc_kvi_*.cpp ../*/*.gch +CLEANFILES = ../include/*.h symlinks ../*/*.moc ../*/moc_kvi_*.cpp diff --git a/src/kvilib/config/Makefile.am b/src/kvilib/config/Makefile.am new file mode 100644 index 00000000..23078cbb --- /dev/null +++ b/src/kvilib/config/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.h diff --git a/src/kvilib/config/kvi_confignames.h b/src/kvilib/config/kvi_confignames.h new file mode 100644 index 00000000..ccff3399 --- /dev/null +++ b/src/kvilib/config/kvi_confignames.h @@ -0,0 +1,61 @@ +#ifndef _KVI_CONFIGNAMES_H_ +#define _KVI_CONFIGNAMES_H_ + +//============================================================================= +// +// File : kvi_confignames.h +// Creation date : Wed Oct 18 2000 14:16:22 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_fileextensions.h" + +//============================================================================= +// This file contains the config file names used in KVIrc +// +// You can play a bit with these, but be aware that some (bad) scripts +// may find themselves in trouble +//============================================================================= + +#define KVI_CONFIGFILE_MAIN "main." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_WINPROPERTIES "winproperties." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_SERVERDB "serverdb." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_PROXYDB "proxydb." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_EVENTS "events." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_RAWEVENTS "rawevents." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_POPUPS "popups." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_SCRIPTTOOLBARS "toolbars." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_CUSTOMTOOLBARS "customtoolbars." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_MEDIATYPES "mediatypes." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_REGUSERDB "reguserdb." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_SHAREDFILES "sharedfiles." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_RECENT "recent." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_TOOLBARS "toolbarpos." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_ALIASES "aliases." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_NICKSERVDATABASE "nickserv." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_TEXTICONS "texticons." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_REGCHANDB "regchan." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_INPUTHISTORY "inputhistory." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_AVATARCACHE "avatarcache." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_USERACTIONS "useractions." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_SCRIPTADDONS "scriptaddons." KVI_FILEEXTENSION_CONFIG +#define KVI_CONFIGFILE_IDENTITIES "identities." KVI_FILEEXTENSION_CONFIG + +#endif //_KVI_CONFIGNAMES_H_ diff --git a/src/kvilib/config/kvi_debug.h b/src/kvilib/config/kvi_debug.h new file mode 100644 index 00000000..8ae1a120 --- /dev/null +++ b/src/kvilib/config/kvi_debug.h @@ -0,0 +1,52 @@ +#ifndef _KVI_DEBUG_H_ +#define _KVI_DEBUG_H_ + +//============================================================================= +// +// File : kvi_debug.h +// Creation date : Fri Mar 19 1999 03:10:39 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <qglobal.h> + +//============================================================================= +// This file contains the definition of the debug macros +// You can enable ALL the debugging output by uncommenting the next line +// +// #define _KVI_DEBUG_CHECK_RANGE_ +// +//============================================================================= + +#ifdef _KVI_DEBUG_CHECK_RANGE_ + #define __range_valid(_expr) if(!(_expr))debug("[kvirc]: ASSERT FAILED: \"%s\" is false in %s (%d)",#_expr,__FILE__,__LINE__) + #define __range_invalid(_expr) if(_expr)debug("[kvirc]: ASSERT FAILED: \"%s\" is true in %s (%d)",#_expr,__FILE__,__LINE__) +#else + #define __range_valid(_expr) + #define __range_invalid(_expr) +#endif + +#if defined(_KVI_DEBUG_) || defined(__KVI_DEBUG__) + #define __ASSERT(_expr) if(!(_expr))debug("[kvirc]: ASSERT FAILED: \"%s\" is false in %s (%d)",#_expr,__FILE__,__LINE__) +#else + #define __ASSERT(_expr) +#endif + +#endif //_KVI_DEBUG_H_ diff --git a/src/kvilib/config/kvi_defaults.h b/src/kvilib/config/kvi_defaults.h new file mode 100644 index 00000000..fc375b05 --- /dev/null +++ b/src/kvilib/config/kvi_defaults.h @@ -0,0 +1,65 @@ +#ifndef _KVI_DEFAULTS_H_ +#define _KVI_DEFAULTS_H_ + +//============================================================================= +// +// File : kvi_defaults.h +// Creation date : Wed Jun 21 2000 13:23:13 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// This file contains (more or less) freely customizable compile time defaults +// +// You can safely play with the ones you understand the meaning of +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_ON_WINDOWS + #define KVI_HOME_CONFIG_FILE_NAME "kvirc.ini" +#else + #define KVI_HOME_CONFIG_FILE_NAME ".kvirc.rc" +#endif + + +#define KVI_DEFAULT_INCOMING_SUBDIRECTORY_NAME "download" + +#define KVI_DEFAULT_NICKNAME1 "newbie" +#define KVI_DEFAULT_NICKNAME2 "[newbie]" +#define KVI_DEFAULT_NICKNAME3 "_newbie_" +#define KVI_DEFAULT_NICKNAME4 "newbie4" +#define KVI_DEFAULT_USERNAME "kvirc" +#define KVI_DEFAULT_REALNAME "KVIrc " VERSION " '" KVI_RELEASE_NAME "' http://kvirc.net/" + +#define KVI_DEFAULT_PART_MESSAGE "No matter how dark the night, somehow the Sun rises once again" +#define KVI_DEFAULT_QUIT_MESSAGE "KVIrc $version $version(r) http://www.kvirc.net/" +#define KVI_DEFAULT_CTCP_USERINFO_REPLY "I'm too lazy to edit this field." +#define KVI_DEFAULT_CTCP_PAGE_REPLY "Your message has been received and logged" +#define KVI_DEFAULT_AWAY_MESSAGE "I'm off to see the wizard." +#define KVI_DEFAULT_AWAY_NICK "%nick%|NotHere" + +#define KVI_MAX_PENDING_AVATARS 20 +#define KVI_MAX_RECENT_SERVERS 10 +#define KVI_MAX_RECENT_CHANNELS 30 +#define KVI_MAX_RECENT_NICKNAMES 10 +#define KVI_RECENT_TOPIC_ENTRIES 20 + +#endif //_KVI_DEFAULTS_H_ diff --git a/src/kvilib/config/kvi_fileextensions.h b/src/kvilib/config/kvi_fileextensions.h new file mode 100644 index 00000000..e181c974 --- /dev/null +++ b/src/kvilib/config/kvi_fileextensions.h @@ -0,0 +1,37 @@ +#ifndef _KVI_FILEEXTENSIONS_H_ +#define _KVI_FILEEXTENSIONS_H_ + +//============================================================================= +// +// File : kvi_fileextensions.h +// Creation date : Tue Dec 26 2006 05:09:22 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// This file contains the file extensions used by KVIrc +//============================================================================= + +#define KVI_FILEEXTENSION_CONFIG "kvc" +#define KVI_FILEEXTENSION_SCRIPT "kvs" +#define KVI_FILEEXTENSION_THEMEPACKAGE "kvt" +#define KVI_FILEEXTENSION_ADDONPACKAGE "kva" + +#endif //_KVI_FILEEXTENSIONS_H_ diff --git a/src/kvilib/config/kvi_settings.h b/src/kvilib/config/kvi_settings.h new file mode 100644 index 00000000..ee6044bd --- /dev/null +++ b/src/kvilib/config/kvi_settings.h @@ -0,0 +1,140 @@ +#ifndef _KVI_SETTINGS_H_ +#define _KVI_SETTINGS_H_ + +//============================================================================= +// +// File : kvi_settings.h +// Creation date : Fri Mar 19 1999 05:21:13 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// This file contains compile time settings, either set by configure or +// non-customizable defaults +// +// Better do not touch this +//============================================================================= + +#include <qglobal.h> + +#if defined(_OS_WIN32_) || defined(Q_OS_WIN32) || defined(Q_OS_WIN32_) + + #define FEEL_LIKE_I_AM_COMPILING_UNDER_WINDOZE + #define COMPILE_ON_WINDOWS + + // Windows has no config.h + + #include "kvi_wincfg.h" + + #ifdef __KVILIB__ + #define KVILIB_API __declspec(dllexport) + #else + #define KVILIB_API __declspec(dllimport) + #endif + + #ifdef __KVIRC__ + #define KVIRC_API __declspec(dllexport) + #else + #define KVIRC_API __declspec(dllimport) + #endif + +#else + + #ifdef KVIRC_EXTERNAL_MODULE + // when compiling an external module + // include the last configuration + #include "kvi_configstatus.h" + #else + #ifdef HAVE_CONFIG_H + #include "config.h" + #else + #error "You're missing the config.h file: you must run configure before running make!" + #endif + #endif + + #define KVILIB_API + #define KVIRC_API + + #ifndef VERSION + #define VERSION "?.?.?" + #endif + + #ifndef BUILD_DATE + #define BUILD_DATE "?" + #endif + + #ifndef BUILD_FLAGS + #define BUILD_FLAGS "?" + #endif + +#endif + +#define KVI_VERSION VERSION +#define KVI_VERSION_BRANCH VERSION_BRANCH +#define KVI_BUILD_DATE BUILD_DATE +#define KVI_BUILD_FLAGS BUILD_FLAGS + +#define KVI_RELEASE_NAME "Virgo" + +// We want _GNU_SOURCE features +#ifndef _GNU_SOURCE + #define _GNU_SOURCE +#endif + + +#if defined(__GNUC__) + // gcc + #if __GNUC__ >= 3 + #define KVI_PTR2MEMBER(__x) &__x + #else + #define KVI_PTR2MEMBER(__x) &(__x) + #endif +#elif defined(COMPILE_ON_WINDOWS) + // Visual C++ + #define KVI_PTR2MEMBER(__x) &__x +#elif defined(__SUNPRO_CC) + // Sun Forte + #define KVI_PTR2MEMBER(__x) (__x) +#else + // default + #define KVI_PTR2MEMBER(__x) &(__x) +#endif + +#ifdef COMPILE_NO_X + #ifndef COMPILE_NO_X_BELL + #define COMPILE_NO_X_BELL + #endif +#endif + +/* +#if __GNUC__ - 0 > 3 || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 >= 2) + #define KVI_DEPRECATED __attribute__ ((deprecated)) +#else + #define KVI_DEPRECATED +#endif +*/ +#define KVI_DEPRECATED + +#ifdef COMPILE_USE_QT4 + #define debug qDebug +#endif + + +#endif //_KVI_SETTINGS_H_ diff --git a/src/kvilib/config/kvi_sourcesdate.h b/src/kvilib/config/kvi_sourcesdate.h new file mode 100644 index 00000000..263fc092 --- /dev/null +++ b/src/kvilib/config/kvi_sourcesdate.h @@ -0,0 +1,40 @@ + +#ifndef _KVI_SOURCESDATE_H_ +#define _KVI_SOURCESDATE_H_ + +//============================================================================= +// +// File : kvi_sourcesdate.h +// Creation date : Sun Mar 5 2006 23:22:22 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#define KVI_SOURCES_DATE "20080323" +#define KVI_SOURCES_DATE_NUMERIC 0x20080323 + +// this is the date of the sources before that we should force a setup +// this is usually changed only when a setup is really needed because +// of an incompatible change in the configuration files +// .. so do NOT change it just when you change KVI_SOURCES_DATE_NUMERIC :) +#define KVI_SOURCES_DATE_NUMERIC_FORCE_SETUP 0x20080101 + +#endif //!_KVI_SOURCESDATE_H_ diff --git a/src/kvilib/config/kvi_version.h b/src/kvilib/config/kvi_version.h new file mode 100644 index 00000000..e09dacef --- /dev/null +++ b/src/kvilib/config/kvi_version.h @@ -0,0 +1,33 @@ +#ifndef _KVI_VERSION_H_ +#define _KVI_VERSION_H_ + +//============================================================================= +// +// File : kvi_version.h +// Creation date : Sun Mar 5 2006 23:22:22 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + + + +#endif //!_KVI_VERSION_H_ + diff --git a/src/kvilib/config/kvi_wincfg.h b/src/kvilib/config/kvi_wincfg.h new file mode 100644 index 00000000..f90998a8 --- /dev/null +++ b/src/kvilib/config/kvi_wincfg.h @@ -0,0 +1,210 @@ +#ifndef _KVI_WINCFG_H_ +#define _KVI_WINCFG_H_ + +//============================================================================= +// +// File : kvi_wincfg.h +// Creation date : Fri Sep 21 16:21:09 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// Windows configuration: do not touch +//============================================================================= + +/* define if you want to compile with new parser */ +#define COMPILE_NEW_KVS 1 + +/* define if you want to use the Qt 4.x support */ +/* #undef COMPILE_USE_QT4 */ + +#define COMPILE_USE_QT4 + +/* define if you want to use only the new KVS parser */ +#define COMPILE_ONLY_NEW_KVS 1 + +/* define if you want to disable DCC VOICE sound support */ +/* #undef COMPILE_WITH_NO_SOUND */ + +/* define if you have libgsm and want the GSM code to be compiled */ +/* #undef COMPILE_USE_GSM */ + +/* define if you want the info tips to be compiled in */ +#define COMPILE_INFO_TIPS 1 + +/* define if you want to compile the KDE 2.x support */ +/* #undef COMPILE_KDE_SUPPORT */ + +/* define if you want the gcc memory profile */ +/* #undef COMPILE_MEMORY_PROFILE */ + +/* define if you want the memory checks */ +/* #undef COMPILE_MEMORY_CHECKS */ + +/* define if you trust your memmove() function */ +#define COMPILE_WITH_SYSTEM_MEMMOVE 1 + +/* define if you want to compile the crypt support */ +#define COMPILE_CRYPT_SUPPORT 1 + +/* define if you want the i386 asm code */ +/* #undef COMPILE_ix86_ASM */ + +/* define if your compiler supports gotos do dynamic labels */ +/* #undef COMPILE_USE_DYNAMIC_LABELS */ + +/* define if you want to compile the localization support */ +#define COMPILE_LOCALE_STUFF 1 + +/* define if you want the IpV6 support */ +#define COMPILE_IPV6_SUPPORT 1 + +/* define if you want zlib support */ +#define COMPILE_ZLIB_SUPPORT 1 + +/* define if you want to use the pthreads library */ +/* #undef COMPILE_THREADS_USE_POSIX */ + +/* define if you want to use the solaris libthread */ +/* #undef COMPILE_THREADS_USE_SOLARIS_LIBTHREAD */ + +#define COMPILE_PSEUDO_TRANSPARENCY + +/* define if you have the SIOCGIFADDR ioctl and the related headers */ +/* #undef COMPILE_GET_INTERFACE_ADDRESS */ + +/* this is the build date (configure date rather) */ +#define BUILD_DATE __DATE__" "__TIME__ + +/* these are the build flags */ +#define BUILD_FLAGS "win32" + +/* define if you have strings.h */ +/* #undef HAVE_STRINGS_H */ + +/* define if you have the getenv function */ +/* #undef HAVE_GETENV */ + +/* define if you have the strerror function */ +#define HAVE_STRERROR 1 + +/* define if you have the inet_aton function */ +/* #define HAVE_INET_ATON 1 */ + +/* define if you have the inet_ntoa function */ +/* #define HAVE_INET_NTOA 1 */ + +/* define if you have the inet_pton function */ +/* #undef HAVE_INET_PTON */ + +/* define if you have the inet_ntop function */ +/* #undef HAVE_INET_NTOP */ + +/* define if you have the getnameinfo function */ +#define HAVE_GETNAMEINFO + +/* define if you have the getaddrinfo function */ +#define HAVE_GETADDRINFO + +/* define this to the number of average channel users */ +#define AVERAGE_CHANNEL_USERS 101 + +/* define this if you want to ignore the SIGALARM signal */ +/* #undef COMPILE_IGNORE_SIGALARM */ + +/* define this if you are on a big endian machine */ +/* #undef BIG_ENDIAN_MACHINE_BYTE_ORDER */ + +/* define this if you want to use the unicode-local 8bit charset translation */ +/* #undef COMPILE_USE_LOCAL_8BIT */ + +/* define this if you want to disable the inter-process communication support */ +/* #undef COMPILE_NO_IPC */ + +/* Define if you have the `getenv' function. */ +/* #undef HAVE_GETENV */ + +/* Define if you have the <linux/soundcard.h> header file. */ +/* #undef HAVE_LINUX_SOUNDCARD_H */ + +/* Define if you have the <soundcard.h> header file. */ +/* #undef HAVE_SOUNDCARD_H */ + +/* Define if you have the <sys/soundcard.h> header file. */ +/* #undef HAVE_SYS_SOUNDCARD_H */ + +/* Name of package */ +#define PACKAGE "kvirc" + +/* Version number of package */ +#define VERSION "3.4.0" + +#define VERSION_BRANCH "3.4" + + +/* Define if the system does not provide POSIX.1 features except with this + defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +// for now we need this....dcc voice is not ported yet +#define COMPILE_WITH_NO_SOUND + +#define COMPILE_DISABLE_DCC_VOICE + +/* No X support */ +#define COMPILE_NO_X + +/* No X bell! */ +#define COMPILE_NO_X_BELL + +/* define if you have openssl and want the ssl support in kvirc */ +#define COMPILE_SSL_SUPPORT + +/* define if you want perl scripting support */ +#define COMPILE_PERL_SUPPORT + +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `long int', as computed by sizeof. */ +#define SIZEOF_LONG_INT 4 + +/* The size of a `long long int', as computed by sizeof. */ +#define SIZEOF_LONG_LONG_INT 8 + +/* The size of a `short int', as computed by sizeof. */ +#define SIZEOF_SHORT_INT 2 + +/* The size of a `unsigned int', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_INT 4 + +/* The size of a `unsigned long int', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_LONG_INT 4 + +/* The size of a `unsigned long long int', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_LONG_LONG_INT 8 + +/* The size of a `unsigned short int', as computed by sizeof. */ +#define SIZEOF_UNSIGNED_SHORT_INT 2 + +#endif //_KVI_WINCFG_H_ diff --git a/src/kvilib/core/Makefile.am b/src/kvilib/core/Makefile.am new file mode 100644 index 00000000..c84487eb --- /dev/null +++ b/src/kvilib/core/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.cpp *.h diff --git a/src/kvilib/core/kvi_bswap.h b/src/kvilib/core/kvi_bswap.h new file mode 100644 index 00000000..5d5ef5bb --- /dev/null +++ b/src/kvilib/core/kvi_bswap.h @@ -0,0 +1,63 @@ +#ifndef _KVI_BSWAP_H_ +#define _KVI_BSWAP_H_ + +//============================================================================= +// +// File : kvi_bswap.h +// Creation date : Fri Mar 19 1999 03:15:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_inttypes.h" + + +// KVILIB_API has been removed from therse two functions +// these should always go inlined + +inline kvi_u64_t kvi_swap64(kvi_u64_t i) +{ + // abcdefgh to hgfedcba + return ((i << 56) | /* h to a */ + ((i & 0xff00) << 40) | /* g to b */ + ((i & 0xff0000) << 24) | /* f to c */ + ((i & 0xff000000) << 8) | /* e to d */ + ((i >> 8) & 0xff000000) | /* d to e */ + ((i >> 24) & 0xff0000) | /* c to f */ + ((i >> 40) & 0xff00) | /* b to g */ + (i >> 56)); /* a to h */ +} + +inline kvi_u32_t kvi_swap32(kvi_u32_t i) +{ + // abcd to dcba + return ((i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24)); +} + +inline kvi_u16_t kvi_swap16(kvi_u16_t i) +{ + // ab to ba + return ((i << 8) | (i >> 8)); +} + + + + +#endif // !_KVI_BSWAP_H_ diff --git a/src/kvilib/core/kvi_error.cpp b/src/kvilib/core/kvi_error.cpp new file mode 100644 index 00000000..6497c757 --- /dev/null +++ b/src/kvilib/core/kvi_error.cpp @@ -0,0 +1,237 @@ +//============================================================================= +// +// File : kvi_error.cpp +// Creation date : Sun Jul 02 2000 18:37:02 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#define _KVI_ERROR_CPP_ + +#include "kvi_locale.h" +#include "kvi_error.h" +#include "kvi_settings.h" + + +#ifdef COMPILE_ON_WINDOWS +#include <winsock2.h> // for the WSAE* error codes +#endif + +#include <errno.h> + +#ifdef HAVE_STRERROR +#include <string.h> // for strerror() +#endif + +// FIXME: This stuff should basically die and be eventually replaced with some +// helper functions for handling ONLY system errors. +// +// WARNING: getDescription() is not even thread safe... it will die in the near future + +const char * g_errorTable[KVI_NUM_ERRORS]= +{ + __tr_no_lookup("Success"), // 000: success + __tr_no_lookup("Unknown error"), // 001: unkonwnError + __tr_no_lookup("Internal error"), // 002: internalError + __tr_no_lookup("Unknown command"), // 003: unknownCommand + __tr_no_lookup("Missing closing brace"), // 004: missingClosingBrace + __tr_no_lookup("Unexpected end of command in string"), // 005: unexpectedEndInString + __tr_no_lookup("Unexpected end of command in dictionary key"), // 006: unexpectedEndInDictionaryKey + __tr_no_lookup("Switch dash without switch letter"), // 007: switchDashWithoutSwitchLetter + __tr_no_lookup("Unknown function"), // 008: unknownFunction + __tr_no_lookup("Unexpected end of command in parenthesis"), // 009: unexpectedEndInParenthesis + __tr_no_lookup("Unexpected end of command in function parameters"), // 010: unexpectedEndInFunctionParams + __tr_no_lookup("Missing variable name"), // 011: missingVariableName + __tr_no_lookup("Variable or identifier expected"), // 012: variableOrIdentifierExpected + __tr_no_lookup("Left operand is not a number"), // 013: leftOperandIsNotANumber + __tr_no_lookup("Multiple operations not supported for numeric operators"), // 014: multipleOpsNotSupportedForOperator + __tr_no_lookup("Division by zero"), // 015: divisionByZero + __tr_no_lookup("Modulo by zero"), // 016: moduloByZero + __tr_no_lookup("Right operand is not a number"), // 017: rightOperandIsNotANumber + __tr_no_lookup("Unterminated expression (missing ')' ?)"), // 018: unterminatedExpression + __tr_no_lookup("Unterminated subexpression (Parenthesis mismatch)"), // 019: unterminatedSubexpression + __tr_no_lookup("Unexpected character"), // 020: unexpectedCharacter + __tr_no_lookup("Unknown operator"), // 021: unknownOperator + __tr_no_lookup("No host to resolve"), // 022 + __tr_no_lookup("(DNS Internal) Unsupported address family"), // 023 + __tr_no_lookup("Valid name but the host has no IP address"), // 024 + __tr_no_lookup("Unrecoverable nameserver error (crashed ?)"), // 025 + __tr_no_lookup("Dns temporaneous fault (try again)"), // 026 + __tr_no_lookup("(DNS Internal) Bad flags"), // 027 + __tr_no_lookup("(DNS Internal) Out of memory"), // 028 + __tr_no_lookup("(DNS Internal) Service not supported"), // 029 + __tr_no_lookup("Unknown node (host not found)"), // 030 + __tr_no_lookup("(DNS Internal) Unsupported socket type"), // 031 + __tr_no_lookup("Dns query failed"), // 032 + __tr_no_lookup("This KVIrc executable has no IPV6 support"), // 033 + __tr_no_lookup("Host not found"), // 034 + __tr_no_lookup("(DNS Internal) IPC failure (slave data corrupted)"), // 035 + __tr_no_lookup("Another connection in progress"), // 036 + __tr_no_lookup("Invalid IP address"), // 037 + __tr_no_lookup("Socket creation failed"), // 038 + __tr_no_lookup("Failed to put the socket in non blocking mode"), // 039 + __tr_no_lookup("Bad file descriptor"), // 040 + __tr_no_lookup("Out of address space"), // 041 + __tr_no_lookup("Connection refused"), // 042 + __tr_no_lookup("Kernel networking panic"), // 043 + __tr_no_lookup("Connection timed out"), // 044 + __tr_no_lookup("Network is unreachable"), // 045 + __tr_no_lookup("Broken pipe"), // 046 + __tr_no_lookup("Invalid proxy address"), // 047 + __tr_no_lookup("Remote end has closed the connection"), // 048 + __tr_no_lookup("Invalid irc context id"), // 049 + __tr_no_lookup("Error in loading module"), // 050 + __tr_no_lookup("No such module command"), // 051 + __tr_no_lookup("No such module function"), // 052 + __tr_no_lookup("Left operand is not a dictionary reference"), // 053 + __tr_no_lookup("Right operand is not a dictionary reference"), // 054 + __tr_no_lookup("Missing object class name"), // 055 + __tr_no_lookup("No such object class"), // 056 + __tr_no_lookup("No such object"), // 057 + __tr_no_lookup("No such object function"), // 058 + __tr_no_lookup("Invalid left operand"), // 059 + __tr_no_lookup("Not enough parameters"), // 060 + __tr_no_lookup("Integer parameter expected"), // 061 + __tr_no_lookup("Invalid parameter"), // 062 + __tr_no_lookup("No such file"), // 063 + __tr_no_lookup("Open parenthesis expected"), // 064 + __tr_no_lookup("Open brace expected"), // 065 + __tr_no_lookup("Can't kill a builtin class"), // 066 + __tr_no_lookup("The SOCKSV4 protocol lacks IpV6 support"), // 067 + __tr_no_lookup("Unrecognized proxy reply"), // 068 + __tr_no_lookup("Proxy response: auth failed: access denied"), + __tr_no_lookup("Proxy response: No acceptable auth method: request rejected"), + __tr_no_lookup("Proxy response: request failed"), + __tr_no_lookup("Proxy response: ident failed"), + __tr_no_lookup("Proxy response: ident not matching"), + __tr_no_lookup("Proxy response: general SOCKS failure"), + __tr_no_lookup("Proxy response: connection not allowed"), + __tr_no_lookup("Proxy response: network unreachable"), + __tr_no_lookup("Proxy response: host unreachable"), + __tr_no_lookup("Proxy response: connection refused"), + __tr_no_lookup("Proxy response: TTL expired"), + __tr_no_lookup("Proxy response: command not supported"), + __tr_no_lookup("Proxy response: address type not supported"), + __tr_no_lookup("Proxy response: invalid address"), + __tr_no_lookup("Invalid port number"), + __tr_no_lookup("Socket not connected"), + __tr_no_lookup("Insufficient resources to complete the operation"), + __tr_no_lookup("Can't setup a listening socket : bind failed"), + __tr_no_lookup("Can't resolve the localhost name"), + __tr_no_lookup("Unsupported image format"), + __tr_no_lookup("Can't open file for appending"), + __tr_no_lookup("Can't open file for writing"), + __tr_no_lookup("File I/O error"), + __tr_no_lookup("Acknowledge error"), + __tr_no_lookup("Can't open file for reading"), + __tr_no_lookup("Can't send a zero-size file"), + __tr_no_lookup("Missing popup name"), + __tr_no_lookup("'item', 'popup', 'label' or 'separator' keyword expected"), + __tr_no_lookup("Self modification not allowed"), + __tr_no_lookup("UNUSED"), + __tr_no_lookup("Feature not available"), + __tr_no_lookup("Unexpected characters in array index"), + __tr_no_lookup("Unexpected end in expression"), + __tr_no_lookup("Unexpected end in array index"), + __tr_no_lookup("Connection thru HTTP proxy failed"), + __tr_no_lookup("Case , match , regexp , default or break keyword expected"), + __tr_no_lookup("Access denied"), + __tr_no_lookup("Address already in use"), + __tr_no_lookup("Can't assign the requested address"), + __tr_no_lookup("Connection reset by peer"), + __tr_no_lookup("Host unreachable (no route to host)"), + __tr_no_lookup("Variable expected"), + __tr_no_lookup("Invalid array index: positive integer expected"), + __tr_no_lookup("listen() call failed"), + __tr_no_lookup("This executable has been compiled without SSL support"), + __tr_no_lookup("Secure Socket Layer error"), + __tr_no_lookup("Slash (/) character expected"), + __tr_no_lookup("Unknown string manipulation operation"), + __tr_no_lookup("Operation aborted"), + __tr_no_lookup("Unexpected token"), + __tr_no_lookup("Scope object already defined (unexpected @)"), + __tr_no_lookup("There is no $this pointer in this scope (unexpected @)") +}; + +namespace KviError +{ + const char * getUntranslatedDescription(int iErrorCode) + { + if((iErrorCode < KVI_NUM_ERRORS) && (iErrorCode >= 0)) + return g_errorTable[iErrorCode]; +#ifdef HAVE_STRERROR + if(iErrorCode < 0)return strerror(-iErrorCode); +#endif + return g_errorTable[KviError_unknownError]; + } + + QString getDescription(int iErrorCode) + { + return __tr2qs_no_xgettext(getUntranslatedDescription(iErrorCode)); + } + + int translateSystemError(int iErrNo) + { +#ifdef COMPILE_ON_WINDOWS + switch(iErrNo) + { + case EBADF: return KviError_badFileDescriptor; break; + case WSAEINVAL: + case WSAEFAULT: + case EFAULT: return KviError_outOfAddressSpace; break; + case WSAECONNREFUSED: return KviError_connectionRefused; break; + case WSAENOTSOCK: return KviError_kernelNetworkingPanic; break; + case WSAETIMEDOUT: return KviError_connectionTimedOut; break; + case WSAENETUNREACH: return KviError_networkUnreachable; break; + case EPIPE: return KviError_brokenPipe; break; + case WSAENOTCONN: return KviError_socketNotConnected; break; + + case WSAEACCES: return KviError_accessDenied; break; + case WSAEADDRINUSE: return KviError_addressAlreadyInUse; break; + case WSAEADDRNOTAVAIL: return KviError_cantAssignRequestedAddress; break; + case WSAEAFNOSUPPORT: return KviError_unsupportedAddressFamily; break; + case WSAECONNRESET: return KviError_connectionResetByPeer; break; + case WSAEHOSTUNREACH: return KviError_hostUnreachable; break; + + //case ENOBUFS: return KviError_insufficientResources; break; + // Unhandled error...pass errno to the strerror function + default: return -iErrNo; break; + } +#else + switch(iErrNo) + { + case EBADF: return KviError_badFileDescriptor; break; + case EFAULT: return KviError_outOfAddressSpace; break; + case ECONNREFUSED: return KviError_connectionRefused; break; + case ENOTSOCK: return KviError_kernelNetworkingPanic; break; + case ETIMEDOUT: return KviError_connectionTimedOut; break; + case ENETUNREACH: return KviError_networkUnreachable; break; + case EPIPE: return KviError_brokenPipe; break; + case ENOTCONN: return KviError_socketNotConnected; break; + case ENOBUFS: return KviError_insufficientResources; break; + case EHOSTUNREACH: return KviError_hostUnreachable; break; + // Unhandled error...pass errno to the strerror function + default: return -iErrNo; break; + } +#endif + } +}; + diff --git a/src/kvilib/core/kvi_error.h b/src/kvilib/core/kvi_error.h new file mode 100644 index 00000000..7ab55e88 --- /dev/null +++ b/src/kvilib/core/kvi_error.h @@ -0,0 +1,188 @@ +#ifndef _KVI_ERROR_H_ +#define _KVI_ERROR_H_ +//============================================================================= +// +// File : kvi_error.h +// Creation date : Sun Jul 02 2000 18:35:56 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" + +#define KviError_success 0 +#define KviError_unknownError 1 +#define KviError_internalError 2 +#define KviError_unknownCommand 3 +#define KviError_missingClosingBrace 4 +#define KviError_unexpectedEndInString 5 +#define KviError_unexpectedEndInDictionaryKey 6 +#define KviError_switchDashWithoutSwitchLetter 7 +#define KviError_unknownFunction 8 +#define KviError_unexpectedEndInParenthesis 9 +#define KviError_unexpectedEndInFunctionParams 10 +#define KviError_missingVariableName 11 +#define KviError_variableOrIdentifierExpected 12 +#define KviError_leftOperandIsNotANumber 13 +#define KviError_multipleOpsNotSupportedForOperator 14 +#define KviError_divisionByZero 15 +#define KviError_moduloByZero 16 +#define KviError_rightOperandIsNotANumber 17 +#define KviError_unterminatedExpression 18 +#define KviError_unterminatedSubexpression 19 +#define KviError_unexpectedCharacter 20 +#define KviError_unknownOperator 21 + +#define KviError_noHostToResolve 22 +#define KviError_unsupportedAddressFamily 23 +#define KviError_validNameButNoIpAddress 24 +#define KviError_unrecoverableNameserverError 25 +#define KviError_dnsTemporaneousFault 26 +#define KviError_dnsInternalErrorBadFlags 27 +#define KviError_dnsInternalErrorOutOfMemory 28 +#define KviError_dnsInternalErrorServiceNotSupported 29 +#define KviError_dnsNoName 30 +#define KviError_dnsInternalErrorUnsupportedSocketType 31 +#define KviError_dnsQueryFailed 32 +#define KviError_noIpV6Support 33 +#define KviError_hostNotFound 34 +#define KviError_dnsInternalIPCFailure 35 + +#define KviError_anotherConnectionInProgress 36 +#define KviError_invalidIpAddress 37 +#define KviError_socketCreationFailed 38 +#define KviError_asyncSocketFailed 39 +#define KviError_badFileDescriptor 40 +#define KviError_outOfAddressSpace 41 +#define KviError_connectionRefused 42 +#define KviError_kernelNetworkingPanic 43 +#define KviError_connectionTimedOut 44 +#define KviError_networkUnreachable 45 +#define KviError_brokenPipe 46 +#define KviError_invalidProxyAddress 47 +#define KviError_remoteEndClosedConnection 48 + +#define KviError_invalidIrcContextId 49 +#define KviError_errorInLoadingModule 50 +#define KviError_noSuchModuleCommand 51 +#define KviError_noSuchModuleFunction 52 + +#define KviError_leftOperandIsNotADictionaryReference 53 +#define KviError_rightOperandIsNotADictionaryReference 54 + +#define KviError_missingObjectClassName 55 +#define KviError_noSuchObjectClass 56 +#define KviError_noSuchObject 57 +#define KviError_noSuchObjectFunction 58 + +#define KviError_invalidLeftOperand 59 + +#define KviError_notEnoughParameters 60 +#define KviError_integerParameterExpected 61 +#define KviError_invalidParameter 62 + +#define KviError_noSuchFile 63 + +#define KviError_openParenthesisExpected 64 +#define KviError_openBraceExpected 65 + +#define KviError_cantKillABuiltinClass 66 +#define KviError_socksV4LacksIpV6Support 67 +#define KviError_unrecognizedProxyReply 68 +#define KviError_proxyAuthFailed 69 +#define KviError_proxyNoAcceptableAuthMethod 70 + +#define KviError_proxyReply91RequestFailed 71 +#define KviError_proxyReply92IdentFailed 72 +#define KviError_proxyReply93IdentNotMatching 73 +#define KviError_proxyReply01GeneralSOCKSFailure 74 +#define KviError_proxyReply02ConnectionNotAllowed 75 +#define KviError_proxyReply03NetworkUnreachable 76 +#define KviError_proxyReply04HostUnreachable 77 +#define KviError_proxyReply05ConnectionRefused 78 +#define KviError_proxyReply06TTLExpired 79 +#define KviError_proxyReply07CommandNotSupported 80 +#define KviError_proxyReply08AddressTypeNotSupported 81 +#define KviError_proxyReply09InvalidAddress 82 + +#define KviError_invalidPortNumber 83 +#define KviError_socketNotConnected 84 +#define KviError_insufficientResources 85 +#define KviError_bindFailed 86 +#define KviError_cantResolveLocalhost 87 + +#define KviError_unsupportedImageFormat 88 + +#define KviError_cantOpenFileForAppending 89 +#define KviError_cantOpenFileForWriting 90 +#define KviError_fileIOError 91 +#define KviError_acknowledgeError 92 +#define KviError_cantOpenFileForReading 93 +#define KviError_cantSendAZeroSizeFile 94 + +#define KviError_missingPopupName 95 +#define KviError_itemPopupOrSeparatorExpected 96 +#define KviError_selfModificationNotAllowed 97 + +//#define KviError_recursionTooDeep 98 +#define KviError_featureNotAvailable 99 + +#define KviError_unexpectedCharactersInArrayIndex 100 +#define KviError_unexpectedEndInExpression 101 +#define KviError_unexpectedEndInArrayIndex 102 + +#define KviError_proxyHttpFailure 103 +#define KviError_caseMatchRegexpDefaultOrBreakExpected 104 + + +#define KviError_accessDenied 105 +#define KviError_addressAlreadyInUse 106 +#define KviError_cantAssignRequestedAddress 107 +#define KviError_connectionResetByPeer 108 +#define KviError_hostUnreachable 109 + +#define KviError_variableExpected 110 +#define KviError_invalidArrayIndex 111 + +#define KviError_listenFailed 112 + +#define KviError_noSSLSupport 113 +#define KviError_SSLError 114 + +#define KviError_slashCharacterExpected 115 +#define KviError_unknownStringManipulationOperator 116 + +#define KviError_operationAborted 117 + +#define KviError_unexpectedToken 118 + +#define KviError_scopeObjectAlreadyDefined 119 +#define KviError_noThisObject 120 + +#define KVI_NUM_ERRORS 121 + +namespace KviError +{ + KVILIB_API QString getDescription(int iErrorCode); + KVILIB_API const char * getUntranslatedDescription(int iErrorCode); + KVILIB_API int translateSystemError(int iErrNo); +}; + +#endif //_KVI_ERROR_H_ diff --git a/src/kvilib/core/kvi_heapobject.cpp b/src/kvilib/core/kvi_heapobject.cpp new file mode 100644 index 00000000..7568086d --- /dev/null +++ b/src/kvilib/core/kvi_heapobject.cpp @@ -0,0 +1,96 @@ +//============================================================================= +// +// File : kvi_heapobject.cpp +// Created on Wed 24 Mar 2004 04:45:17 by Szymon Stefanek +// +// This file is part of the KVIrc IRC client distribution +// Copyright (C) 2004-2006 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_heapobject.h" +#include "kvi_malloc.h" + +// On windows we need to override new and delete operators +// to ensure that always the right new/delete pair is called for an object instance +// This bug jumps out because windows uses a local heap for each +// executable module (exe or dll). +// (this is a well known bug described in Q122675 of MSDN) + +// on Linux it is not needed: there is a single global heap + + + +// 05.02.2005 : scalar/vector deleting destructors in modules +// +// There are also other issues involving the MSVC compiler. +// When the operator new is called on an object with a virtual +// destructor the compiler generates a helper function +// called "vector deleting destructor" that is used to both +// free the object's memory and call the object's destructor. +// (In fact there is also a "scalar deleting destructor" but +// MSVC seems to call the vector version also for scalar deletes ?!?) +// The problem arises when operator new is called in a module: +// the helper function gets stuffed in one of the module's sections +// and when the module is unloaded any attempt to delete +// the object will simply jump into no man's land. + +// An "unhandled exception" in a "call [%eax]" corresponding +// to a delete <pointer> may be a symptom of this problem. + +// I haven't been able to find a solution nicer than having +// a static allocation function in each class that can be +// created from inside a module and destroyed anywhere else +// and has a virtual destructor. + +#ifdef COMPILE_ON_WINDOWS + void * KviHeapObject::operator new(size_t uSize) + { + return kvi_malloc(uSize); + } + + void KviHeapObject::operator delete(void * pData) + { + kvi_free(pData); + } + + void * KviHeapObject::operator new[](size_t uSize) + { + return kvi_malloc(uSize); + } + + void KviHeapObject::operator delete[](void * pData) + { + kvi_free(pData); + } + + // these are the debug versions... + void * KviHeapObject::operator new(size_t uSize,const char *,int) + { + return kvi_malloc(uSize); + } + + void KviHeapObject::operator delete(void * pData,const char *,int) + { + kvi_free(pData); + } +#endif + + diff --git a/src/kvilib/core/kvi_heapobject.h b/src/kvilib/core/kvi_heapobject.h new file mode 100644 index 00000000..3d1638cf --- /dev/null +++ b/src/kvilib/core/kvi_heapobject.h @@ -0,0 +1,50 @@ +#ifndef _KVI_HEAPOBJECT_H_ +#define _KVI_HEAPOBJECT_H_ +//============================================================================= +// +// File : kvi_heapobject.h +// Created on Wed 24 Mar 2004 04:45:17 by Szymon Stefanek +// +// This file is part of the KVIrc IRC client distribution +// Copyright (C) 2004-2006 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +// See kvi_heapobject.cpp for comments on this class + +#ifdef COMPILE_ON_WINDOWS + + class KVILIB_API KviHeapObject + { + public: + void * operator new(size_t uSize); + void operator delete(void * pData); + void * operator new[](size_t uSize); + void operator delete[](void * pData); + void * operator new(size_t uSize,const char *,int); + void operator delete(void * pData,const char *,int); + }; +#else //!COMPILE_ON_WINDOWS + class KVILIB_API KviHeapObject + { + // on other platforms this crap is not necessary + }; +#endif //!COMPILE_ON_WINDOWS + +#endif //!_KVI_HEAPOBJECT_H_ diff --git a/src/kvilib/core/kvi_inttypes.h b/src/kvilib/core/kvi_inttypes.h new file mode 100644 index 00000000..6405ee79 --- /dev/null +++ b/src/kvilib/core/kvi_inttypes.h @@ -0,0 +1,95 @@ +#ifndef _KVI_INTTYPES_H_ +#define _KVI_INTTYPES_H_ +//============================================================================= +// +// File : kvi_inttypes.h +// Creation date : Wed Sep 4 22:28:00 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_ON_WINDOWS + // we don't have a configure script here + // so we can't check the size of types + // We rely on the ms specific definitions then + typedef __int64 kvi_i64_t; + typedef unsigned __int64 kvi_u64_t; + typedef int kvi_i32_t; + typedef unsigned int kvi_u32_t; + typedef short int kvi_i16_t; + typedef short unsigned int kvi_u16_t; + typedef char kvi_i8_t; + typedef unsigned char kvi_u8_t; +#else + #if SIZEOF_LONG_INT == 8 + // the most common case on 64 bit machines + typedef long int kvi_i64_t; + typedef unsigned long int kvi_u64_t; + #elif SIZEOF_INT == 8 + // 64 bit ints ?.. a Cray ? :D + typedef int kvi_i64_t; + typedef unsigned int kvi_u64_t; + #elif SIZEOF_LONG_LONG_INT == 8 + // the most common case on 32 bit machines + typedef long long int kvi_i64_t; + typedef unsigned long long int kvi_u64_t; + #else + // attempt to live without a 64bit integer type anyway... + // dunno if it will work tough... + typedef long long int kvi_i64_t; + typedef unsigned long long int kvi_u64_t; + #endif + + #if SIZEOF_INT == 4 + // the most common case + typedef int kvi_i32_t; + typedef unsigned int kvi_u32_t; + #elif SIZEOF_SHORT_INT == 4 + // 32 bit shorts ?.. a Cray ? :D + typedef short int kvi_i32_t; + typedef short unsigned int kvi_u32_t; + #elif SIZEOF_LONG_INT == 4 + typedef long int kvi_i32_t; + typedef unsigned long int kvi_u32_t; + #else + #error "Can't find a 32 bit integral type on this system" + #error "Please report to pragma at kvirc dot net" + #endif + + #if SIZEOF_SHORT_INT == 2 + // the most common case + typedef short int kvi_i16_t; + typedef short unsigned int kvi_u16_t; + #elif SIZEOF_INT == 2 + // this isn't going to work anyway, I think.. + typedef int kvi_i16_t; + typedef long int kvi_u16_t; + #else + #error "Can't find a 16 bit integral type on this system" + #error "Please report to pragma at kvirc dot net" + #endif + + // assume that char is always 8 bit + typedef char kvi_i8_t; + typedef unsigned char kvi_u8_t; +#endif + +#endif //_KVI_INTTYPES_H_ diff --git a/src/kvilib/core/kvi_malloc.cpp b/src/kvilib/core/kvi_malloc.cpp new file mode 100644 index 00000000..9c418ec5 --- /dev/null +++ b/src/kvilib/core/kvi_malloc.cpp @@ -0,0 +1,198 @@ +//============================================================================= +// +// File : kvi_malloc.cpp +// Creation date : Sun Jun 18 2000 18:26:27 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// C memory allocation routines +// This stuff is rather unused, because in normal compilations +// kvi_malloc , kvi_free and kvi_realloc are macros (see kvi_malloc.h) +//============================================================================= + +#define __KVILIB__ + +#define _KVI_MALLOC_CPP_ +#include "kvi_malloc.h" + +#include <stdio.h> + + + +#ifdef COMPILE_MEMORY_PROFILE + + // + // Memory profile stuff + // Used to find memory leaks etc... + // + + #include "kvi_pointerlist.h" + + typedef struct _KviMallocEntry { + struct _KviMallocEntry * prev; + void * pointer; + int size; + void * return_addr1; + void * return_addr2; + struct _KviMallocEntry * next; + } KviMallocEntry; + + int g_iMaxRequestSize = 0; + void * g_pMaxRequestReturnAddress1 = 0; + void * g_pMaxRequestReturnAddress2 = 0; + unsigned int g_iMallocCalls = 0; + unsigned int g_iReallocCalls = 0; + unsigned int g_iFreeCalls = 0; + unsigned int g_iTotalMemAllocated = 0; + unsigned int g_uAllocationPeak = 0; + KviMallocEntry * g_pEntries = 0; + + void * kvi_malloc(int size) + { + g_iMallocCalls ++; + g_iTotalMemAllocated += size; + if(g_iTotalMemAllocated > g_uAllocationPeak)g_uAllocationPeak = g_iTotalMemAllocated; + if(g_iMaxRequestSize < size){ + g_iMaxRequestSize = size; + g_pMaxRequestReturnAddress1 = __builtin_return_address(1); + g_pMaxRequestReturnAddress2 = __builtin_return_address(2); + } + KviMallocEntry * e = (KviMallocEntry *)malloc(sizeof(KviMallocEntry)); + e->pointer = malloc(size); + e->size = size; + e->return_addr1 = __builtin_return_address(1); + e->return_addr2 = __builtin_return_address(2); + e->next = g_pEntries; + e->prev = 0; + if(g_pEntries)g_pEntries->prev = e; + g_pEntries = e; + return e->pointer; + } + + void * kvi_realloc(void * ptr,int size) + { + g_iReallocCalls ++; + if(ptr == 0)return kvi_malloc(size); + if(g_iMaxRequestSize < size){ + g_iMaxRequestSize = size; + g_pMaxRequestReturnAddress1 = __builtin_return_address(1); + g_pMaxRequestReturnAddress2 = __builtin_return_address(2); + } + KviMallocEntry *e = g_pEntries; + while(e){ + if(e->pointer == ptr){ + g_iTotalMemAllocated -= e->size; + g_iTotalMemAllocated += size; + if(g_iTotalMemAllocated > g_uAllocationPeak)g_uAllocationPeak = g_iTotalMemAllocated; + e->pointer = realloc(ptr,size); + e->size = size; + e->return_addr1 = __builtin_return_address(1); + e->return_addr2 = __builtin_return_address(2); + return e->pointer; + } + e = e->next; + } + fprintf(stderr,"Attempt to realloc an inexisting pointer (%p) (called from %p (%p))\n",ptr,__builtin_return_address(1),__builtin_return_address(2)); + return realloc(ptr,size); + } + + void kvi_free(void * ptr) + { + g_iFreeCalls++; + if(ptr == 0){ + fprintf(stderr,"Attempt to free a null pointer (called from %p (%p))\n",__builtin_return_address(1),__builtin_return_address(2)); + exit(-1); + } + KviMallocEntry * e= g_pEntries; + while(e){ + if(e->pointer == ptr){ + g_iTotalMemAllocated -= e->size; + if(e->prev){ + if(e == g_pEntries)fprintf(stderr,"Mem profiling internal error!\n"); + e->prev->next = e->next; + if(e->next)e->next->prev = e->prev; + } else { + if(e != g_pEntries)fprintf(stderr,"Mem profiling internal error!\n"); + if(e->next)e->next->prev = 0; + g_pEntries = e->next; + } + free(e); + return; + } + e = e->next; + } + fprintf(stderr,"Attempt to free an inexisting pointer (%p) (called from %p (%p))\n",ptr,__builtin_return_address(1),__builtin_return_address(2)); + } + + void kvi_memory_profile() __attribute__((destructor)); + void kvi_memory_profile() + { + unsigned int countUnfreed = 0; + KviMallocEntry * e = g_pEntries; + while(e){ + countUnfreed++; + e = e->next; + } + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Memory profile for KVIrc\n"); + fprintf(stderr,"| Unfreed chunks : %d\n",countUnfreed); + fprintf(stderr,"| Total unfreed memory : %u bytes\n",g_iTotalMemAllocated); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Possible unfreed chunks dump:\n"); + e = g_pEntries; + while(e){ + fprintf(stderr,"|====|====|\n"); + fprintf(stderr,"| Currently unfreed chunk: %p\n",e->pointer); + fprintf(stderr,"| Size: %d\n",e->size); + fprintf(stderr,"| Caller address 1: %p\n",e->return_addr1); + fprintf(stderr,"| Caller address 2: %p\n",e->return_addr2); + if(e->size > 10)fprintf(stderr,"| Data: %.10s\n",e->pointer); + else if(e->size > 5)fprintf(stderr,"| Data: %.5s\n",e->pointer); + KviMallocEntry *toFree = e; + e = e->next; + free(toFree); + } + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Allocation peak : %u bytes\n",g_uAllocationPeak); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Max request size : %d bytes\n",g_iMaxRequestSize); + fprintf(stderr,"| Called from %p (%p)\n",g_pMaxRequestReturnAddress1,g_pMaxRequestReturnAddress2); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Malloc calls: %u\n",g_iMallocCalls); + fprintf(stderr,"| Realloc calls: %u\n",g_iReallocCalls); + fprintf(stderr,"| Free calls: %u\n",g_iFreeCalls); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + } + +#else + + #ifdef COMPILE_MEMORY_CHECKS + + void outOfMemory() + { + //What a cool message :) + fprintf(stderr,"Virtual memory exhausted in malloc call....bye!\n"); + exit(-1); + } + + #endif + +#endif diff --git a/src/kvilib/core/kvi_malloc.h b/src/kvilib/core/kvi_malloc.h new file mode 100644 index 00000000..8a7204a5 --- /dev/null +++ b/src/kvilib/core/kvi_malloc.h @@ -0,0 +1,88 @@ +#ifndef _KVI_MALLOC_H_ +#define _KVI_MALLOC_H_ + +//============================================================================= +// +// File : kvi_malloc.h +// Creation date : Sun Jun 18 2000 18:18:36 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// C memory allocation routines: macros in common compilations +//============================================================================= + +#include "kvi_settings.h" + +#include <stdlib.h> + +#ifdef COMPILE_MEMORY_PROFILE + + #ifdef COMPILE_ON_WINDOWS + #error "This stuff should be never compiled on Windows" + #endif + + extern void * kvi_malloc(int size); + extern void * kvi_realloc(void * ptr,int size); + extern void kvi_free(void * ptr); + +#else + + #ifndef COMPILE_MEMORY_CHECKS + + // These two are the "common" ones + #define kvi_malloc(__size_) malloc(__size_) + #define kvi_realloc(__ptr_,__size_) realloc((void *)__ptr_,__size_) + + #else + + #ifdef COMPILE_ON_WINDOWS + #error "This stuff should be never compiled on Windows" + #endif + + // Want to check all the pointers + #define kvi_malloc(__size_) kvi_safe_malloc(__size_) + #define kvi_realloc(__ptr_,__size_) kvi_safe_realloc((void *)__ptr_,__size_) + + #ifndef _KVI_MALLOC_CPP_ + extern void outOfMemory(); + #endif + + inline void * kvi_safe_malloc(int size) + { + void * ptr = malloc(size); + if(!ptr)outOfMemory(); + return ptr; + } + + inline void * kvi_safe_realloc(void * ptr,int size) + { + ptr = realloc(ptr,size); + if(!ptr)outOfMemory(); + return ptr; + } + + #endif //COMPILE_MEMORY_CHECKS + + #define kvi_free(__ptr_) free((void *)__ptr_) + +#endif + +#endif //_KVI_MALLOC_H_ diff --git a/src/kvilib/core/kvi_memmove.cpp b/src/kvilib/core/kvi_memmove.cpp new file mode 100644 index 00000000..1beb920a --- /dev/null +++ b/src/kvilib/core/kvi_memmove.cpp @@ -0,0 +1,253 @@ +//============================================================================= +// +// File : kvi_memmove.cpp +// Creation date : Sun Jun 18 2000 18:27:50 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#define _KVI_DEBUG_CHECK_RANGE_ +#include "kvi_debug.h" + +#define _KVI_MEMMOVE_CPP_ +#include "kvi_memmove.h" + +// FIXME: #warning "With system memmove could be guessed by configure" + +#ifndef COMPILE_WITH_SYSTEM_MEMMOVE + + #ifdef COMPILE_ix86_ASM + + + void *kvi_memmove(void * dst_ptr,const void *src_ptr,int len) + { + __range_valid(dst_ptr); + __range_valid(src_ptr); + __range_valid(len >= 0); + // Save pointer registers + asm(" pushl %esi"); // save %esi + asm(" pushl %edi"); // save %edi + // Load arguments + asm(" movl 16(%ebp),%ecx"); // %ecx = len + asm(" movl 12(%ebp),%esi"); // %esi = src + asm(" movl 8(%ebp),%edi"); // %edi = dst + // Compare src and dest + asm(" cmpl %esi,%edi"); // %edi - %esi + asm(" jbe move_from_bottom_to_top"); // if(%edi < %esi) jump to move_from_bottom_to_top + // dst_ptr > src_ptr + asm(" addl %ecx,%esi"); // %esi += %ecx (src_ptr += len); + asm(" addl %ecx,%edi"); // %edi += %ecx (dst_ptr += len); + asm(" decl %esi"); // %esi--; (src_ptr--); + asm(" decl %edi"); // %edi--; (dst_ptr--); + asm(" std"); // set direction flag (decrement esi and edi in movsb) + // Optimization : check for non-odd len (1,3,5,7...) + asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF + asm(" jnc move_two_bytes_top_to_bottom_directly"); // if !carry (CF == 0) skip this move + // Move the first byte (non-odd) + asm(" movsb %ds:(%esi),%es:(%edi)"); // *dst-- = *src-- if DF else *dst++ = *src++ + asm("move_two_bytes_top_to_bottom_directly:"); + asm(" decl %esi"); // %esi--; (src_ptr--); + asm(" decl %edi"); // %edi--; (dst_ptr--); + asm("move_two_bytes_top_to_bottom:"); + asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF + asm(" jnc move_the_rest_top_to_bottom_directly"); // if !carry (CF == 0) skip this move + // Move the next two bytes + asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++ + asm("move_the_rest_top_to_bottom_directly:"); + asm(" subl $2,%esi"); // %esi-=2; (src-=2); + asm(" subl $2,%edi"); // %edi-=2; (dst-=2); + asm(" jmp move_the_rest"); // call last repnz movsl + // dst_ptr <= src_ptr + asm("move_from_bottom_to_top:"); + asm(" cld"); // clear direction flag (increment esi and edi in movsb) + // Optimization : check for non-odd len (1,3,5,7...) + asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF + asm(" jnc move_two_bytes"); // if !carry (CF == 0) skip this move + // Move the first byte (non-odd) + asm(" movsb %ds:(%esi),%es:(%edi)"); // *dst-- = *src-- if DF else *dst++ = *src++ + // Optimization : pass 2 , check for %2 and %3 + asm("move_two_bytes:"); + asm(" shr $1,%ecx"); // %ecx >> 1 , shifted bit -> CF + asm(" jnc move_the_rest"); // if !carry (CF == 0) skip this move + // Move the next two bytes + asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++ + // Main move remaining part + asm("move_the_rest:"); + asm(" repnz; movsl %ds:(%esi),%es:(%edi)"); // loop moving 4 bytes at once (increment or decrement as above) + // Restore pointer registers + asm(" popl %edi"); // restore %edi + asm(" popl %esi"); // restore %esi + return dst_ptr; //asm(" movl 8(%ebp),%eax"); <-- gcc will put that (AFTER THE OPTIMISATION PASS!) + } + + void *kvi_memmoveodd(void * dst_ptr,const void *src_ptr,int len) + { + __range_valid(dst_ptr); + __range_valid(src_ptr); + __range_valid(len >= 0); + // Save pointer registers + asm(" pushl %esi"); // save %esi + asm(" pushl %edi"); // save %edi + // Load arguments + asm(" movl 16(%ebp),%ecx"); // %ecx = len + asm(" movl 12(%ebp),%esi"); // %esi = src + asm(" movl 8(%ebp),%edi"); // %edi = dst + // Compare src and dest + asm(" cmpl %esi,%edi"); // %edi - %esi + asm(" jbe xmove_from_bottom_to_top"); // if(%edi < %esi) jump to move_from_bottom_to_top + // dst_ptr > src_ptr + asm(" addl %ecx,%esi"); // %esi += %ecx (src_ptr += len); + asm(" addl %ecx,%edi"); // %edi += %ecx (dst_ptr += len); + asm(" std"); // set direction flag (decrement esi and edi in movsb) + // start moving + asm(" shr $2,%ecx"); // %ecx >> 2 , last shifted bit -> CF + asm(" jnc xmove_the_rest_top_to_bottom_directly"); // if !carry (CF == 0) skip this move + // Move the next two bytes + asm(" subl $2,%esi"); // %esi-=2; (src_ptr-=2); + asm(" subl $2,%edi"); // %edi-=2; (dst_ptr-=2); + asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++ + asm(" subl $2,%esi"); // %esi-=2; (src_ptr-=2); + asm(" subl $2,%edi"); // %edi-=2; (dst_ptr-=2); + asm(" jmp xmove_the_rest"); + asm("xmove_the_rest_top_to_bottom_directly:"); + asm(" subl $4,%esi"); // %esi-=4; (src-=4); + asm(" subl $4,%edi"); // %edi-=4; (dst-=4); + asm(" jmp xmove_the_rest"); // call last repnz movsl + // dst_ptr <= src_ptr + asm("xmove_from_bottom_to_top:"); + asm(" cld"); // clear direction flag (increment esi and edi in movsb) + // move it + asm(" shr $2,%ecx"); // %ecx >> 2 , last shifted bit -> CF + asm(" jnc xmove_the_rest"); // if !carry (CF == 0) skip this move + // Move the next two bytes + asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++ + // Main move remaining part + asm("xmove_the_rest:"); + asm(" repnz; movsl %ds:(%esi),%es:(%edi)"); // loop moving 4 bytes at once (increment or decrement as above) + // Restore pointer registers + asm(" popl %edi"); // restore %edi + asm(" popl %esi"); // restore %esi + return dst_ptr; //asm(" movl 8(%ebp),%eax"); <-- gcc will put that (AFTER THE OPTIMISATION PASS!) + } + + #else // ndef COMPILE_ix86_ASM + + + + // The next 4 functions could be optimized with the & and shift technique + // used in the assembly implementations but the compilers usually + // will not translate the carry bit trick producing code + // that works slower on short block of memory (really near the average case) + + // The trick would be: + // + // if(len & 1) // the length is even + // *dst-- = *src--; // move one byte + // len >> 1; // drop the last bit (thus divide by 2) + // if(len & 1) // the length is still even + // *((short *)dst)-- = *((short *)src)--; // move two bytes + // len >> 1; // again drop the last bit (thus divide by 2) + // while(len--)*((int *)dst)-- = *((int *)src)--; // move four bytes at a time + // + // + + void *kvi_memmove(void *dst_ptr,const void *src_ptr,int len) + { + __range_valid(dst_ptr); + __range_valid(src_ptr); + __range_valid(len >= 0); + register char *dst; + register const char *src; + if(dst_ptr > src_ptr){ + dst = (char *)dst_ptr + len - 1; + src = (const char *)src_ptr + len - 1; + while(len--)*dst-- = *src--; + } else { //it is valid even if dst_ptr == src_ptr + dst = (char *)dst_ptr; + src = (const char *)src_ptr; + while(len--)*dst++ = *src++; + } + return dst_ptr; + } + + void *kvi_memmoveodd(void *dst_ptr,const void *src_ptr,int len) + { + __range_valid(dst_ptr); + __range_valid(src_ptr); + __range_valid(len >= 0); + __range_valid((len & 1) == 0); + register short *dst; + register const short *src; + if(dst_ptr > src_ptr){ + dst = (short *) (((char *)dst_ptr) + len - 2); + src = (const short *) (((const char *)src_ptr) + len - 2); + while(len > 0) + { + *dst-- = *src--; + len -= 2; + } + } else { //it is valid even if dst_ptr == src_ptr + dst = (short *)dst_ptr; + src = (const short *)src_ptr; + while(len > 0) + { + *dst++ = *src++; + len -= 2; + } + } + return dst_ptr; + } + + void kvi_fastmove(void *dst_ptr,const void *src_ptr,int len) + { + __range_valid(dst_ptr); + __range_valid(src_ptr); + __range_valid(len >= 0); + register const char *src = (const char *)src_ptr; + register char *dst = (char *)dst_ptr; + while(len--)*dst++ = *src++; + } + + void kvi_fastmoveodd(void *dst_ptr,const void *src_ptr,int len) + { + __range_valid(dst_ptr); + __range_valid(src_ptr); + __range_valid(len >= 0); + __range_valid((len & 1) == 0); + register const short *src = (const short *)src_ptr; + register short *dst = (short *)dst_ptr; + while(len > 0){ + *dst++ = *src++; + len -= 2; + } + } + + #endif // !COMPILE_ix86_ASM + + void kvi_memset(void *dst_ptr,char c,int len) + { + __range_valid(dst_ptr); + __range_valid(len >= 0); + register char *dst = (char *)dst_ptr; + while(len--)*dst++ = c; + } + +#endif // !COMPILE_WITH_SYSTEM_MEMMOVE diff --git a/src/kvilib/core/kvi_memmove.h b/src/kvilib/core/kvi_memmove.h new file mode 100644 index 00000000..d1319a41 --- /dev/null +++ b/src/kvilib/core/kvi_memmove.h @@ -0,0 +1,105 @@ +#ifndef _KVI_MEMMOVE_H_ +#define _KVI_MEMMOVE_H_ + +//============================================================================= +// +// File : kvi_memmove.h +// Creation date : Fri Mar 19 1999 03:15:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include "kvi_settings.h" + +//#undef COMPILE_WITH_SYSTEM_MEMMOVE +//#define COMPILE_MMX_ASM + +#ifndef _KVI_MEMMOVE_CPP_ + + #ifdef COMPILE_WITH_SYSTEM_MEMMOVE + + #include <string.h> + + #define kvi_memmove memmove + #define kvi_memmoveodd memmove + #define kvi_memset memset + #define kvi_fastmove memcpy + #define kvi_fastmoveodd memcpy + + #else + + #ifdef COMPILE_ON_WINDOWS + #error "This stuff should be never compiled on Windows" + #endif + + extern void *kvi_memmove(void *dst_ptr,const void *src_ptr,int len); + extern void *kvi_memmoveodd(void *dst_ptr,const void *src_ptr,int len); + extern void *kvi_memset(void *dst_ptr,char c,int len); + // In fastmove the src and dst may not overlap + + #ifdef COMPILE_ix86_ASM + + // WE WANT repnz; movsq\n"!!! + + inline void kvi_fastmove(void * dst_ptr,const void *src_ptr,int len) + { + __asm__ __volatile__( + " cld\n" + " shr $1,%0\n" + " jnc 1f\n" + " movsb\n" + "1:\n" + " shr $1,%0\n" + " jnc 2f\n" + " movsw\n" + "2:\n" + " repnz; movsl\n" + : "=c" (len), "=&S" (src_ptr), "=&D" (dst_ptr) + : "0" (len), "1" (src_ptr), "2" (dst_ptr) + ); + } + + inline void kvi_fastmoveodd(void * dst_ptr,const void *src_ptr,int len) + { + __asm__ __volatile__( + " cld\n" + " shr $2,%0\n" + " jnc 1f\n" + " movsw\n" + "1:\n" + " repnz; movsl\n" + : "=c" (len), "=&S" (src_ptr), "=&D" (dst_ptr) + : "0" (len), "1" (src_ptr), "2" (dst_ptr) + ); + } + + #else // ! COMPILE_ix86_ASM + + extern void kvi_fastmove(void *dst_ptr,const void *src_ptr,int len); + extern void kvi_fastmoveodd(void *dst_ptr,const void *src_ptr,int len); + + #endif // !COMPILE_ix86_ASM + + #endif // COMPILE_WITH_SYSTEM_MEMMOVE + +#endif // _KVI_MEMMOVE_CPP_ + +#endif // !_KVI_MEMMOVE_H_ diff --git a/src/kvilib/core/kvi_pointerhashtable.h b/src/kvilib/core/kvi_pointerhashtable.h new file mode 100644 index 00000000..9066c091 --- /dev/null +++ b/src/kvilib/core/kvi_pointerhashtable.h @@ -0,0 +1,999 @@ +#ifndef _KVI_POINTERHASHTABLE_H_ +#define _KVI_POINTERHASHTABLE_H_ +//================================================================================================= +// +// File : kvi_pointerhashtable.h +// Creation date : Sat Jan 12 2008 04:53 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2008 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//================================================================================================= + +#include "kvi_settings.h" +#include "kvi_pointerlist.h" +#include "kvi_string.h" +#include "kvi_qstring.h" +#include "kvi_malloc.h" +#include "kvi_memmove.h" + +#include <ctype.h> + +/// +/// Hash functions for various data types +/// + +inline unsigned int kvi_hash_hash(const char * szKey,bool bCaseSensitive) +{ + unsigned int uResult = 0; + if(bCaseSensitive) + { + while(*szKey) + { + uResult += (unsigned char)(*(szKey)); + szKey++; + } + } else { + while(*szKey) + { + uResult += (unsigned char)tolower(*(szKey)); + szKey++; + } + } + return uResult; +} + +inline bool kvi_hash_key_equal(const char * szKey1,const char * szKey2,bool bCaseSensitive) +{ + if(bCaseSensitive) + { + while(*szKey1 && *szKey2) + { + if(*szKey1 != *szKey2) + return false; + szKey1++; + szKey2++; + } + } else { + while(*szKey1 && *szKey2) + { + if(tolower(*szKey1) != tolower(*szKey2)) + return false; + szKey1++; + szKey2++; + } + } + return true; +} + +inline void kvi_hash_key_copy(const char * const &szFrom,const char * &szTo,bool bDeepCopy) +{ + if(bDeepCopy) + { + int len = kvi_strLen(szFrom); + char * dst = (char *)kvi_malloc(len+1); + kvi_fastmove(dst,szFrom,len+1); + szTo = dst; + } else { + szTo = szFrom; // we never modify it anyway + } +} + +inline void kvi_hash_key_destroy(const char * &szKey,bool bDeepCopy) +{ + if(bDeepCopy) + kvi_free(szKey); +} + +inline const char * & kvi_hash_key_default(const char **) +{ + static const char * static_null = NULL; + return static_null; +} + +inline unsigned int kvi_hash_hash(const KviStr &szKey,bool bCaseSensitive) +{ + unsigned int uResult = 0; + const char * p = szKey.ptr(); + if(bCaseSensitive) + { + while(*p) + { + uResult += *((const unsigned char *)p); + p++; + } + } else { + while(*p) + { + uResult += tolower(*((const unsigned char *)p)); + p++; + } + } + return uResult; +} + +inline bool kvi_hash_key_equal(const KviStr &szKey1,const KviStr &szKey2) +{ + return kvi_hash_key_equal(szKey1.ptr(),szKey2.ptr()); +} + +inline void kvi_hash_key_copy(const KviStr &szFrom,KviStr &szTo,bool) +{ + szTo = szFrom; +} + +inline void kvi_hash_key_destroy(KviStr &szKey,bool) +{ +} + +inline const KviStr & kvi_hash_key_default(KviStr *) +{ + return KviStr::emptyString(); +} + +inline unsigned int kvi_hash_hash(const int &iKey,bool) +{ + return (unsigned int)iKey; +} + +inline bool kvi_hash_key_equal(const int &iKey1,const int &iKey2,bool) +{ + return iKey1 == iKey2; +} + +inline void kvi_hash_key_copy(const int &iKeyFrom,int &iKeyTo,bool) +{ + iKeyTo = iKeyFrom; +} + +inline void kvi_hash_key_destroy(int &iKey,bool) +{ +} + +inline const int & kvi_hash_key_default(int *) +{ + static int static_default = 0; + return static_default; +} + +inline unsigned int kvi_hash_hash(const unsigned short &iKey,bool) +{ + return (unsigned int)iKey; +} + +inline bool kvi_hash_key_equal(const unsigned short &iKey1,const unsigned short &iKey2,bool) +{ + return iKey1 == iKey2; +} + +inline void kvi_hash_key_copy(const unsigned short &iKeyFrom,unsigned short &iKeyTo,bool) +{ + iKeyTo = iKeyFrom; +} + +inline void kvi_hash_key_destroy(unsigned short &iKey,bool) +{ +} + +inline const unsigned short & kvi_hash_key_default(unsigned short *) +{ + static unsigned short static_default = 0; + return static_default; +} + + +inline unsigned int kvi_hash_hash(void * pKey,bool) +{ + unsigned char * pBytes = (unsigned char *)&(pKey); + unsigned char * pEnd = pBytes + sizeof(void *); + unsigned int uSum = 0; + while(pBytes < pEnd) + { + uSum += *pBytes; + pBytes++; + } + return uSum; +} + +inline bool kvi_hash_key_equal(void *pKey1,void *pKey2,bool) +{ + return pKey1 == pKey2; +} + +inline void kvi_hash_key_copy(void * const &pKeyFrom,void *&pKeyTo,bool) +{ + pKeyTo = pKeyFrom; +} + +inline void kvi_hash_key_destroy(void *iKey,bool) +{ +} + +inline void * & kvi_hash_key_default(void *) +{ + static void * static_default = NULL; + return static_default; +} + +inline unsigned int kvi_hash_hash(const QString &szKey,bool bCaseSensitive) +{ + unsigned int uResult = 0; + const QChar * p = KviQString::nullTerminatedArray(szKey); + if(!p)return 0; + if(bCaseSensitive) + { + while(p->unicode()) + { + uResult += p->unicode(); + p++; + } + } else { + while(p->unicode()) + { +#ifdef COMPILE_USE_QT4 + uResult += p->toLower().unicode(); +#else + uResult += p->lower().unicode(); +#endif + p++; + } + } + return uResult; +} + +inline bool kvi_hash_key_equal(const QString &szKey1,const QString &szKey2,bool bCaseSensitive) +{ + if(bCaseSensitive) + return KviQString::equalCS(szKey1,szKey2); + return KviQString::equalCI(szKey1,szKey2); +} + +inline void kvi_hash_key_copy(const QString &szFrom,QString &szTo,bool) +{ + szTo = szFrom; +} + +inline void kvi_hash_key_destroy(QString &szKey,bool) +{ +} + +inline const QString & kvi_hash_key_default(QString *) +{ + return KviQString::empty; +} + +template<typename Key,typename T> class KviPointerHashTable; +template<typename Key,typename T> class KviPointerHashTableIterator; + +template<typename Key,typename T> class KviPointerHashTableEntry +{ + friend class KviPointerHashTable<Key,T>; +protected: + T * pData; + Key hKey; +public: + Key & key(){ return hKey; }; + T * data(){ return pData; }; +}; + +/// +/// +/// \class KviPointerHashTable +/// \brief A fast pointer hash table implementation +/// +/// A very cool, very fast hash table implementation :P +/// +/// To use this hash table you need to provide implementations +/// for the following functions: +/// +/// \verbatim +/// +/// unsigned int kvi_hash_hash(const Key &hKey,bool bCaseSensitive); +/// bool kvi_hash_key_equal(const Key &hKey1,const Key &hKey2,bool bCaseSensitive); +/// void kvi_hash_key_copy(const Key &hKeyFrom,Key &hKeyTo,bool bDeepCopy); +/// void kvi_hash_key_destroy(Key &hKey,bool bIsDeepCopy); +/// const Key & kvi_hash_key_default(Key *); +/// +/// \endverbatim +/// +/// Implementations for the most likey Key data types are provided below. +/// KviPointerHashTable will automagically work with const char *,QString,KviStr +/// and integer types as keys. +/// +/// For string Key types, the hash table may or may not be case sensitive. +/// For other Key types the case sensitive flag has no meaning and will +/// (hopefully) be optimized out by the compiler. +/// +/// For pointer based keys the hash table may or may not mantain deep copies +/// of Key data. For example, with char * keys, if deep copying is enabled +/// then a private copy of the string data will be mantained. With deep +/// copying disabled only char * pointers will be kept. For types +/// that do not have meaning of deep copy the deep copying code will +/// (hopefully) be optimized out by the compiler. +/// +/// The hashtable mantains an array of KviPointerList based buckets. +/// The number of buckets may be specified by the application user +/// and does NOT need to be a prime number. Yet better to have it a power +/// of two so the memory allocation routines will feel better and are +/// less likely to waste space. +/// +template<class Key,class T> class KviPointerHashTable +{ + friend class KviPointerHashTableIterator<Key,T>; +protected: + KviPointerList<KviPointerHashTableEntry<Key,T> > ** m_pDataArray; + bool m_bAutoDelete; + unsigned int m_uSize; + unsigned int m_uCount; + bool m_bCaseSensitive; + bool m_bDeepCopyKeys; + unsigned int m_uIteratorIdx; +public: + /// + /// Returns the item associated to the key hKey + /// or NULL if no such item exists in the hash table. + /// Places the hash table iterator at the position + /// of the item found. + /// + T * find(const Key & hKey) + { + m_uIteratorIdx = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize; + if(!m_pDataArray[m_uIteratorIdx])return 0; + for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();e;e = m_pDataArray[m_uIteratorIdx]->next()) + { + if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive))return (T *)e->pData; + } + return 0; + } + + /// + /// Returns the item associated to the key hKey + /// or NULL if no such item exists in the hash table. + /// Places the hash table iterator at the position + /// of the item found. This is an alias to find(). + /// + T * operator[](const Key & hKey) + { + return find(hKey); + } + + /// + /// Returns the number of items in this hash table + /// + unsigned int count() const + { + return m_uCount; + } + + /// + /// Returns true if the hash table is empty + /// + bool isEmpty() const + { + return m_uCount == 0; + } + + /// + /// Inserts the item pData at the position specified by the key hKey. + /// Replaces any previous item with the same key + /// The replaced item is deleted if autodelete is enabled. + /// The hash table iterator is placed at the newly inserted item. + /// + void insert(const Key & hKey,T * pData) + { + if(!pData)return; + unsigned int uEntry = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize; + if(!m_pDataArray[uEntry])m_pDataArray[uEntry] = new KviPointerList<KviPointerHashTableEntry<Key,T> >(true); + for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[uEntry]->first();e;e = m_pDataArray[uEntry]->next()) + { + if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive)) + { + if(!m_bCaseSensitive) + { + // must change the key too + kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys); + kvi_hash_key_copy(hKey,e->hKey,m_bDeepCopyKeys); + } + if(m_bAutoDelete)delete e->pData; + e->pData = pData; + return; + } + } + KviPointerHashTableEntry<Key,T> * n = new KviPointerHashTableEntry<Key,T>; + kvi_hash_key_copy(hKey,n->hKey,m_bDeepCopyKeys); + n->pData = pData; + m_pDataArray[uEntry]->append(n); + m_uCount++; + } + + /// + /// Inserts the item pData at the position specified by the key hKey. + /// Replaces any previous item with the same key + /// The replaced item is deleted if autodelete is enabled. + /// The hash table iterator is placed at the newly inserted item. + /// This is just an alias to insert() with a different name. + /// + void replace(const Key & hKey,T * pData) + { + insert(hKey,pData); + } + + /// + /// Removes the item pointer associated to the key hKey, if such an item + /// exists in the hash table. The item is deleted if autodeletion + /// is enabled. Returns true if the item was found and removed and false if it wasn't found. + /// Invalidates the hash table iterator. + /// + bool remove(const Key & hKey) + { + unsigned int uEntry = kvi_hash_hash(hKey,m_bCaseSensitive) % m_uSize; + if(!m_pDataArray[uEntry])return false; + for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[uEntry]->first();e;e = m_pDataArray[uEntry]->next()) + { + if(kvi_hash_key_equal(e->hKey,hKey,m_bCaseSensitive)) + { + kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys); + if(m_bAutoDelete)delete ((T *)(e->pData)); + m_pDataArray[uEntry]->removeRef(e); + if(m_pDataArray[uEntry]->isEmpty()) + { + delete m_pDataArray[uEntry]; + m_pDataArray[uEntry] = 0; + } + m_uCount--; + return true; + } + } + return false; + } + + /// + /// Removes the first occurence of the item pointer pRef. The item is deleted if autodeletion + /// is enabled. Returns true if the pointer was found and false otherwise + /// Invalidates the hash table iterator. + /// + bool removeRef(const T * pRef) + { + for(unsigned int i=0;i<m_uSize;i++) + { + if(m_pDataArray[i]) + { + for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[i]->first();e;e = m_pDataArray[i]->next()) + { + if(e->pData == pRef) + { + kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys); + if(m_bAutoDelete)delete ((T *)(e->pData)); + m_pDataArray[i]->removeRef(e); + if(m_pDataArray[i]->isEmpty()) + { + delete m_pDataArray[i]; + m_pDataArray[i] = 0; + } + m_uCount--; + return true; + } + } + } + } + return false; + } + + /// + /// Removes all the items from the hash table. + /// The items are deleted if autodeletion is enabled. + /// Invalidates the hash table iterator. + /// + void clear() + { + for(unsigned int i=0;i<m_uSize;i++) + { + if(m_pDataArray[i]) + { + for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[i]->first();e;e = m_pDataArray[i]->next()) + { + kvi_hash_key_destroy(e->hKey,m_bDeepCopyKeys); + if(m_bAutoDelete) + delete ((T *)(e->pData)); + } + delete m_pDataArray[i]; + m_pDataArray[i] = 0; + } + } + m_uCount = 0; + } + + /// + /// Searches for the item pointer pRef and returns + /// it's hash table entry, if found, and NULL otherwise. + /// The hash table iterator is placed at the item found. + /// + KviPointerHashTableEntry<Key,T> * findRef(const T * pRef) + { + for(m_uIteratorIdx = 0;m_uIteratorIdx<m_uSize;m_uIteratorIdx++) + { + if(m_pDataArray[m_uIteratorIdx]) + { + for(KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first();e;e = m_pDataArray[m_uIteratorIdx]->next()) + { + if(e->pData == pRef)return e; + } + } + } + return 0; + } + + /// + /// Returns the entry pointed by the hash table iterator. + /// This function must be preceeded by a call to firstEntry(), first() + /// or findRef(). + /// + KviPointerHashTableEntry<Key,T> * currentEntry() + { + if(m_uIteratorIdx >= m_uSize)return 0; + if(m_pDataArray[m_uIteratorIdx])return m_pDataArray[m_uIteratorIdx]->current(); + return 0; + } + + /// + /// Places the hash table iterator at the first entry + /// and returns it. + /// + KviPointerHashTableEntry<Key,T> * firstEntry() + { + m_uIteratorIdx = 0; + while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx])) + { + m_uIteratorIdx++; + } + if(m_uIteratorIdx == m_uSize)return 0; + return m_pDataArray[m_uIteratorIdx]->first(); + } + + /// + /// Places the hash table iterator at the next entry + /// and returns it. + /// This function must be preceeded by a call to firstEntry(), first() + /// or findRef(). + /// + KviPointerHashTableEntry<Key,T> * nextEntry() + { + if(m_uIteratorIdx >= m_uSize)return 0; + + if(m_uIteratorIdx < m_uSize) + { + KviPointerHashTableEntry<Key,T> * t = m_pDataArray[m_uIteratorIdx]->next(); + if(t)return t; + } + + m_uIteratorIdx++; + + while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx])) + { + m_uIteratorIdx++; + } + + if(m_uIteratorIdx == m_uSize)return 0; + + return m_pDataArray[m_uIteratorIdx]->first(); + + } + + /// + /// Returns the data value pointer pointed by the hash table iterator. + /// This function must be preceeded by a call to firstEntry(), first() + /// or findRef(). + /// + T * current() + { + if(m_uIteratorIdx >= m_uSize)return 0; + if(m_pDataArray[m_uIteratorIdx]) + { + KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->current(); + if(!e)return 0; + return e->data(); + } + return 0; + } + + /// + /// Returns the key pointed by the hash table iterator. + /// This function must be preceeded by a call to firstEntry(), first() + /// or findRef(). + /// + const Key & currentKey() + { + if(m_uIteratorIdx >= m_uSize)return kvi_hash_key_default(((Key *)NULL)); + if(m_pDataArray[m_uIteratorIdx]) + { + KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->current(); + if(!e)return kvi_hash_key_default(((Key *)NULL)); + return e->key(); + } + return kvi_hash_key_default(((Key *)NULL)); + } + + /// + /// Places the hash table iterator at the first entry + /// and returns the associated data value pointer. + /// + T * first() + { + m_uIteratorIdx = 0; + while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx])) + { + m_uIteratorIdx++; + } + if(m_uIteratorIdx == m_uSize)return 0; + KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first(); + if(!e)return 0; + return e->data(); + } + + /// + /// Places the hash table iterator at the next entry + /// and returns the associated data value pointer. + /// This function must be preceeded by a call to firstEntry(), first() + /// or findRef(). + /// + T * next() + { + if(m_uIteratorIdx >= m_uSize)return 0; + + if(m_uIteratorIdx < m_uSize) + { + KviPointerHashTableEntry<Key,T> * t = m_pDataArray[m_uIteratorIdx]->next(); + if(t) + { + return t->data(); + } + } + + m_uIteratorIdx++; + + while(m_uIteratorIdx < m_uSize && (!m_pDataArray[m_uIteratorIdx])) + { + m_uIteratorIdx++; + } + + if(m_uIteratorIdx == m_uSize)return 0; + + KviPointerHashTableEntry<Key,T> * e = m_pDataArray[m_uIteratorIdx]->first(); + if(!e)return 0; + return e->data(); + } + + /// + /// Removes all items in the hash table and then + /// makes a complete shallow copy of the data contained in t. + /// The removed items are deleted if autodeletion is enabled. + /// The hash table iterator is invalidated. + /// Does not change autodelete flag: make sure you not delete the items twice :) + /// + void copyFrom(KviPointerHashTable<Key,T> &t) + { + clear(); + for(KviPointerHashTableEntry<Key,T> * e = t.firstEntry();e;e = t.nextEntry()) + insert(e->key(),e->data()); + } + + /// + /// Inserts a complete shallow copy of the data contained in t. + /// The hash table iterator is invalidated. + /// + void insert(KviPointerHashTable<Key,T> &t) + { + for(KviPointerHashTableEntry<Key,T> * e = t.firstEntry();e;e = t.nextEntry()) + insert(e->key(),e->data()); + } + + /// + /// Enables or disabled the autodeletion feature. + /// Items are deleted upon removal when the feature is enabled. + /// + void setAutoDelete(bool bAutoDelete) + { + m_bAutoDelete = bAutoDelete; + } + + /// + /// Creates an empty hash table. + /// Automatic deletion is enabled. + /// + /// \param uSize The number of hash buckets: does NOT necesairly need to be prime + /// \param bCaseSensitive Are the key comparisons case sensitive ? + /// \param Do we need to mantain deep copies of keys ? + /// + KviPointerHashTable(unsigned int uSize = 32,bool bCaseSensitive = true,bool bDeepCopyKeys = true) + { + m_uCount = 0; + m_bCaseSensitive = bCaseSensitive; + m_bAutoDelete = true; + m_bDeepCopyKeys = bDeepCopyKeys; + m_uSize = uSize > 0 ? uSize : 32; + m_pDataArray = new KviPointerList<KviPointerHashTableEntry<Key,T> > *[m_uSize]; + for(unsigned int i=0;i<m_uSize;i++)m_pDataArray[i] = NULL; + } + + /// + /// First creates an empty hash table + /// and then inserts a copy of all the item pointers present in t. + /// The autodelete feature is automatically disabled (take care!). + /// + KviPointerHashTable(KviPointerHashTable<Key,T> &t) + { + m_uCount = 0; + m_bAutoDelete = false; + m_bCaseSensitive = t.m_bCaseSensitive; + m_bDeepCopyKeys = t.m_bDeepCopyKeys; + m_uSize = t.m_uSize; + m_pDataArray = new KviPointerList<KviPointerHashTableEntry<Key,T> > *[m_uSize]; + for(unsigned int i=0;i<m_uSize;i++)m_pDataArray[i] = NULL; + copyFrom(t); + } + + /// + /// Destroys the hash table and all the items contained within. + /// Items are deleted if autodeletion is enabled. + /// + ~KviPointerHashTable() + { + clear(); + delete [] m_pDataArray; + } +}; + +template<typename Key,typename T> class KviPointerHashTableIterator +{ +protected: + const KviPointerHashTable<Key,T> * m_pHashTable; + unsigned int m_uEntryIndex; + KviPointerListIterator<KviPointerHashTableEntry<Key,T> > * m_pIterator; +public: + /// + /// Creates an iterator copy. + /// The new iterator points exactly to the item pointed by src. + /// + void operator = (const KviPointerHashTableIterator<Key,T> &src) + { + m_pHashTable = src.m_pHashTable; + m_uEntryIndex = src.m_uEntryIndex; + if(src.m_pIterator) + m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(src.m_pIterator)); + else + m_pIterator = NULL; + } + + /// + /// Moves the iterator to the first element of the hash table. + /// Returns true in case of success or false if the hash table is empty. + /// + bool moveFirst() + { + if(m_pIterator) + { + delete m_pIterator; + m_pIterator = NULL; + } + + m_uEntryIndex = 0; + while((m_uEntryIndex < m_pHashTable->m_uSize) && (!(m_pHashTable->m_pDataArray[m_uEntryIndex]))) + { + m_uEntryIndex++; + } + + if(m_uEntryIndex == m_pHashTable->m_uSize) + return false; + + m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex])); + bool bRet = m_pIterator->moveFirst(); + if(!bRet) + { + delete m_pIterator; + m_pIterator = NULL; + } + return bRet; + } + + /// + /// Moves the iterator to the last element of the hash table. + /// Returns true in case of success or false if the hash table is empty. + /// + bool moveLast() + { + if(m_pIterator) + { + delete m_pIterator; + m_pIterator = NULL; + } + + m_uEntryIndex = m_pHashTable->m_uSize; + while(m_uEntryIndex > 0) + { + m_uEntryIndex--; + if(m_pHashTable->m_pDataArray[m_uEntryIndex]) + { + m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex])); + bool bRet = m_pIterator->moveLast(); + if(!bRet) + { + delete m_pIterator; + m_pIterator = NULL; + } + return bRet; + } + } + return false; + } + + /// + /// Moves the iterator to the next element of the hash table. + /// The iterator must be actually valid for this function to work. + /// Returns true in case of success or false if there is no next item. + /// + bool moveNext() + { + if(!m_pIterator) + return false; + if(m_pIterator->moveNext()) + return true; + if(m_pIterator) + { + delete m_pIterator; + m_pIterator = NULL; + } + m_uEntryIndex++; + while((m_uEntryIndex < m_pHashTable->m_uSize) && (!(m_pHashTable->m_pDataArray[m_uEntryIndex]))) + { + m_uEntryIndex++; + } + if(m_uEntryIndex == m_pHashTable->m_uSize) + return false; + m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex])); + bool bRet = m_pIterator->moveFirst(); + if(!bRet) + { + delete m_pIterator; + m_pIterator = NULL; + } + return bRet; + } + + /// + /// Moves the iterator to the next element of the hash table. + /// The iterator must be actually valid for this function to work. + /// Returns true in case of success or false if there is no next item. + /// This is just an alias to moveNext(). + /// + bool operator ++() + { + return moveNext(); + } + + /// + /// Moves the iterator to the previous element of the hash table. + /// The iterator must be actually valid for this function to work. + /// Returns true in case of success or false if there is no previous item. + /// + bool movePrev() + { + if(!m_pIterator) + return false; + if(m_pIterator->movePrev()) + return true; + if(m_pIterator) + { + delete m_pIterator; + m_pIterator = NULL; + } + if(m_uEntryIndex >= m_pHashTable->m_uSize) + return false; + while(m_uEntryIndex > 0) + { + m_uEntryIndex--; + if(m_pHashTable->m_pDataArray[m_uEntryIndex]) + { + m_pIterator = new KviPointerListIterator<KviPointerHashTableEntry<Key,T> >(*(m_pHashTable->m_pDataArray[m_uEntryIndex])); + bool bRet = m_pIterator->moveLast(); + if(!bRet) + { + delete m_pIterator; + m_pIterator = NULL; + } + return bRet; + } + } + return false; + } + + + /// + /// Moves the iterator to the previous element of the hash table. + /// The iterator must be actually valid for this function to work. + /// Returns true in case of success or false if there is no previous item. + /// This is just an alias to movePrev() with a different name. + /// + bool operator --() + { + return movePrev(); + } + + /// + /// Returs the value pointed by the iterator + /// or a default constructed value if the iterator is not valid. + /// This is an alias to operator *() with just a different name. + /// + T * current() const + { + return m_pIterator ? m_pIterator->current()->data() : NULL; + } + + /// + /// Returs the value pointed by the iterator + /// or a default constructed value if the iterator is not valid. + /// This is an alias to current() with just a different name. + /// + T * operator *() const + { + return m_pIterator ? m_pIterator->current()->data() : NULL; + } + + /// + /// Returs the key pointed by the iterator + /// or a default constructed key if the iterator is not valid. + /// + const Key & currentKey() const + { + return m_pIterator ? m_pIterator->current()->key() : kvi_hash_key_default(((Key *)NULL)); + } + + /// + /// Moves the iterator to the first element of the hash table. + /// Returns the first item found or NULL if the hash table is empty. + /// + T * toFirst() + { + if(!moveFirst()) + return NULL; + return current(); + } +public: + /// + /// Creates an iterator pointing to the first item in the hash table, if any. + /// + KviPointerHashTableIterator(const KviPointerHashTable<Key,T> &hTable) + { + m_pHashTable = &hTable; + m_uEntryIndex = 0; + m_pIterator = NULL; + moveFirst(); + } + + /// + /// Destroys the iterator + /// + ~KviPointerHashTableIterator() + { + if(m_pIterator) + delete m_pIterator; + } +}; + + + + +#endif //_KVI_POINTERHASHTABLE_H_ diff --git a/src/kvilib/core/kvi_pointerlist.h b/src/kvilib/core/kvi_pointerlist.h new file mode 100644 index 00000000..381780c8 --- /dev/null +++ b/src/kvilib/core/kvi_pointerlist.h @@ -0,0 +1,1069 @@ +#ifndef _KVI_POINTERLIST_H_ +#define _KVI_POINTERLIST_H_ +//================================================================================================= +// +// File : kvi_pointerlist.h +// Creation date : Tue Jul 6 1999 14:52:20 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//================================================================================================= +//============================================================================= +// +// C++ Template based double linked pointer list class +// Original ss_list.h Created on 10 Dec 2001 +// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net) +// Added to KVIrc on 02 Jan 2008. +// +//============================================================================= + +// Qt changes the collection classes too much and too frequently. +// I think we need to be independent of that to the maximum degree possible. +// That's why we have our own fast pointer list class. +// This does not depend on Qt AT ALL and has an interface similar +// to the Qt<=3.x series. The pointer lists with the autodelete +// feature was great and I don't completly understand why they have +// been removed from Qt4 in favor of the value based non-autodeleting +// lists... anyway: here we go :) + +#include "kvi_settings.h" + +template<typename T> class KviPointerList; +template<typename T> class KviPointerListIterator; + +#ifndef NULL + #define NULL 0 +#endif + +/// +/// \internal +/// +class KviPointerListNode +{ +public: + KviPointerListNode * m_pPrev; + void * m_pData; + KviPointerListNode * m_pNext; +}; + +/// +/// \class KviPointerListIterator +/// \brief A fast KviPointerList iterator. +/// +/// This class allows traversing the list sequentially. +/// Multilpe iterators can traverse the list at the same time. +/// +/// Iteration example 1: +/// +/// \verbatim +/// KviPointerListIterator<T> it(list); +/// for(bool b = it.moveFirst();b;b = it.moveNext()) +/// { +/// T * pData = it.data(); +/// doSomethingWithData(pData); +/// } +/// \endverbatim +/// +/// Iteration example 2: +/// +/// \verbatim +/// KviPointerListIterator<T> it(list); +/// if(it.moveFirst()) +/// { +/// do { +/// T * pData = it.data(); +/// doSomethingWithData(pData); +/// } while(it.moveNext()); +/// } +/// \endverbatim +/// +/// Iteration example 3: +/// +/// \verbatim +/// KviPointerListIterator<T> it(list.iteratorAt(10)); +/// if(it.isValid()) +/// { +/// do { +/// T * pData = it.data(); +/// doSomethingWithData(pData); +/// while(it.movePrev()); +/// } +/// \endverbatim +/// +/// Please note that you must NOT remove any item from +/// the list when using the iterators. An iterator pointing +/// to a removed item will crash your application if you use it. +/// The following code will NOT work (and crash): +/// +/// \verbatim +/// KviPointerList<T> l; +/// l.append(new KviStr("x")); +/// l.append(new KviStr("y")); +/// KviPointerListIterator<T> it(l); +/// it.moveFirst(); +/// l.removeFirst(); +/// KviStr * tmp = it.data(); <-- this will crash +/// \endverbatim +/// +/// In the rare cases in that you need to remove items +/// while traversing the list you should put them +/// in a temporary list and remove them after the iteration. +/// +/// I've choosen this way because usually you don't modify +/// the list while traversing it and a fix for this +/// would add a constant overhead to several list operation. +/// You just must take care of it yourself. +/// +/// \warning This class is not thread safe by itself. +/// +template<typename T> class KviPointerListIterator +{ +protected: + KviPointerList<T> * m_pList; + KviPointerListNode * m_pNode; +public: + /// + /// Creates an iterator copy. + /// The new iterator points exactly to the item pointed by src. + /// + KviPointerListIterator(const KviPointerListIterator<T> &src) + { + m_pList = src.m_pList; + m_pNode = src.m_pNode; + } + + /// + /// Creates an iterator for the list l. + /// The iterator points to the first list item, if any. + /// + KviPointerListIterator(KviPointerList<T> &l) + { + m_pList = (KviPointerList<T> *)&l; + m_pNode = m_pList->m_pHead; + } + + /// + /// Creates an iterator for the list l. + /// The iterator points to the specified list node. + /// + KviPointerListIterator(KviPointerList<T> &l,KviPointerListNode * pNode) + { + m_pList = (KviPointerList<T> *)&l; + m_pNode = pNode; + } + + /// + /// Creates an iterator copy. + /// The new iterator points exactly to the item pointed by src. + /// + void operator = (const KviPointerListIterator<T> &src) + { + m_pList = src.m_pList; + m_pNode = src.m_pNode; + } +public: + /// + /// Moves the iterator to the first element of the list. + /// Returns true in case of success or false if the list is empty. + /// + bool moveFirst() + { + m_pNode = m_pList->m_pHead; + return m_pNode != NULL; + } + + /// + /// Moves the iterator to the last element of the list. + /// Returns true in case of success or false if the list is empty. + /// + bool moveLast() + { + m_pNode = m_pList->m_pTail; + return m_pNode != NULL; + } + + /// + /// Moves the iterator to the next element of the list. + /// The iterator must be actually valid for this function to work. + /// Returns true in case of success or false if there is no next item. + /// + bool moveNext() + { + if(!m_pNode)return false; + m_pNode = m_pNode->m_pNext; + return m_pNode != NULL; + } + + /// + /// Moves the iterator to the next element of the list. + /// The iterator must be actually valid for this operator to work. + /// Returns true in case of success or false if there is no next item. + /// This is just a convenient alias to moveNext(). + /// + bool operator ++() + { + if(!m_pNode)return false; + m_pNode = m_pNode->m_pNext; + return m_pNode != NULL; + } + + /// + /// Moves the iterator to the previous element of the list. + /// The iterator must be actually valid for this function to work. + /// Returns true in case of success or false if there is no previous item. + /// + bool movePrev() + { + if(!m_pNode)return false; + m_pNode = m_pNode->m_pPrev; + return m_pNode != NULL; + } + + /// + /// Moves the iterator to the previous element of the list. + /// The iterator must be actually valid for this operator to work. + /// Returns true in case of success or false if there is no previous item. + /// This is just a convenient alias to movePrev(). + /// + bool operator --() + { + if(!m_pNode)return false; + m_pNode = m_pNode->m_pPrev; + return m_pNode != NULL; + } + + /// + /// Returs the value pointed by the iterator + /// or NULL if the iterator is not valid. + /// + T * current() + { + return m_pNode ? (T *)(m_pNode->m_pData) : NULL; + } + + /// + /// Returs the value pointed by the iterator + /// or NULL if the iterator is not valid. + /// This is just an alias to current(). + /// + T * operator *() + { + return m_pNode ? (T *)(m_pNode->m_pData) : NULL; + } + + /// + /// Returns true if this iterator points to a valid + /// element of the list and false otherwise. + /// + bool isValid() + { + return m_pNode != NULL; + } +}; + +/// +/// \class KviPointerList +/// \brief A template double linked list of pointers. +/// +/// The main advantage of this type of list is speed. +/// Insertion of pointers is very fast when compared +/// to the typical "copy constructor" call used +/// in the "plain type" template list implementations. +/// +/// Iterating over pointers is also very fast and this +/// class contains an internal iterator that allows to +/// write loops in a compact and clean way. +/// See the first(), next(), current() and findRef() +/// functions for the description of this feature. +/// +/// There is also a non-const external iterator +/// that you can use to traverse the list concurrently. +/// There is no const iterator (and no const access methods) +/// since the list provides the autoDelete() method +/// which vould implicitly violate constness. +/// If you have to deal with const objects then +/// you need to use a QList instead. +/// +/// Your objects also do not need to support copy constructors +/// or >= operators. This class will work fine without them +/// as opposed to a plain QList. +/// +/// This class also supports automatic deletion of the inseted items. +/// See the setAutoDelete() and autoDelete() members for the +/// description of the feature. +/// +/// Typcal usage: +/// +/// \verbatim +/// KviPointerList<MyClass> list(); +/// list.append(new MyClass()); +/// list.append(new MyClass()); +/// ... +/// for(MyClass * c = list.first();c;c = list.next())doSomethingWith(c); +/// delete list; // autodelete is set to true in the constructor +/// \endverbatim +/// +/// \warning This class is absolutely NOT thread safe. You must +/// protect concurrent access from multiple threads by +/// using an external synchronization tool (such as KviMutex). +/// +template<typename T> class KviPointerList +{ + friend class KviPointerListIterator<T>; +protected: + bool m_bAutoDelete; //< do we automatically delete items when they are removed ? + + KviPointerListNode * m_pHead; //< our list head pointer (NULL if there are no items in the list) + KviPointerListNode * m_pTail; //< our list tail + KviPointerListNode * m_pAux; //< our iteration pointer + + unsigned int m_uCount; //< the count of items in the list +protected: + /// + /// \internal + /// + /// inserts the item d before the item ref or at the beginning + /// if ref is not found in the list + /// also sets the current iteration pointer to the newly inserted item + /// + void insertBeforeSafe(KviPointerListNode * ref,const T * d) + { + m_pAux = ref; + KviPointerListNode * n = new KviPointerListNode; + n->m_pPrev = m_pAux->m_pPrev; + n->m_pNext = m_pAux; + if(m_pAux->m_pPrev) + { + m_pAux->m_pPrev->m_pNext = n; + } else { + m_pHead = n; + } + m_pAux->m_pPrev = n; + n->m_pData = (void *)d; + m_uCount++; + } + + /// + /// \internal + /// + /// Grabs the first element from the list src + /// and puts it as the first element of this list. + /// + void grabFirstAndPrepend(KviPointerList<T> * src) + { + KviPointerListNode * pNewHead = src->m_pHead; + if(!pNewHead) + return; + + if(pNewHead->m_pNext) + { + src->m_pHead = pNewHead->m_pNext; + src->m_pHead->m_pPrev = NULL; + } else { + src->m_pHead = NULL; + src->m_pTail = NULL; + } + + if(m_pHead) + { + m_pHead->m_pPrev = pNewHead; + pNewHead->m_pNext = m_pHead; + m_pHead = pNewHead; + } else { + m_pHead = pNewHead; + m_pTail = pNewHead; + m_pHead->m_pNext = NULL; + } + m_uCount++; + src->m_uCount--; + } + + /// + /// \internal + /// + /// Removes the current iteration item assuming that it is valid. + /// + void removeCurrentSafe() + { + if(m_pAux->m_pPrev) + m_pAux->m_pPrev->m_pNext = m_pAux->m_pNext; + else + m_pHead = m_pAux->m_pNext; + if(m_pAux->m_pNext) + m_pAux->m_pNext->m_pPrev = m_pAux->m_pPrev; + else + m_pTail = m_pAux->m_pPrev; + const T * pAuxData = (const T *)(m_pAux->m_pData); + delete m_pAux; + m_pAux = NULL; + m_uCount--; + if(m_bAutoDelete) + delete pAuxData; // this can cause recursion, so do it at the end + } + +public: + /// + /// Inserts the list src inside this list + /// by respecting the sort order. + /// The src list elements are removed. + /// + void merge(KviPointerList<T> * src) + { + m_pAux = m_pHead; + KviPointerListNode * n = src->m_pHead; + m_uCount += src->m_uCount; + while(m_pAux && n) + { + if(kvi_compare((const T *)(m_pAux->m_pData),(const T *)(n->m_pData)) > 0) + { + // our element is greater, n->m_pData goes first + KviPointerListNode * pNext = n->m_pNext; + n->m_pPrev = m_pAux->m_pPrev; // his prev becomes + n->m_pNext = m_pAux; + if(m_pAux->m_pPrev) + m_pAux->m_pPrev->m_pNext = n; + else + m_pHead = n; + m_pAux->m_pPrev = n; + n = pNext; + } else { + // that element is greater + m_pAux = m_pAux->m_pNext; + } + } + if(n) + { + // last items to append + if(m_pTail) + { + m_pTail->m_pNext = n; + n->m_pPrev = m_pTail; + } else { + m_pHead = n; + m_pTail = n; + n->m_pPrev = NULL; + } + m_pTail = src->m_pTail; + } + + src->m_pHead = NULL; + src->m_pTail = NULL; + src->m_uCount = 0; + } + + void swap(KviPointerList<T> * src) + { + KviPointerListNode * n = m_pHead; + m_pHead = src->m_pHead; + src->m_pHead = n; + n = m_pTail; + m_pTail = src->m_pTail; + src->m_pTail = n; + unsigned int uCount = m_uCount; + m_uCount = src->m_uCount; + src->m_uCount = uCount; + } + + + /// + /// Sorts this list in ascending order. + /// There must be an int kvi_compare(const T *p1,const T *p2) function + /// which returns a value less than, equal to + /// or greater than zero when the item p1 is considered lower than, + /// equal to or greater than p2. + /// + void sort() + { + if(m_uCount < 2)return; + + KviPointerList<T> carry; + KviPointerList<T> tmp[64]; + KviPointerList * fill = &tmp[0]; + KviPointerList * counter; + + do { + carry.grabFirstAndPrepend(this); + + for(counter = &tmp[0];counter != fill && !counter->isEmpty();++counter) + { + counter->merge(&carry); + carry.swap(counter); + } + carry.swap(counter); + if(counter == fill) + ++fill; + } while(m_uCount > 0); + + for(counter = &tmp[1];counter != fill;++counter) + counter->merge(counter-1); + swap(fill-1); + } + + /// + /// Inserts the item respecting the sorting order inside the list. + /// The list itself must be already sorted for this to work correctly. + /// There must be a int kvi_compare(const T *p1,const T * p2) + /// that returns a value less than, equal to + /// or greater than zero when the item p1 is considered lower than, + /// equal to or greater than p2. + /// + void inSort(T * t) + { + KviPointerListNode * x = m_pHead; + while(x && (kvi_compare(((T *)x->m_pData),t) > 0))x = x->m_pNext; + if(!x)append(t); + else insertBeforeSafe(x,t); + } + + /// + /// Returns true if the list is empty + /// + bool isEmpty() const + { + return (m_pHead == NULL); + } + + /// + /// Returns the count of the items in the list + /// + unsigned int count() const + { + return m_uCount; + } + + /// + /// Sets the iteration pointer to the first item in the list + /// and returns that item (or 0 if the list is empty) + /// + T * first() + { + if(!m_pHead) + { + m_pAux = NULL; + return NULL; + } + m_pAux = m_pHead; + return (T *)(m_pAux->m_pData); + } + + /// + /// Removes the first element from the list + /// and returns it to the caller. This function + /// obviously never deletes the item (regadless of autoDeletion()). + /// + T * takeFirst() + { + if(!m_pHead)return NULL; + T * pData = (T *)m_pHead->m_pData; + if(m_pHead->m_pNext) + { + m_pHead = m_pHead->m_pNext; + delete m_pHead->m_pPrev; + m_pHead->m_pPrev = NULL; + } else { + delete m_pHead; + m_pHead = NULL; + m_pTail = NULL; + } + m_uCount--; + return pData; + } + + /// + /// Returns an iterator pointing to the first item of the list. + /// + KviPointerListIterator<T> iteratorAtFirst() + { + return KviPointerListIterator<T>(*this,m_pHead); + } + + /// + /// Sets the iteration pointer to the last item in the list + /// and returns that item (or 0 if the list is empty) + /// + T * last() + { + if(!m_pTail) + { + m_pAux = NULL; + return NULL; + } + m_pAux = m_pTail; + return (T *)(m_pAux->m_pData); + } + + /// + /// Returns an iterator pointing to the first item of the list. + /// + KviPointerListIterator<T> iteratorAtLast() + { + return KviPointerListIterator<T>(*this,m_pTail); + } + + /// + /// Returns the current iteration item + /// A call to this function MUST be preceded by a call to + /// first(),last(),at() or findRef() + /// + T * current() + { + return (T *)(m_pAux->m_pData); + } + + /// + /// Returns the current iteration item + /// A call to this function should be preceded by a call to + /// first(),last(),at() or findRef(). + /// This function will return a NULL pointer if the current + /// item has been invalidated due to a remove operation. + /// + T * safeCurrent() + { + return m_pAux ? (T *)(m_pAux->m_pData) : NULL; + } + + + /// + /// Returns an iterator pointing to the current item in the list. + /// A call to this function MUST be preceded by a call to + /// first(),last(),at() or findRef() + /// + KviPointerListIterator<T> iteratorAtCurrent() + { + return KviPointerListIterator<T>(*this,m_pAux); + } + + /// + /// Sets the iteration pointer to the next item in the list + /// and returns that item (or 0 if the end of the list has been reached) + /// A call to this function MUST be preceded by a _succesfull_ call to + /// first(),last(),at() or findRef(). + /// + T * next() + { + if(!m_pAux)return NULL; + m_pAux = m_pAux->m_pNext; + if(m_pAux)return (T *)(m_pAux->m_pData); + return NULL; + } + + /// + /// Sets the iteration pointer to the previous item in the list + /// and returns that item (or 0 if the beginning of the list has been reached) + /// A call to this function MUST be preceded by a _succesfull_ call to + /// first(),last(),at() or findRef() + /// + T * prev() + { + if(!m_pAux)return NULL; + m_pAux = m_pAux->m_pPrev; + if(m_pAux)return (T *)(m_pAux->m_pData); + return NULL; + } + + /// + /// Sets the iteration pointer to the nTh item in the list + /// and returns that item (or 0 if the index is out of range) + /// + T * at(int idx) + { + T * t = first(); + int cnt = 0; + while(t) + { + if(idx == cnt)return t; + t = next(); + cnt++; + } + return 0; + } + + /// + /// Returns an iterator pointing to the item at the specified index. + /// + KviPointerListIterator<T> iteratorAt(int idx) + { + KviPointerListNode * n = m_pHead; + int cnt = 0; + while(n) + { + if(idx == cnt) + return KviPointerListIterator<T>(*this,n); + n = n->m_pNext; + cnt++; + } + return KviPointerListIterator<T>(*this,NULL); + } + + /// + /// Sets the iteration pointer to the item with pointer d + /// and returns its position (zero based index) in the list or -1 if the + /// item cannot be found + /// + int findRef(const T * d) + { + int ret = 0; + for(T * t = first();t;t = next()) + { + if(t == d)return ret; + ret++; + } + return -1; + } + + /// + /// Returns an iterator pointing to the item with pointer d. + /// + KviPointerListIterator<T> iteratorAtRef(const T * d) + { + KviPointerListNode * n = m_pHead; + while(n) + { + if(n->m_pData == d) + return KviPointerListIterator<T>(*this,n); + n = n->m_pNext; + } + return KviPointerListIterator<T>(*this,NULL); + } + + /// + /// Appends an item at the end of the list + /// + void append(const T * d) + { + if(!m_pHead) + { + m_pHead = new KviPointerListNode; + m_pHead->m_pPrev = NULL; + m_pHead->m_pNext = NULL; + m_pHead->m_pData = (void *)d; + m_pTail = m_pHead; + } else { + m_pTail->m_pNext = new KviPointerListNode; + m_pTail->m_pNext->m_pPrev = m_pTail; + m_pTail->m_pNext->m_pNext = NULL; + m_pTail->m_pNext->m_pData = (void *)d; + m_pTail = m_pTail->m_pNext; + } + m_uCount++; + } + + /// + /// Appends all the items from the list l to this list + /// + void append(KviPointerList<T> * l) + { + for(T * t = l->first();t;t = l->next())append(t); + } + + /// + /// Prepends (inserts in head position) all the items from + /// the list l to this list + /// + void prepend(KviPointerList<T> * l) + { + for(T * t = l->last();t;t = l->prev())prepend(t); + } + + /// + /// Inserts the item d in the head position + /// + void prepend(const T * d) + { + if(!m_pHead) + { + m_pHead = new KviPointerListNode; + m_pHead->m_pPrev = NULL; + m_pHead->m_pNext = NULL; + m_pHead->m_pData = (void *)d; + m_pTail = m_pHead; + } else { + m_pHead->m_pPrev = new KviPointerListNode; + m_pHead->m_pPrev->m_pNext = m_pHead; + m_pHead->m_pPrev->m_pPrev = NULL; + m_pHead->m_pPrev->m_pData = (void *)d; + m_pHead = m_pHead->m_pPrev; + m_uCount++; + } + } + + /// + /// Inserts the item d at the zero-based position + /// specified by iIndex. If the specified position + /// is out of the list then the item is appended. + /// Note that this function costs O(n). + /// It's really better to use insertAfter() or + /// insertBefore(), if possible. + /// + void insert(int iIndex,const T * d) + { + m_pAux = m_pHead; + while(m_pAux && iIndex > 0) + { + iIndex--; + m_pAux = m_pAux->m_pNext; + } + if(m_pAux) + insertBeforeSafe(m_pAux,d); + else + append(d); + } + + /// + /// Removes the firstitem (if any) + /// the item is deleted if autoDelete() is set to true + /// + bool removeFirst() + { + if(!m_pHead)return false; + const T * pAuxData; + if(m_pHead->m_pNext) + { + m_pHead = m_pHead->m_pNext; + pAuxData = (const T *)(m_pHead->m_pPrev->m_pData); + delete m_pHead->m_pPrev; + m_pHead->m_pPrev = NULL; + } else { + pAuxData = (const T *)(m_pHead->m_pData); + delete m_pHead; + m_pHead = NULL; + m_pTail = NULL; + } + m_pAux = NULL; + m_uCount--; + if(m_bAutoDelete) + delete pAuxData; + return true; + } + + /// + /// Removes the firstitem (if any) + /// the item is deleted if autoDelete() is set to true + /// + bool removeLast() + { + if(!m_pTail)return false; + const T * pAuxData; + if(m_pTail->m_pPrev) + { + m_pTail = m_pTail->m_pPrev; + pAuxData = (const T *)(m_pTail->m_pNext->m_pData); + delete m_pTail->m_pNext; + m_pTail->m_pNext = NULL; + } else { + pAuxData = (const T *)(m_pTail->m_pData); + delete m_pTail; + m_pHead = NULL; + m_pTail = NULL; + } + m_pAux = NULL; + m_uCount--; + if(m_bAutoDelete) + delete pAuxData; + return true; + } + + /// + /// Removes the item at zero-based position iIndex. + /// Does nothing and returns false if iIndex is out of the list. + /// Please note that this function costs O(n). + /// + bool remove(int iIndex) + { + m_pAux = m_pHead; + while(m_pAux && iIndex > 0) + { + iIndex--; + m_pAux = m_pAux->m_pNext; + } + if(!m_pAux) + return false; + removeCurrentSafe(); + return true; + } + + /// + /// Sets the autodelete flag + /// When this flag is on (default) , all the items + /// are deleted when removed from the list (or when the list is destroyed + /// or cleared explicitly) + /// + void setAutoDelete(bool bAutoDelete) + { + m_bAutoDelete = bAutoDelete; + } + + /// + /// Returns the autodelete flag. + /// + bool autoDelete() + { + return m_bAutoDelete; + }; + + /// + /// Removes all the items from the list + /// (the items are deleted if the autoDelete() flag is set to true) + /// + void clear() + { + while(m_pHead)removeFirst(); + } + + /// + /// Removes the current iteration item. + /// Returns true if the current iteration item was valid (and was removed) + /// and false otherwise. + /// + bool removeCurrent() + { + if(!m_pAux) + return false; + removeCurrentSafe(); + return true; + } + + /// + /// Removes the item pointed by d (if found in the list) + /// the item is deleted if the autoDelete() flag is set to true) + /// Returns true if the item was in the list and false otherwise. + /// + bool removeRef(const T * d) + { + if(findRef(d) == -1)return false; + removeCurrentSafe(); + return true; + } + + /// + /// inserts the item d after the item ref or at the end + /// if ref is not found in the list + /// also sets the current iteration pointer to the newly inserted item + /// + void insertAfter(const T * ref,const T * d) + { + if(findRef(ref) == -1) + { + append(d); + return; + } + KviPointerListNode * n = new KviPointerListNode; + n->m_pPrev = m_pAux; + n->m_pNext = m_pAux->m_pNext; + if(m_pAux->m_pNext) + m_pAux->m_pNext->m_pPrev = n; + else + m_pTail = n; + m_pAux->m_pNext = n; + n->m_pData = (void *)d; + m_uCount++; + } + + /// + /// inserts the item d before the item ref or at the beginning + /// if ref is not found in the list + /// also sets the current iteration pointer to the newly inserted item + /// + void insertBefore(const T * ref,const T * d) + { + if(findRef(ref) == -1) + { + prepend(d); + return; + } + KviPointerListNode * n = new KviPointerListNode; + n->m_pPrev = m_pAux->m_pPrev; + n->m_pNext = m_pAux; + if(m_pAux->m_pPrev) + m_pAux->m_pPrev->m_pNext = n; + else + m_pHead = n; + m_pAux->m_pPrev = n; + n->m_pData = (void *)d; + m_uCount++; + } + + /// + /// Inverts the elements in the list. + /// + void invert() + { + if(!m_pHead)return; + KviPointerListNode * oldHead = m_pHead; + KviPointerListNode * oldTail = m_pTail; + KviPointerListNode * n = m_pHead; + while(n) + { + KviPointerListNode * next = n->m_pNext; + n->m_pNext = n->m_pPrev; + n->m_pPrev = next; + n = next; + } + m_pTail = oldHead; + m_pHead = oldTail; + } + + /// + /// clears the list and inserts all the items from the list l + /// + void copyFrom(KviPointerList<T> * l) + { + clear(); + for(T * t = l->first();t;t = l->next())append(t); + } + + /// + /// equivalent to copyFrom(l) + /// + KviPointerList<T> & operator = (KviPointerList<T> &l) + { + copyFrom(&l); + return *this; + } + + /// + /// creates a template list + /// + KviPointerList<T>(bool bAutoDelete = true) + { + m_bAutoDelete = bAutoDelete; + m_pHead = NULL; + m_pTail = NULL; + m_uCount = 0; + m_pAux = NULL; + }; + + /// + /// destroys the list + /// if autoDelete() is set to true, all the items are deleted + /// + virtual ~KviPointerList<T>() + { + clear(); + }; +}; + +#define KviPointerListBase KviPointerList + +// BROKEN MSVC LINKER +#ifdef COMPILE_ON_WINDOWS + #include "kvi_string.h" + template class KVILIB_API KviPointerList<KviStr>; +#endif + +#endif //_KVI_POINTERLIST_H_ diff --git a/src/kvilib/core/kvi_qcstring.h b/src/kvilib/core/kvi_qcstring.h new file mode 100644 index 00000000..0693e205 --- /dev/null +++ b/src/kvilib/core/kvi_qcstring.h @@ -0,0 +1,39 @@ +#ifndef _KVI_QCSTRING_H_ +#define _KVI_QCSTRING_H_ + +//============================================================================= +// +// File : kvi_qcstring.h +// Creation date : Thu Jan 18 2007 00:34:33 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include <q3cstring.h> // includes <qbytearray.h> + #define KviQCString QByteArray +#else + // this is dead in Qt 4.x + #include <qcstring.h> + #define KviQCString QCString +#endif + +#endif //!_KVI_QCSTRING_H_ diff --git a/src/kvilib/core/kvi_qstring.cpp b/src/kvilib/core/kvi_qstring.cpp new file mode 100644 index 00000000..eba255aa --- /dev/null +++ b/src/kvilib/core/kvi_qstring.cpp @@ -0,0 +1,1125 @@ +//============================================================================= +// +// File : kvi_qstring.cpp +// Creation date : Mon Aug 04 2003 13:36:33 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2003-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// +// Helper functions for the QString class +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_qstring.h" +#include "kvi_string.h" +#include "kvi_malloc.h" +#include "kvi_locale.h" + +#include <ctype.h> // for tolower() +#include <stdio.h> // for sprintf() +#include <qregexp.h> + +// kvi_string.cpp +extern unsigned char iso88591_toLower_map[256]; +extern unsigned char iso88591_toUpper_map[256]; + +#define MY_MIN(a,b) (((a) < (b)) ? (a) : (b)) + +namespace KviQString +{ + // The global empty (and null) string + const QString empty; + + bool equalCSN(const QString &sz1,const QString &sz2,unsigned int len) + { + if(len == 0)return true; // assume equal + const QChar * c1 = sz1.unicode(); + const QChar * c2 = sz2.unicode(); + unsigned int lmin = MY_MIN(sz1.length(),sz2.length()); + if(lmin < len)return false; + const QChar * c1e = c1 + len; + + if(!c1 || !c2)return (c1 == c2); + + while(c1 < c1e) + { + if(c1->unicode() != c2->unicode())return false; + c1++; + c2++; + } + return (c1 == c1e); + } + + bool equalCIN(const QString &sz1,const QString &sz2,unsigned int len) + { + if(len == 0)return true; // assume equal + const QChar * c1 = sz1.unicode(); + const QChar * c2 = sz2.unicode(); + unsigned int lmin = MY_MIN(sz1.length(),sz2.length()); + if(lmin < len)return false; + const QChar * c1e = c1 + len; + + if(!c1 || !c2)return (c1 == c2); + + while(c1 < c1e) + { +#ifdef COMPILE_USE_QT4 + if(c1->toLower().unicode() != c2->toLower().unicode())return false; +#else + if(c1->lower().unicode() != c2->lower().unicode())return false; +#endif + c1++; + c2++; + } + return (c1 == c1e); + } + + bool equalCSN(const QString &sz1,const char * sz2,unsigned int len) + { + if(len == 0)return true; // assume equal + const QChar * c1 = sz1.unicode(); + if(sz1.length() < len)return false; + const QChar * c1e = c1 + len; + + if(!sz2)return !c1; + if(!c1)return !sz2; + + while((c1 < c1e) && (*sz2)) + { + if(c1->unicode() != *sz2)return false; + c1++; + sz2++; + } + return (c1 == c1e); + } + + bool equalCIN(const QString &sz1,const char * sz2,unsigned int len) + { + if(len == 0)return true; // assume equal + const QChar * c1 = sz1.unicode(); + if(sz1.length() < len)return false; + const QChar * c1e = c1 + len; + + if(!sz2)return !c1; + if(!c1)return !(*sz2); + + while((c1 < c1e) && (*sz2)) + { +#ifdef COMPILE_USE_QT4 + if(c1->toLower().unicode() != tolower(*sz2))return false; +#else + if(c1->lower().unicode() != tolower(*sz2))return false; +#endif + c1++; + sz2++; + } + return (c1 == c1e); + } + + // sz2 is assumed to be null terminated, sz1 is not! + bool equalCIN(const QString &sz1,const QChar *sz2,unsigned int len) + { + if(len == 0)return true; // assume equal + const QChar * c1 = sz1.unicode(); + if(sz1.length() < len)return false; + const QChar * c1e = c1 + len; + + if(!sz2)return !c1; + if(!c1)return !(sz2->unicode()); + + while((c1 < c1e) && (sz2->unicode())) + { +#ifdef COMPILE_USE_QT4 + if(c1->toLower().unicode() != sz2->toLower().unicode())return false; +#else + if(c1->lower().unicode() != sz2->lower().unicode())return false; +#endif + c1++; + sz2++; + } + return (c1 == c1e); + } + + QString makeSizeReadable(size_t bytes) + { + double size = bytes; + if(size<900) + return QString(__tr2qs("%1 bytes")).arg(size,0,'f',3); + + size/=1024; + if(size<900) + return QString(__tr2qs("%1 KB")).arg(size,0,'f',3); + + size/=1024; + if(size<900) + return QString(__tr2qs("%1 MB")).arg(size,0,'f',3); + + //Pirated DVD?;) + size/=1024; + if(size<900) + return QString(__tr2qs("%1 GB")).arg(size,0,'f',3); + + //Uhm.. We are downloading a whole internet:))) + size/=1024; + return QString(__tr2qs("%1 TB")).arg(size,0,'f',3); + } + + bool equalCS(const QString &sz1,const QString &sz2) + { + if(sz1.length() != sz2.length())return false; + + const QChar * c1 = sz1.unicode(); + const QChar * c2 = sz2.unicode(); + const QChar * c1e = c1 + sz1.length(); + + if(!c1 || !c2)return (c1 == c2); + + while(c1 < c1e) + { + if(c1->unicode() != c2->unicode())return false; + c1++; + c2++; + } + return (c1 == c1e); + } + + bool equalCI(const QString &sz1,const QString &sz2) + { + if(sz1.length() != sz2.length())return false; + + const QChar * c1 = sz1.unicode(); + const QChar * c2 = sz2.unicode(); + const QChar * c1e = c1 + sz1.length(); + + if(!c1 || !c2)return (c1 == c2); + + while(c1 < c1e) + { +#ifdef COMPILE_USE_QT4 + if(c1->toLower().unicode() != c2->toLower().unicode())return false; +#else + if(c1->lower().unicode() != c2->lower().unicode())return false; +#endif + c1++; + c2++; + } + return (c1 == c1e); + } + + // sz2 is assumed to be null terminated, sz1 is not! + bool equalCI(const QString &sz1,const QChar *sz2) + { + const QChar * c1 = sz1.unicode(); + const QChar * c1e = c1 + sz1.length(); + + if(!c1 || !sz2)return (c1 == sz2); + + while(c1 < c1e) + { + if(!sz2->unicode())return false; // sz1 has at least another character +#ifdef COMPILE_USE_QT4 + if(c1->toLower().unicode() != sz2->toLower().unicode())return false; +#else + if(c1->lower().unicode() != sz2->lower().unicode())return false; +#endif + c1++; + sz2++; + } + return (c1 == c1e) && (!sz2->unicode()); + } + + bool equalCS(const QString &sz1,const char * sz2) + { + const QChar * c1 = sz1.unicode(); + const QChar * c1e = c1 + sz1.length(); + + if(!c1)return !sz2; + + while((c1 < c1e) && (*sz2)) + { + if(c1->unicode() != *sz2)return false; + c1++; + sz2++; + } + return ((c1 == c1e) && (*sz2 == '\0')); + } + + bool equalCI(const QString &sz1,const char * sz2) + { + const QChar * c1 = sz1.unicode(); + const QChar * c1e = c1 + sz1.length(); + + if(!c1)return !sz2; + + while((c1 < c1e) && (*sz2)) + { +#ifdef COMPILE_USE_QT4 + if(c1->toLower().unicode() != tolower(*sz2))return false; +#else + if(c1->lower().unicode() != tolower(*sz2))return false; +#endif + c1++; + sz2++; + } + return ((c1 == c1e) && (*sz2 == '\0')); + } + + int cmpCS(const QString &sz1,const QString &sz2) + { + const QChar * c1 = sz1.unicode(); + const QChar * c2 = sz2.unicode(); + const QChar * c1e = c1 + sz1.length(); + const QChar * c2e = c2 + sz2.length(); + + if(!c1) + { + if(!c2)return 0; + return -1; + } + if(!c2)return 1; + + + for(;;) + { + if(c1 >= c1e) + { + if(c2 < c2e)return /* 0 */ - (c2->unicode()); + return 0; + } + if(c2 >= c2e)return c1->unicode() /* - 0 */; + + int diff = c1->unicode() - c2->unicode(); + if(diff)return diff; + + c1++; + c2++; + } + + return 0; // never here + } + + int cmpCI(const QString &sz1,const QString &sz2) + { + const QChar * c1 = sz1.unicode(); + const QChar * c2 = sz2.unicode(); + const QChar * c1e = c1 + sz1.length(); + const QChar * c2e = c2 + sz2.length(); + + if(!c1) + { + if(!c2)return 0; + return -1; + } + if(!c2)return 1; + + for(;;) + { + if(c1 >= c1e) + { +#ifdef COMPILE_USE_QT4 + if(c2 < c2e)return /* 0 */ - (c2->toLower().unicode()); +#else + if(c2 < c2e)return /* 0 */ - (c2->lower().unicode()); +#endif + return 0; + } +#ifdef COMPILE_USE_QT4 + if(c2 >= c2e)return c1->toLower().unicode() /* - 0 */; +#else + if(c2 >= c2e)return c1->lower().unicode() /* - 0 */; +#endif + +#ifdef COMPILE_USE_QT4 + int diff = c1->toLower().unicode() - c2->toLower().unicode(); +#else + int diff = c1->lower().unicode() - c2->lower().unicode(); +#endif + if(diff)return diff; + + c1++; + c2++; + } + + return 0; // never here + } + + int cmpCIN(const QString &sz1,const QString &sz2,unsigned int len) + { + if(len == 0)return 0; // assume equal + unsigned int l1 = MY_MIN(len,sz1.length()); + unsigned int l = MY_MIN(l1,sz2.length()); // FIXME: THIS IS NOT OK + + const QChar * c1 = sz1.unicode(); + const QChar * c2 = sz2.unicode(); + const QChar * c1e = c1 + l; + + if(!c1) + { + if(!c2)return 0; + return -1; + } + if(!c2)return 1; + + int diff = 0; + +#ifdef COMPILE_USE_QT4 + while((c1 < c1e) && !(diff = (c1->toLower().unicode() - c2->toLower().unicode()))) +#else + while((c1 < c1e) && !(diff = (c1->lower().unicode() - c2->lower().unicode()))) +#endif + { + c1++; + c2++; + } + + return diff; + } + + void ensureLastCharIs(QString &szString,const QChar &c) + { + if(!lastCharIs(szString,c))szString.append(c); + } + + QString getToken(QString &szString,const QChar &sep) + { + int i=0; + while(i < szString.length()) + { + if(szString[i] == sep)break; + i++; + } + QString ret; + if(i == szString.length()) + { + ret = szString; + szString = ""; + } else { + ret = szString.left(i); + while(i < szString.length()) + { + if(szString[i] != sep)break; + i++; + } + if(i == szString.length())szString = ""; + else szString.remove(0,i); + } + return ret; + } + + void stripRightWhiteSpace(QString &s) + { + int iRemove = 0; + while(iRemove < s.length()) + { + if(s.at(s.length() - (iRemove + 1)).isSpace())iRemove++; + else break; + } + if(iRemove > 0)s.remove(s.length() - iRemove,iRemove); + } + + void stripRight(QString &s,const QChar &c) + { + int iRemove = 0; + while(iRemove < s.length()) + { + if(s.at(s.length() - (iRemove + 1)) == c)iRemove++; + else break; + } + if(iRemove > 0)s.remove(s.length() - iRemove,iRemove); + } + + void stripLeft(QString &s,const QChar &c) + { + int iRemove = 0; + while(iRemove < s.length()) + { + if(s[iRemove] == c) + iRemove++; + else + break; + } + if(iRemove > 0)s.remove(0,iRemove); + } + + void detach(QString &sz) + { +#ifdef COMPILE_USE_QT4 + sz.resize(sz.length()); +#else + sz.setLength(sz.length()); +#endif + } + + const QChar * nullTerminatedArray(const QString &sz) + { + //sz.setLength(sz.length()); // detach! +#ifdef COMPILE_USE_QT4 + return sz.constData(); +#else + return (const QChar *)sz.ucs2(); // MAY BE NULL! +#endif + } + + void appendNumber(QString &s,double dReal) + { + char buffer[512]; + ::sprintf(buffer,"%f",dReal); + s.append(buffer); + } + + void appendNumber(QString &s,int iInteger) + { + char buffer[64]; + ::sprintf(buffer,"%d",iInteger); + s.append(buffer); + } + + void appendNumber(QString &s,kvi_i64_t iInteger) + { + char buffer[64]; + ::sprintf(buffer,"%ld",iInteger); + s.append(buffer); + } + + void appendNumber(QString &s,kvi_u64_t uInteger) + { + char buffer[64]; + ::sprintf(buffer,"%lu",uInteger); + s.append(buffer); + } + + void appendNumber(QString &s,unsigned int uInteger) + { + char buffer[64]; + ::sprintf(buffer,"%u",uInteger); + s.append(buffer); + } + + void vsprintf(QString &s,const QString &szFmt,kvi_va_list list) + { +#define MEMINCREMENT 32 + + int reallen = 0; + int allocsize = MEMINCREMENT; + + //s.setLength(allocsize); + + const QChar * fmt = nullTerminatedArray(szFmt); + if(!fmt) + { + s = QString::null; + return; + } + + QChar * buffer = (QChar *)kvi_malloc(sizeof(QChar) * allocsize); + //QChar * p = (QChar *)s.unicode(); + + char *argString; + long argValue; + unsigned long argUValue; + + //9999999999999999999999999999999\0 + char numberBuffer[32]; //enough ? 10 is enough for 32bit unsigned int... + char *pNumBuf; + unsigned int tmp; + + QChar * p = buffer; + +#define INCREMENT_MEM \ + { \ + allocsize += MEMINCREMENT; \ + buffer = (QChar *)kvi_realloc(buffer,sizeof(QChar) * allocsize); \ + p = buffer + reallen; \ + } + +#define INCREMENT_MEM_BY(numchars) \ + { \ + allocsize += numchars + MEMINCREMENT; \ + buffer = (QChar *)kvi_realloc(buffer,sizeof(QChar) * allocsize); \ + p = buffer + reallen; \ + } + + + for(; fmt->unicode() ; ++fmt) + { + if(reallen == allocsize)INCREMENT_MEM + + //copy up to a '%' + if(fmt->unicode() != '%') + { + *p++ = *fmt; + reallen++; + continue; + } + + ++fmt; //skip this '%' + switch(fmt->unicode()) + { + case 's': // char * string + { + argString = kvi_va_arg(list,char *); + if(!argString)argString = "[!NULL!]"; + QString str(argString); + if(str.isEmpty())continue; + int len = str.length(); + const QChar * ch = str.unicode(); + if(!ch)continue; + if((allocsize - reallen) < len)INCREMENT_MEM_BY(len) + while(len--)*p++ = *ch++; + reallen += str.length(); + continue; + } + case 'S': // KviStr * string + { + KviStr * str = kvi_va_arg(list,KviStr *); + if(!str)continue; + if((allocsize - reallen) < str->len())INCREMENT_MEM_BY(str->len()) + argString = str->ptr(); + while(*argString)*p++ = QChar(*argString++); + reallen += str->len(); + continue; + } + case 'Q': // QString * string + { + QString * str = kvi_va_arg(list,QString *); + if(!str)continue; + if(str->isEmpty())continue; + int len = str->length(); + const QChar * ch = str->unicode(); + if(!ch)continue; + if((allocsize - reallen) < len)INCREMENT_MEM_BY(len) + while(len--)*p++ = *ch++; + reallen += str->length(); + continue; + } + case 'c': //char + { + // + // I'm not sure about this... + // In the linux kernel source the + // unsigned char is extracted from an integer type. + // We assume that gcc stacks a char argument + // as sizeof(int) bytes value. + // Is this always true ? + // + *p++ = (char)kvi_va_arg(list,int); + reallen++; + continue; + } + case 'q': // QChar * + { + // + // I'm not sure about this... + // In the linux kernel source the + // unsigned char is extracted from an integer type. + // We assume that gcc stacks a char argument + // as sizeof(int) bytes value. + // Is this always true ? + // + *p++ = *((QChar *)kvi_va_arg(list,QChar *)); + reallen++; + continue; + } + case 'd': //signed integer + { + argValue = kvi_va_arg(list,int); + if(argValue < 0) + { //negative integer + *p++ = '-'; + reallen++; + argValue = -argValue; //need to have it positive + // most negative integer exception (avoid completely senseless (non digit) responses) + if(argValue < 0)argValue = 0; //we get -0 here + } + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argValue / 10; + *pNumBuf++ = argValue - (tmp * 10) + '0'; + } while((argValue = tmp)); + //copy now.... + argUValue = pNumBuf - numberBuffer; //length of the number string + if((allocsize - reallen) < (int)argUValue)INCREMENT_MEM_BY(argUValue) + do { *p++ = QChar(*--pNumBuf); } while(pNumBuf != numberBuffer); + reallen += argUValue; + continue; + } + case 'u': //unsigned integer + { + argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argUValue / 10; + *pNumBuf++ = argUValue - (tmp * 10) + '0'; + } while((argUValue = tmp)); + //copy now.... + argValue = pNumBuf - numberBuffer; //length of the number string + if((allocsize - reallen) < argValue)INCREMENT_MEM_BY(argValue) + do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer); + reallen += argValue; + continue; + } + case 'h': + case 'x': // hexadecimal unsigned integer + { + static char hexsmalldigits[]="0123456789abcdef"; + argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argUValue / 16; + *pNumBuf++ = hexsmalldigits[argUValue - (tmp * 16)]; + } while((argUValue = tmp)); + //copy now.... + argValue = pNumBuf - numberBuffer; //length of the number string + if((allocsize - reallen) < argValue)INCREMENT_MEM_BY(argValue) + do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer); + reallen += argValue; + continue; + } + case 'H': + case 'X': // hexadecimal unsigned integer + { + static char hexbigdigits[]="0123456789ABCDEF"; + argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argUValue / 16; + *pNumBuf++ = hexbigdigits[argUValue - (tmp * 16)]; + } while((argUValue = tmp)); + //copy now.... + argValue = pNumBuf - numberBuffer; //length of the number string + if((allocsize - reallen) < argValue)INCREMENT_MEM_BY(argValue) + do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer); + reallen += argValue; + continue; + } + default: //a normal percent followed by some char + { + *p++ = '%'; //write it + reallen++; + if(fmt->unicode()) + { + if(reallen == allocsize)INCREMENT_MEM + *p++ = *fmt; + reallen++; + } + continue; + } + } + } + + s.setUnicode(buffer,reallen); + kvi_free(buffer); + //s.squeeze(); + } + + + QString & sprintf(QString &s,const QString &szFmt,...) + { + kvi_va_list list; + kvi_va_start_by_reference(list,szFmt); + //print...with max 256 chars + KviQString::vsprintf(s,szFmt,list); + kvi_va_end(list); + return s; + } + + void appendFormatted(QString &s,const QString &szFmt,...) + { + QString tmp; + kvi_va_list list; + kvi_va_start_by_reference(list,szFmt); + //print...with max 256 chars + KviQString::vsprintf(tmp,szFmt,list); + kvi_va_end(list); + s.append(tmp); + } + + bool matchWildExpressionsCI(const QString &szM1,const QString &szM2) + { + //Matches two regular expressions containging wildcards (* and ?) + + // s1 + // m1 + // mask1 : *xor + // mask2 : xorand*xor + // m2 + // s2 + + // s2 + // m2 + // | + // XorT!xor@111.111.111.11 + // + // *!*@*.net + // | + // m1 + // s1 + // + +#ifdef COMPILE_USE_QT4 + const QChar * m1 = (const QChar *)szM1.constData(); + const QChar * m2 = (const QChar *)szM2.constData(); +#else + const QChar * m1 = (const QChar *)szM1.ucs2(); + const QChar * m2 = (const QChar *)szM2.ucs2(); +#endif + + if(!(m1 && m2 && (m1->unicode())))return false; + const QChar * savePos1 = 0; + const QChar * savePos2 = m2; + while(m1->unicode()) + { + //loop managed by m1 (initially first mask) + if(m1->unicode()=='*') + { + //Found a wildcard in m1 + savePos1 = ++m1; //move to the next char and save the position...this is our jolly + if(!savePos1->unicode())return true; //last was a wildcard , matches everything ahead... + savePos2 = m2+1; //next return state for the second string + continue; //and return + } + if(!m2->unicode())return false; //m2 finished and we had something to match here! +#ifdef COMPILE_USE_QT4 + if(m1->toLower()==m2->toLower()) +#else + if(m1->lower()==m2->lower()) +#endif + { + //chars matched + m1++; //Go ahead in the two strings + m2++; // + if((!(m1->unicode())) && m2->unicode() && savePos1) + { + //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)... + //retry matching the string following the * from the savePos2 (one char ahead last time) + m1 = savePos1; //back to char after wildcard + m2 = savePos2; //back to last savePos2 + savePos2++; //next savePos2 will be next char + } + } else { + if(m2->unicode() == '*') + { + //A wlidcard in the second string + //Invert the game : mask1 <-> mask2 + //mask2 now leads the game... + savePos1 = m1; //aux + m1 = m2; //...swap + m2 = savePos1; //...swap + savePos1 = m1; //sync save pos1 + savePos2 = m2 + 1; //sync save pos2 + continue; //...and again + } + // m1 != m2 , m1 != * , m2 != * + if((m1->unicode() == '?') || (m2->unicode() == '?')) + { + m1++; + m2++; + if((!(m1->unicode())) && m2->unicode() && savePos1) + { + //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)... + //retry matching the string following the * from the savePos2 (one char ahead last time) + m1 = savePos1; //back to char after wildcard + m2 = savePos2; //back to last savePos2 + savePos2++; //next savePos2 will be next char + } + } else { + if(savePos1) + { + //Have a jolly man...allow not matching... + m1 = savePos1; //go back to char after wildcard...need to rematch... + m2 = savePos2; //back to last savePos2 + savePos2++; //and set next savePos2 + } else return false; //No previous wildcards...not matched! + } + } + } + return (!(m2->unicode())); //m1 surely finished , so for the match , m2 must be finished too + } + + bool matchStringCI(const QString &szExp,const QString &szStr,bool bIsRegExp,bool bExact) + { + QString szWildcard; +#ifdef COMPILE_USE_QT4 + QChar* ptr=(QChar*)szExp.constData(); +#else + QChar* ptr=(QChar*)szExp.ucs2(); +#endif + if(!ptr) return 0; + while(ptr->unicode()) + { + if((ptr->unicode()=='[') || (ptr->unicode()==']')) + { + szWildcard.append("["); + szWildcard.append(*ptr); + szWildcard.append("]"); + } else { + szWildcard.append(*ptr); + } + ptr++; + } +#ifdef COMPILE_USE_QT4 + QRegExp re(szWildcard,Qt::CaseInsensitive,bIsRegExp ? QRegExp::RegExp : QRegExp::Wildcard); +#else + QRegExp re(szWildcard,false,!bIsRegExp); +#endif + if(bExact) return re.exactMatch(szStr); +#ifdef COMPILE_USE_QT4 + return re.indexIn(szStr) != -1; +#else + return re.search(szStr) != -1; +#endif + } + + bool matchStringCS(const QString &szExp,const QString &szStr,bool bIsRegExp,bool bExact) + { + QString szWildcard; +#ifdef COMPILE_USE_QT4 + QChar* ptr=(QChar*)szExp.constData(); +#else + QChar* ptr=(QChar*)szExp.ucs2(); +#endif + if(!ptr) return 0; + while(ptr->unicode()) + { + if((ptr->unicode()=='[')) // <-- hum ? + { + szWildcard.append("["); + szWildcard.append(*ptr); + szWildcard.append("]"); + } else { + szWildcard.append(*ptr); + } + ptr++; + } +#ifdef COMPILE_USE_QT4 + QRegExp re(szWildcard,Qt::CaseSensitive,bIsRegExp ? QRegExp::RegExp : QRegExp::Wildcard); +#else + QRegExp re(szWildcard,true,!bIsRegExp); +#endif + if(bExact) return re.exactMatch(szStr); +#ifdef COMPILE_USE_QT4 + return re.indexIn(szStr) != -1; +#else + return re.search(szStr) != -1; +#endif + } + + void cutFromFirst(QString &s,const QChar &c,bool bIncluded) + { +#ifdef COMPILE_USE_QT4 + int idx = s.indexOf(c); +#else + int idx = s.find(c); +#endif + if(idx == -1)return; + s.truncate(bIncluded ? idx : idx + 1); + } + + void cutFromLast(QString &s,const QChar &c,bool bIncluded) + { +#ifdef COMPILE_USE_QT4 + int idx = s.lastIndexOf(c); +#else + int idx = s.findRev(c); +#endif + if(idx == -1)return; + s.truncate(bIncluded ? idx : idx + 1); + } + + void cutToFirst(QString &s,const QChar &c,bool bIncluded,bool bClearIfNotFound) + { +#ifdef COMPILE_USE_QT4 + int idx = s.indexOf(c); +#else + int idx = s.find(c); +#endif + if(idx == -1) + { + if(bClearIfNotFound)s = ""; + return; + } + s.remove(0,bIncluded ? idx + 1 : idx); + } + + void cutToLast(QString &s,const QChar &c,bool bIncluded,bool bClearIfNotFound) + { +#ifdef COMPILE_USE_QT4 + int idx = s.lastIndexOf(c); +#else + int idx = s.findRev(c); +#endif + if(idx == -1) + { + if(bClearIfNotFound)s = ""; + return; + } + s.remove(0,bIncluded ? idx + 1 : idx); + } + + void cutFromFirst(QString &s,const QString &c,bool bIncluded) + { +#ifdef COMPILE_USE_QT4 + int idx = s.indexOf(c); +#else + int idx = s.find(c); +#endif + if(idx == -1)return; + s.truncate(bIncluded ? idx : idx + c.length()); + } + + void cutFromLast(QString &s,const QString &c,bool bIncluded) + { +#ifdef COMPILE_USE_QT4 + int idx = s.lastIndexOf(c); +#else + int idx = s.findRev(c); +#endif + if(idx == -1)return; + s.truncate(bIncluded ? idx : idx + c.length()); + } + + void cutToFirst(QString &s,const QString &c,bool bIncluded,bool bClearIfNotFound) + { +#ifdef COMPILE_USE_QT4 + int idx = s.indexOf(c); +#else + int idx = s.find(c); +#endif + if(idx == -1) + { + if(bClearIfNotFound)s = ""; + return; + } + s.remove(0,bIncluded ? idx + c.length() : idx); + } + + void cutToLast(QString &s,const QString &c,bool bIncluded,bool bClearIfNotFound) + { +#ifdef COMPILE_USE_QT4 + int idx = s.lastIndexOf(c); +#else + int idx = s.findRev(c); +#endif + if(idx == -1) + { + if(bClearIfNotFound)s = ""; + return; + } + s.remove(0,bIncluded ? idx + c.length() : idx); + } + + QString upperISO88591(const QString &szSrc) + { + const QChar * c = nullTerminatedArray(szSrc); + if(!c) + { + QString ret; + return ret; + } + QChar * buffer = (QChar *)kvi_malloc(sizeof(QChar) * szSrc.length()); + QChar * b = buffer; + unsigned short us = c->unicode(); + while(us) + { + if(us < 256) + *b=QChar((unsigned short)iso88591_toUpper_map[us]); + else + *b = *c; + c++; + b++; + us = c->unicode(); + } + QString ret(buffer,szSrc.length()); + kvi_free(buffer); + return ret; + } + + QString lowerISO88591(const QString &szSrc) + { + const QChar * c = nullTerminatedArray(szSrc); + if(!c) + { + QString ret; + return ret; + } + QChar * buffer = (QChar *)kvi_malloc(sizeof(QChar) * szSrc.length()); + QChar * b = buffer; + unsigned short us = c->unicode(); + while(us) + { + if(us < 256) + { + *b=QChar((unsigned short)iso88591_toLower_map[us]); + } else + *b = *c; + c++; + b++; + us = c->unicode(); + } + QString ret(buffer,szSrc.length()); + kvi_free(buffer); + return ret; + } + + void transliterate(QString &s,const QString &szToFind,const QString &szReplacement) + { + int i=0; + int il = MY_MIN(szToFind.length(),szReplacement.length()); + while(i < il) + { + int k=0; + int kl = s.length(); + while(k < kl) + { + if(s[k] == szToFind[i])s[k] = szReplacement[i]; + k++; + } + i++; + } + } + + static char hexdigits[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; + + void bufferToHex(QString &szRetBuffer,const unsigned char * buffer,unsigned int len) + { +#ifdef COMPILE_USE_QT4 + szRetBuffer.resize(len * 2); +#else + szRetBuffer.setLength(len * 2); +#endif + unsigned int i=0; + while(i < (len*2)) + { + szRetBuffer[int(i)] = QChar( (unsigned int) hexdigits[(*buffer) / 16] ); + i++; + szRetBuffer[int(i)] = QChar( (unsigned int)hexdigits[(*buffer) % 16] ); + i++; + buffer++; + } + } +}; diff --git a/src/kvilib/core/kvi_qstring.h b/src/kvilib/core/kvi_qstring.h new file mode 100644 index 00000000..c82063e9 --- /dev/null +++ b/src/kvilib/core/kvi_qstring.h @@ -0,0 +1,293 @@ +#ifndef _KVI_QSTRING_H_ +#define _KVI_QSTRING_H_ + +//============================================================================= +// +// File : kvi_qstring.h +// Creation date : Mon Aug 04 2003 13:36:33 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2003-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// +// Helper functions for the QString class +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_inttypes.h" +#include "kvi_stdarg.h" +#include "kvi_qcstring.h" + +#include <qstring.h> + +/// +/// \namespace KviQString +/// +/// \brief A namespace for QString helper functions +/// +/// This namespace contains several helper functions +/// that are used when dealing with QString. +/// +namespace KviQString +{ + extern KVILIB_API QString makeSizeReadable(size_t size); + extern KVILIB_API bool equalCS(const QString &sz1,const QString &sz2); + extern KVILIB_API bool equalCI(const QString &sz1,const QString &sz2); + extern KVILIB_API bool equalCS(const QString &sz1,const char * sz2); + extern KVILIB_API bool equalCI(const QString &sz1,const char * sz2); + // sz2 is assumed to be null terminated here! + extern KVILIB_API bool equalCI(const QString &sz1,const QChar * sz2); + inline bool equalCS(const char * sz1,const QString &sz2) + { return equalCS(sz2,sz1); }; + inline bool equalCI(const char * sz1,const QString &sz2) + { return equalCI(sz2,sz1); }; + // sz1 is assumed to be null terminated here! + inline bool equalCI(const QChar * sz1,const QString &sz2) + { return equalCI(sz2,sz1); }; + + extern KVILIB_API bool equalCSN(const QString &sz1,const QString &sz2,unsigned int len); + extern KVILIB_API bool equalCIN(const QString &sz1,const QString &sz2,unsigned int len); + extern KVILIB_API bool equalCSN(const QString &sz1,const char * sz2,unsigned int len); + extern KVILIB_API bool equalCIN(const QString &sz1,const char * sz2,unsigned int len); + // sz2 is assumed to be null terminated here! + extern KVILIB_API bool equalCIN(const QString &sz1,const QChar * sz2,unsigned int len); + inline bool equalCSN(const char * sz1,const QString &sz2,unsigned int len) + { return equalCSN(sz2,sz1,len); }; + inline bool equalCIN(const char * sz1,const QString &sz2,unsigned int len) + { return equalCIN(sz2,sz1,len); }; + // sz1 is assumed to be null terminated here! + inline bool equalCIN(const QChar * sz1,const QString &sz2,unsigned int len) + { return equalCIN(sz2,sz1,len); }; + + //note that greater here means that come AFTER in the alphabetic order + // return < 0 ---> str1 < str2 + // return = 0 ---> str1 = str2 + // return > 0 ---> str1 > str2 + extern KVILIB_API int cmpCI(const QString &sz1,const QString &sz2); + extern KVILIB_API int cmpCIN(const QString &sz1,const QString &sz2,unsigned int len); + extern KVILIB_API int cmpCS(const QString &sz1,const QString &sz2); + + extern KVILIB_API void detach(QString &sz); + + // this makes the QString sz appear as a null terminated array + // it MAY RETURN 0 when the QString is null! + extern KVILIB_API const QChar * nullTerminatedArray(const QString &sz); + + inline bool lastCharIs(QString &szString,const QChar &c) + { return szString.endsWith(c); }; + + extern KVILIB_API void ensureLastCharIs(QString &szString,const QChar &c); + + // wild expression matching + extern KVILIB_API bool matchWildExpressionsCI(const QString &szM1,const QString &szM2); + // wild or regexp matching + extern KVILIB_API bool matchStringCI(const QString &szExp,const QString &szStr,bool bIsRegExp = false,bool bExact = false); + extern KVILIB_API bool matchStringCS(const QString &szExp,const QString &szStr,bool bIsRegExp = false,bool bExact = false); + + extern KVILIB_API void vsprintf(QString &s,const QString &szFmt,kvi_va_list list); + extern KVILIB_API QString & sprintf(QString &s,const QString &szFmt,...); + extern KVILIB_API void stripRightWhiteSpace(QString &s); + extern KVILIB_API void stripLeft(QString &s,const QChar &c); + extern KVILIB_API void stripRight(QString &s,const QChar &c); + extern KVILIB_API void appendFormatted(QString &s,const QString &szFmt,...); + extern KVILIB_API void appendNumber(QString &s,double dReal); + extern KVILIB_API void appendNumber(QString &s,kvi_i64_t iInteger); + extern KVILIB_API void appendNumber(QString &s,int iInteger); + extern KVILIB_API void appendNumber(QString &s,unsigned int uInteger); + extern KVILIB_API void appendNumber(QString &s,kvi_u64_t uInteger); + + extern KVILIB_API void cutFromFirst(QString &s,const QChar &c,bool bIncluded = true); + extern KVILIB_API void cutFromLast(QString &s,const QChar &c,bool bIncluded = true); + extern KVILIB_API void cutToFirst(QString &s,const QChar &c,bool bIncluded = true,bool bClearIfNotFound = false); + extern KVILIB_API void cutToLast(QString &s,const QChar &c,bool bIncluded = true,bool bClearIfNotFound = false); + extern KVILIB_API void cutFromFirst(QString &s,const QString &c,bool bIncluded = true); + extern KVILIB_API void cutFromLast(QString &s,const QString &c,bool bIncluded = true); + extern KVILIB_API void cutToFirst(QString &s,const QString &c,bool bIncluded = true,bool bClearIfNotFound = false); + extern KVILIB_API void cutToLast(QString &s,const QString &c,bool bIncluded = true,bool bClearIfNotFound = false); + + extern KVILIB_API QString upperISO88591(const QString &szSrc); + extern KVILIB_API QString lowerISO88591(const QString &szSrc); + extern KVILIB_API QString getToken(QString &szString,const QChar &sep); + + extern KVILIB_API void transliterate(QString &s,const QString &szToFind,const QString &szReplacement); + + extern KVILIB_API void bufferToHex(QString &szRetBuffer,const unsigned char * buffer,unsigned int len); + + // a global empty string (note that this is ALSO NULL under Qt 3.x) + extern KVILIB_API const QString empty; + + /// + /// A portability wrapper which with Qt3 and Qt4. + /// Returns a lowcase version of the parameter string. + /// + inline QString toLower(const QString &s) + { +#ifdef COMPILE_USE_QT4 + return s.toLower(); +#else + return s.lower(); +#endif + } + + inline int find(const QString &s,QChar c,int index = 0,bool cs = true) + { +#ifdef COMPILE_USE_QT4 + return s.indexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive); +#else + return s.find(c,index,cs); +#endif + } + + inline int find(const QString &s,char c,int index = 0,bool cs = true) + { +#ifdef COMPILE_USE_QT4 + return s.indexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive); +#else + return s.find(c,index,cs); +#endif + } + + inline int find(const QString &s,const QString & str,int index = 0,bool cs = true) + { +#ifdef COMPILE_USE_QT4 + return s.indexOf(str,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive); +#else + return s.find(str,index,cs); +#endif + } + + inline int find(const QString &s,const QRegExp & rx,int index = 0) + { +#ifdef COMPILE_USE_QT4 + return s.indexOf(rx,index); +#else + return s.find(rx,index); +#endif + } + + inline int find(const QString &s,const char * str,int index = 0) + { +#ifdef COMPILE_USE_QT4 + return s.indexOf(QString(str),index); +#else + return s.find(str,index); +#endif + } + + inline int findRev(const QString &s,QChar c,int index = -1,bool cs = true) + { +#ifdef COMPILE_USE_QT4 + return s.lastIndexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive); +#else + return s.findRev(c,index,cs); +#endif + } + + inline int findRev(const QString &s,char c,int index = -1,bool cs = true) + { +#ifdef COMPILE_USE_QT4 + return s.lastIndexOf(c,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive); +#else + return s.findRev(c,index,cs); +#endif + } + + inline int findRev(const QString &s,const QString & str,int index = -1,bool cs = true) + { +#ifdef COMPILE_USE_QT4 + return s.lastIndexOf(str,index,cs ? Qt::CaseSensitive : Qt::CaseInsensitive); +#else + return s.findRev(str,index,cs); +#endif + } + + inline int findRev(const QString &s,const QRegExp & rx,int index = -1) + { +#ifdef COMPILE_USE_QT4 + return s.lastIndexOf(rx,index); +#else + return s.findRev(rx,index); +#endif + } + + inline int findRev(const QString &s,const char * str,int index = -1) + { +#ifdef COMPILE_USE_QT4 + return s.lastIndexOf(QString(str),index); +#else + return s.findRev(str,index); +#endif + } + + inline QString trimmed(const QString &s) + { +#ifdef COMPILE_USE_QT4 + return s.trimmed(); +#else + return s.stripWhiteSpace(); +#endif + } + + // WARNING: DO NOT USE CONSTRUCTS LIKE char * c = KviQString::toUtf8(something).data(); + // They are dangerous since with many compilers the returned string gets destroyed + // at the end of the instruction and the c pointer gets thus invalidated. + // Use + // KviQCString tmp = KviQString::toUtf8(something); + // char * c = tmp.data(); + // instead. + // Yes, I know that it sucks, but it's the only way to + // transit to qt 4.x more or less cleanly... + inline KviQCString toUtf8(const QString &s) + { +#ifdef COMPILE_USE_QT4 + return s.toUtf8(); +#else + return s.utf8(); +#endif + } + + inline KviQCString toLocal8Bit(const QString &s) + { + return s.local8Bit(); + } + + inline kvi_i64_t toI64(QString &szNumber,bool * bOk) + { +#if SIZEOF_LONG_INT == 8 + return szNumber.toLong(bOk); +#else + return szNumber.toLongLong(bOk); +#endif + } + + inline kvi_u64_t toU64(QString &szNumber,bool * bOk) + { +#if SIZEOF_LONG_INT == 8 + return szNumber.toULong(bOk); +#else + return szNumber.toULongLong(bOk); +#endif + } +}; + +// QT4SUX: Because QString::null is gone. QString() is SLOWER than QString::null since it invokes a constructor and destructor. + +#endif //!_KVI_QSTRING_H_ diff --git a/src/kvilib/core/kvi_strasm.h b/src/kvilib/core/kvi_strasm.h new file mode 100644 index 00000000..5d3b19ca --- /dev/null +++ b/src/kvilib/core/kvi_strasm.h @@ -0,0 +1,194 @@ +#ifndef _KVI_STRASM_H_ +#define _KVI_STRASM_H_ + +//============================================================================= +// +// File : kvi_strasm.h +// Creation date : Sun Jun 18 2000 18:38:26 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// +// Inline assembly implementations of the commonly used string functions +// These will work only on i386 based machines and can be compiled +// only by gcc +// +//============================================================================= + +extern inline bool kvi_strEqualCS(const char * str1,const char * str2) +{ + // An instruction pattern is really useful in this case. + // When inlining, GCC can optimize to load esi and edi + // directly with the strings , without pushing and getting it + // from the stack... + register bool eax; + __asm__ __volatile__ ( + " cld\n" + "1:\n" + " lodsb %%ds:(%%esi),%%al\n" + " scasb %%es:(%%edi),%%al\n" + " jne 2f\n" + " testb %%al,%%al\n" + " jne 1b\n" + " movl $0x1,%%eax\n" + " jmp 3f\n" + "2:\n" + " xorl %%eax,%%eax\n" + "3:" + : "=a" (eax), "=&S" (str1), "=&D" (str2) + : "1" (str1), "2" (str2) + ); + return eax; +} + +extern inline bool kvi_strEqualCSN(const char * str1,const char * str2,int len) +{ + register bool eax; + __asm__ __volatile__ ( + "1:\n" + " decl %3\n" + " js 2f\n" + " movb (%1),%%al\n" + " incl %1\n" + " cmpb %%al,(%2)\n" + " jne 3f\n" + " incl %2\n" + " testb %%al,%%al\n" + " jne 1b\n" + "2:\n" + " movl $0x1,%%eax\n" + " jmp 4f\n" + "3:\n" + " xorl %%eax,%%eax\n" + "4:\n" + : "=a" (eax), "=r" (str1), "=r" (str2), "=r" (len) + : "1" (str1), "2" (str2), "3" (len) + ); + return eax; +} + +// OPTIMIZATION +// The following two functions are used to compare a variable string with one in that +// only A-Z<->a-z case insensivity is significant. +// For example +// kvi_strEqualNoLocalCI("a string that does not contain any strange char",str2) +// will always give the correct result +// These will NOT work with localizable characters: +// 'a' with umlaut will be not equal to 'A' with umlaut + +extern inline bool kvi_strEqualNoLocaleCI(const char *str1,const char *str2) +{ + // Trivial implementation + // Ignores completely locales....only A-Z chars are transformed to a-z + // Anyway...it will work for IRC :) + register int reg; + register bool eax; + __asm__ __volatile__ ( + "1:\n" + " movb (%2),%%al\n" + " cmpb $65,%%al\n" + " jb 2f\n" + " cmpb $90,%%al\n" + " ja 2f\n" + " addb $32,%%al\n" + "2:\n" + " movb (%3),%b1\n" + " cmpb $65,%b1\n" + " jb 3f\n" + " cmpb $90,%b1\n" + " ja 3f\n" + " addb $32,%b1\n" + "3:\n" + " cmpb %%al,%b1\n" + " jne 4f\n" + " incl %2\n" + " incl %3\n" + " testb %%al,%%al\n" + " jne 1b\n" + " movl $1,%%eax\n" + " jmp 5f\n" + "4:\n" + " xorl %%eax,%%eax\n" + "5:\n" + : "=a" (eax), "=q" (reg), "=r" (str1), "=r" (str2) + : "2" (str1), "3" (str2) + ); + return eax; +} + +extern inline bool kvi_strEqualNoLocaleCIN(const char *str1,const char *str2,int len) +{ + + register int reg; + register bool eax; + __asm__ __volatile__ ( + "1:\n" + " decl %4\n" + " js 4f\n" + " movb (%2),%%al\n" + " cmpb $65,%%al\n" + " jb 2f\n" + " cmpb $90,%%al\n" + " ja 2f\n" + " addb $32,%%al\n" + "2:\n" + " movb (%3),%b1\n" + " cmpb $65,%b1\n" + " jb 3f\n" + " cmpb $90,%b1\n" + " ja 3f\n" + " addb $32,%b1\n" + "3:\n" + " cmpb %%al,%b1\n" + " jne 5f\n" + " incl %2\n" + " incl %3\n" + " testb %%al,%%al\n" + " jne 1b\n" + "4:\n" + " movl $1,%%eax\n" + " jmp 6f\n" + "5:\n" + " xorl %%eax,%%eax\n" + "6:\n" + : "=a" (eax), "=q" (reg), "=r" (str1), "=r" (str2), "=r" (len) + : "2" (str1), "3" (str2), "4" (len) + ); + return eax; +} + + +extern inline int kvi_strLen(const char * str) +{ + register int ecx; + __asm__ __volatile__( + " cld\n" + " repne\n" + " scasb\n" + " notl %0\n" + " decl %0" + : "=c" (ecx), "=&D" (str) + : "0" (0xffffffff), "1" (str), "a" (0) + ); + return ecx; +} + +#endif //_KVI_STRASM_H_ diff --git a/src/kvilib/core/kvi_string.cpp b/src/kvilib/core/kvi_string.cpp new file mode 100644 index 00000000..3f201352 --- /dev/null +++ b/src/kvilib/core/kvi_string.cpp @@ -0,0 +1,3063 @@ +//============================================================================= +// +// File : kvi_string.cpp +// Creation date : Fri Mar 19 1999 03:20:45 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#define _KVI_DEBUG_CHECK_RANGE_ +#include "kvi_debug.h" + +#define _KVI_STRING_CPP_ +#include "kvi_string.h" + +#include "kvi_memmove.h" +#include "kvi_malloc.h" + +#include "kvi_qstring.h" + +kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str) +{ + const kvi_wchar_t * ptr = str; + while(*ptr)ptr++; + return (ptr - str); +} + + +// %s = Latin1 char string (can't be null) +// %d = signed int (short,char) +// %u = unsigned int (short,char) +// %c = char value (kvi_wchar_t value) + +// %f = double value + +// %w = kvi_wchar_t string (can't be null) + +// %S = Latin1 KviStr pointer (#ifdef WSTRINGCONFIG_USE_KVISTR) : can't be NULL! +// %W = KviWStr pointer : can't be NULL! +// %Q = QString pointer : can't be NULL! + +#define _WSTRING_WMEMCPY(_dst,_src,_len) kvi_fastmoveodd((void *)(_dst),(const void *)(_src),sizeof(kvi_wchar_t) * (_len)) +#define _WSTRING_STRLEN(_str) kvi_strLen(_str) + +#define WVSNPRINTF_BODY \ +\ + register kvi_wchar_t *p; \ + long int argValue; \ + unsigned long argUValue; \ +\ + kvi_wchar_t numberBuffer[32]; \ + kvi_wchar_t *pNumBuf; \ + unsigned int tmp; \ +\ + for(p=buffer ; *fmt ; ++fmt) \ + { \ + if(len < 1)return (-1); \ +\ + if(*fmt != '%') \ + { \ + *p++ = *fmt; \ + --len; \ + continue; \ + } \ +\ + ++fmt; \ +\ + switch(*fmt) \ + { \ + case 's': \ + { \ + char * argString = kvi_va_arg(list,char *); \ + argValue = (int)_WSTRING_STRLEN(argString); \ + if(len <= argValue)return (-1); \ + while(*argString)*p++ = *argString++; \ + len -= argValue; \ + } \ + break; \ + case 'S': \ + { \ + KviStr * pString = kvi_va_arg(list,KviStr *); \ + char * argString = pString->ptr(); \ + if(len <= ((int)(pString->len())))return (-1); \ + while(*argString)*p++ = *argString++; \ + len -= pString->len(); \ + } \ + break; \ + case 'Q': \ + { \ + QString * pString = kvi_va_arg(list,QString *); \ + if(pString->length() > 0) \ + { \ + if(len <= ((int)(pString->length())))return (-1); \ + _WSTRING_WMEMCPY(p,pString->unicode(),pString->length()); \ + p += pString->length(); \ + len -= pString->length(); \ + } \ + } \ + break; \ + case 'd': \ + argValue = kvi_va_arg(list,int); \ + if(argValue < 0) \ + { \ + *p++ = '-'; \ + if(--len == 0)return (-1); \ + argValue = -argValue; \ + if(argValue < 0)argValue = 0; \ + } \ + pNumBuf = numberBuffer; \ + do { \ + tmp = argValue / 10; \ + *pNumBuf++ = argValue - (tmp * 10) + '0'; \ + } while((argValue = tmp)); \ + argUValue = pNumBuf - numberBuffer; \ + if(((unsigned int)len) <= argUValue)return (-1); \ + do { \ + *p++ = *--pNumBuf; \ + } while(pNumBuf != numberBuffer); \ + len -= argUValue; \ + break; \ + case 'u': \ + argUValue = kvi_va_arg(list,unsigned int); \ + pNumBuf = numberBuffer; \ + do { \ + tmp = argUValue / 10; \ + *pNumBuf++ = argUValue - (tmp * 10) + '0'; \ + } while((argUValue = tmp)); \ + argValue = pNumBuf - numberBuffer; \ + if(len <= argValue)return (-1); \ + do { \ + *p++ = *--pNumBuf; \ + } while(pNumBuf != numberBuffer); \ + len -= argValue; \ + break; \ + case 'f': \ + { \ + double dVal = (double)kvi_va_arg(list,double); \ + char sprintfBuffer[32]; \ + argValue = sprintf(sprintfBuffer,"%f",dVal); \ + if(len <= argValue)return (-1); \ + char * pSprintfBuffer = sprintfBuffer; \ + while(*pSprintfBuffer)*p++ = *pSprintfBuffer++; \ + len -= argValue; \ + } \ + break; \ + case 'c': \ + *p++ = (kvi_wchar_t)kvi_va_arg(list,int); \ + --len; \ + break; \ + default: \ + *p++ = '%'; \ + if(--len == 0)return (-1); \ + if(*fmt){ \ + *p++ = *fmt; \ + --len; \ + } \ + break; \ + } \ + continue; \ + } \ + if(len < 1)return (-1); \ + *p = 0; \ + return p-buffer; + +int kvi_wvsnprintcf(kvi_wchar_t *buffer,kvi_wslen_t len,const char *fmt,kvi_va_list list) +{ + WVSNPRINTF_BODY +} + +int kvi_wvsnprintf(kvi_wchar_t *buffer,kvi_wslen_t len,const kvi_wchar_t *fmt,kvi_va_list list) +{ + WVSNPRINTF_BODY +} + +bool kvi_qstringEqualCI(const QString &s1,const QString &s2) +{ + const QChar * p1 = s1.unicode(); + const QChar * p2 = s2.unicode(); + int l = s1.length() < s2.length() ? s1.length() : s2.length(); +#ifdef COMPILE_USE_QT4 + while(l-- && (p1->toLower() == p2->toLower()))p1++,p2++; +#else + while(l-- && (p1->lower() == p2->lower()))p1++,p2++; +#endif + if(l==-1)return true; + return false; +} + +bool kvi_matchStringCI(register const char * exp,register const char * str) +{ + // a + // . + // exp = a*x?mem*a + // str = arexoxmexamemizazv + // . + // n + const char * afterWild = 0; + const char * nextStrToCheck = 0; + + while(*exp) + { + if(*exp == '*') + { + // exp is a wildcard... + afterWild = ++exp; + nextStrToCheck = str + 1; + if(!(*exp))return true; // and it's the last char in the string: matches everything ahead + continue; + } + + if(!(*str))return false; // str finished but we had something to match :( + + if(tolower(*exp) == tolower(*str)) + { + // chars matched + ++exp; + ++str; + if((!(*exp)) && *str)goto check_recovery; + continue; + } + + if(*exp == '?') + { + // any-char wildcard + ++exp; + ++str; + continue; + } + +check_recovery: + // chars unmatched!!! + if(afterWild) + { + // we had a wildcard in exp... + // let's use this jolly then + exp = afterWild; + str = nextStrToCheck; + nextStrToCheck++; + // and try to compare now + continue; + } + + return false; // no match :( + } + return (!(*str)); +} + + +bool kvi_matchStringCS(register const char * exp,register const char * str) +{ + // a + // . + // exp = a*x?mem*a + // str = arexoxmexamemizazv + // . + // n + const char * afterWild = 0; + const char * nextStrToCheck = 0; + + while(*exp) + { + if(*exp == '*') + { + // exp is a wildcard... + afterWild = ++exp; + nextStrToCheck = str + 1; + if(!(*exp))return true; // and it's the last char in the string: matches everything ahead + continue; + } + + if(!(*str))return false; // str finished but we had something to match :( + + if(*exp == *str) + { + // chars matched + ++exp; + ++str; + if((!(*exp)) && *str)goto check_recovery; + continue; + } + + if(*exp == '?') + { + // any-char wildcard + ++exp; + ++str; + continue; + } + +check_recovery: + // chars unmatched!!! + if(afterWild) + { + // we had a wildcard in exp... + // let's use this jolly then + exp = afterWild; + str = nextStrToCheck; + nextStrToCheck++; + // and try to compare now + continue; + } + + return false; // no match :( + } + return (!(*str)); +} + + + +bool kvi_matchStringWithTerminator(register const char * exp,register const char * str,char terminator,const char ** r1,const char ** r2) +{ +#define NOT_AT_END(__str) (*__str && (*__str != terminator)) + + // a + // . + // exp = a*x?mem*a + // str = arexoxmexamemizazv + // . + // n + const char * afterWild = 0; + const char * nextStrToCheck = 0; + + while(NOT_AT_END(exp)) + { + if(*exp == '*') + { + // exp is a wildcard... + afterWild = ++exp; + nextStrToCheck = str + 1; + if(!(NOT_AT_END(exp))) + { + while(NOT_AT_END(str))str++; + *r1 = exp; + *r2 = str; + return true; // and it's the last char in the string: matches everything ahead + } + continue; + } + + if(!(*str))return false; // str finished but we had something to match :( + + if(tolower(*exp) == tolower(*str)) + { + // chars matched + ++exp; + ++str; + if((!(NOT_AT_END(exp))) && NOT_AT_END(str))goto check_recovery; + continue; + } + + if(*exp == '?') + { + // any-char wildcard + ++exp; + ++str; + continue; + } + +check_recovery: + // chars unmatched!!! + if(afterWild) + { + // we had a wildcard in exp... + // let's use this jolly then + exp = afterWild; + str = nextStrToCheck; + nextStrToCheck++; + // and try to compare now + continue; + } + + return false; // no match :( + } + *r1 = exp; + *r2 = str; + return (!(NOT_AT_END(str))); + +#undef NOT_AT_END +} + +bool kvi_matchWildExpr(register const char *m1,register const char *m2) +{ + //Matches two regular expressions containging wildcards (* and ?) + + // s1 + // m1 + // mask1 : *xor + // mask2 : xorand*xor + // m2 + // s2 + + // s2 + // m2 + // | + // XorT!xor@111.111.111.11 + // + // *!*@*.net + // | + // m1 + // s1 + // + + if(!(m1 && m2 && (*m1)))return false; + const char * savePos1 = 0; + const char * savePos2 = m2; + while(*m1) + { + //loop managed by m1 (initially first mask) + if(*m1=='*') + { + //Found a wildcard in m1 + savePos1 = ++m1; //move to the next char and save the position...this is our jolly + if(!*savePos1)return true; //last was a wildcard , matches everything ahead... + savePos2 = m2+1; //next return state for the second string + continue; //and return + } + if(!(*m2))return false; //m2 finished and we had something to match here! + if(tolower(*m1)==tolower(*m2)) + { + //chars matched + m1++; //Go ahead in the two strings + m2++; // + if((!(*m1)) && *m2 && savePos1) + { + //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)... + //retry matching the string following the * from the savePos2 (one char ahead last time) + m1 = savePos1; //back to char after wildcard + m2 = savePos2; //back to last savePos2 + savePos2++; //next savePos2 will be next char + } + } else { + if(*m2 == '*') + { + //A wlidcard in the second string + //Invert the game : mask1 <-> mask2 + //mask2 now leads the game... + savePos1 = m1; //aux + m1 = m2; //...swap + m2 = savePos1; //...swap + savePos1 = m1; //sync save pos1 + savePos2 = m2 + 1; //sync save pos2 + continue; //...and again + } + // m1 != m2 , m1 != * , m2 != * + if((*m1 == '?') || (*m2 == '?')) + { + m1++; + m2++; + if((!(*m1)) && *m2 && savePos1) + { + //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)... + //retry matching the string following the * from the savePos2 (one char ahead last time) + m1 = savePos1; //back to char after wildcard + m2 = savePos2; //back to last savePos2 + savePos2++; //next savePos2 will be next char + } + } else { + if(savePos1) + { + //Have a jolly man...allow not matching... + m1 = savePos1; //go back to char after wildcard...need to rematch... + m2 = savePos2; //back to last savePos2 + savePos2++; //and set next savePos2 + } else return false; //No previous wildcards...not matched! + } + } + } + return (!(*m2)); //m1 surely finished , so for the match , m2 must be finished too + +} + +/* + + WARNING: Don't remove: working code but actually unused in KVIrc + Later it might become useful + +bool kvi_matchWildExprCS(register const char *m1,register const char *m2) +{ + if(!(m1 && m2 && (*m1)))return false; + const char * savePos1 = 0; + const char * savePos2 = m2; + while(*m1){ //loop managed by m1 (initially first mask) + if(*m1=='*'){ + //Found a wildcard in m1 + savePos1 = ++m1; //move to the next char and save the position...this is our jolly + if(!*savePos1)return true; //last was a wildcard , matches everything ahead... + savePos2 = m2+1; //next return state for the second string + continue; //and return + } + if(!(*m2))return false; //m2 finished and we had something to match here! + if((*m1)==(*m2)){ + //chars matched + m1++; //Go ahead in the two strings + m2++; // + if((!(*m1)) && *m2 && savePos1){ + //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)... + //retry matching the string following the * from the savePos2 (one char ahead last time) + m1 = savePos1; //back to char after wildcard + m2 = savePos2; //back to last savePos2 + savePos2++; //next savePos2 will be next char + } + } else { + if(*m2 == '*'){ + //A wlidcard in the second string + //Invert the game : mask1 <-> mask2 + //mask2 now leads the game... + savePos1 = m1; //aux + m1 = m2; //...swap + m2 = savePos1; //...swap + savePos1 = m1; //sync save pos1 + savePos2 = m2 + 1; //sync save pos2 + continue; //...and again + } + if(savePos1){ //Have a jolly man...allow not matching... + m1 = savePos1; //go back to char after wildcard...need to rematch... + m2 = savePos2; //back to last savePos2 + savePos2++; //and set next savePos2 + } else return false; //No previous wildcards...not matched! + } + } + return (!(*m2)); //m1 surely finished , so for the match , m2 must be finished too + +} +*/ + +bool kvi_matchWildExprWithTerminator(register const char *m1,register const char *m2,char terminator, + const char ** r1,const char ** r2) +{ + //Matches two regular expressions containging wildcards + +#define NOT_AT_END(__str) (*__str && (*__str != terminator)) + + bool bSwapped = false; + if(!(m1 && m2 && (NOT_AT_END(m1))))return false; + const char * savePos1 = 0; + const char * savePos2 = m2; + while(NOT_AT_END(m1)) + { + //loop managed by m1 (initially first mask) + if(*m1=='*') + { + //Found a wildcard in m1 + savePos1 = ++m1; //move to the next char and save the position...this is our jolly + if(!NOT_AT_END(savePos1)) + { + //last was a wildcard , matches everything ahead... + while(NOT_AT_END(m2))m2++; + *r1 = bSwapped ? m2 : m1; + *r2 = bSwapped ? m1 : m2; + return true; + } + savePos2 = m2+1; //next return state for the second string + continue; //and return + } + if(!NOT_AT_END(m2))return false; //m2 finished and we had something to match here! + if(tolower(*m1)==tolower(*m2)) + { + //chars matched + m1++; //Go ahead in the two strings + m2++; // + if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1) + { + //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)... + //retry matching the string following the * from the savePos2 (one char ahead last time) + m1 = savePos1; //back to char after wildcard + m2 = savePos2; //back to last savePos2 + savePos2++; //next savePos2 will be next char + } + } else { + if(*m2 == '*') + { + //A wlidcard in the second string + //Invert the game : mask1 <-> mask2 + //mask2 now leads the game... + bSwapped = !bSwapped; + savePos1 = m1; //aux + m1 = m2; //...swap + m2 = savePos1; //...swap + savePos1 = m1; //sync save pos1 + savePos2 = m2 + 1; //sync save pos2 + continue; //...and again + } + // m1 != m2 , m1 != * , m2 != * + if((*m1 == '?') || (*m2 == '?')) + { + m1++; + m2++; + if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1) + { + //m1 finished , but m2 not yet and we have a savePosition for m1 (there was a wildcard)... + //retry matching the string following the * from the savePos2 (one char ahead last time) + m1 = savePos1; //back to char after wildcard + m2 = savePos2; //back to last savePos2 + savePos2++; //next savePos2 will be next char + } + } else { + if(savePos1) + { + //Have a jolly man...allow not matching... + m1 = savePos1; //go back to char after wildcard...need to rematch... + m2 = savePos2; //back to last savePos2 + savePos2++; //and set next savePos2 + } else return false; //No previous wildcards...not matched! + } + } + } + *r1 = bSwapped ? m2 : m1; + *r2 = bSwapped ? m1 : m2; + + return (!NOT_AT_END(m2)); //m1 surely finished , so for the match , m2 must be finished too + +#undef NOT_AT_END +} + + + +const char * kvi_extractToken(KviStr &str,const char *aux_ptr,char sep) +{ + __range_valid(aux_ptr); + while(*aux_ptr && (*aux_ptr == sep))aux_ptr++; + const char *p=aux_ptr; + while(*p && (*p != sep))p++; + str.m_len=p-aux_ptr; + str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1); + kvi_fastmove(str.m_ptr,aux_ptr,str.m_len); + *(str.m_ptr+str.m_len)='\0'; + while(*p && (*p == sep))p++; + return p; +} + +const char * kvi_extractUpTo(KviStr &str,const char *aux_ptr,char sep) +{ + __range_valid(aux_ptr); + const char *p=aux_ptr; + while(*p && (*p != sep))p++; + str.m_len=p-aux_ptr; + str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1); + kvi_fastmove(str.m_ptr,aux_ptr,str.m_len); + *(str.m_ptr+str.m_len)='\0'; + return p; +} + +int kvi_vsnprintf(char *buffer,int len,const char *fmt,kvi_va_list list) +{ + __range_valid(fmt); + __range_valid(buffer); + __range_valid(len > 0); //printing 0 characters is senseless + + register char *p; + char *argString; + long argValue; + unsigned long argUValue; + + //9999999999999999999999999999999\0 + char numberBuffer[32]; //enough ? 10 is enough for 32bit unsigned int... + char *pNumBuf; + unsigned int tmp; + + + for(p=buffer ; *fmt ; ++fmt) + { + if(len < 1)return (-1); //not enough space ... (in fact this could be len < 2 for the terminator) + //copy up to a '%' + if(*fmt != '%') + { + *p++ = *fmt; + --len; + continue; + } + + ++fmt; //skip this '%' + switch(*fmt) + { + case 's': //string + argString = kvi_va_arg(list,char *); + if(!argString)continue; + argValue = (long)strlen(argString); + //check for space... + if(len <= argValue)return (-1); //not enough space for buffer and terminator + while(*argString)*p++ = *argString++; + len -= argValue; + continue; + case 'd': //signed integer + argValue = kvi_va_arg(list,int); + if(argValue < 0){ //negative integer + *p++ = '-'; + if(--len == 0)return (-1); + argValue = -argValue; //need to have it positive + // most negative integer exception (avoid completely senseless (non digit) responses) + if(argValue < 0)argValue = 0; //we get -0 here + } + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argValue / 10; + *pNumBuf++ = argValue - (tmp * 10) + '0'; + } while((argValue = tmp)); + //copy now.... + argUValue = pNumBuf - numberBuffer; //length of the number string + if(((uint)len) <= argUValue)return (-1); //not enough space for number and terminator + do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer); + len -= argUValue; + continue; + case 'u': //unsigned integer + argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argUValue / 10; + *pNumBuf++ = argUValue - (tmp * 10) + '0'; + } while((argUValue = tmp)); + //copy now.... + argValue = pNumBuf - numberBuffer; //length of the number string + if(len <= argValue)return (-1); //not enough space for number and terminator + do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer); + len -= argValue; + continue; + case 'c': //char + // + // I'm not sure about this... + // In the linux kernel source the + // unsigned char is extracted from an integer type. + // We assume that gcc stacks a char argument + // as sizeof(int) bytes value. + // Is this always true ? + // + *p++ = (char)kvi_va_arg(list,int); + --len; + continue; + case 'Q': // QString! (this should almost never happen) + { + QString * s = kvi_va_arg(list,QString *); + KviQCString cs = KviQString::toUtf8(*s); + const char * t = cs.data(); + if(!t)continue; // nothing to do + //check for space... + if(len <= (int)cs.length())return (-1); //not enough space for buffer and terminator + while(*t)*p++ = *t++; + len -= cs.length(); + continue; + } + default: //a normal percent + *p++ = '%'; //write it + if(--len == 0)return (-1); //not enough space for next char or terminator + if(*fmt){ //this if is just in case that we have a % at the end of the string. + *p++ = *fmt; //and write this char + --len; + } + continue; + } + } + if(len < 1)return (-1); //missing space for terminator + *p = '\0'; + return p-buffer; +} + +// +// Nearly the same as the above function... +// + +int kvi_irc_vsnprintf(char *buffer,const char *fmt,kvi_va_list list,bool *bTruncated) +{ + __range_valid(fmt); + __range_valid(buffer); + if( !( buffer && fmt) ) return false; + register char *p; + char *argString; + long argValue; + unsigned long argUValue; + char numberBuffer[64]; //enough ? 10 is enough for 32bit unsigned int... + char *pNumBuf; + unsigned int tmp; + *bTruncated = false; + int len = 512; + + for (p=buffer ; *fmt ; ++fmt) { + if(len < 3)goto truncate; + //copy up to a '%' + if (*fmt != '%') { + *p++ = *fmt; + --len; + continue; + } + ++fmt; //skip this '%' + switch(*fmt){ + case 's': //string + argString = kvi_va_arg(list,char *); + if(!argString)continue; + //check for space... + while(*argString){ + *p++ = *argString++; + if(--len < 3)goto truncate; + } + continue; + case 'Q': // QString! (this should almost never happen) + { + QString * s = kvi_va_arg(list,QString *); + KviQCString cs = KviQString::toUtf8(*s); + const char * t = cs.data(); + if(!t)continue; // nothing to do + while(*t) + { + *p++ = *t++; + if(--len < 3)goto truncate; + } + continue; + } + case 'd': //signed integer + argValue = kvi_va_arg(list,int); + if(argValue < 0){ //negative integer + *p++ = '-'; + if(--len < 3)goto truncate; //place just for CRLF + argValue = -argValue; //need to have it positive + if(argValue < 0)argValue = 0; // -0 (hack the exception) + } + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argValue / 10; + *pNumBuf++ = argValue - (tmp * 10) + '0'; + } while((argValue = tmp)); + //copy now.... + do { + *p++ = *--pNumBuf; + if(--len < 3)goto truncate; + } while(pNumBuf != numberBuffer); + continue; + case 'u': //unsigned integer + argUValue = kvi_va_arg(list,unsigned int); //many implementations place int here + //write the number in a temporary buffer + pNumBuf = numberBuffer; + do { + tmp = argUValue / 10; + *pNumBuf++ = argUValue - (tmp * 10) + '0'; + } while((argUValue = tmp)); + //copy now.... + if(--len < 3)goto truncate; //no place for digits + do { + *p++ = *--pNumBuf; + if(--len < 3)goto truncate; + } while(pNumBuf != numberBuffer); + continue; + case 'c': //char + *p++ = (char)kvi_va_arg(list,int); + --len; + continue; + default: //a normal percent + *p++ = '%'; //write it + if(--len < 3)goto truncate; //not enough space for next char + if(*fmt){ //this if is just in case that we have a % at the end of the string. + *p++ = *fmt; //and write this char + --len; + } + continue; + } + } + //succesfull finish + __range_valid(len >= 2); + *p++ = '\r'; + *p = '\n'; + return ((p-buffer)+1); +truncate: + __range_valid(len >= 2); + *bTruncated = true; + *p++ = '\r'; + *p = '\n'; + return ((p-buffer)+1); +} + +#ifndef COMPILE_ix86_ASM + +bool kvi_strEqualCS(const char *str1,const char *str2) +{ + __range_valid(str1); + __range_valid(str2); + if( !( str1 && str2 ) ) return false; + register unsigned char *s1 = (unsigned char *)str1; + register unsigned char *s2 = (unsigned char *)str2; + while(*s1)if(*s1++ != *s2++)return false; + return (*s1 == *s2); +} + +bool kvi_strEqualCSN(const char *str1,const char *str2,int len) +{ + __range_valid(str1); + __range_valid(str2); + __range_valid(len >= 0); + if( !( str1 && str2 && (len >= 0) ) ) return false; + register unsigned char *s1 = (unsigned char *)str1; + register unsigned char *s2 = (unsigned char *)str2; + while(len-- && *s1)if(*s1++ != *s2++)return false; + return (len < 0); +} + +#endif + +bool kvi_strEqualCIN(const char *str1,const char *str2,int len) +{ + __range_valid(str1); + __range_valid(str2); + __range_valid(len >= 0); + if( !( str1 && str2 && (len >= 0) ) ) return false; + register unsigned char *s1 = (unsigned char *)str1; + register unsigned char *s2 = (unsigned char *)str2; + while(len-- && *s1)if(tolower(*s1++) != tolower(*s2++))return false; + return (len < 0); +} + +bool kvi_strEqualCI(const char *str1,const char *str2) +{ + __range_valid(str1); + __range_valid(str2); + if( !( str1 && str2) ) return false; + register unsigned char *s1 = (unsigned char *)str1; + register unsigned char *s2 = (unsigned char *)str2; + while(*s1)if(tolower(*s1++) != tolower(*s2++))return false; + return (*s1 == *s2); +} + +//note that greater here means that come AFTER in the alphabetic order +// return < 0 ---> str1 < str2 +// return = 0 ---> str1 = str2 +// return > 0 ---> str1 > str2 +int kvi_strcmpCI(const char *str1,const char *str2) +{ + //abcd abce + __range_valid(str1); + __range_valid(str2); + if( !( str1 && str2) ) return false; + register unsigned char *s1 = (unsigned char *)str1; + register unsigned char *s2 = (unsigned char *)str2; + int diff; + unsigned char rightchar; + while(!(diff=(rightchar=tolower(*s1++)) - tolower(*s2++)))if(!rightchar)break; + return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1 +} + +// +////note that greater here means that come AFTER in the alphabetic order +//// return < 0 ---> str1 < str2 +//// return = 0 ---> str1 = str2 +//// return > 0 ---> str1 > str2 +//int kvi_strcmpCIN(const char *str1,const char *str2,int len) +//{ +// //abcd abce +// __range_valid(str1); +// __range_valid(str2); +// register unsigned char *s1 = (unsigned char *)str1; +// register unsigned char *s2 = (unsigned char *)str2; +// int diff; +// unsigned char rightchar; +// while(len--) +// { +// if(!(diff=(rightchar=tolower(*s1++)) - tolower(*s2++)))break; +// if(!rightchar)break; +// } +// return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1 +//} + +int kvi_strcmpCS(const char *str1,const char *str2) +{ + //abcd abce + __range_valid(str1); + __range_valid(str2); + if( !( str1 && str2) ) return false; + register unsigned char *s1 = (unsigned char *)str1; + register unsigned char *s2 = (unsigned char *)str2; + int diff; + while(!(diff=(*s1)-(*s2++)))if(!*s1++)break; + return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1 +} + +int kvi_strMatchRevCS(const char *str1, const char *str2, int index) +{ + __range_valid(str1); + __range_valid(str2); + if( !( str1 && str2) ) return false; + register char *s1=(char *)str1; + register char *s2=(char *)str2; + + int curlen=(int)strlen(str1); + int diff; + + if (index<0 || index >= curlen) index = curlen-1; + + s1+=index; + while (*s2) s2++; + s2--; + + // now start comparing + while (1){ + /* in this case, we have str1 = "lo" and str2 = "hello" */ + if (s1<str1 && !(s2<str2)) return 256; + if (s2<str2) return 0; + if ((diff=(*s1)-(*s2))) return diff; + s1--; + s2--; + } +} + +KviStr::KviStr() +{ + m_ptr = (char *)kvi_malloc(1); + *m_ptr = '\0'; + m_len = 0; +} + +KviStr::KviStr(const char *str) +{ + //Deep copy constructor + if(str){ + //Deep copy + m_len = (int)strlen(str); + m_ptr = (char *)kvi_malloc(m_len+1); + kvi_fastmove(m_ptr,str,m_len+1); + } else { + m_ptr = (char *)kvi_malloc(1); + *m_ptr = '\0'; + m_len = 0; + } +} + +KviStr::KviStr(const KviQCString &str) +{ + //Deep copy constructor + if(str.data()) + { + //Deep copy + m_len = str.length(); + m_ptr = (char *)kvi_malloc(m_len+1); + kvi_fastmove(m_ptr,str,m_len+1); + } else { + m_ptr = (char *)kvi_malloc(1); + *m_ptr = '\0'; + m_len = 0; + } +} + + +KviStr::KviStr(const char *str,int len) +{ + __range_valid(str); + //__range_valid(len <= ((int)strlen(str))); <-- we trust the user here (and a strlen() call may run AFTER len if data is not null terminated) + __range_valid(len >= 0); + m_len = len; + m_ptr = (char *)kvi_malloc(m_len+1); + kvi_fastmove(m_ptr,str,m_len); + *(m_ptr+m_len) = '\0'; +} + +KviStr::KviStr(const char *bg,const char *end) +{ + __range_valid(bg); + __range_valid(end); + __range_valid(bg <= end); + m_len = end-bg; + m_ptr = (char *)kvi_malloc(m_len +1); + kvi_fastmove(m_ptr,bg,m_len); + *(m_ptr + m_len)='\0'; +} + +KviStr::KviStr(KviFormatConstructorTag tag,const char *fmt,...) +{ + m_ptr=(char *)kvi_malloc(256); + //First try + kvi_va_list list; + kvi_va_start(list,fmt); + //print...with max 256 chars + m_len=kvi_vsnprintf(m_ptr,256,fmt,list); + kvi_va_end(list); + + //check if we failed + if(m_len < 0){ + //yes , failed.... + int dummy=256; + do{ //we failed , so retry with 256 more chars + dummy+=256; + //realloc + m_ptr=(char *)kvi_realloc(m_ptr,dummy); + //print... + kvi_va_start(list,fmt); + m_len=kvi_vsnprintf(m_ptr,dummy,fmt,list); + kvi_va_end(list); + } while(m_len < 0); + } + //done... + //now m_len is the length of the written string not including the terminator... + //perfect! :) + m_ptr=(char *)kvi_realloc(m_ptr,m_len+1); +} + +KviStr::KviStr(const KviStr &str) +{ + __range_valid(str.m_ptr); + m_len = str.m_len; + m_ptr = (char *)kvi_malloc(m_len+1); + kvi_fastmove(m_ptr,str.m_ptr,m_len+1); +} + +KviStr::KviStr(const QString &str) +{ + KviQCString sz = KviQString::toUtf8(str); + if(sz.length() > 0) + { + m_len = sz.length(); + m_ptr = (char *)kvi_malloc(m_len+1); + kvi_fastmove(m_ptr,sz.data(),m_len+1); + } else { + m_ptr = (char *)kvi_malloc(1); + *m_ptr = '\0'; + m_len = 0; + } +} + +KviStr::KviStr(char c,int fillLen) +{ + __range_valid(fillLen >= 0); + m_len = fillLen; + m_ptr = (char *)kvi_malloc(m_len+1); + register char *p=m_ptr; + while(fillLen--)*p++=c; + *p='\0'; +} + + +KviStr::KviStr(const kvi_wchar_t * unicode) +{ + if(!unicode) + { + m_len = 0; + m_ptr = (char *)kvi_malloc(1); + *m_ptr = 0; + } else { + m_len = kvi_wstrlen(unicode); + m_ptr = (char *)kvi_malloc(m_len + 1); + register char * p = m_ptr; + while(*unicode)*p++ = *unicode++; + *p = 0; + } +} + +KviStr::KviStr(const kvi_wchar_t * unicode,int len) +{ + m_len = len; + m_ptr = (char *)kvi_malloc(m_len + 1); + register char * p = m_ptr; + char * end = p + len; + while(p != end) + { + *p++ = *unicode++; + } + *p = 0; +} + + + + +KviStr::~KviStr() +{ + kvi_free(m_ptr); +} + +void KviStr::setLength(int iLen) +{ + __range_valid(iLen >= 0); + m_len = iLen; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + *(m_ptr + m_len) = '\0'; +} + +KviStr & KviStr::operator=(const KviStr &str) +{ + __range_valid(str.m_ptr); + __range_valid(str.m_ptr != m_ptr); + m_len = str.m_len; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + kvi_fastmove(m_ptr,str.m_ptr,m_len+1); + return (*this); +} + +KviStr & KviStr::operator=(const KviQCString &str) +{ + m_len = str.length(); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + if(str.data())kvi_fastmove(m_ptr,str.data(),m_len+1); + else *m_ptr = 0; + return (*this); +} + +KviStr & KviStr::operator=(const char *str) +{ + //__range_valid(str); + if(str){ + m_len = (int)strlen(str); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + kvi_memmove(m_ptr,str,m_len+1); + } else { + m_ptr = (char *)kvi_realloc(m_ptr,1); + *m_ptr = '\0'; + m_len = 0; + } + return (*this); +} + +void KviStr::clear() +{ + m_ptr = (char *)kvi_realloc(m_ptr,1); + *m_ptr = '\0'; + m_len = 0; +} + + +bool KviStr::hasNonWhiteSpaceData() const +{ + const char * aux = m_ptr; + while(*aux) + { + if(((*aux) != ' ') && ((*aux) != '\t'))return true; + aux++; + } + return false; +} + +static char hexdigits[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; + +void KviStr::bufferToHex(const char *buffer,int len) +{ + __range_valid(buffer); + m_len = (len * 2); + m_ptr = (char *)kvi_realloc(m_ptr,m_len + 1); + char * aux = m_ptr; + while(len) + { + *aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) / 16)]; + aux++; + *aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) % 16)]; + aux++; + len--; + buffer++; + } + *(m_ptr+m_len) = '\0'; +} + + + +static char get_decimal_from_hex_digit_char(char dgt) +{ + if((dgt >= '0') && (dgt <= '9'))return (dgt - '0'); + if((dgt >= 'A') && (dgt <= 'F'))return (10 + (dgt - 'A')); + if((dgt >= 'a') && (dgt <= 'f'))return (10 + (dgt - 'a')); + return -1; +} + +// This is just error-correcting...it treats non hex stuff as zeros +/* +static inline char get_decimal_from_hex_digit_char(char dgt) +{ + char c = pedantic_get_decimal_from_hex_digit(dgt); + if(c == -1)return 0; + return c; +} + +int KviStr::hexToBuffer(char ** buffer,bool bNullToNewlines) +{ + int len; + if(m_len % 2)len = (m_len / 2) + 1; + else len = (m_len / 2); + *buffer = (char *)kvi_malloc(len); + + char * ptr = *buffer; + + char * aux = m_ptr; + while(*aux) + { + *ptr = get_decimal_from_hex_digit_char(*aux) * 16; + aux++; + if(*aux) + { + *ptr += get_decimal_from_hex_digit_char(*aux); + aux++; + } + if(bNullToNewlines)if(!(*ptr))*ptr = '\n'; + ptr++; + } + return len; +} +*/ + +int KviStr::hexToBuffer(char ** buffer,bool bNullToNewlines) +{ + *buffer = 0; + if((m_len == 0) || (m_len & 1))return -1; // this is an error + int len = (m_len / 2); + if(len < 1)return -1; + *buffer = (char *)kvi_malloc(len); + + char * ptr = *buffer; + char * aux = m_ptr; + + char aux2; + + while(*aux) + { + *ptr = get_decimal_from_hex_digit_char(*aux) * 16; + if(*ptr == -1) + { + kvi_free(*buffer); + *buffer = 0; + return -1; + } + aux++; + aux2 = get_decimal_from_hex_digit_char(*aux); + if(aux2 == -1) + { + kvi_free(*buffer); + *buffer = 0; + return -1; + } + *ptr += aux2; + aux++; + if(bNullToNewlines)if(!(*ptr))*ptr = '\n'; + ptr++; + } + return len; +} + +static const char * base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +void KviStr::bufferToBase64(const char * buffer,int len) +{ + m_len = (len / 3) << 2; + if(len % 3)m_len += 4; + + m_ptr = (char *)kvi_realloc(m_ptr,m_len + 1); + + unsigned char aux1,aux2,aux3; + char * aux_ptr = m_ptr; + while(len > 2) + { + aux1 = (unsigned char)*buffer++; + aux2 = (unsigned char)*buffer++; + aux3 = (unsigned char)*buffer++; + *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2]; + *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)]; + *aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2) | ((aux3 & 0xC0) >> 6)]; + *aux_ptr++ = base64_chars[(aux3 & 0x3F)]; + len -= 3; + } + switch(len) + { + case 2: + aux1 = (unsigned char)*buffer++; + aux2 = (unsigned char)*buffer++; + *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2]; + *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)]; + *aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2)]; + *aux_ptr++ = '='; + break; + case 1: + aux1 = (unsigned char)*buffer++; + aux2 = (unsigned char)*buffer++; + *aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2]; + *aux_ptr++ = base64_chars[((aux1 & 0x03) << 4)]; + *aux_ptr++ = '='; + *aux_ptr++ = '='; + break; + } + *aux_ptr = 0; +} + +static unsigned char get_base64_idx(char base64) +{ + if((base64 >= 'A') && (base64 <= 'Z'))return (base64 - 'A'); + if((base64 >= 'a') && (base64 <= 'z'))return ((base64 - 'a') + 26); + if((base64 >= '0') && (base64 <= '9'))return ((base64 - '0') + 52); + if(base64 == '+')return 62; + if(base64 == '/')return 63; + if(base64 == '=')return 64; + return 65; +} + + +int KviStr::base64ToBuffer(char ** buffer,bool bNullToNewlines) +{ + *buffer = 0; + if((m_len == 0) || (m_len & 3))return -1; // this is an error + int len = (m_len >> 2) * 3; + *buffer = (char *)kvi_malloc(len); + + char * auxBuf = *buffer; + + unsigned char aux1,aux2,aux3,aux4; + char * aux_ptr = m_ptr; + + int newLen = len; + + while(*aux_ptr) + { + if(newLen != len) + { + // ops... there was a padding and we still have chars after it + // this is an error + kvi_free(*buffer); + *buffer = 0; + return -1; + } + aux1 = get_base64_idx(*aux_ptr++); + aux2 = get_base64_idx(*aux_ptr++); + aux3 = get_base64_idx(*aux_ptr++); + aux4 = get_base64_idx(*aux_ptr++); + if((aux3 > 64) || (aux4 > 64)) + { + // error + kvi_free(*buffer); + *buffer = 0; + return -1; + } + if((aux1 | aux2) > 63) + { + // again error...impossible padding + kvi_free(*buffer); + *buffer = 0; + return -1; + } + if(aux4 == 64) + { + if(aux3 == 64) + { + // Double padding, only one digit here + *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4)); + newLen -= 2; + } else { + // Single padding, two digits here + *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4)); // >> 4 is a shr , not a ror! :) + *auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2)); + newLen -= 1; + } + } else { + if(aux3 == 64) + { + // error... impossible padding + kvi_free(*buffer); + *buffer = 0; + return -1; + } else { + // Ok , no padding, three digits here + *auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4)); + *auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2)); + *auxBuf++ = (char)((aux3 << 6) | aux4); + } + } + } + + if(newLen != len)*buffer = (char *)kvi_realloc(*buffer,newLen); + return newLen; +} + +KviStr & KviStr::setStr(const char *str,int len) +{ + if(!str) + { + clear(); + return *this; + } + int alen = (int)strlen(str); + if((len < 0) || (len > alen))m_len = alen; + else m_len = len; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + kvi_memmove(m_ptr,str,m_len); + *(m_ptr+m_len) = '\0'; + return (*this); +} + +KviStr & KviStr::operator=(const QString &str) +{ + KviQCString sz = KviQString::toUtf8(str); + if(sz.length() > 0){ + m_len = sz.length(); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + kvi_fastmove(m_ptr,sz.data(),m_len+1); + } else { + m_ptr = (char *)kvi_realloc(m_ptr,1); + *m_ptr = '\0'; + m_len = 0; + } + return (*this); +} + +KviStr & KviStr::operator=(char c) +{ + m_len = 1; + m_ptr = (char *)kvi_realloc(m_ptr,2); + *m_ptr = c; + *(m_ptr+1)='\0'; + return (*this); +} + +void KviStr::append(char c) +{ + m_ptr = (char *)kvi_realloc(m_ptr,m_len+2); + *(m_ptr+m_len)=c; + m_len++; + *(m_ptr+m_len)='\0'; +} + +void KviStr::append(const KviStr &str) +{ + __range_valid(str.m_ptr); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+str.m_len+1); + kvi_fastmove((m_ptr+m_len),str.m_ptr,str.m_len+1); + m_len += str.m_len; +} + +void KviStr::append(const char *str) +{ + if(!str)return; + int len = (int)strlen(str); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1); + kvi_fastmove((m_ptr+m_len),str,len+1); + m_len += len; +} + +void KviStr::append(const QString &str) +{ + KviQCString sz = KviQString::toUtf8(str); + if(sz.length() < 1)return; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+sz.length()+1); + kvi_fastmove((m_ptr+m_len),sz.data(),sz.length()+1); + m_len += sz.length(); +} + +void KviStr::append(const char *str,int len) +{ + __range_valid(str); +// __range_valid(len <= ((int)strlen(str))); + __range_valid(len >= 0); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1); + kvi_fastmove((m_ptr+m_len),str,len); + m_len += len; + *(m_ptr + m_len)='\0'; +} + +void KviStr::append(KviFormatConstructorTag tag,const char *fmt,...) +{ + int auxLen; + m_ptr=(char *)kvi_realloc(m_ptr,m_len + 256); + //First try + kvi_va_list list; + kvi_va_start(list,fmt); + //print...with max 256 chars + auxLen =kvi_vsnprintf(m_ptr + m_len,256,fmt,list); + kvi_va_end(list); + + //check if we failed + if(auxLen < 0){ + //yes , failed.... + int dummy=256; + do{ //we failed , so retry with 256 more chars + dummy+=256; + //realloc + m_ptr=(char *)kvi_realloc(m_ptr,m_len + dummy); + //print... + kvi_va_start(list,fmt); + auxLen=kvi_vsnprintf(m_ptr + m_len,dummy,fmt,list); + kvi_va_end(list); + } while(auxLen < 0); + } + m_len += auxLen; + //done... + //now m_len is the length of the written string not including the terminator... + //perfect! :) + m_ptr=(char *)kvi_realloc(m_ptr,m_len+1); +} + +void KviStr::extractFromString(const char *begin,const char *end) +{ + __range_valid(begin); + __range_valid(end); + __range_valid(end >= begin); + m_len = end-begin; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + kvi_fastmove(m_ptr,begin,m_len); + *(m_ptr + m_len)='\0'; +} + +void KviStr::prepend(const KviStr &str) +{ + __range_valid(str.m_ptr); + __range_valid(str.m_ptr != m_ptr); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+str.m_len+1); + kvi_memmove((m_ptr+str.m_len),m_ptr,m_len+1); //move self + kvi_fastmove(m_ptr,str.m_ptr,str.m_len); + m_len += str.m_len; +} + +void KviStr::prepend(const char *str) +{ + if(!str)return; + int len = (int)strlen(str); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1); + kvi_memmove((m_ptr+len),m_ptr,m_len+1); //move self + kvi_fastmove(m_ptr,str,len); + m_len += len; +} + +void KviStr::prepend(const char *str,int len) +{ + __range_valid(str); + __range_valid(len <= ((int)strlen(str))); + __range_valid(len >= 0); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1); + kvi_memmove((m_ptr+len),m_ptr,m_len+1); //move self + kvi_fastmove(m_ptr,str,len); + m_len += len; +} + +unsigned char iso88591_toUpper_map[256]= +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +void KviStr::toUpperISO88591() +{ + register char *p=m_ptr; + while(*p) + { + *p=(char)iso88591_toUpper_map[(unsigned char)*p]; + p++; + } +} + +void KviStr::toUpper() +{ + register char *p=m_ptr; + while(*p) + { + *p=toupper(*p); + p++; + } +} + +unsigned char iso88591_toLower_map[256]= +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +void KviStr::toLowerISO88591() +{ + register char *p=m_ptr; + while(*p) + { + *p=(char)iso88591_toLower_map[(unsigned char)*p]; + p++; + } +} + + +void KviStr::toLower() +{ + register char *p=m_ptr; + while(*p) + { + *p=tolower(*p); + p++; + } +} + +KviStr KviStr::upper() const +{ + KviStr tmp(*this); + tmp.toUpper(); + return tmp; +} + +KviStr KviStr::upperISO88591() const +{ + KviStr tmp(*this); + tmp.toUpperISO88591(); + return tmp; +} + +KviStr KviStr::lower() const +{ + KviStr tmp(*this); + tmp.toLower(); + return tmp; +} + +KviStr KviStr::lowerISO88591() const +{ + KviStr tmp(*this); + tmp.toLowerISO88591(); + return tmp; +} + +KviStr KviStr::left(int maxLen) const +{ + if(maxLen <= 0) + { + KviStr empty; + return empty; + } + if(maxLen > m_len)maxLen=m_len; + KviStr str(m_ptr,maxLen); + return str; +} + +KviStr KviStr::right(int maxLen) const +{ + if(maxLen <= 0) + { + KviStr empty; + return empty; + } + if(maxLen > m_len)maxLen=m_len; + KviStr str((m_ptr+(m_len-maxLen)),maxLen); + return str; +} + +KviStr KviStr::middle(int idx,int maxLen) const +{ + __range_valid(maxLen >= 0); + __range_valid(idx >= 0); + if((maxLen <= 0) || (idx < 0)){ //max len negative...invalid params + KviStr ret; + return ret; + } + if((maxLen + idx) <= m_len){ //valid params + KviStr str(m_ptr+idx,maxLen); + return str; + } + if(idx < m_len){ //string shorter than requested + KviStr str(m_ptr+idx); + return str; + } + // idx out of bounds + KviStr ret; + return ret; +} + +KviStr ** KviStr::splitToArray(char sep,int max,int * realCount) const +{ + KviStr ** strings = (KviStr **)kvi_malloc(sizeof(KviStr *)); + int number = 0; + char * ptr = m_ptr; + char * last = ptr; + while((max > 0) && *ptr) + { + strings = (KviStr **)kvi_realloc((void *)strings,sizeof(KviStr *) * (number + 2)); + if(max > 1) + { + while(*ptr && (*ptr != sep))ptr++; + strings[number] = new KviStr(last,ptr - last); + } else { + strings[number] = new KviStr(ptr); + } + number++; + max--; + if(*ptr) + { + ptr++; + last = ptr; + } + } + if(realCount)*realCount = number; + strings[number] = 0; + return strings; +} +/* + WORKING BUT UNUSED + +KviStr ** KviStr::splitToArray(const char * sep,int max,int * realCount) const +{ + KviStr ** strings = (KviStr **)kvi_malloc(sizeof(KviStr *)); + KviStr tmp = *this; + int idx = tmp.findFirstIdx(sep); + int number = 0; + int seplen = kvi_strLen(sep); + + + while(idx != -1) + { + strings = (KviStr **)kvi_realloc(sizeof(KviStr *) * (number + 2)); + strings[number] = new KviStr(tmp.ptr(),idx); + tmp.cutLeft(idx + seplen); + number++; + idx = tmp.findFirstIdx(sep); + } + + if(tmp.hasData()) + { + strings = (KviStr **)kvi_realloc(sizeof(KviStr *) * (number + 2)); + strings[number] = new KviStr(tmp); + number++; + } + + if(realCount)*realCount = number; + strings[number] = 0; + return strings; +} +*/ +void KviStr::freeArray(KviStr ** strings) +{ + if(!strings)return; + KviStr ** aux = strings; + while(*aux) + { + delete (*aux); // delete (KviStr *) + aux++; + } + kvi_free(strings); +} + +void KviStr::freeBuffer(char * buffer) +{ + if(!buffer)return; + kvi_free(buffer); +} + +void KviStr::joinFromArray(KviStr ** strings,const char * sep,bool bLastSep) +{ + setLen(0); + if(!strings)return; + + while(*strings) + { + append(*(*strings)); + strings++; + if(*strings) + { + if(sep)append(sep); + } else { + if(sep && bLastSep)append(sep); + } + } +} + +KviStr & KviStr::insert(int idx,const char *data) +{ + __range_valid(data); + if(idx <= m_len){ + int len = (int)strlen(data); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+len+1); + kvi_memmove(m_ptr+idx+len,m_ptr+idx,(m_len - idx)+1); + kvi_fastmove(m_ptr+idx,data,len); + m_len+=len; + } + return (*this); +} + +KviStr & KviStr::insert(int idx,char c) +{ + if(idx <= m_len){ + m_ptr = (char *)kvi_realloc(m_ptr,m_len+2); + kvi_memmove(m_ptr+idx+1,m_ptr+idx,(m_len - idx)+1); + m_len++; + *(m_ptr + idx) = c; + } + return (*this); +} + +// FIXME: #warning "Double check the following two functions !!!" + +KviStr & KviStr::hexEncodeWithTable(const unsigned char table[256]) +{ + char * aux = m_ptr; + char * begin = m_ptr; + + char * n = 0; + int curSize = 0; + + while(*aux) + { + if(table[*((unsigned char *)aux)] || (*aux == '%')) + { + int len = aux - begin; + n = (char *)kvi_realloc(n,curSize + len + 3); + kvi_memmove(n + curSize,begin,len); + curSize += len; + + n[curSize] = '%'; + curSize++; + n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) / 16)]; + curSize++; + n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) % 16)]; + curSize++; + + aux++; + begin = aux; + + } else aux++; + } + + int len = aux - begin; + n = (char *)kvi_realloc(n,curSize + len + 1); + kvi_memmove(n + curSize,begin,len); + curSize += len; + + n[curSize] = '\0'; + + kvi_free((void *)m_ptr); + m_ptr = n; + m_len = curSize; + + return (*this); +} + +KviStr & KviStr::hexEncodeWhiteSpace() +{ + static unsigned char ascii_jump_table[256]= + { + // 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 + // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI + 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , + // 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 + // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US + 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , + // 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 + // ! " # $ % & ' ( ) * + , - . / + 1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 + // @ A B C D E F G H I J K L M N O + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 + // P Q R S T U V W X Y Z [ \ ] ^ _ + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 + // ` a b c d e f g h i j k l m n o + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 + // p q r s t u v w x y z { | } ~ + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 + // � � � � � � � � � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 + // � � � � � � � � � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 + // � � � � � � � � � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 + // � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + }; + + return hexEncodeWithTable(ascii_jump_table); +} + +KviStr & KviStr::hexDecode(const char * pFrom) +{ + // WARNING: pFrom can be also m_ptr here! + const char * aux = pFrom; + const char * begin = pFrom; + + char * n = 0; + int curSize = 0; + + while(*aux) + { + if(*aux == '%') + { + // move last block + int len = aux - begin; + n = (char *)kvi_realloc(n,curSize + len + 1); + kvi_memmove(n + curSize,begin,len); + curSize += len; + + // get the hex code + aux++; + + char theChar = get_decimal_from_hex_digit_char(*aux); + if(theChar < 0) + { + n[curSize] = '%'; // wrong code...just a '%' + curSize++; + } else { + aux++; + char theChar2 = get_decimal_from_hex_digit_char(*aux); + if(theChar2 < 0) + { + // wrong code...just a '%' and step back + n[curSize] = '%'; + curSize++; + aux--; + } else { + n[curSize] = (theChar * 16) + theChar2; + curSize++; + aux++; + } + } + + begin = aux; + + } else aux++; + } + + int len = aux - begin; + n = (char *)kvi_realloc(n,curSize + len + 2); + kvi_memmove(n + curSize,begin,len); + curSize += len; + n[curSize] = '\0'; + + kvi_free((void *)m_ptr); + m_ptr = n; + m_len = curSize; + + return (*this); +} + +KviStr & KviStr::replaceAll(char c,const char *str) +{ + int idx = findFirstIdx(c); + KviStr tmp; + while(idx >= 0){ + if(idx > 0)tmp += left(idx); + cutLeft(idx+1); + tmp.append(str); + idx = findFirstIdx(c); + } + tmp.append(*this); + // Now copy + m_len = tmp.m_len; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + kvi_fastmove(m_ptr,tmp.m_ptr,m_len+1); + return (*this); +} + +KviStr & KviStr::replaceAll(char *toFind,const char *str,bool bCaseS) +{ + int len = (int)strlen(toFind); + int idx = findFirstIdx(toFind,bCaseS); + KviStr tmp; + while(idx >= 0) + { + if(idx > 0)tmp += left(idx); + cutLeft(idx+len); + tmp.append(str); + idx = findFirstIdx(toFind,bCaseS); + } + tmp.append(*this); + // Now copy + m_len = tmp.m_len; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + kvi_fastmove(m_ptr,tmp.m_ptr,m_len+1); + return (*this); +} + +KviStr & KviStr::transliterate(const char * szToFind,const char * szReplacement) +{ + while(*szToFind && *szReplacement) + { + char * p = m_ptr; + while(*p) + { + if(*p == *szToFind)*p = *szReplacement; + ++p; + } + ++szToFind; + ++szReplacement; + } + return (*this); +} + + +int KviStr::occurences(char c,bool caseS) const +{ + register char *p = m_ptr; + int cnt=0; + if(caseS){ + while(*p){ + if(*p == c)cnt++; + p++; + } + } else { + char b=tolower(c); + while(*p){ + if(tolower(*p) == b)cnt++; + p++; + } + } + return cnt; +} + +int KviStr::occurences(const char *str,bool caseS) const +{ + __range_valid(str); + register char *p = m_ptr; + int cnt=0; + int len = (int)strlen(str); + if(caseS){ + while(*p){ + if(*p == *str){ + if(kvi_strEqualCSN(p,str,len))cnt++; + } + p++; + } + } else { + while(*p){ + char c = tolower(*str); + if(tolower(*p) == c){ + if(kvi_strEqualCIN(p,str,len))cnt++; + } + p++; + } + } + return cnt; +} + +bool KviStr::contains(char c,bool caseS) const +{ + register char *p = m_ptr; + if(caseS) + { + while(*p) + { + if(*p == c)return true; + p++; + } + } else { + char b=tolower(c); + while(*p) + { + if(tolower(*p) == b)return true; + p++; + } + } + return false; +} + +bool KviStr::contains(const char *str,bool caseS) const +{ + __range_valid(str); + register char *p = m_ptr; + int len = (int)strlen(str); + if(caseS) + { + while(*p) + { + if(*p == *str) + { + if(kvi_strEqualCSN(p,str,len))return true; + } + p++; + } + } else { + while(*p) + { + char c = tolower(*str); + if(tolower(*p) == c) + { + if(kvi_strEqualCIN(p,str,len))return true; + } + p++; + } + } + return false; +} + + +KviStr & KviStr::setNum(long num) +{ + char numberBuffer[30]; + bool bNegative = false; + long tmp; + register char *p; + register char *pNumBuf = numberBuffer; + + // somebody can explain me why -(-2147483648) = -2147483648 ? (2^31) + // it is like signed char x = 128 ---> 10000000 that is signed -0 (!?) + // mmmmh...or it is assumed to be -128 (a number rappresentation exception) + // at least on my machine it happens... + + // found the solution by myself today... + // + // ABS(3) Linux Programmer's Manual ABS(3) + // NAME + // abs - computes the absolute value of an integer. + // ... + // DESCRIPTION + // The abs() function computes the absolute value of the integer argument j. + // RETURN VALUE + // Returns the absolute value of the integer argument. + // CONFORMING TO + // SVID 3, POSIX, BSD 4.3, ISO 9899 + // NOTE ################################################################################## + // Trying to take the absolute value of the most negative integer is not defined. + // ####################################################################################### + + // so should i use temporaneous doubles to make calculations ? + + if(num < 0){ //negative integer + bNegative = true; + num = -num; //need to have it positive + if(num < 0){ // 2^31 exception + // We need to avoid absurd responses like ".(./),." :) + num = 0; // we get a negative zero here...it is still an exception + } + } + + //write the number in a temporary buffer (at least '0') + do { + tmp = num / 10; + *pNumBuf++ = num - (tmp * 10) + '0'; + } while((num = tmp)); + + //copy now.... + m_len = pNumBuf - numberBuffer; //length of the number string + if(bNegative){ + m_len++; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + p=m_ptr; + *p++='-'; + } else { + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + p=m_ptr; + } + do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer); + *(m_ptr + m_len)='\0'; + return (*this); +} + +KviStr & KviStr::setNum(unsigned long num) +{ + char numberBuffer[30]; + unsigned long tmp; + register char *p; + register char *pNumBuf = numberBuffer; + + //write the number in a temporary buffer (at least '0') + do { + tmp = num / 10; + *pNumBuf++ = num - (tmp * 10) + '0'; + } while((num = tmp)); + + //copy now.... + m_len = pNumBuf - numberBuffer; //length of the number string + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + p=m_ptr; + do { *p++ = *--pNumBuf; } while(pNumBuf != numberBuffer); + *(m_ptr + m_len)='\0'; + return (*this); +} + +long KviStr::toLong(bool *bOk) const +{ + long result = 0; + if(bOk)*bOk = false; + register char *p=m_ptr; + bool bNeg = false; + while(isspace(*p))p++; //skip spaces + if(*p == '-'){ + bNeg = true; + p++; + } else { + if(*p == '+')p++; + } + if(isdigit(*p)){ //point to something interesting ? + do{ + result = (result * 10) + (*p - '0'); + p++; + } while(isdigit(*p)); + if(bNeg)result = -result; + while(isspace(*p))p++; //skip trailing spaces + if(*p)return 0; //if this is not the end...die. + if(bOk)*bOk = true; + return result; + } + return 0; +} + +unsigned long KviStr::toULong(bool *bOk) const +{ + unsigned long result = 0; + if(bOk)*bOk = false; + register char *p=m_ptr; + while(isspace(*p))p++; //skip spaces + if(isdigit(*p)){ //point to something interesting ? + do{ + result = (result * 10) + (*p - '0'); + p++; + } while(isdigit(*p)); + while(isspace(*p))p++; //skip trailing spaces + if(*p)return 0; //if this is not the end...die. + if(bOk)*bOk = true; + return result; + } + return 0; +} + +long KviStr::toLongExt(bool *bOk,int base) +{ + if(m_len == 0){ + if(bOk)*bOk = false; + return 0; + } + char * endptr; + long result = strtol(m_ptr,&endptr,base); + if(*endptr){ + // must be whitespaces , otherwise there is trailing garbage inside + while(isspace(*endptr) && (*endptr))endptr++; + if(*endptr){ + // still not at the end + // trailing garbage not allowed + if(bOk)*bOk = false; + return result; + } + } + if(bOk)*bOk = true; + return result; +} + +// +//working code , but unused in kvirc +// +//unsigned long KviStr::toULongExt(bool *bOk = 0,int base = 0) +//{ +// if(m_len == 0){ +// if(bOk)*bOk = false; +// return 0; +// } +// char * endptr; +// unsigned long result = strtoul(m_ptr,&endptr,base); +// if(*endptr != '\0'){ +// if(bOk)*bOk = false; +// } +// return result; +//} + +KviStr & KviStr::cutLeft(int len) +{ + __range_valid(len >= 0); + if(len <= m_len){ + m_len -= len; + kvi_memmove(m_ptr,m_ptr+len,m_len+1); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + } else { + m_ptr = (char *)kvi_realloc(m_ptr,1); + *m_ptr = '\0'; + m_len = 0; + } + return (*this); +} + +KviStr & KviStr::cutRight(int len) +{ + __range_valid(len >= 0); + if(len <= m_len){ + m_len -= len; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + *(m_ptr +m_len)='\0'; + } else { + m_ptr = (char *)kvi_realloc(m_ptr,1); + *m_ptr = '\0'; + m_len = 0; + } + return (*this); +} + +KviStr & KviStr::cut(int idx,int len) +{ + __range_valid(idx >= 0); + __range_valid(len >= 0); + if(idx < m_len){ + // idx = 3 len = 3 m_len = 10 + // 0123456789 + // abcdefghij + // ^ ^ + // p1 p2 + char * p1 = m_ptr+idx; + if(len + idx > m_len)len = m_len - idx; + char * p2 = p1+len; + kvi_memmove(p1,p2,(m_len - (len+idx)) +1); + m_len -= len; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + } + return (*this); +} + +KviStr & KviStr::cutToFirst(char c,bool bIncluded) +{ + int idx = findFirstIdx(c); + if(idx != -1)cutLeft(bIncluded ? idx + 1 : idx); + return (*this); +} + +KviStr KviStr::leftToFirst(char c,bool bIncluded) const +{ + int idx = findFirstIdx(c); + if(idx == -1)return KviStr(*this); + return KviStr(m_ptr,bIncluded ? idx + 1 : idx); +} + + +KviStr KviStr::leftToLast(char c,bool bIncluded) const +{ + int idx = findLastIdx(c); + return KviStr(m_ptr,bIncluded ? idx + 1 : idx); +} + +KviStr & KviStr::cutFromFirst(char c,bool bIncluded) +{ + int idx = findFirstIdx(c); + if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1))); + return (*this); +} + +KviStr & KviStr::cutToLast(char c,bool bIncluded) +{ + int idx = findLastIdx(c); + if(idx != -1)cutLeft(bIncluded ? idx + 1 : idx); + return (*this); +} + +KviStr & KviStr::cutFromLast(char c,bool bIncluded) +{ + int idx = findLastIdx(c); + if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1))); + return (*this); +} + +KviStr & KviStr::cutToFirst(const char *c,bool bIncluded) +{ + int len = (int)strlen(c); + int idx = findFirstIdx(c); + if(idx != -1)cutLeft(bIncluded ? idx + len : idx); + return (*this); +} + +KviStr & KviStr::cutFromFirst(const char *c,bool bIncluded) +{ + int len = (int)strlen(c); + int idx = findFirstIdx(c); + if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len))); + return (*this); +} + +KviStr & KviStr::cutToLast(const char *c,bool bIncluded) +{ + int len = (int)strlen(c); + int idx = findLastIdx(c); + if(idx != -1)cutLeft(bIncluded ? idx + len : idx); + return (*this); +} + +KviStr & KviStr::cutFromLast(const char *c,bool bIncluded) +{ + int len = (int)strlen(c); + int idx = findLastIdx(c); + if(idx != -1)cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len))); + return (*this); +} + +KviStr & KviStr::setLen(int len) +{ + __range_valid(len >= 0); + m_ptr = (char *)kvi_realloc(m_ptr,len+1); + *(m_ptr+len)='\0'; + m_len = len; + return (*this); +} + +KviStr & KviStr::stripLeftWhiteSpace() +{ + register char *p=m_ptr; + while(isspace(*p))p++; + m_len -= (p-m_ptr); + kvi_memmove(m_ptr,p,m_len+1); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + return (*this); +} + +KviStr & KviStr::stripLeft(char c) +{ + __range_valid(c != '\0'); + register char *p=m_ptr; + while(*p == c)p++; + m_len -= (p-m_ptr); + kvi_memmove(m_ptr,p,m_len+1); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + return (*this); +} + +bool KviStr::getToken(KviStr & str,char sep) +{ + __range_valid(str.m_ptr); + __range_valid(str.m_ptr != m_ptr); + register char *p=m_ptr; + //skip to the end + while(*p && (*p != sep))p++; + //0123456789 + //abcd xyz + //^ ^ + str.m_len = p-m_ptr; + str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1); + kvi_fastmove(str.m_ptr,m_ptr,str.m_len); + *(str.m_ptr + str.m_len)='\0'; + while(*p && (*p == sep))p++; + cutLeft(p-m_ptr); + return (m_len != 0); +} + +bool KviStr::getLine(KviStr &str) +{ + __range_valid(str.m_ptr); + __range_valid(str.m_ptr != m_ptr); + if(m_len == 0)return false; + register char *p=m_ptr; + //skip to the end + while(*p && (*p != '\n'))p++; + //0123456789 + //abcd xyz + //^ ^ + str.m_len = p-m_ptr; + str.m_ptr = (char *)kvi_realloc(str.m_ptr,str.m_len+1); + kvi_fastmove(str.m_ptr,m_ptr,str.m_len); + *(str.m_ptr + str.m_len)='\0'; + p++; + cutLeft(p-m_ptr); + return true; +} + +KviStr KviStr::getToken(char sep) +{ + register char *p=m_ptr; + while(*p && (*p != sep))p++; + KviStr ret(m_ptr,p); + while(*p && (*p == sep))p++; + cutLeft(p-m_ptr); + return ret; +} + +KviStr & KviStr::sprintf(const char *fmt,...) +{ + m_ptr=(char *)kvi_realloc(m_ptr,256); + //First try + kvi_va_list list; + kvi_va_start(list,fmt); + //print...with max 256 chars + m_len=kvi_vsnprintf(m_ptr,256,fmt,list); + kvi_va_end(list); + + //check if we failed + if(m_len < 0){ + //yes , failed.... + int dummy=256; + do{ //we failed , so retry with 256 more chars + dummy+=256; + //realloc + m_ptr=(char *)kvi_realloc(m_ptr,dummy); + //print... + kvi_va_start(list,fmt); + m_len=kvi_vsnprintf(m_ptr,dummy,fmt,list); + kvi_va_end(list); + } while(m_len < 0); + } + //done... + //now m_len is the length of the written string not including the terminator... + //perfect! :) + m_ptr=(char *)kvi_realloc(m_ptr,m_len+1); + return (*this); +} + +int KviStr::find(const char *str,int idx,bool caseS) const +{ + if(idx >= m_len)return -1; + register char *p=m_ptr + idx; + int len = (int)strlen(str); + if(caseS){ + for(;;){ + while(*p && (*p != *str))p++; + if(*p){ + if(kvi_strEqualCSN(str,p,len))return (p-m_ptr); + else p++; + } else return -1; + } + } else { + for(;;){ + char tmp = toupper(*str); + while(*p && (toupper(*p) != tmp))p++; + if(*p){ + if(kvi_strEqualCIN(str,p,len))return (p-m_ptr); + else p++; + } else return -1; + } + } +} + +int KviStr::find(char c,int idx) const +{ + if(idx >= m_len)return -1; + register char *p=m_ptr + idx; + while(*p && (*p != c))p++; + return (*p ? p-m_ptr : -1); +} + + +int KviStr::findRev(const char *str,int idx,bool caseS) const +{ + if((m_len + idx) < 0)return -1; + register char *p=m_ptr + m_len + idx; + int len = (int)strlen(str); + if(caseS) + { + for(;;) + { + while((p >= m_ptr) && (*p != *str))p--; + if(p >= m_ptr){ + if(kvi_strEqualCSN(str,p,len))return (p-m_ptr); + else p--; + } else return -1; + } + } else { + for(;;){ + char tmp = toupper(*str); + while((p >= m_ptr) && (toupper(*p) != tmp))p--; + if(p >= m_ptr){ + if(kvi_strEqualCIN(str,p,len))return (p-m_ptr); + else p--; + } else return -1; + } + } +} + +int KviStr::findFirstIdx(char c) const +{ + register char *p=m_ptr; + while(*p && (*p != c))p++; + return (*p ? p-m_ptr : -1); +} + +int KviStr::findFirstIdx(const char *str,bool caseS) const +{ + // This function can't be used to search inside + // multibyte encoded strings... convert your + // code to QString and use QString::findRev(). + // We must throw away KviStr at all in this case... + + // return QString(m_ptr).find(QString(str),0,caseS);; + + // Both this KviStr and the const char * str are assumed + // to be in the proper (and same) encoding. + // If KviStr is in encoding A then QString(m_ptr) might + // or not be decoded correctly. + // Also if KviStr is in UTF-8 (for example), then + // a position in QString() does not map to the position in the char array + // since a single UNICODE char may use one or more bytes... + + __range_valid(str); + register char *p=m_ptr; + int len = (int)strlen(str); + if(caseS){ + for(;;){ + while(*p && (*p != *str))p++; + if(*p){ + if(kvi_strEqualCSN(str,p,len))return (p-m_ptr); + else p++; + } else return -1; + } + } else { + // this will NOT work for strings that aren't in the current system encoding :( + for(;;){ + char tmp = toupper(*str); + while(*p && (toupper(*p) != tmp))p++; + if(*p){ + if(kvi_strEqualCIN(str,p,len))return (p-m_ptr); + else p++; + } else return -1; + } + } +} + +int KviStr::findLastIdx(char c) const +{ + //Empty string ? + if(m_len < 1)return -1; + //p points to the last character in the string + register char *p=((m_ptr+m_len)-1); + //go back until we find a match or we run to the first char in the string. + while((*p != c) && (p > m_ptr))p--; + //if *p == c --> matched , else we are at the beginning of the string. + return ((*p == c)? p-m_ptr : -1); +} + +int KviStr::findLastIdx(const char *str,bool caseS) const +{ + // This function can't be used to search inside + // multibyte encoded strings... convert your + // code to QString and use QString::findRev(). + // We must throw away KviStr at all in this case... + + // return QString(m_ptr).findRev(QString(str),-1,caseS); + + __range_valid(str); + //Calc the len of the searched string + int len = (int)strlen(str); + //Too long ? + if(m_len < len)return -1; + //p points to the last character in the string + register char *p=((m_ptr+m_len)-1); + if(caseS){ + for(;;){ + //go back until we find a character that mathes or we run to the first char. + while((*p != *str) && (p > m_ptr))p--; + if(*p == *str){ + //maybe occurence.... + if(kvi_strEqualCSN(str,p,len))return (p-m_ptr); + else { + //Nope...continue if there is more data to check... + if(p == m_ptr)return -1; + p--; + } + } else return -1; //Beginning of the string + } + } else { + // case insensitive + for(;;){ + //go back until we find a character that mathes or we run to the first char. + char tmp = toupper(*str); + while((toupper(*p) != tmp) && (p > m_ptr))p--; + if(toupper(*p) == tmp){ + //maybe occurence.... + if(kvi_strEqualCIN(str,p,len))return (p-m_ptr); + else { + //Nope...continue if there is more data to check... + if(p == m_ptr)return -1; + p--; + } + } else return -1; //Beginning of the string + } + } +} + +KviStr & KviStr::stripWhiteSpace() +{ + // 0123456789 + // abcd 0 + // ^ ^ + // left right + register char *left=m_ptr; + register char *right=m_ptr+m_len-1; + // skip initial spaces + while(isspace(*left))left++; + if(*left){ + // valid string , left points to first non-space + while((right >= left) && isspace(*right))right--; + // 0123456789 + // abcd 0 + // ^ ^ + // left right + m_len = (right - left)+1; + kvi_memmove(m_ptr,left,m_len); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + *(m_ptr+m_len)='\0'; + } else { + m_ptr = (char *)kvi_realloc(m_ptr,1); + *m_ptr = '\0'; + m_len = 0; + } + return (*this); +} + +KviStr & KviStr::stripRightWhiteSpace() +{ + if(*m_ptr) + { + register char *right=m_ptr+m_len-1; + const char *start=right; + while((right >= m_ptr) && isspace( *right ))right--; + if(right != start) + { + m_len = (right - m_ptr) + 1; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + *(m_ptr+m_len)='\0'; + } + } + return (*this); +} + +KviStr & KviStr::stripRight(char c) +{ + if(*m_ptr) + { + register char *right=m_ptr+m_len-1; + const char *start=right; + while((right >= m_ptr) && (*right == c))right--; + if(right != start) + { + m_len = (right - m_ptr) + 1; + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + *(m_ptr+m_len)='\0'; + } + } + return (*this); +} + +KviStr & KviStr::stripSpace() +{ + // 0123456789 + // abcd 0 + // ^ ^ + // left right + register char *left=m_ptr; + register char *right=m_ptr+m_len-1; + // skip initial spaces + while((*left == ' ') || (*left == '\t'))left++; + if(*left){ + // valid string , left points to first non-space + while((right >= left) && ((*right == ' ') || (*right == '\t')))right--; + // 0123456789 + // abcd 0 + // ^ ^ + // left right + m_len = (right - left)+1; + kvi_memmove(m_ptr,left,m_len); + m_ptr = (char *)kvi_realloc(m_ptr,m_len+1); + *(m_ptr+m_len)='\0'; + } else { + m_ptr = (char *)kvi_realloc(m_ptr,1); + *m_ptr = '\0'; + m_len = 0; + } + return (*this); +} + +bool KviStr::isNum() const +{ + register char *p=m_ptr; + while(isspace(*p))p++; + if(*p=='-')p++; + if(!isdigit(*p))return false; + while(isdigit(*p))p++; + while(isspace(*p))p++; + return (*p=='\0'); +} + +bool KviStr::isUnsignedNum() const +{ + register char *p=m_ptr; + while(isspace(*p))p++; + if(!isdigit(*p))return false; + while(isdigit(*p))p++; + while(isspace(*p))p++; + return (*p=='\0'); +} + +static KviStr g_szApplicationWideEmptyString; + +KviStr & KviStr::emptyString() +{ + return g_szApplicationWideEmptyString; +} + + +bool KviStr::ext_contains(register const char * data,const char * item,bool caseS) +{ + if(item && data) + { + int len = (int)strlen(item); + char c = tolower(*item); + if(caseS) + { + while(*data) + { + while(*data && (tolower(*data) != c))data++; + if(*data) + { + if(kvi_strEqualCSN(item,data,len))return true; + else data++; + } + } + } else { + while(*data) + { + while(*data && (tolower(*data) != c))data++; + if(*data) + { + if(kvi_strEqualCIN(item,data,len))return true; + else data++; + } + } + } + } + return false; +} + + +//void KviStr::pointerToBitString(const void * ptr) +//{ +// m_len = (sizeof(void *) * 8); +// m_ptr = kvi_realloc(m_ptr,m_len + 1); +// for(int i=0;i < m_len;i++) +// { +// m_ptr[i] = (ptr & 1) ? '1' : '0'; +// ptr >> 1; +// } +// m_ptr[i] = '\0'; +//} +// +//void * KviStr::bitStringToPointer() +//{ +// if(m_len != (sizeof(void *) * 8))return 0; +// const char * aux = m_ptr; +// void * ptr = 0; +// for(int i=m_len - 1;i >= 0;i--) +// { +// if(m_ptr[i] == '1')ptr &= 1; +// else if(m_ptr[i] !='0')return 0; +// ptr << 1; +// } +// return ptr; +//} + + + + +// static char ascii_jump_table[256]= +// { +// // 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 +// // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 +// // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 +// // ! " # $ % & ' ( ) * + , - . / +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 +// // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 +// // @ A B C D E F G H I J K L M N O +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 +// // P Q R S T U V W X Y Z [ \ ] ^ _ +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 +// // ` a b c d e f g h i j k l m n o +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 +// // p q r s t u v w x y z { | } ~ +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 +// // +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 +// // +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 +// // +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 +// // +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 +// // � � � � � � � � � � � � � � � � +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 +// // � � � � � � � � � � � � � � � � +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 +// // � � � � � � � � � � � � � � � � +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , +// // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 +// // � � � � � � � � +// 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 +// }; diff --git a/src/kvilib/core/kvi_string.h b/src/kvilib/core/kvi_string.h new file mode 100644 index 00000000..602173cd --- /dev/null +++ b/src/kvilib/core/kvi_string.h @@ -0,0 +1,552 @@ +#ifndef _KVI_STRING_H_ +#define _KVI_STRING_H_ +//============================================================================= +// +// File : kvi_string.h +// Creation date : Fri Mar 19 1999 03:06:26 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#ifdef HAVE_STRINGS_H + #include <strings.h> // useless ? +#endif + +#include <qglobal.h> +#include <qstring.h> + + +#include "kvi_qcstring.h" +#include "kvi_inttypes.h" +#include "kvi_heapobject.h" +#include "kvi_stdarg.h" + + + +// +// sigh... +// IRC is not UNICODE ...(yet) :( +// + +#undef __KVI_EXTERN +#ifdef _KVI_STRING_CPP_ + #define __KVI_EXTERN +#else + #define __KVI_EXTERN extern +#endif + + +__KVI_EXTERN KVILIB_API bool kvi_qstringEqualCI(const QString &s1,const QString &s2); + + +// Include inlined assembly implementations if required +#ifdef COMPILE_ix86_ASM + #include "kvi_strasm.h" +#else + // Returns true if the string str1 is equal to str2. case sensitive. + __KVI_EXTERN KVILIB_API bool kvi_strEqualCS(const char *str1,const char *str2); + // Returns true if the forst len characters of string str1 are equal to str2. + // case sensitive. + // Note that if str1 or str2 are shorter than len characters then are considered as NOT equal! + __KVI_EXTERN KVILIB_API bool kvi_strEqualCSN(const char *str1,const char *str2,int len); + // no such tricks in non-asm + #define kvi_strEqualNoLocaleCI(str1,str2) kvi_strEqualCI(str1,str2) + #define kvi_strEqualNoLocaleCIN(str1,str2,len) kvi_strEqualCIN(str1,str2,len) + #define kvi_strLen(str) strlen(str) +#endif + +// Returns true if the string str1 is equal to str2. +// case insensitive. +__KVI_EXTERN KVILIB_API bool kvi_strEqualCI(const char *str1,const char *str2); +// Returns true if the forst len characters of string str1 are equal to str2. +// case insensitive. +// Note that if str1 or str2 are shorter than len characters then are considered as NOT equal! +__KVI_EXTERN KVILIB_API bool kvi_strEqualCIN(const char *str1,const char *str2,int len); +// My own implementations of strcmp and strncasecmp +// Once I wrote it , I KNOW what they do : ALWAYS :) +// Note that greater here means that comes AFTER in the alphabetic order. +__KVI_EXTERN KVILIB_API int kvi_strcmpCI(const char *str1,const char *str2); +//__KVI_EXTERN KVILIB_API int kvi_strcmpCIN(const char *str1,const char *str2,int len); +__KVI_EXTERN KVILIB_API int kvi_strcmpCS(const char *str1,const char *str2); + +// some wide char stuff +typedef kvi_u16_t kvi_wchar_t; +typedef kvi_u32_t kvi_wslen_t; + +__KVI_EXTERN KVILIB_API kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str); +__KVI_EXTERN KVILIB_API int kvi_wvsnprintcf(kvi_wchar_t * buffer,kvi_wslen_t len,const char *fmt,kvi_va_list list); +__KVI_EXTERN KVILIB_API int kvi_wvsnprintf(kvi_wchar_t * buffer,kvi_wslen_t len,const kvi_wchar_t *fmt,kvi_va_list list); + +//============================================================================= +// +// A simple string class.<br> +// -No data sharing.<br> +// -Not UNICODE.<br> +// -Has ALWAYS NON-NULL DATA.<br> +// -(Maybe)Unsafe :)<br> +// WARNING : Handle with care and use at own risk :)<br> +// +//============================================================================= + +class KVILIB_API KviStr : public KviHeapObject +{ +public: + // No particular reason for these two names... + // It is just because I like it :) + + enum KviFormatConstructorTag { Format , Sprintf }; + + //============================================================================= + // Constructors + //============================================================================= + + // Empty string == "", len = 0, 1 byte allocated + KviStr(); + + // Deep copy of the NULL TERMINATED string (NULL str SAFE) + KviStr(const char *str); + + // Copy len characters from string str (NOT NULL str SAFE, str MUST be at least len chars long) + KviStr(const char *str,int len); + + // bg and end are pointers to a SINGLE string.<br> + // A string is extracted starting from bg and ending at end (not included).<br> + KviStr(const char *bg,const char *end); + + // Format constructor.<br> + // tag is....yes....a dummy number used to resolve ambiguities.<br> + // It is SAFE: will fail only if we run out of memory,<br> + // but can handle only %s %d %u and %c. + KviStr(KviFormatConstructorTag tag,const char *fmt,...); + + // Carbon copy :)...fast + KviStr(const KviStr &str); + + // Compat with QT...<br> + // WARNING : With QT2.x it WILL loose UNICODE data.<br> + // Safe even if the QString is null. + KviStr(const QString &str); + + KviStr(const KviQCString &str); + + // Fill sonstructor. + // Creates a string long fillLen characters filled with character c.<br> + KviStr(char c,int fillLen = 1); + + KviStr(const kvi_wchar_t * unicode); + + KviStr(const kvi_wchar_t * unicode,int len); + + // just free(m_ptr) + ~KviStr(); +public: + //yes...public..but think it as private...:) + char *m_ptr; // pointer to allocated buffer , do not change this! + int m_len; // string data length not including the terminator + +public: + //============================================================================= + // Basic const interface (read stuff) + //============================================================================= + + // Internal data buffer + char * ptr() const { return m_ptr; }; + // Length: fast, cached + int len() const { return m_len; }; + + // I hate this operator...but sometimes it is really useful + // especially in macros (kvi_options.cpp) + operator const char * () const { return m_ptr; }; + + bool isEmpty() const { return (m_len == 0); }; + bool hasData() const { return (m_len != 0); }; + + // this is better than string = "", it does not call strlen + void clear(); + + // forces the length of this string to be iLen (iLen does NOT include the trailing null : it is automatically added) + void setLength(int iLen); + + // Returns true if there is something "readable" inside the string + bool hasNonWhiteSpaceData() const; + + // Character at zero-based index : always safe! + char & at(int idx) const { return ((idx < m_len) ? m_ptr[idx] : m_ptr[m_len]); }; + + // character checks + bool lastCharIs(char ch) const { return (m_len > 0) ? (*(m_ptr + m_len - 1) == ch) : false; }; + bool firstCharIs(char ch) const { return (*m_ptr == ch); }; + + // upper and lower case copies + KviStr upper() const; + KviStr lower() const; + KviStr upperISO88591() const; + KviStr lowerISO88591() const; + + // left , right & co. + // all parameters are safety-checked + KviStr left(int maxLen) const; + KviStr right(int maxLen) const ; + KviStr middle(int idx,int maxLen) const; + + KviStr leftToFirst(char c,bool bIncluded = false) const; + KviStr leftToLast(char c,bool bIncluded = false) const; +// KviStr leftToFirst(const char * str); const; + + //============================================================================= + // Non-const interface (write stuff) + //============================================================================= + + // Null terminator is NOT included in len + KviStr & setLen(int len); + // str must not be 0, but len can be anything (it is checked) + KviStr & setStr(const char *str,int len = -1); + // Like the special constructor that gets the same args. + void extractFromString(const char *begin,const char *end); + + + // Safe sprintf. This one will never write past the end of the string + // It can handle only %s %d %u and %c format flags. + KviStr & sprintf(const char *fmt,...); + + // append functions + void append(const KviStr &str); + void append(const QString &str); + void append(char c); + void append(const char *str); // str CAN be 0 + void append(const char *str,int len); // str CAN NOT be 0, and MUST be at least len chars long + void append(KviFormatConstructorTag dummy,const char *fmt,...); + + // prepend stuff , same as above + void prepend(const KviStr &str); + void prepend(const char *str); // str CAN be 0 + void prepend(const char *str,int len); // str CAN NOT be 0, and MUST be at least len chars long + + // if lastCharIs ch does nothing otherwise appends it + void ensureLastCharIs(char ch) { if(!lastCharIs(ch))append(ch); }; + + // Change THIS string to uppercase or lowercase + void toUpperISO88591(); + void toUpper(); // this is LOCALE AWARE (in Turkish it maps i to Ý!) + void toLowerISO88591(); + void toLower(); + + // Assignment + KviStr & operator=(const KviStr &str); // deep copy + KviStr & operator=(const char *str); // str can be NULL here + KviStr & operator=(char c); // 2 bytes allocated ,m_len = 1 + KviStr & operator=(const QString &str); + KviStr & operator=(const KviQCString &str); + + // Append operators + KviStr & operator+=(const KviStr &str) { append(str); return (*this); }; + KviStr & operator+=(const char *str) { append(str); return (*this); }; + KviStr & operator+=(char c) { append(c); return (*this); }; + KviStr & operator+=(const QString &str) { append(str); return (*this); }; + + // Comparison + bool equalsCI(const KviStr &other) const { if(m_len != other.m_len)return false; return kvi_strEqualCI(m_ptr,other.m_ptr); }; + bool equalsCS(const KviStr &other) const { if(m_len != other.m_len)return false; return kvi_strEqualCS(m_ptr,other.m_ptr); }; + bool equalsCI(const char * other) const { return kvi_strEqualCI(m_ptr,other); }; + bool equalsCS(const char * other) const { return kvi_strEqualCS(m_ptr,other); }; + bool equalsCIN(const char * other,int len) const { return kvi_strEqualCIN(m_ptr,other,len); }; + bool equalsCSN(const char * other,int len) const { return kvi_strEqualCSN(m_ptr,other,len); }; + + //============================================================================= + // HEX and Base64 stuff + //============================================================================= + + // HEX transforms functions + void bufferToHex(const char *buffer,int len); + // Allocates the needed buffer and returns the allocated length, + // returns -1 in case of error (and allocates nothing) + // The string MUST contain only hex digits, and the digits MUST be in couples. (len % 2) must equal 0! + // So this will fail also if there are leading or trailing spaces! + int hexToBuffer(char ** buffer,bool bNullToNewlines = false); + // BASE64 stuff + void bufferToBase64(const char * buffer,int len); + // same as hexToBuffer but obviously transforms base64 notation to binary data (len % 4) must equal 0! + int base64ToBuffer(char ** buffer,bool bNullToNewlines = false); + + // frees a buffer allocated by hexToBuffer or base64ToBuffer + static void freeBuffer(char * buffer); + + //============================================================================= + // Splitters + //============================================================================= + + // cut + KviStr & cutLeft(int len); // kills the first len characters + KviStr & cutRight(int len); // kills the last len characters + KviStr & cut(int idx,int len); + KviStr & cutToFirst(char c,bool bIncluded = true); // cuts the left part of the string up to the first character c or does nothing if the char c is not in the string + KviStr & cutToLast(char c,bool bIncluded = true); + KviStr & cutFromFirst(char c,bool bIncluded = true); + KviStr & cutFromLast(char c,bool bIncluded = true); + KviStr & cutToFirst(const char *c,bool bIncluded = true); // cuts the left part of the string up to the first character c or does nothing if the char c is not in the string + KviStr & cutToLast(const char *c,bool bIncluded = true); + KviStr & cutFromFirst(const char *c,bool bIncluded = true); + KviStr & cutFromLast(const char *c,bool bIncluded = true); + // & paste + KviStr & insert(int idx,const char *data); + KviStr & insert(int idx,char c); + //Replaces all occurences of char c with the string str + KviStr & replaceAll(char c,const char *str); + //same as above but with a string + KviStr & replaceAll(char *toFind,const char *str,bool bCaseS = true); + + KviStr & transliterate(const char * szToFind,const char * szReplacement); + + // Strips whitespace characters from beginning of this string. + KviStr & stripLeftWhiteSpace(); + KviStr & stripRightWhiteSpace(); + // Stips inital and final WHITESPACE characters (see man isspace),<br> + // and returns a reference to this string. + KviStr & stripWhiteSpace(); + + // Strips spaces and tabs only + KviStr & stripSpace(); + // Strips all occurences of the character c from the beginning of the string.<br> + // Note that c can not be '\0' :) + KviStr & stripLeft(char c); + KviStr & stripRight(char c); + + //============================================================================= + // Tokenize + //============================================================================= + + // Extracts (copy to str and remove) a token from this string ,<br> + // and returns true if there are more tokens to extract<br> + // Does not strip initial separators!!<br> + // str can NOT be this string. + bool getToken(KviStr &str,char sep); + // Does not strip initial separators!<br> + // Can assign also to this string. + KviStr getToken(char sep); + // Extracts a line from the string.<br> + // Returns false if there was no data to extract + bool getLine(KviStr &str); + + // splits this string in a null-terminated array of strings + // separated by sep. + KviStr ** splitToArray(char sep,int max,int * realCount) const; + //KviStr ** splitToArray(const char * sep,int max,int * realCount) const; + static void freeArray(KviStr ** strings); + // joins the array to this string + // if sep is not 0 , it is inserted between the strings + // if bLastSep is true and sep is non 0 , then sep is also appended at the end + // of the buffer (after the last string) + void joinFromArray(KviStr ** strings,const char * sep = 0,bool bLastSep = false); + + //============================================================================= + // Utils + //============================================================================= + + // encodes chars that have nonzero in the jumptable + // into %HH equivalents + KviStr & hexEncodeWithTable(const unsigned char table[256]); + KviStr & hexEncodeWhiteSpace(); + KviStr & hexDecode(const char * pFrom); + KviStr & hexDecode(){ return hexDecode(m_ptr); }; + + //============================================================================= + // Contains / occurence count + //============================================================================= + + // Returns true if at least one occurence of str is found + bool contains(const char *str,bool caseS=true) const; + // Returns true if at least one occurence of character c is found in this string + bool contains(char c,bool caseS=true) const; + // Returns the number of occurences of string str in this string.<br> + // Overlapped matches are counted. + int occurences(const char *str,bool caseS=true) const; + // Returns the number of occurences of character c in this string + int occurences(char c,bool caseS=true) const; + + //============================================================================= + // Find + //============================================================================= + + // Finds the first occurence of the character c in this string,<br> + // and returns its zero-based index or -1 if c can not be found.<br> + // c can NOT be '\0' here. + int findFirstIdx(char c) const; + // Finds the first occurence of the sub-string str in this string,<br> + // and returns its zero-based index or -1 if the sub-string can not be found.<br> + // str can NOT be 0 here. + int findFirstIdx(const char *str,bool caseS = true) const; + // Finds the last occurence of the character c in this string,<br> + // and returns its zero-based index or -1 if the character can not be found. + int findLastIdx(char c) const; + // Finds the last occurence of the sub-string str in this string,<br> + // and returns its zero-based index or -1 if the sub-string can not be found.<br> + // str can NOT be 0 here. + int findLastIdx(const char *str,bool caseS = true) const; + + int find(char c,int startIdx) const; + int find(const char * str,int startIdx,bool caseS = true) const; + int findRev(const char * str,int startIdx,bool caseS = true) const; + + //============================================================================= + // Numbers + //============================================================================= + + // everything in base 10.... no overflow checks here + long toLong(bool *bOk=0) const; + unsigned long toULong(bool *bOk=0) const; + char toChar(bool *bOk=0) const { return (char)toLong(bOk); }; + unsigned char toUChar(bool *bOk=0) const { return (unsigned char)toULong(bOk); }; + int toInt(bool *bOk=0) const { return (int)toLong(bOk); }; + unsigned int toUInt(bool *bOk=0) const { return (unsigned int)toULong(bOk); }; + short toShort(bool *bOk=0) const { return (short)toLong(bOk); }; + unsigned short toUShort(bool *bOk=0) const { return (unsigned short)toLong(bOk); }; + + KviStr & setNum(long num); + KviStr & setNum(unsigned long num); + + KviStr & setNum(int num) { return setNum((long)num); }; + KviStr & setNum(unsigned int num) { return setNum((unsigned long)num); }; + KviStr & setNum(short num) { return setNum((long)num); }; + KviStr & setNum(unsigned short num) { return setNum((unsigned long)num); }; + KviStr & setNum(char num) { return setNum((long)num); }; + KviStr & setNum(unsigned char num) { return setNum((unsigned long)num); }; + + // Retuns true if the string contains only digits and an optional '-' character + // at the beginning.<be> + // Space characters are allowed at the begginning and the end.<br> + // There is no overflow check! + bool isNum() const; + bool isUnsignedNum() const; + + // special functions for multiple bases + long toLongExt(bool *bOk = 0,int base = 0); + // unsigned long toULongExt(bool *bOk = 0,int base = 0); //never used + + // returns an empty string... + // this if often useful! + static KviStr & emptyString(); + + //============================================================================= + // Dead interface + //============================================================================= + + // Transform a pointer to a string with all 0 and 1 + // void pointerToBitString(const void * ptr); + // Get a pointer from a string all of 0 and 1 : return 0 if invalid + // void * bitStringToPointer(); + + //============================================================================= + // "External string" helper functions + //============================================================================= + + // FIXME: Should it be KviStrExt::contains namespace ? + static bool ext_contains(register const char * data,const char * item,bool caseS = true); +}; + +// FIXME: the functions below should end in the KviStr namespace ??? + + +// Cool string parsing function. +// It will extract the first found token from the string aux_ptr , and return +// a pointer to the beginning of the next token , or end of the string. +// It skips the initial sep characters! +__KVI_EXTERN KVILIB_API const char * kvi_extractToken(KviStr &str,const char *aux_ptr,char sep =' '); +// Does not skip the beginning separators! +// Extracts data from the string up to the next separator character or the end of the string. +// and returns a pointer to that separator (or string end). +__KVI_EXTERN KVILIB_API const char * kvi_extractUpTo(KviStr &str,const char *aux_ptr,char sep=' '); +// Reduced vsnprintf... +// Handles %s,%c,%d,%u (%% are TWO percents here and not one.) +// Returns -1 if the formatted string exceeded the buffer length. +// Otherwise returns the length of the formatted buffer...(not including '\0') +__KVI_EXTERN KVILIB_API int kvi_vsnprintf(char *buffer,int len,const char *fmt,kvi_va_list list); +// Reduced vsnprintf: special version for irc. +// Handles %s,%c,%d,%u (%% are TWO percents here and not one.) +// Writes up to 510 characters and terminates the string with a CRLF +// Sets bTruncated if the requested format string was too large to fit in 512 bytes +// otherwise sets it to false; The buffer MUST be at least 512 bytes long. +// Always returns the length of the formatted buffer...(max 512 - min 2=CRLF) +__KVI_EXTERN KVILIB_API int kvi_irc_vsnprintf(char *buffer,const char *fmt,kvi_va_list list,bool *bTruncated); + +// WILDCARD EXPRESSION MATCHING FUNCTIONS + +// Returns true if the two regular expressions with wildcards matches +__KVI_EXTERN KVILIB_API bool kvi_matchWildExpr(register const char *m1,register const char *m2); +// Returns true if the two regular expressions with wildcards matches, case sensitive +//__KVI_EXTERN bool kvi_matchWildExprCS(register const char *m1,register const char *m2); // actually unused +// Same as kvi_matchWildExpr but with an additional char that acts as string terminator +// If there is a match this function returns true and puts the pointers where it stopped in r1 and r2 +__KVI_EXTERN KVILIB_API bool kvi_matchWildExprWithTerminator(register const char *m1,register const char *m2,char terminator, + const char ** r1,const char ** r2); + +// Returns true if the wildcard expression exp matches the string str +__KVI_EXTERN KVILIB_API bool kvi_matchStringCI(register const char * exp,register const char * str); +#define kvi_matchString kvi_matchStringCI +__KVI_EXTERN KVILIB_API bool kvi_matchStringCS(register const char * exp,register const char * str); +__KVI_EXTERN KVILIB_API bool kvi_matchStringWithTerminator(register const char * exp,register const char * str,char terminator,const char ** r1,const char ** r2); + +// This function works like a particular case of strncmp. +// It evaluates if str2 is the terminal part of str1. +// example: if str1 is "this is an experiment" and str2 is "xperiment" +// return 0. +// With the index parameter, the match start on str1 from the specified +// index. For example: +// if str1 is "this is an experiment" and str2 is "an" we have return !0 +// but "this is an experiment" +// 012345678901234567890 +// if we call kvi_strsubRevCS("this is an experiment","an", 9) we got a match. +__KVI_EXTERN KVILIB_API int kvi_strMatchRevCS(const char *str1, const char *str2, int index=-1); + +// KviStr comparison non-member operators +__KVI_EXTERN KVILIB_API inline bool operator==(const KviStr &left,const KviStr &right) +{ return (left.m_len == right.m_len) ? kvi_strEqualCS(left.m_ptr,right.m_ptr) : false; } +__KVI_EXTERN KVILIB_API inline bool operator==(const KviStr &left,const char *right) +{ return kvi_strEqualCS(left.m_ptr,right); } +__KVI_EXTERN KVILIB_API inline bool operator==(const char *left,const KviStr &right) +{ return kvi_strEqualCS(left,right.m_ptr); } +__KVI_EXTERN KVILIB_API inline bool operator!=(const KviStr &left,const KviStr &right) +{ return !kvi_strEqualCS(left.m_ptr,right.m_ptr); } +__KVI_EXTERN KVILIB_API inline bool operator!=(const KviStr &left,const char *right) +{ return !kvi_strEqualCS(left.m_ptr,right); } +__KVI_EXTERN KVILIB_API inline bool operator!=(const char *left,const KviStr &right) +{ return !kvi_strEqualCS(left,right.m_ptr); } + +__KVI_EXTERN KVILIB_API inline KviStr operator+(const KviStr &left,const KviStr &right) +{ KviStr ret(left); ret += right; return ret; } +__KVI_EXTERN KVILIB_API inline KviStr operator+(const KviStr &left,const char *right) +{ KviStr ret(left); ret += right; return ret; } +__KVI_EXTERN KVILIB_API inline KviStr operator+(const char *left,const KviStr &right) +{ KviStr ret(left); ret += right; return ret; } +__KVI_EXTERN KVILIB_API inline KviStr operator+(const KviStr &left,char right) +{ KviStr ret(left); ret += right; return ret; } +__KVI_EXTERN KVILIB_API inline KviStr operator+(char left,const KviStr &right) +{ KviStr ret(left); ret += right; return ret; } + +inline int kvi_compare(const KviStr * p1,const KviStr * p2) +{ + return kvi_strcmpCI(p1->ptr(),p2->ptr()); +} + +#endif //_KVI_STRING_H_ diff --git a/src/kvilib/core/kvi_stringarray.cpp b/src/kvilib/core/kvi_stringarray.cpp new file mode 100644 index 00000000..d160ce28 --- /dev/null +++ b/src/kvilib/core/kvi_stringarray.cpp @@ -0,0 +1,119 @@ +//================================================================================================= +// +// File : kvi_stringarray.cpp +// Creation date : Tue Jun 6 02:20:20 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//================================================================================================= + +#define __KVILIB__ + + +#include "kvi_stringarray.h" +#include "kvi_malloc.h" + +KviStringArray::KviStringArray() +{ + m_uSize = 0; + m_pData = 0; + m_uHighestIdx = 0; +} + +KviStringArray::~KviStringArray() +{ + if(m_pData)clear(); +} + + +void KviStringArray::clear() +{ + if(!m_pData)return; + for(unsigned int i=0;i<m_uSize;i++) + { + if(m_pData[i])delete m_pData[i]; + } + kvi_free(m_pData); + m_pData = 0; + m_uHighestIdx = 0; + m_uSize = 0; +} + +void KviStringArray::insert(unsigned int uIdx,KviStr * pVal) +{ + if(m_uSize <= uIdx) + { + unsigned int uOldSize = m_uSize; + m_uSize = uIdx + KVI_STRING_ARRAY_FREESPACE_SIZE; + m_pData = (KviStr **)kvi_realloc(m_pData,m_uSize * sizeof(KviStr *)); + for(unsigned int u = uOldSize;u < m_uSize;u++) + { + m_pData[u] = 0; + } + } else { + if(m_pData[uIdx])delete m_pData[uIdx]; + } + if(uIdx > m_uHighestIdx)m_uHighestIdx = uIdx; + m_pData[uIdx] = pVal; +} + +void KviStringArray::remove(unsigned int uIdx) +{ + if(uIdx > m_uHighestIdx)return; + if(m_pData[uIdx]) + { + delete m_pData[uIdx]; + m_pData[uIdx] = 0; + if(uIdx == m_uHighestIdx) + { + // shrink the array + if(m_uHighestIdx == 0)clear(); + else { + unsigned int u = m_uHighestIdx - 1; + while(!m_pData[u])u--; + if((m_uHighestIdx - u) > KVI_STRING_ARRAY_FREESPACE_SIZE)shrink(u); + else m_uHighestIdx = u; // just set the max index + } + } + } +} + +void KviStringArray::shrink(unsigned int uMaxItem) +{ + m_uHighestIdx = uMaxItem; + m_uSize = uMaxItem + 1; + m_pData = (KviStr **)kvi_realloc(m_pData,sizeof(KviStr *) * m_uSize); +} + +void KviStringArray::copyFrom(KviStringArray * a) +{ + clear(); + m_uSize = a->m_uSize; + m_uHighestIdx = a->m_uHighestIdx; + if(m_uSize > 0) + { + m_pData = (KviStr **)kvi_malloc(sizeof(KviStr *) * m_uSize); + for(unsigned int i=0;i<m_uSize;i++) + { + if(a->m_pData[i])m_pData[i] = new KviStr(*(a->m_pData[i])); + else m_pData[i] = 0; + } + } else { + m_pData = 0; + } +} diff --git a/src/kvilib/core/kvi_stringarray.h b/src/kvilib/core/kvi_stringarray.h new file mode 100644 index 00000000..3db9a564 --- /dev/null +++ b/src/kvilib/core/kvi_stringarray.h @@ -0,0 +1,55 @@ +#ifndef _KVI_STRINGARRAY_H_ +#define _KVI_STRINGARRAY_H_ +//================================================================================================= +// +// File : kvi_stringarray.h +// Creation date : Tue Jun 6 02:20:20 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//================================================================================================= + +#include "kvi_settings.h" +#include "kvi_string.h" +#include "kvi_heapobject.h" + +#define KVI_STRING_ARRAY_FREESPACE_SIZE 16 + +class KVILIB_API KviStringArray : public KviHeapObject +{ +public: + KviStringArray(); + ~KviStringArray(); +public: + unsigned int m_uSize; + unsigned int m_uHighestIdx; + KviStr ** m_pData; +public: + void clear(); + void insert(unsigned int uIdx,KviStr * pVal); + void copyFrom(KviStringArray * a); + unsigned int size(){ return (m_uSize == 0) ? 0 : (m_uHighestIdx + 1); }; + bool isEmpty(){ return m_uSize == 0; }; + void remove(unsigned int uIdx); + void shrink(unsigned int uMaxItem); + KviStr * uncheckedAt(unsigned int uIdx){ return m_pData[uIdx]; }; + KviStr * at(unsigned int uIdx){ return m_uSize > uIdx ? m_pData[uIdx] : 0; }; + KviStr * getAt(unsigned int uIdx){ KviStr * t = at(uIdx); if(t)m_pData[uIdx] = 0; return t; }; +}; + +#endif //_KVI_STRINGARRAY_H_ diff --git a/src/kvilib/core/kvi_valuelist.h b/src/kvilib/core/kvi_valuelist.h new file mode 100644 index 00000000..fde9d5b6 --- /dev/null +++ b/src/kvilib/core/kvi_valuelist.h @@ -0,0 +1,37 @@ +#ifndef _KVI_VALUELIST_H_ +#define _KVI_VALUELIST_H_ +//================================================================================================= +// +// File : kvi_valuelist.h +// Creation date : Mon Jan 15 2007 04:53 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//================================================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include <q3valuelist.h> + #define KviValueList Q3ValueList +#else + #include <qvaluelist.h> + #define KviValueList QValueList +#endif + +#endif //_KVI_VALUELIST_H_ diff --git a/src/kvilib/ext/Makefile.am b/src/kvilib/ext/Makefile.am new file mode 100644 index 00000000..c84487eb --- /dev/null +++ b/src/kvilib/ext/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.cpp *.h diff --git a/src/kvilib/ext/kvi_accel.h b/src/kvilib/ext/kvi_accel.h new file mode 100644 index 00000000..34cca3c1 --- /dev/null +++ b/src/kvilib/ext/kvi_accel.h @@ -0,0 +1,38 @@ +#ifndef _KVI_ACCEL_H_ +#define _KVI_ACCEL_H_ + +//============================================================================= +// +// File : kvi_accel.h +// Creation date : Wed Feb 01 2007 01:45:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include <q3accel.h> + #define KviAccel Q3Accel +#else + #include <qaccel.h> + #define KviAccel QAccel +#endif + +#endif //!_KVI_ACCEL_H_ diff --git a/src/kvilib/ext/kvi_cmdformatter.cpp b/src/kvilib/ext/kvi_cmdformatter.cpp new file mode 100644 index 00000000..e2b3e1f6 --- /dev/null +++ b/src/kvilib/ext/kvi_cmdformatter.cpp @@ -0,0 +1,242 @@ +//============================================================================= +// +// File : kvi_cmdformatter.cpp +// Creation date : Tue Jun 12 2001 03:08:12 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include "kvi_cmdformatter.h" + +namespace KviCommandFormatter +{ + bool hasLeadingChars(KviStr ** array,char c) + { + if(!(*array))return false; // can't have more leading chars + bool bGotIt = false; + while(*array) + { + if(*((*array)->ptr()) == c) + { + // found at least one such leading char + bGotIt = true; + } else { + // we pretend this line to be empty + KviStr tmp = *(*array); + tmp.stripWhiteSpace(); + if(tmp.hasData())return false; + *(*array) = ""; // set it to empty also in the main buffer + } + array++; + } + return bGotIt; + } + + bool hasLeadingChars(QStringList &list,const QChar &c) + { + bool bGotIt = false; + for(QStringList::Iterator it = list.begin();it != list.end();++it) + { + if((*it).length() < 1)continue; + if((*it).at(0) == c) + { + // found at least one such leading char + bGotIt = true; + } else { + // we pretend this line to be empty + QString tmp = *it; +#ifdef COMPILE_USE_QT4 + tmp = tmp.trimmed(); +#else + tmp = tmp.stripWhiteSpace(); +#endif + if(!tmp.isEmpty())return false; + *it = ""; // set it to empty also in the main buffer + } + } + return bGotIt; + } + + void trimLeading(KviStr ** array) + { + while(*array) + { + if((*array)->hasData())(*array)->cutLeft(1); + array++; + } + } + + void trimLeading(QStringList &list) + { + for(QStringList::Iterator it = list.begin();it != list.end();++it) + { + (*it).remove(0,1); + } + } + + + void addLeading(KviStr ** array,char c) + { + while(*array) + { + if((*array)->hasData())(*array)->prepend(c); + array++; + } + } + + void addLeading(QStringList &list,const QChar & c) + { + for(QStringList::Iterator it = list.begin();it != list.end();++it) + { + (*it).prepend(c); + } + } + + + void unindent(KviStr &buffer) + { + // we can format correctly up to 65536 lines (that's really enough) + int realLen; + KviStr ** array = buffer.splitToArray('\n',65536,&realLen); + if(array) + { + while(hasLeadingChars(array,'\t') || hasLeadingChars(array,' '))trimLeading(array); + buffer.joinFromArray(array,"\n",true); + KviStr::freeArray(array); + } + } + + + void unindent(QString &buffer) + { +#ifdef COMPILE_USE_QT4 + QStringList list = buffer.split("\n",QString::KeepEmptyParts); +#else + QStringList list = QStringList::split("\n",buffer,true); +#endif + while(hasLeadingChars(list,QChar('\t')) || hasLeadingChars(list,QChar(' ')))trimLeading(list); + //buffer = list.join("\n"); join implementation sux :D + // we WANT the last newline + buffer = ""; + for(QStringList::Iterator it = list.begin();it != list.end();++it) + { + buffer.append(*it); + buffer.append(QChar('\n')); + } + } + + + void bufferFromBlock(KviStr &buffer) + { + buffer.stripWhiteSpace(); + + if((*(buffer.ptr()) == '{') && buffer.lastCharIs('}')) + { + // leading and trailing { must be stripped + buffer.cutLeft(1); + buffer.cutRight(1); + } + + unindent(buffer); + + buffer.stripWhiteSpace(); + } + + void bufferFromBlock(QString &buffer) + { +#ifdef COMPILE_USE_QT4 + buffer = buffer.trimmed(); +#else + buffer = buffer.stripWhiteSpace(); +#endif + + if(buffer.isEmpty())return; + + if((buffer.at(0) == QChar('{')) && buffer.endsWith(QChar('}'))) + { + buffer.remove(0,1); + buffer.remove(buffer.length() - 1,1); + while((buffer.length() > 0) && ((buffer.at(0) == QChar('\n')) || (buffer.at(0) == QChar('\r')))) + buffer.remove(0,1); + } + + unindent(buffer); + +#ifdef COMPILE_USE_QT4 + buffer = buffer.trimmed(); +#else + buffer = buffer.stripWhiteSpace(); +#endif + } + + + void indent(KviStr &buffer) + { + // we can format correctly up to 65536 lines (that's really enough) + int realLen; + KviStr ** array = buffer.splitToArray('\n',65536,&realLen); + if(array) + { + addLeading(array,'\t'); + buffer.joinFromArray(array,"\n",true); + KviStr::freeArray(array); + } + } + + void indent(QString &buffer) + { +#ifdef COMPILE_USE_QT4 + QStringList list = buffer.split("\n",QString::KeepEmptyParts); +#else + QStringList list = QStringList::split("\n",buffer,true); +#endif + addLeading(list,QChar('\t')); + //buffer = list.join("\n"); join implementation sux :D + // we WANT the last newline + buffer = ""; + for(QStringList::Iterator it = list.begin();it != list.end();++it) + { + buffer.append(*it); + buffer.append(QChar('\n')); + } + } + + + void blockFromBuffer(KviStr &buffer) + { + indent(buffer); + buffer.prepend("{\n"); + buffer.stripRightWhiteSpace(); + buffer.ensureLastCharIs('\n'); + buffer.append("}\n"); + } + + void blockFromBuffer(QString &buffer) + { + indent(buffer); + buffer.prepend("{\n"); + KviQString::stripRightWhiteSpace(buffer); + KviQString::ensureLastCharIs(buffer,'\n'); + buffer.append("}\n"); + } +}; + +// FIXME: #warning "move popups and events to this formatting stuff!" diff --git a/src/kvilib/ext/kvi_cmdformatter.h b/src/kvilib/ext/kvi_cmdformatter.h new file mode 100644 index 00000000..b6efa98b --- /dev/null +++ b/src/kvilib/ext/kvi_cmdformatter.h @@ -0,0 +1,64 @@ +#ifndef _KVI_CMDFORMATTER_H_ +#define _KVI_CMDFORMATTER_H_ + +//============================================================================= +// +// File : kvi_cmdformatter.h +// Creation date : Tue Jun 12 2001 03:04:05 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_string.h" +#include "kvi_settings.h" + +#include "kvi_qstring.h" +#include <qstringlist.h> + +namespace KviCommandFormatter +{ + extern KVILIB_API bool hasLeadingChars(KviStr * array,char c); + extern KVILIB_API bool hasLeadingChars(QStringList &list,const QChar &c); + + extern KVILIB_API void trimLeading(KviStr ** array); + extern KVILIB_API void trimLeading(QStringList &list); + + extern KVILIB_API void addLeading(KviStr ** array,char c); + extern KVILIB_API void addLeading(QStringList &list,const QChar &c); + + extern KVILIB_API void trimBlockBraces(KviStr &buffer); + extern KVILIB_API void trimBlockBraces(QString &buffer); + + extern KVILIB_API void unindent(KviStr &buffer); + extern KVILIB_API void unindent(QString &buffer); + + extern KVILIB_API void bufferFromBlock(KviStr &buffer); + extern KVILIB_API void bufferFromBlock(QString &buffer); + + extern KVILIB_API void addBlockBraces(KviStr &buffer); + extern KVILIB_API void addBlockBraces(QString &buffer); + + extern KVILIB_API void indent(KviStr &buffer); + extern KVILIB_API void indent(QString &buffer); + + extern KVILIB_API void blockFromBuffer(KviStr &buffer); + extern KVILIB_API void blockFromBuffer(QString &buffer); +}; + +#endif //_KVI_CMDFORMATTER_H_ diff --git a/src/kvilib/ext/kvi_config.cpp b/src/kvilib/ext/kvi_config.cpp new file mode 100644 index 00000000..eb3dc0bc --- /dev/null +++ b/src/kvilib/ext/kvi_config.cpp @@ -0,0 +1,1007 @@ +//========================================================================================== +// +// File : kvi_config.cpp +// Last major modification : Thu Jan 14 1999 18:03:59 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//========================================================================================== + +#define __KVILIB__ + +#include "kvi_config.h" +#include "kvi_fileutils.h" +#include "kvi_pixmap.h" +#include "kvi_msgtype.h" +#include "kvi_stringconversion.h" +#include "kvi_memmove.h" +#include "kvi_malloc.h" +#include "kvi_file.h" + + +KviConfig::KviConfig(const QString &filename,FileMode f,bool bLocal8Bit) +{ + m_bLocal8Bit = bLocal8Bit; + m_szFileName = filename; + m_bDirty = false; + m_szGroup = KVI_CONFIG_DEFAULT_GROUP; + m_bPreserveEmptyGroups = false; + m_bReadOnly = (f == KviConfig::Read); + m_pDict = new KviPointerHashTable<QString,KviConfigGroup>(17,false); + m_pDict->setAutoDelete(true); + if(f != KviConfig::Write)load(); +} + +KviConfig::KviConfig(const char* filename,FileMode f,bool bLocal8Bit) +{ + m_bLocal8Bit = bLocal8Bit; + m_szFileName = QString::fromUtf8(filename); + m_bDirty = false; + m_szGroup = KVI_CONFIG_DEFAULT_GROUP; + m_bPreserveEmptyGroups = false; + m_bReadOnly = (f == KviConfig::Read); + m_pDict = new KviPointerHashTable<QString,KviConfigGroup>(17,false); + m_pDict->setAutoDelete(true); + if(f != KviConfig::Write)load(); +} + + +KviConfig::~KviConfig() +{ + if(m_bDirty)save(); + delete m_pDict; +} + +void KviConfig::clear() +{ + delete m_pDict; + m_pDict = new KviPointerHashTable<QString,KviConfigGroup>(17,false); + m_pDict->setAutoDelete(true); + m_bDirty = false; + m_szGroup = KVI_CONFIG_DEFAULT_GROUP; +} + +void KviConfig::clearGroup(const QString & szGroup) +{ + m_bDirty = true; + m_pDict->remove(szGroup); + if(!m_pDict->find(m_szGroup))m_szGroup = KVI_CONFIG_DEFAULT_GROUP; //removed the current one +} + +void KviConfig::clearKey(const QString & szKey) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + p_group->remove(szKey); + if(p_group->count() == 0)clearGroup(m_szGroup); +} + +/* +void KviConfig::getContentsString(KviStr &buffer) +{ + buffer = __tr("Contents of config file "); + buffer.append(m_szFileName.ptr()); + buffer.append('\n'); + int sections = 0; + int keys = 0; + KviPointerHashTableIterator<QString,KviStrDict> it(*m_pDict); + while(it.current()){ + buffer.append(" Section ["); + buffer.append(it.currentKey()); + buffer.append("]\n"); + int sectionKeys = 0; + KviPointerHashTableIterator<QString,KviStr> it2(*it.current()); + while(it2.current()){ + buffer.append(" Key ["); + buffer.append(it2.currentKey()); + buffer.append("] : "); + buffer.append(it2.current()->ptr()); + buffer.append('\n'); + ++it2; + ++sectionKeys; + ++keys; + } + KviStr tmp(KviStr::Format,__tr(" Total: %d keys"),sectionKeys); + buffer.append(tmp); + buffer.append('\n'); + ++it; + ++sections; + } + KviStr tmp(KviStr::Format,__tr("Total: %d keys in %d sections"),keys,sections); + buffer.append(tmp); +} +*/ + + + +#define LOAD_BLOCK_SIZE 32768 + +bool KviConfig::load() +{ + // this is really faster than the old version :) + + // open the file + KviFile f(m_szFileName); + if(!f.openForReading())return false; + + KviStr tmp; + KviConfigGroup * p_group = 0; + + int iLoadBlockSize = LOAD_BLOCK_SIZE; + + char * buffer = (char *)kvi_malloc(iLoadBlockSize * sizeof(char)); + + int toRead; + int readedLen; + int remainingLen = 0; + + char * p = buffer; // start writing to the beginning of the buffer + + do { + // compute the length to read + toRead = iLoadBlockSize - remainingLen; + if(toRead < 1) + { + // ops... a string longer than iLoadBlockSize - 1 chars + iLoadBlockSize += LOAD_BLOCK_SIZE; + int iOffset = p - buffer; + buffer = (char *)kvi_realloc(buffer,iLoadBlockSize * sizeof(char)); + p = buffer + iOffset; + toRead += LOAD_BLOCK_SIZE; + } + + // do read + readedLen = f.readBlock(p,toRead); + if(readedLen < toRead) + { + // check for errors + if(readedLen <= 0) + { + if(readedLen < 0) + { + // error at all + f.close(); + kvi_free(buffer); + return true; // nothing more to parse anyway + } else { + // just a zero byte read + if(remainingLen == 0) + { + // there was nothing in the buffer + f.close(); // nothing to parse anyway + kvi_free(buffer); + return true; + } + // there is something in the buffer but we have readed 0 bytes + // this usually means that the last line in the file has no trailing newline + // ...we just fake it :) + *p = '\n'; + readedLen = 1; + } + } else { + // just readed something but less than expected + // check if the last readed char is a newline + // if it isn't , fake it + if(*(p + readedLen - 1) != '\n') + { + *(p + readedLen) = '\n'; + readedLen++; + } + } + } + // compute the end pointer + char * endp = p + readedLen; + + p = buffer; // start from beginning of the data buffer at all + // begin of the current string + char * begin = p; + + // and loop + while(p < endp) + { + // find a newline + if(*p != '\n') + { + p++; + continue; + } + // newline! + *p = 0; + // now begin points to the string that terminates in p + // skip leading whitespace + while((*begin == '\t') || (*begin == ' '))begin++; + + if(p == begin) + { + // empty line + p++; + begin = p; + continue; + } + // now p > begin + // check if there are trailing spaces (include CR so CRLF is trimmed too) + char * trail = p - 1; + + p++; + + while(trail >= begin) + { + if((*trail == '\r') || (*trail == '\t') || (*trail == ' '))*trail = 0; + else break; + trail--; + } + + // yeah, have some data in this line :D + switch(*begin) + { + case 0: + // empty line + break; + case '#': + // comment: just skip it + break; + case '[': + // group ? + begin++; + if(*begin && (*begin != ']')) + { + char * z = begin; +#define COMPAT_WITH_OLD_CONFIGS +#ifdef COMPAT_WITH_OLD_CONFIGS + // run to the end of the string + while(*z)z++; + // run back to the trailing ']' + while((z > begin) && (*z != ']'))z--; + // if it is not ther just run back to the end of the string + if(*z != ']')while(*z)z++; +#else + // new configs have it always encoded properly + while(*z && (*z != ']'))z++; +#endif + *z = 0; + tmp.hexDecode(begin); + tmp.stripRightWhiteSpace(); // no external spaces in group names + + if(!tmp.isEmpty()) + { + QString szGroup = m_bLocal8Bit ? + QString::fromLocal8Bit(tmp.ptr(),tmp.len()) : + QString::fromUtf8(tmp.ptr(),tmp.len()); + p_group = m_pDict->find(szGroup); + if(!p_group) + { + p_group = new KviConfigGroup(17,false); + p_group->setAutoDelete(true); + m_pDict->insert(szGroup,p_group); + } + } + } + break; + default: + { + // real data ? + char * z = begin; + while(*z && (*z != '='))z++; + if(*z && (z != begin)) + { + *z = 0; + tmp.hexDecode(begin); + tmp.stripRightWhiteSpace(); // No external spaces at all in keys + if(!tmp.isEmpty()) + { + QString szKey = m_bLocal8Bit ? + QString::fromLocal8Bit(tmp.ptr(),tmp.len()) : + QString::fromUtf8(tmp.ptr(),tmp.len()); + z++; + while(*z && ((*z == ' ') || (*z == '\t')))z++; + if(*z) + { + tmp.hexDecode(z); + QString * pVal = new QString( m_bLocal8Bit ? + QString::fromLocal8Bit(tmp.ptr(),tmp.len()) : + QString::fromUtf8(tmp.ptr(),tmp.len()) + ); + if(!p_group) + { + // ops...we're missing a group + // use the default one + p_group = new KviConfigGroup(17,false); + p_group->setAutoDelete(true); + m_pDict->insert(KVI_CONFIG_DEFAULT_GROUP,p_group); + } + p_group->replace(szKey,pVal); + } else { + // we in fact need this (mercy :D) + // otherwise the empty options will be treated as non-existing ones + // and will get the defaults (which is bad) + QString * pVal = new QString(QString::null); + p_group->replace(szKey,pVal); + } + } + } + } + break; + } + begin = p; + } + if(begin != endp) + { + // there is data with no trailing newline in the buffer + remainingLen = endp-begin; + if(buffer != begin) + { + kvi_memmove(buffer,begin,remainingLen); + p = buffer + remainingLen; + } // else p remains where it is + } else { + p = buffer; + } + } while(readedLen == toRead); + + f.close(); + kvi_free(buffer); + return true; +} + +/* + +bool KviConfig::load() +{ + QFile f(m_szFileName); + if(!f.open(IO_ReadOnly))return false; + + + KviConfigGroup * p_group = 0; + + KviStr dataLine; + bool bContinue; + + do { + bContinue = kvi_readLine(&f,dataLine); + dataLine.stripWhiteSpace(); + if(dataLine.hasData()) + { + switch(*(dataLine.ptr())) + { + case '#': + // just skip it , it is a comment + break; + case '[': + { + //set the group + dataLine.cutLeft(1); + dataLine.cutRight(1); + dataLine.hexDecode(); + if(dataLine.hasData()) + { + QString szUtf8 = QString::fromUtf8(dataLine.ptr()); + p_group = m_pDict->find(szUtf8); + + if(!p_group) + { + p_group = new KviConfigGroup(17,false); + p_group->setAutoDelete(true); + m_pDict->insert(szUtf8,p_group); + } + } + } + break; + default: + { + //data entry...split in two... + KviStr name=dataLine.getToken('='); + name.stripRightWhiteSpace(); // strip any whitespace added externally + name.hexDecode(); + if(name.hasData()) + { + dataLine.stripLeftWhiteSpace(); // strip any whitespace added externally + dataLine.hexDecode(); + //insert (replace items if needed) + QString *p_data=new QString(QString::fromUtf8(dataLine.ptr())); + if(!p_group) + { + // ops...we're missing a group + // use the default one + p_group = new KviConfigGroup(17,false); + p_group->setAutoDelete(true); + m_pDict->insert(KVI_CONFIG_DEFAULT_GROUP,p_group); + } + QString szName = QString::fromUtf8(name.ptr()); + p_group->replace(szName,p_data); + } + } + break; + } + } + } while (bContinue); + + f.close(); + return true; +} + +*/ + +bool KviConfig::save() +{ + static unsigned char encode_table[256]= + { + // 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 + // NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI + 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , + // 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 + // DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US + 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 , + // 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 + // ! " # $ % & ' ( ) * + , - . / + 1 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 , + // 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 + // @ A B C D E F G H I J K L M N O + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 + // P Q R S T U V W X Y Z [ \ ] ^ _ + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 , + // 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 + // ` a b c d e f g h i j k l m n o + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 + // p q r s t u v w x y z { | } ~ + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 + // + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 + // � � � � � � � � � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 + // � � � � � � � � � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 + // � � � � � � � � � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + // 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 + // � � � � � � � � + 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + }; + + + if(m_bReadOnly)return false; + + KviFile f(m_szFileName); + if(!f.openForWriting())return false; + if(f.writeBlock("# KVIrc configuration file\n",27) != 27)return false; + + KviPointerHashTableIterator<QString,KviConfigGroup> it(*m_pDict); + while (it.current()) + { + if((it.current()->count() != 0) || (m_bPreserveEmptyGroups)) + { + KviStr group(m_bLocal8Bit ? KviQString::toLocal8Bit(it.currentKey()) : KviQString::toUtf8(it.currentKey())); + group.hexEncodeWithTable(encode_table); + + if(!f.putChar('['))return false; + if(f.writeBlock(group.ptr(),group.len()) < (int) group.len())return false; + if(f.writeBlock("]\n",2) < 2)return false; + + KviConfigGroup * dict = (KviConfigGroup *)it.current(); + KviConfigGroupIterator it2(*dict); + + KviStr szName,szValue; + while(QString * p_str = it2.current()) + { + szName = m_bLocal8Bit ? KviQString::toLocal8Bit(it2.currentKey()) : KviQString::toUtf8(it2.currentKey()); + szValue = m_bLocal8Bit ? KviQString::toLocal8Bit(*p_str) : KviQString::toUtf8(*p_str); + szName.hexEncodeWithTable(encode_table); + szValue.hexEncodeWhiteSpace(); + + if(f.writeBlock(szName.ptr(),szName.len()) < (int) szName.len())return false; + if(!f.putChar('='))return false; + if(f.writeBlock(szValue.ptr(),szValue.len()) < (int) szValue.len())return false; + if(!f.putChar('\n'))return false; + ++it2; + } + } + ++it; + } + f.close(); + m_bDirty = false; + return true; +} + +void KviConfig::setGroup(const QString & szGroup) +{ + m_szGroup = szGroup; + if(m_bPreserveEmptyGroups) + { + if(!hasGroup(szGroup)) + { + getCurrentGroup(); // we need it to be created. + m_bDirty = true; + } + } +} + +bool KviConfig::hasKey(const QString & szKey) +{ + KviConfigGroup * p_group = getCurrentGroup(); + return (p_group->find(szKey) != 0); +} + +bool KviConfig::hasGroup(const QString & szGroup) +{ + return (m_pDict->find(szGroup) != 0); +} + +KviConfigGroup * KviConfig::getCurrentGroup() +{ + if(m_szGroup.isEmpty())m_szGroup = KVI_CONFIG_DEFAULT_GROUP; + KviConfigGroup * p_group = m_pDict->find(m_szGroup); + if(!p_group) + { + //create the group + p_group = new KviConfigGroup(17,false); + p_group->setAutoDelete(true); + m_pDict->insert(m_szGroup,p_group); + } + return p_group; +} + +////////////////////////////////// KviStr + +void KviConfig::writeEntry(const QString & szKey,const QString & szValue) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data=new QString(szValue); + p_group->replace(szKey,p_data); +} + +// FIXME: #warning "We have probs here ?" + +QString KviConfig::readEntry(const QString & szKey,const QString & szDefault) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str) + { + m_szStrBuffer = szDefault; + } else { + m_szStrBuffer = *p_str; + } + return m_szStrBuffer; +} + +//////////////////////////////////// QString + +/* +QString KviConfig::readQStringEntry(const char *szKey,const QString &szDefault) +{ + KviStrDict * p_group = getCurrentGroup(); + KviStr * p_str = p_group->find(szKey); + if(!p_str)return szDefault; + return QString::fromUtf8(p_str->ptr()); +} +*/ + +/* +void KviConfig::writeEntry(const char *szKey,const QString &szValue) +{ + m_bDirty = true; + KviStrDict * p_group = getCurrentGroup(); + p_group->replace(szKey,new KviStr(szValue.utf8().data())); +} +*/ + +////////////////////////////////// QStringList + +static QString g_szConfigStringListSeparator(",\\[ITEM],"); + +QStringList KviConfig::readStringListEntry(const QString & szKey,const QStringList &list) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return list; +#ifdef COMPILE_USE_QT4 + return p_str->split(g_szConfigStringListSeparator); +#else + return QStringList::split(g_szConfigStringListSeparator,*p_str); +#endif +} + +void KviConfig::writeEntry(const QString & szKey,const QStringList &list) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data=new QString(list.join(g_szConfigStringListSeparator)); + p_group->replace(szKey,p_data); +} + +////////////////////////////////// KviValueList<int> + +KviValueList<int> KviConfig::readIntListEntry(const QString & szKey,const KviValueList<int> &list) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str) + { + //debug("Returning default list for group %s and key %s",m_szGroup.latin1(),szKey.latin1()); + return list; + } +#ifdef COMPILE_USE_QT4 + QStringList sl = p_str->split(","); +#else + QStringList sl = QStringList::split(",",*p_str); +#endif + KviValueList<int> ret; + + //debug("Got option list for group %s and key %s: %s",m_szGroup.latin1(),szKey.latin1(),p_str->latin1()); + + for(QStringList::Iterator it = sl.begin();it != sl.end();++it) + { + bool bOk; + int iTmp = (*it).toInt(&bOk); + if(bOk)ret.append(iTmp); + } + + return ret; +} + + +void KviConfig::writeEntry(const QString & szKey,const KviValueList<int> &list) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + KviStr szData; + for(KviValueList<int>::ConstIterator it = list.begin();it != list.end();++it) + { + if(szData.hasData())szData.append(','); + szData.append(KviStr::Format,"%d",*it); + } + //debug("Writing option list for group %s and key %s: %s",m_szGroup.latin1(),szKey.latin1(),szData.ptr()); + + p_group->replace(szKey,new QString(szData.ptr())); +} + +////////////////////////////////// KviPixmap + +// FIXME: #warning "Spaces in image names ?" + +void KviConfig::writeEntry(const QString & szKey,const KviPixmap &pixmap) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data=new QString(); + KviStringConversion::toString(pixmap,*p_data); + p_group->replace(szKey,p_data); +} + +KviPixmap KviConfig::readPixmapEntry(const QString & szKey,const KviPixmap &pixDef) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(p_str) + { + KviPixmap ret(""); + return KviStringConversion::fromString(*p_str,ret) ? ret : pixDef; + } else { + return pixDef; + } +} + +////////////////////////////////// KviMsgType + +void KviConfig::writeEntry(const QString & szKey,const KviMsgType &msg) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString szData; + KviStringConversion::toString(msg,szData); + p_group->replace(szKey,new QString(szData)); +} + +KviMsgType KviConfig::readMsgTypeEntry(const QString & szKey,const KviMsgType &msgDef) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return msgDef; + KviMsgType ret = msgDef; + KviStringConversion::fromString(*p_str,ret); + return ret; +} + +////////////////////////////////// QColor + +void KviConfig::writeEntry(const QString & szKey,const QColor &clr) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + KviStr szData(KviStr::Format,"%d,%d,%d",clr.red(),clr.green(),clr.blue()); + p_group->replace(szKey,new QString(szData.ptr())); +} + +QColor KviConfig::readColorEntry(const QString & szKey,const QColor &clr) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QColor color(clr); + QString * pointer_that_IS_initialized = p_group->find(szKey); + + + if(pointer_that_IS_initialized) + { + + KviStr str(*pointer_that_IS_initialized); + str.stripLeftWhiteSpace(); + + KviStr red,green,blue; + + str.getToken(red,','); + str.getToken(green,','); + str.getToken(blue,','); + + if((red.isUnsignedNum())&&(green.isUnsignedNum())&&(blue.isUnsignedNum())){ + bool bOk; + int r = red.toInt(&bOk) % 256; + int g = green.toInt(&bOk) % 256; + int b = blue.toInt(&bOk) % 256; + if(r < 0)r = -r; + if(g < 0)g = -g; + if(b < 0)b = -b; + color.setRgb(r,g,b); + } + } + return color; +} + +////////////////////////////////// QFont + +void KviConfig::getFontProperties(KviStr & buffer,QFont *fnt) +{ + QString tmp; + KviStringConversion::toString(*fnt,tmp); + buffer = tmp; +} + +void KviConfig::writeEntry(const QString & szKey,QFont &fnt) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data = new QString(); + KviStringConversion::toString(fnt,*p_data); + p_group->replace(szKey,p_data); +} + + +void KviConfig::setFontProperties(KviStr & str,QFont *fnt) +{ + KviStringConversion::fromString(str.ptr(),*fnt); +} + +QFont KviConfig::readFontEntry(const QString & szKey,const QFont &fnt) +{ + QFont font(fnt); + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(p_str) + { + //FontEntry=Arial,12,9,0,100,italic,underline,strikeout, + KviStr str(*p_str); + str.stripLeftWhiteSpace(); + setFontProperties(str,&font); + } + return font; +} + +////////////////////////////////// bool + +void KviConfig::writeEntry(const QString & szKey,bool bTrue) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data = new QString(bTrue ? "true" : "false"); + p_group->replace(szKey,p_data); +} + +bool KviConfig::readBoolEntry(const QString & szKey,bool bTrue) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return bTrue; + static QString szTrue = "true"; + return (KviQString::toLower(*p_str) == szTrue); +} + +////////////////////////////////// QRect + +void KviConfig::writeEntry(const QString & szKey,const QRect &rct) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString szBuf; + KviStringConversion::toString(rct,szBuf); + p_group->replace(szKey,new QString(szBuf)); +} + +QRect KviConfig::readRectEntry(const QString & szKey,const QRect &rct) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * str = p_group->find(szKey); + if(!str)return rct; + QRect ret; + return KviStringConversion::fromString(*str,ret) ? ret : rct; +} + +////////////////////////////////// unsigned short + +void KviConfig::writeEntry(const QString & szKey,unsigned short usValue) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data = new QString(); + p_data->setNum(usValue); + p_group->replace(szKey,p_data); +} + +unsigned short int KviConfig::readUShortEntry(const QString & szKey,unsigned short int usDefault) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return usDefault; + bool bOk; + unsigned short int usVal=p_str->toUShort(&bOk); + return bOk ? usVal : usDefault; +} + +/* +////////////////////////////////// unsigned long + +Unused code +void KviConfig::writeEntry(const char *szKey,unsigned long lValue) +{ + m_bDirty = true; + KviStrDict * p_group = getCurrentGroup(); + KviStr *p_data = new KviStr(); + p_data->setNum(lValue); + p_group->replace(szKey,p_data); +} + +unsigned long KviConfig::readULongEntry(const char *szKey,unsigned long lDefault) +{ + KviStrDict * p_group = getCurrentGroup(); + KviStr * p_str = p_group->find(szKey); + if(!p_str)return lDefault; + bool bOk; + unsigned long lVal=p_str->toULong(&bOk); + return bOk ? lVal : lDefault; +} +*/ + +////////////////////////////////// int + +void KviConfig::writeEntry(const QString & szKey,int iValue) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data = new QString(); + p_data->setNum(iValue); + p_group->replace(szKey,p_data); +} + +int KviConfig::readIntEntry(const QString & szKey,int iDefault) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return iDefault; + bool bOk; + int iVal=p_str->toInt(&bOk); + return bOk ? iVal : iDefault; +} + +////////////////////////////////// unsigned int + +void KviConfig::writeEntry(const QString & szKey,unsigned int iValue) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data = new QString(); + p_data->setNum(iValue); + p_group->replace(szKey,p_data); +} + +unsigned int KviConfig::readUIntEntry(const QString & szKey,unsigned int iDefault) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return iDefault; + bool bOk; + unsigned int iVal=p_str->toUInt(&bOk); + return bOk ? iVal : iDefault; +} + +////////////////////////////////// char + +void KviConfig::writeEntry(const QString & szKey,char iValue) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_data = new QString(); + p_data->setNum(iValue); + p_group->replace(szKey,p_data); +} + +char KviConfig::readCharEntry(const QString & szKey,char iDefault) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return iDefault; + bool bOk; + char iVal=(char)p_str->toInt(&bOk); + return bOk ? iVal : iDefault; +} + +////////////////////////////////// unsigned char + +void KviConfig::writeEntry(const QString & szKey,unsigned char iValue) +{ + m_bDirty = true; + KviConfigGroup * p_group = getCurrentGroup(); + QString *p_data = new QString(); + p_data->setNum(iValue); + p_group->replace(szKey,p_data); +} + +unsigned char KviConfig::readUCharEntry(const QString & szKey,unsigned char iDefault) +{ + KviConfigGroup * p_group = getCurrentGroup(); + QString * p_str = p_group->find(szKey); + if(!p_str)return iDefault; + bool bOk; + unsigned char iVal=(unsigned char)p_str->toUInt(&bOk); + return bOk ? iVal : iDefault; +} + + +#ifdef COMPILE_ON_WINDOWS + + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + + void * KviConfig::operator new(size_t tSize) + { + return kvi_malloc(tSize); + } + + void KviConfig::operator delete(void * p) + { + kvi_free(p); + } + +#endif diff --git a/src/kvilib/ext/kvi_config.h b/src/kvilib/ext/kvi_config.h new file mode 100644 index 00000000..6eef4e05 --- /dev/null +++ b/src/kvilib/ext/kvi_config.h @@ -0,0 +1,162 @@ +#ifndef _KVI_CONFIG_H_INCLUDED_ +#define _KVI_CONFIG_H_INCLUDED_ + +//============================================================================= +// +// File : kvi_config.h (/usr/build/NEW_kvirc/kvirc/kvilib/kvi_config.h) +// Last major modification : Thu Jan 14 1999 18:01:22 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_string.h" +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_pointerhashtable.h" +#include "kvi_valuelist.h" + +#include <qcolor.h> +#include <qfont.h> +#include <qrect.h> +#include <qstringlist.h> + +#define KVI_CONFIG_DEFAULT_GROUP "KVIrc" + +class KviPixmap; +class KviMsgType; + +typedef KviPointerHashTable<QString,QString> KviConfigGroup; +typedef KviPointerHashTableIterator<QString,QString> KviConfigGroupIterator; +typedef KviPointerHashTableIterator<QString,KviConfigGroup> KviConfigIterator; + +class KVILIB_API KviConfig : public KviHeapObject +{ +public: + enum FileMode { Read = 1 , Write = 2 , ReadWrite = 3 }; +public: + KviConfig(const QString &filename,FileMode f/* = ReadWrite*/,bool bLocal8Bit = false); + KviConfig(const char *filename,FileMode f/* = ReadWrite*/,bool bLocal8Bit = false); + ~KviConfig(); +private: + bool m_bLocal8Bit; + KviPointerHashTable<QString,KviConfigGroup> * m_pDict; + QString m_szFileName; + bool m_bDirty; + QString m_szStrBuffer; + QString m_szGroup; + bool m_bPreserveEmptyGroups; + bool m_bReadOnly; +private: + bool load(); + bool save(); + KviConfigGroup * getCurrentGroup(); +public: + // + // Useful when saving... + // Normally this class does not save empty groups + // and setGroup() is never a config modification. + // If the group is not existing it will be effectively + // created only at the first attempt to read from it or write to it. + // With this flag set to true the KviConfig class will + // write down also the empty groups , and calls to setGroup() + // will create the groups if not existing yet (and set the config data + // as modified). + // + void preserveEmptyGroups(bool bPreserve){ m_bPreserveEmptyGroups = bPreserve; }; + const QString & fileName(){ return m_szFileName; }; + bool readOnly(){ return m_bReadOnly; }; + void setReadOnly(bool bReadOnly){ m_bReadOnly = bReadOnly; }; + bool dirty(){ return m_bDirty; }; + // + // This sets the save path for the config file + // In this way you can load a system-wide read-only config file + // as default configuration, alter its settings and save it to the + // user local configuration directory + void setSavePath(const QString & savePath){ m_szFileName = savePath; }; + KviPointerHashTable<QString,KviConfigGroup> *dict(){ return m_pDict; }; + + void clearDirtyFlag(){ m_bDirty = false; }; + void clear(); + void clearGroup(const QString & szGroup); + void clearKey(const QString & szKey); + unsigned int groupsCount(){ return m_pDict->count(); }; + bool sync(){ return save(); }; + bool hasKey(const QString & szKey); + bool hasGroup(const QString & szGroup); + void setGroup(const QString & szGroup); + //void getContentsString(KviStr &buffer); + const QString & group(){ return m_szGroup; }; + void writeEntry(const QString & szKey,const QString & szValue); + void writeEntry(const QString & szKey,const char * szValue) + { writeEntry(szKey,QString::fromUtf8(szValue)); }; + QString readEntry(const QString & szKey,const QString & szDefault = QString::null); + // HACK for KviOptions.. (FIXME) + QString readKviStrEntry(const QString &szKey,const KviStr &szDefault) + { return readEntry(szKey,szDefault.ptr()); }; + //void writeEntry(const char *szKey,KviStr &szValue); + //const char * readEntry(const char *szKey,KviStr &szDefault); + void writeEntry(const QString & szKey,const KviPixmap &pixmap); + KviPixmap readPixmapEntry(const QString & szKey,const KviPixmap &pixDef); + void writeEntry(const QString & szKey,const KviMsgType &msg); + KviMsgType readMsgTypeEntry(const QString & szKey,const KviMsgType &msgDef); + void writeEntry(const QString & szKey,const QColor &clr); + QColor readColorEntry(const QString & szKey,const QColor &clr); + void writeEntry(const QString & szKey,QFont &fnt); + QFont readFontEntry(const QString & szKey,const QFont &fnt); + void writeEntry(const QString & szKey,bool bTrue); + bool readBoolEntry(const QString & szKey,bool bTrue); + QRect readRectEntry(const QString & szKey,const QRect &rct); + void writeEntry(const QString & szKey,const QRect &rct); + QStringList readStringListEntry(const QString & szKey,const QStringList &list); + void writeEntry(const QString & szKey,const QStringList &list); + KviValueList<int> readIntListEntry(const QString & ,const KviValueList<int> &list); + void writeEntry(const QString & szKey,const KviValueList<int> &list); + QString readQStringEntry(const QString & szKey,const QString &szDefault = QString::null) + { return readEntry(szKey,szDefault); }; + //void writeEntry(const QString & szKey,const QString &szValue); + //void writeEntry(const char *szKey,unsigned long lValue); + //unsigned long readULongEntry(const char *szKey,unsigned long lDefault); + //void writeEntry(const char *szKey,long lValue); + //long readLongEntry(const char *szKey,long lDefault); + void writeEntry(const QString & szKey,int iValue); + int readIntEntry(const QString & szKey,int iDefault); + void writeEntry(const QString & szKey,unsigned short int usValue); + unsigned short int readUShortEntry(const QString & szKey,unsigned short int usDefault); + void writeEntry(const QString & szKey,unsigned int iValue); + unsigned int readUIntEntry(const QString & szKey,unsigned int iDefault); + void writeEntry(const QString & szKey,char iValue); + char readCharEntry(const QString & szKey,char iDefault); + void writeEntry(const QString & szKey,unsigned char iValue); + unsigned char readUCharEntry(const QString & szKey,unsigned char iDefault); + + static void getFontProperties(KviStr & buffer,QFont *fnt); + static void setFontProperties(KviStr & str,QFont *fnt); + +#ifdef COMPILE_ON_WINDOWS + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + void * operator new(size_t tSize); + void operator delete(void * p); +#endif +}; + +#endif //!_KVI_CONFIG_H_INCLUDED_ diff --git a/src/kvilib/ext/kvi_crypt.cpp b/src/kvilib/ext/kvi_crypt.cpp new file mode 100644 index 00000000..84a636aa --- /dev/null +++ b/src/kvilib/ext/kvi_crypt.cpp @@ -0,0 +1,240 @@ +//============================================================================= +// +// File : kvi_crypt.cpp +// Creation date : Fri Nov 03 2000 02:34:43 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include "kvi_crypt.h" +#include "kvi_locale.h" + +#ifdef COMPILE_ON_WINDOWS + #include "kvi_malloc.h" +#endif + +/* + @doc: crypt_engines + @type: + generic + @keyterms: + cryptography, privacy, private key, text transformation + @title: + Cryptography and text transformation + @short: + Crypt/text transformation engines and how to use them + @body: + [big]Introduction[/big][br] + Well , there is a concrete background noise about security around the net. + And I've thought that adding a little cryptography support to KVIrc wasn't + a bad idea. So I've first comed out with the "crypt engines", that + allowed to have secure conversations on channels, queries and dcc chats; + then found out that the realized structure was perfect to be "generalized" + into "text transformation" support.[br] + [big]The concept[/big][br] + In few words, the "text transformation" engine is a layer between the user and the + IRC connection. You type some text in the input line of a query window (for example), + the engine transforms the text in some way and then sends it to the remote target. + The trick works also in the reverse way: some data come from the remote target, + the engine retransforms the text in some other way and displays it to the local user.[br] + The "incoming" transformation is usually the inverse of the "outgoing" one, but it + is not mandatory. It will become clear in few sentences that some engines will do no "incoming" + transformation at all. The original use of the transformation engines was to crypt the + outgoing data and to decrypt the incoming data; anyway, the engines can perform + other funky tasks. One of them is remapping the local charset to a "standardized" one + when sending text to a channel (or some other target) and doing the inverse map on + the way back. A totally "fantastic" usage of this concept could be an "on-the-fly translator"; + it could translate for example Italian to English while sending to a channel + and English to Italian on the way back...the implementation of a such engine is left + to the reader as exercise :) Another (maybe less interesting) usage is to + colorize the outgoing text, or transform it + in a way that it is still readable but has a different look. This engine + would not require a back transformation (so no "decrypt stage"). A "symmetric" + idea could be an engine that strips the color codes from the incoming text: this + engine would not require a "crypting" stage.[br] + + [big]The name of this stuf[/big][br] + Initially all this stuff was named "cryptography support". + Then the "cryptography" comed out to be not "enough" to describe + the framework, so "text transformation" is a more generic term. + Anyway, both terms were used in the documentation and the source. + Just as example, the "text transformation engine" is called + KviCryptEngine in the sources. So actually the terms "crypt" + and "text transformations" refer to the "same thing". + You will often find the term "encrypt" standing for "outgoing text + transformation" and "decrypt" standing for "incoming text transformation".[br] + + [big]Yes, but why cryptography (on IRC) ?[/big][br] + Because it MAY be useful. More than once people have asked me to add some + crypting support to the dcc chats. Yes , I know that there are other + "secure communication" tools , but actually I can't find one that is able to + implement a "secure real time conversation". And what about a MULTIPLE real + time secure conversation ? This can be done on an IRC channel now.[br] + + [big]The working things[/big][br] + KVIrc can use a text transformation engine on irc channels, in the queries + and the dcc chats. At the time I am writing, only the [module:rijndael]Rijndael[/module] crypt engine + is available: this is a private key encryption algorithm that assures + a "pretty good" security level. More engines will be surely available + at the time of the 3.0.0 release of KVIrc. The engines + can be activated by the dedicated dialog that can be accessed from the "button bar" + of the window. Once an engine has been enabled all the text that you type + in the input line (that is not a command obviously) is encrypted + and sent to the remote endpoint. If you want to sent a non crypted message + while an engine is working you can use the CTRL+P escape: by placing + that character as the FIRST CHARACTER of the line you will avoid crypting. + Every engine has different capabilities: some can both encrypt + and decrypt, other perform only half of the operations. Some engines + need a key (the crypt engines obviously), or two keys (you can specify + one for the outgoing data and one for the incoming). You can specify + all these options in the crypt/text transformation dialog.[br] + Obviously (with the current implementations) all the conversation endpoints + must agree on the engine (or better algorithm) used and on the key(s). + The key is user specified, so you have to find a secure way to negotiate + it with your communication engpoints. If you can meet the persons in the "real life", + this is the best way to exchange the keys, otherwise you can use mail & pgp. + Yes, this is a "miss" of the crypt protocol: it is missing a public key handshake.[br] + + [big]The first test[/big][br] + A cool way to test a crypting engine is to use a "self query": connect to + any irc server, and execute [cmd]query[/cmd] <yournickname>; a query window + with you both as source and target will popup; activate a crypt engine + and enable both encryption and decryption; specify the same key for + bot directions and then type some text in the input line: you will see + the message twice: one is "your local text" and the other is the server routed one. + Then you can try to activate encryption only and leaving decryption disabled: + you will see how the text would appear to a possible "man in the middle". + You can also try to use different keys for encrypting and decrypting, + and play with the CTRL+P escape.[br] + + [big]The protocol[/big][br] + Well, there is no protocol actually , only the existing implementations , that + can be accessed by anyone that want to reproduce them. There are only some + points relating to the crypting engines that need to be cleared:[br] + The crypted text must be suitable to be sent thru an IRC connection; + this means that some characters can not appear in the crypted text (e.g. CR,LF,NULL....). + KVIrc solves it in a simple way: the crypted binary data is encoded, + either as hexadecimal numeric string or in base64.[br] + An escape character has been defined to identify messages that are "crypted" from the + ones that are not: this character has ascii code 30 (decimal).[br] + The encoding is used in private messages only and has the following format:[br] + PRIVMSG <target> :<escape_char_ascii_30><encrypted message>[br] + ASCII 30 does not correspond to any widely used escape sequence and allows + mixing encrypted and plain text messages in a conversation...Well, this is not + so pretty but you can exchange crypted messages with one or two friends while + talking on a normal IRC channel: nobody else than your friends will be able + to understand the message; others will see senseless sequences of characters. + You will be still able to read the unencrypted messages of the other people + on the channel.[br] The escape character is not needed if the engine + performs non-crypting tasks: a charset mapper will produce text that + is meant to be readed by anyone on the channel, a text colorizer will + act in a similar way too. So the escape character is used for the "crypting" + engines only. + + [big]An idea for the future implementations[/big][br] + A "public key" handshake protocol could be implemented. +*/ + + + KviCryptEngine::KviCryptEngine() + { +#ifdef COMPILE_CRYPT_SUPPORT + setLastError(__tr2qs("Invalid crypt engine")); + m_iMaxEncryptLen = -1; // unlimited + m_deallocFunc = 0; +#endif //COMPILE_CRYPT_SUPPORT + } + + KviCryptEngine::~KviCryptEngine() + { + } + +#ifdef COMPILE_CRYPT_SUPPORT + + bool KviCryptEngine::init(const char *,int,const char *,int) + { + return false; + } + + KviCryptEngine::EncryptResult KviCryptEngine::encrypt(const char *,KviStr &) + { +// debug("Pure virtual KviCryptEngine::encrypt() called"); + return EncryptError; + } + + KviCryptEngine::DecryptResult KviCryptEngine::decrypt(const char *,KviStr &) + { +// debug("Pure virtual KviCryptEngine::decrypt() called"); + return DecryptError; + } + + + KviCryptEngineManager::KviCryptEngineManager() + { + m_pEngineDict = new KviPointerHashTable<QString,KviCryptEngineDescription>; + m_pEngineDict->setAutoDelete(true); + } + + KviCryptEngineManager::~KviCryptEngineManager() + { + delete m_pEngineDict; + } + + void KviCryptEngineManager::registerEngine(KviCryptEngineDescription * d) + { + m_pEngineDict->replace(d->szName,d); + } + + void KviCryptEngineManager::unregisterEngine(const QString &szName) + { + m_pEngineDict->remove(szName); + } + + void KviCryptEngineManager::unregisterEngines(void * providerHandle) + { + KviPointerHashTableIterator<QString,KviCryptEngineDescription> it(*m_pEngineDict); + while(it.current()) + { + if(it.current()->providerHandle == providerHandle) + m_pEngineDict->remove(it.currentKey()); + else + ++it; + } + } + + KviCryptEngine * KviCryptEngineManager::allocateEngine(const QString &szName) + { + KviCryptEngineDescription * d = m_pEngineDict->find(szName); + if(!d)return 0; + KviCryptEngine * e = d->allocFunc(); + if(!e)return 0; + e->m_deallocFunc = d->deallocFunc; // remember the dealloc func from now on + return e; + } + + void KviCryptEngineManager::deallocateEngine(KviCryptEngine * e) + { + if(!e)return; + crypt_engine_deallocator_func deallocFunc = e->m_deallocFunc; + deallocFunc(e); + } + +#endif //COMPILE_CRYPT_SUPPORT diff --git a/src/kvilib/ext/kvi_crypt.h b/src/kvilib/ext/kvi_crypt.h new file mode 100644 index 00000000..ae3bc4f0 --- /dev/null +++ b/src/kvilib/ext/kvi_crypt.h @@ -0,0 +1,160 @@ +#ifndef _KVI_CRYPT_H_ +#define _KVI_CRYPT_H_ + +//============================================================================= +// +// File : kvi_crypt.h +// Creation date : Fri Nov 03 2000 01:45:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + + +// +// Base class for all IRC crypt engines +// These intend to encrypt plain text into something +// that can be sent through the IRC protocol... +// so it should not contain NULL, CR , LF and other +// similar stuff... +// + + +#include "kvi_qstring.h" +#include "kvi_string.h" +#include "kvi_heapobject.h" +#include "kvi_pointerhashtable.h" + +#include <qobject.h> + +#ifdef COMPILE_CRYPT_SUPPORT + class KviCryptEngine; + + typedef KviCryptEngine * (*crypt_engine_allocator_func)(); + typedef void (*crypt_engine_deallocator_func)(KviCryptEngine *); +#endif //COMPILE_CRYPT_SUPPORT + + // we must include this declaration to make moc happy even + // if we're not compiling the crypt support + + class KVILIB_API KviCryptEngine : public QObject, public KviHeapObject + { + Q_OBJECT + friend class KviCryptEngineManager; + public: + KviCryptEngine(); + virtual ~KviCryptEngine(); + +#ifdef COMPILE_CRYPT_SUPPORT + private: + crypt_engine_deallocator_func m_deallocFunc; // this is accessed by KviCryptEngineManager only + QString m_szLastError; + int m_iMaxEncryptLen; + public: + void setMaxEncryptLen(int m){ m_iMaxEncryptLen = m; }; + int maxEncryptLen(){ return m_iMaxEncryptLen; }; + virtual bool init(const char * encKey,int encKeyLen,const char * decKey,int decKeyLen); + // + // Encrypts utf8 plainText and returns the encrypted + // data in outBuffer. The encrypted data must be + // suitable for sending thru an IRC (eventually DCC + // that is less restrictive) connection and must be utf8 encoded: so + // no NULL, CR and LF in the output. + // 0x01 should be also avoided since + // it is the CTCP delimiter. + // Converting the result in a HEX string + // is a good trick...also Base64 could be used. + // Should return false in case of an error. + // Theoretically we could allow NULLs in plainText + // but this is not the case of KVIrc. + // + enum EncryptResult { Encrypted, Encoded, EncryptError }; + virtual EncryptResult encrypt(const char * plainText,KviStr &outBuffer); + // + // Decrypts the utf8 data in inBuffer and puts the decrypted utf8 + // stuff in plainText. inBuffer is the thingie + // that we got from outBuffer of encrupt() so it + // follows the same rules. + // Should return false in case of error. + // + enum DecryptResult { DecryptOkWasEncrypted, DecryptOkWasEncoded, DecryptOkWasPlainText, DecryptError }; + virtual DecryptResult decrypt(const char * inBuffer,KviStr &plainText); + // + // Returns the string containing the description + // of the last error or an empty string if there + // was no error after the last init() call. + // + const QString &lastError(){ return m_szLastError; }; + protected: + // + // The following two should have clear meaning + // + void clearLastError(){ m_szLastError = ""; }; + void setLastError(const QString &err){ m_szLastError = err; }; +#endif //COMPILE_CRYPT_SUPPORT + }; + +#ifdef COMPILE_CRYPT_SUPPORT + #define KVI_CRYPTENGINE_CAN_ENCRYPT 1 + #define KVI_CRYPTENGINE_CAN_DECRYPT 2 + #define KVI_CRYPTENGINE_WANT_ENCRYPT_KEY 4 + #define KVI_CRYPTENGINE_WANT_DECRYPT_KEY 8 + + class KVILIB_API KviCryptEngineDescription : public KviHeapObject + { + public: + KviCryptEngineDescription(){}; + virtual ~KviCryptEngineDescription(){}; + public: + QString szName; // engine name + QString szDescription; // details + QString szAuthor; // algorithm author + int iFlags; // properties + crypt_engine_allocator_func allocFunc; // engine allocator + crypt_engine_deallocator_func deallocFunc; // deallocation function (if called from outside the origin module) + void * providerHandle; // used to identify the provider module + }; + + + class KVILIB_API KviCryptEngineManager + { + public: + KviCryptEngineManager(); + virtual ~KviCryptEngineManager(); + private: + KviPointerHashTable<QString,KviCryptEngineDescription> * m_pEngineDict; + public: + const KviPointerHashTable<QString,KviCryptEngineDescription> * engineDict(){ return m_pEngineDict; }; + void registerEngine(KviCryptEngineDescription * d); + void unregisterEngine(const QString &szName); + void unregisterEngines(void * providerHandle); + // + // Allocates a crypt engine + // Please note that the engine may be deleted from outside + // so you'd better connect the "destroyed" signal + // + KviCryptEngine * allocateEngine(const QString &szName); + void deallocateEngine(KviCryptEngine * e); + }; + +#endif //COMPILE_CRYPT_SUPPORT + + +#endif //!_KVI_CRYPT_H_ diff --git a/src/kvilib/ext/kvi_databuffer.cpp b/src/kvilib/ext/kvi_databuffer.cpp new file mode 100644 index 00000000..7cad39c4 --- /dev/null +++ b/src/kvilib/ext/kvi_databuffer.cpp @@ -0,0 +1,135 @@ +// +// File : kvi_databuffer.cpp +// Creation date : Thu Aug 23 17:04:24 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#define _KVI_DEBUG_CHECK_RANGE_ + +#include "kvi_debug.h" + +#include "kvi_databuffer.h" +#include "kvi_malloc.h" +#include "kvi_memmove.h" + +// FIXME: this could resize in chunks!...this would be damn faster :) + +KviDataBuffer::KviDataBuffer(int uSize,const unsigned char * data) +{ + __range_valid(uSize > 0); + m_uSize = uSize; + m_pData = (unsigned char *)kvi_malloc(sizeof(unsigned char) * uSize); + if(data)kvi_memmove(m_pData,data,uSize); +} + +KviDataBuffer::KviDataBuffer() +{ + m_uSize = 0; + m_pData = 0; +} + +KviDataBuffer::~KviDataBuffer() +{ + if(m_pData) + { + __range_valid(m_uSize); + kvi_free(m_pData); + } +} + +int KviDataBuffer::find(const unsigned char * block,int uSize) +{ + if(uSize < 1)return -1; + if(uSize > m_uSize)return -1; + + int uSearchSize = (m_uSize - uSize) + 1; + + for(int i=0;i<uSearchSize;i++) + { + if(m_pData[i] == *block) + { + // good beginning + if(uSize == 1)return i; + int j; + for(j = 1;j<uSize;j++) + { + if(m_pData[i + j] != block[j]) + { + j = 0; + break; + } + } + if(j > 0)return i; + } + } + + return -1; +} + +int KviDataBuffer::find(unsigned char c) +{ + const unsigned char * p = m_pData; + const unsigned char * e = p + m_uSize; + while(p < e) + { + if(*p == c)return (p - m_pData); + p++; + } + return -1; +} + + +void KviDataBuffer::remove(int uSize) +{ + __range_valid((uSize <= m_uSize) && (uSize > 0)); + + m_uSize -= uSize; + + if(m_uSize > 0) + { + kvi_memmove(m_pData,m_pData + uSize,m_uSize); + m_pData = (unsigned char *)kvi_realloc(m_pData,m_uSize * sizeof(unsigned char)); + } else { + kvi_free(m_pData); + m_pData = 0; + } +} + +void KviDataBuffer::resize(int uSize) +{ + __range_valid(uSize >= 0); + if(uSize > 0) + { + m_pData = (unsigned char *)kvi_realloc(m_pData,uSize * sizeof(unsigned char)); + } else { + kvi_free(m_pData); + m_pData = 0; + } + m_uSize = uSize; +} + +void KviDataBuffer::append(const unsigned char * data,int uSize) +{ + m_pData = (unsigned char *)kvi_realloc(m_pData,m_uSize + uSize); + kvi_memmove(m_pData + m_uSize,data,uSize); + m_uSize += uSize; +} diff --git a/src/kvilib/ext/kvi_databuffer.h b/src/kvilib/ext/kvi_databuffer.h new file mode 100644 index 00000000..62e09b06 --- /dev/null +++ b/src/kvilib/ext/kvi_databuffer.h @@ -0,0 +1,56 @@ +#ifndef _KVI_DATABUFFER_H_ +#define _KVI_DATABUFFER_H_ +// +// File : kvi_databuffer.h +// Creation date : Thu Aug 23 17:04:25 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_heapobject.h" + +class KVILIB_API KviDataBuffer : public KviHeapObject +{ +public: + // uSize MUST be greater than 0 + // if data is non-zero, it MUST point to a buffer at least uSize bytes long + // and the data is COPIED from that buffer! + KviDataBuffer(int uSize,const unsigned char * data = 0); + KviDataBuffer(); + ~KviDataBuffer(); +private: + int m_uSize; + unsigned char * m_pData; +public: + int size() const { return m_uSize; }; + unsigned char * data() const { return m_pData; }; + // uSize MUST be smaller or equal to size() + // consumes data! + void remove(int uSize); + void clear(){ if(m_uSize > 0)remove(m_uSize); }; + // uSize MUST be greater than 0 + void resize(int uSize); + void addSize(int uSize){ resize(m_uSize + uSize); }; + void append(const unsigned char * data,int uSize); + void append(const KviDataBuffer &b){ append(b.data(),b.size()); }; + int find(unsigned char c); + int find(const unsigned char * block,int uSize); +}; + +#endif //_KVI_DATABUFFER_H_ diff --git a/src/kvilib/ext/kvi_dcophelper.cpp b/src/kvilib/ext/kvi_dcophelper.cpp new file mode 100644 index 00000000..83f34f4e --- /dev/null +++ b/src/kvilib/ext/kvi_dcophelper.cpp @@ -0,0 +1,357 @@ +//============================================================================= +// +// File : kvi_dcophelper.cpp +// Created on Sat 20 Jan 2007 12:35:21 by Alexander Stillich +// +// This file is part of the KVIrc IRC client distribution +// Copyright (C) 2005 Szymon Stefanek <pragma at kvirc dot net> +// Copyright (C) 2007 Alexander Stillich <torque at pltn dot org> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_dcophelper.h" + +#ifdef COMPILE_KDE_SUPPORT + +#include "dcopclient.h" + +#include <qdatastream.h> +#include <qvaluelist.h> + +// must be included this way, since kvilib is built +// before kvirc and symlinks to headers aren't set yet +#include "../../kvirc/kernel/kvi_app.h" +#include "kvi_thread.h" + +KviDCOPHelper::KviDCOPHelper(bool bStartApp, const KviQCString &szAppId) +{ + m_szAppId = szAppId; +} + +KviDCOPHelper::~KviDCOPHelper() +{ +} + +bool KviDCOPHelper::ensureAppRunning(const QString &szApp) +{ + if (findRunningApp(m_szAppId)) + return true; + + if (m_bStartApp) + return startApp(m_szAppId,400); + + return false; +} + + +bool KviDCOPHelper::voidRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data; + return g_pApp->dcopClient()->send(m_szAppId,szObj,szFunc,data); +} + +bool KviDCOPHelper::voidRetBoolDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,bool bVal) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << bVal; + return g_pApp->dcopClient()->send(m_szAppId,szObj,szFunc,data); +} + +bool KviDCOPHelper::voidRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int iVal) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << iVal; + return g_pApp->dcopClient()->send(m_szAppId,szObj,szFunc,data); +} + +bool KviDCOPHelper::voidRetIntBoolDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int iVal, bool bVal) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << iVal; + arg << bVal; + return g_pApp->dcopClient()->send(m_szAppId,szObj,szFunc,data); +} + +bool KviDCOPHelper::voidRetIntIntIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int iVal1, int iVal2, int iVal3) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << iVal1; + arg << iVal2; + arg << iVal3; + return g_pApp->dcopClient()->send(m_szAppId,szObj,szFunc,data); +} + +bool KviDCOPHelper::voidRetFloatDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,float fVal) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << fVal; + return g_pApp->dcopClient()->send(m_szAppId,szObj,szFunc,data); +} + +bool KviDCOPHelper::voidRetStringDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,const QString &szVal) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << szVal; + return g_pApp->dcopClient()->send(m_szAppId,szObj,szFunc,data); +} + +bool KviDCOPHelper::stringRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,QString &szRet) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data, replyData; + KviQCString replyType; + if(!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + QDataStream reply( replyData, IO_ReadOnly ); + if(replyType == "QString") + { + reply >> szRet; + return true; + } + return false; +} + +bool KviDCOPHelper::stringRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,QString &szRet,int iVal) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data, replyData; + KviQCString replyType; + + QDataStream arg(data, IO_WriteOnly); + arg << iVal; + + if(!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + + QDataStream reply( replyData, IO_ReadOnly ); + if(replyType == "QString") + { + reply >> szRet; + return true; + } + return false; +} + +bool KviDCOPHelper::intRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int &ret) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data, replyData; + KviQCString replyType; + if(!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + QDataStream reply( replyData, IO_ReadOnly ); + if(replyType == "int") + { + reply >> ret; + return true; + } + return false; +} + +bool KviDCOPHelper::intRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int &ret, int iVal) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data, replyData; + KviQCString replyType; + + QDataStream arg(data, IO_WriteOnly); + arg << iVal; + + if(!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + + QDataStream reply( replyData, IO_ReadOnly ); + if(replyType == "int") + { + reply >> ret; + return true; + } + return false; +} + +bool KviDCOPHelper::boolRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,bool &ret) +{ + if(!ensureAppRunning(m_szAppId))return false; + QByteArray data, replyData; + KviQCString replyType; + if(!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + QDataStream reply( replyData, IO_ReadOnly ); + if(replyType == "bool") + { + reply >> ret; + return true; + } + return false; +} + +bool KviDCOPHelper::qvalueListIntRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,KviValueList<int> &ret, int iVal) +{ + if(!ensureAppRunning(m_szAppId)) + return false; + + QByteArray data, replyData; + KviQCString replyType; + QDataStream arg(data, IO_WriteOnly); + + arg << iVal; + + + if(!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + + if(replyType != "QValueList<int>") + return false; + + QDataStream replyStream(replyData, IO_ReadOnly); + replyStream >> ret; + + return true; +} + +bool KviDCOPHelper::qcstringListRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,KviQCStringList &ret) +{ + QByteArray data, replyData; + KviQCString replyType; + + if (!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + + if (replyType != "KviQCStringList") + return false; + + QDataStream replyStream(replyData, IO_ReadOnly); + replyStream >> ret; + + return true; +} + +bool KviDCOPHelper::qcstringListRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,KviQCStringList &ret, int iVal) +{ + QByteArray data, replyData; + KviQCString replyType; + + QDataStream arg(data, IO_WriteOnly); + arg << iVal; + + if (!g_pApp->dcopClient()->call(m_szAppId,szObj,szFunc,data,replyType,replyData)) + return false; + + if (replyType != "KviQCStringList") + return false; + + QDataStream replyStream(replyData, IO_ReadOnly); + replyStream >> ret; + + return true; +} + +bool KviDCOPHelper::findRunningApp(const QString &szApp) +{ + QValueList<KviQCString> allApps = g_pApp->dcopClient() ->registeredApplications(); + QValueList<KviQCString>::iterator iterator; + KviQCString sz = szApp.local8Bit(); + for (iterator = allApps.begin();iterator != allApps.end();iterator++) + { + if(*iterator == sz) + return true; + } + return false; +} + +int KviDCOPHelper::detectApp(const QString &szApp,bool bStart,int iScoreWhenFound,int iScoreWhenStarted) +{ + // dcop available + if(!g_pApp->dcopClient()) + return 0; + + if(findRunningApp(szApp)) + return 95; // found a running app, no need to run further + + // no app found running + if(bStart) + { + // try to start it + if(!startApp(szApp,5000)) + return 10; // very low possibility + return findRunningApp(szApp) ? 99 : 0; // try to find it again + } + + return 30; // it still might be installed on the system but we're just unable to start it... +} + + +bool KviDCOPHelper::startApp(const QString &szApp,int iWaitMSecs) +{ + // we could use KApplication::startServiceByDesktopName here + // but we want to be able to wait a defined amount of time + QStringList tmp; + QByteArray data, replyData; + KviQCString replyType; + QDataStream arg(data, IO_WriteOnly); + arg << szApp << tmp; + if(!g_pApp->dcopClient()->call( + "klauncher", + "klauncher", + "start_service_by_desktop_name(QString,QStringList)", + data, + replyType, + replyData)) + { + return false; + } else { + QDataStream reply(replyData, IO_ReadOnly); + if(replyType != "serviceResult")return false; + int result; + KviQCString dcopName; + QString error; + reply >> result >> dcopName >> error; + if(result != 0)return false; + } + // ok , we seem to have started it.. but it might take some seconds + // for the app to get registered + // we wait up to five seconds + if(iWaitMSecs > 0) + { + int i = 0; + while(i < iWaitMSecs) + { + if(findRunningApp(szApp))return true; + KviThread::msleep(100); + i += 100; + } + return findRunningApp(szApp); + } + return true; +} + + +#endif //COMPILE_KDE_SUPPORT diff --git a/src/kvilib/ext/kvi_dcophelper.h b/src/kvilib/ext/kvi_dcophelper.h new file mode 100644 index 00000000..de605e37 --- /dev/null +++ b/src/kvilib/ext/kvi_dcophelper.h @@ -0,0 +1,82 @@ +#ifndef _KVI_DCOPHELPER_H_ +#define _KVI_DCOPHELPER_H_ +//============================================================================= +// +// File : kvi_dcophelper.h +// Created on Sat 20 Jan 2007 12:35:21 by Alexander Stillich +// +// This file is part of the KVIrc IRC client distribution +// Copyright (C) 2005 Szymon Stefanek <pragma at kvirc dot net> +// Copyright (C) 2007 Alexander Stillich <torque at pltn dot org> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" +#include "kvi_qcstring.h" +#include "kvi_valuelist.h" + +#ifdef COMPILE_KDE_SUPPORT + +typedef KviValueList<KviQCString> KviQCStringList; + +class KVILIB_API KviDCOPHelper +{ + +public: + + // Constructs a DCOP helper object. + // bStartApp: tries to start application when a dcop call is about to be made and the app is not already running + // szAppID: application name as seen by DCOP + KviDCOPHelper(bool bStartApp, const KviQCString &szAppId); + ~KviDCOPHelper(); + +protected: + + KviQCString m_szAppId; + bool m_bStartApp; + +protected: + + bool ensureAppRunning(const QString &szApp); + bool findRunningApp(const QString &szApp); + bool startApp(const QString &szApp,int iWaitMSecs = 0); + int detectApp(const QString &szApp,bool bStart,int iScoreWhenFound,int iScoreWhenStarted); + + // naming convention: [return value] Ret [argument type(s)] DCOPCall + + bool voidRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc); + bool voidRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int iVal); + bool voidRetIntBoolDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int iVal, bool bVal); + bool voidRetIntIntIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int iVal1, int iVal2, int iVal3); + bool voidRetBoolDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,bool bVal); + bool voidRetStringDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,const QString &szVal); + bool voidRetFloatDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,float fVal); + bool stringRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,QString &szRet); + bool stringRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,QString &szRet,int iVal); + bool intRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int &ret); + bool intRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,int &ret, int iVal); + bool boolRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,bool &ret); + + bool qvalueListIntRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,KviValueList<int> &ret, int iVal); + bool qcstringListRetIntDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,KviQCStringList &ret, int iVal); + bool qcstringListRetVoidDCOPCall(const KviQCString &szObj,const KviQCString &szFunc,KviQCStringList &ret); +}; + +#endif //COMPILE_KDE_SUPPORT + +#endif // _KVI_DCOPHELPER_H_ diff --git a/src/kvilib/ext/kvi_doublebuffer.cpp b/src/kvilib/ext/kvi_doublebuffer.cpp new file mode 100644 index 00000000..5997e934 --- /dev/null +++ b/src/kvilib/ext/kvi_doublebuffer.cpp @@ -0,0 +1,90 @@ +//============================================================================= +// +// File : kvi_doublebuffer.cpp +// Created on Fri 27 Jan 2006 18:59:54 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include "kvi_doublebuffer.h" + +static QPixmap * g_pMemoryPixmap = 0; +static unsigned int g_uMaxRequestedWidth = 0; +static unsigned int g_uMaxRequestedHeight = 0; + +KviDoubleBuffer::KviDoubleBuffer(unsigned int uWidth,unsigned int uHeight) +{ + if((g_pMemoryPixmap->width() < uWidth) || (g_pMemoryPixmap->height() < uHeight)) + { + // The memory buffer is too small + // There is either no such user requirement or it has grown by the meantime + unsigned int uMaxW = uWidth > g_pMemoryPixmap->width() ? uWidth : g_pMemoryPixmap->width(); + unsigned int uMaxH = uHeight > g_pMemoryPixmap->height() ? uHeight : g_pMemoryPixmap->height(); +#ifdef COMPILE_USE_QT4 + // QT4SUX: QPixmap::resize() is missing (it's a widely used function and assigning a new QPixmap() seems to be slower and not intuitive) + *g_pMemoryPixmap = QPixmap(uMaxW,uMaxH); +#else + g_pMemoryPixmap->resize(uMaxW,uMaxH); +#endif + } + + if(uWidth > g_uMaxRequestedWidth)g_uMaxRequestedWidth = uWidth; + if(uHeight > g_uMaxRequestedHeight)g_uMaxRequestedHeight = uHeight; +} + +KviDoubleBuffer::~KviDoubleBuffer() +{ + // We never shrink here (it's time consuming) +} + +QPixmap * KviDoubleBuffer::pixmap() +{ + return g_pMemoryPixmap; +} + +void KviDoubleBuffer::init() +{ + if(g_pMemoryPixmap)return; + g_pMemoryPixmap = new QPixmap(); +} + +void KviDoubleBuffer::done() +{ + if(!g_pMemoryPixmap)return; + delete g_pMemoryPixmap; + g_pMemoryPixmap = 0; +} + +void KviDoubleBuffer::heartbeat() +{ + if(((g_uMaxRequestedHeight + 64) < g_pMemoryPixmap->height()) || ((g_uMaxRequestedWidth + 64) < g_pMemoryPixmap->width())) + { + // do shrink :) +#ifdef COMPILE_USE_QT4 + // QT4SUX: QPixmap::resize() is missing (it's a widely used function and assigning a new QPixmap() seems to be slower and not intuitive) + *g_pMemoryPixmap = QPixmap(g_uMaxRequestedWidth,g_uMaxRequestedHeight); +#else + g_pMemoryPixmap->resize(g_uMaxRequestedWidth,g_uMaxRequestedHeight); +#endif + } + g_uMaxRequestedHeight = 0; + g_uMaxRequestedWidth = 0; +} diff --git a/src/kvilib/ext/kvi_doublebuffer.h b/src/kvilib/ext/kvi_doublebuffer.h new file mode 100644 index 00000000..103759a1 --- /dev/null +++ b/src/kvilib/ext/kvi_doublebuffer.h @@ -0,0 +1,62 @@ +#ifndef _KVI_DOUBLEBUFFER_H_ +#define _KVI_DOUBLEBUFFER_H_ +//============================================================================= +// +// File : kvi_doublebuffer.h +// Created on Fri 27 Jan 2006 18:59:54 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <qpixmap.h> + +// +// This class is basically a huge shared memory pixmap meant to be used in double-buffer +// painting operations. The memory buffer is resized on the fly so you will always obtain +// a pixmap that is at least of the specified size. The problem is that this is a time +// consuming operation (not good in a paint event). We solve it by keeping the buffer +// with the greatest requested size in the last N minutes. +// +// The keyword in all this thingie is "memory is cheap, processing time is not". +// We know in advance that KVIrc needs a huge double buffer anyway... +// So we basically grow instantly but we are really lazy at shrinking. +// + +class KVILIB_API KviDoubleBuffer +{ +public: + KviDoubleBuffer(unsigned int uWidth,unsigned int uHeight); + ~KviDoubleBuffer(); +public: + // This returns a pointer to the memory buffer. The buffer is at least + // of the size declared in the constructor. + QPixmap * pixmap(); + + // The stuff below is internal (used only by KviApp) + + // to be called at application initialisation and cleanup + static void init(); + static void done(); + // this has to be called at sensible intervals (like 2 minutes) + static void heartbeat(); +}; + +#endif //!_KVI_DOUBLEBUFFER_H_ diff --git a/src/kvilib/ext/kvi_draganddrop.h b/src/kvilib/ext/kvi_draganddrop.h new file mode 100644 index 00000000..c8bd9f3e --- /dev/null +++ b/src/kvilib/ext/kvi_draganddrop.h @@ -0,0 +1,45 @@ +#ifndef _KVI_DRAGANDDROP_H_ +#define _KVI_DRAGANDDROP_H_ + +//============================================================================= +// +// File : kvi_draganddrop.h +// Creation date : Wed Feb 01 2007 01:45:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + + +#ifdef COMPILE_USE_QT4 + #include <q3dragobject.h> + #define KviDragObject Q3DragObject + #define KviUriDrag Q3UriDrag + #define KviTextDrag Q3TextDrag + #define KviImageDrag Q3ImageDrag +#else + #include <qdragobject.h> + #define KviDragObject QDragObject + #define KviUriDrag QUriDrag + #define KviTextDrag QTextDrag + #define KviImageDrag QImageDrag +#endif + +#endif //!_KVI_DRAGANDDROP_H_ diff --git a/src/kvilib/ext/kvi_garbage.cpp b/src/kvilib/ext/kvi_garbage.cpp new file mode 100644 index 00000000..0e2e8881 --- /dev/null +++ b/src/kvilib/ext/kvi_garbage.cpp @@ -0,0 +1,148 @@ +// +// File : kvi_garbage.cpp +// Creation date : Mon Dec 3 16:49:15 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +#define __KVILIB__ + + + +#include "kvi_garbage.h" + +#include <qvariant.h> + +KviGarbageCollector::KviGarbageCollector() +: QObject(0) +{ + m_pGarbageList = 0; + m_pCleanupTimer = 0; + m_bForceCleanupNow = false; +} + +KviGarbageCollector::~KviGarbageCollector() +{ + m_bForceCleanupNow = true; + cleanup(); +} + +void KviGarbageCollector::collect(QObject * g) +{ + if(!m_pGarbageList) + { + m_pGarbageList = new KviPointerList<QObject>; + m_pGarbageList->setAutoDelete(true); + } + //debug("COLLECTING GARBAGE %s",g->className()); + m_pGarbageList->append(g); +// debug("Registering garbage object %d (%s:%s)",g,g->className(),g->name()); + connect(g,SIGNAL(destroyed()),this,SLOT(garbageSuicide())); + triggerCleanup(0); +} + +void KviGarbageCollector::garbageSuicide() +{ + if(!m_pGarbageList) + { + debug("Ops... garbage suicide while no garbage list"); + return; + } + int idx = m_pGarbageList->findRef(sender()); + if(idx == -1) + { + debug("Ops... unregistered garbage suicide"); + return; + } + m_pGarbageList->removeRef(sender()); + if(m_pGarbageList->isEmpty()) + { + cleanup(); + } +} + +void KviGarbageCollector::triggerCleanup(int iTimeout) +{ + //debug("TRIGGERING CLEANUP AFTER %d msecs",iTimeout); + if(m_pCleanupTimer) + { + m_pCleanupTimer->stop(); + } else { + m_pCleanupTimer = new QTimer(this); + connect(m_pCleanupTimer,SIGNAL(timeout()),this,SLOT(cleanup())); + } + m_pCleanupTimer->start(iTimeout); +} + +void KviGarbageCollector::cleanup() +{ + //debug("CLEANUP CALLED !"); + if(m_pGarbageList) + { + //debug("SOME GARBAGE TO DELETE"); + KviPointerList<QObject> dying; + dying.setAutoDelete(false); + for(QObject * o = m_pGarbageList->first();o;o = m_pGarbageList->next()) + { + //debug("CHECKING GARBAGE CLASS %s",o->className()); + bool bDeleteIt = m_bForceCleanupNow; + if(!bDeleteIt) + { + //debug("CLEANUP NOT FORCED"); + QVariant v = o->property("blockingDelete"); + if(v.isValid()) + { + //debug("HAS A VALID VARIANT!"); +// debug("[Garbage collector]: garbage has a blockingDelete property"); + bDeleteIt = !(v.toBool()); +// if(!bDeleteIt)debug("And doesn't want to be delete now!"); + } else bDeleteIt = true; // must be deleted + } + if(bDeleteIt)dying.append(o); + } + + for(QObject * o2 = dying.first();o2;o2 = dying.next()) + { + //debug("KILLING GARBAGE CLASS %s",o2->className()); + disconnect(o2,SIGNAL(destroyed()),this,SLOT(garbageSuicide())); + m_pGarbageList->removeRef(o2); + } + + if(m_pGarbageList->isEmpty()) + { + delete m_pGarbageList; + m_pGarbageList = 0; + } + } + + if(m_pGarbageList) + { +// debug("[Garbage collector cleanup]: Some stuff left to be deleted, will retry in a while"); + // something left to be destroyed + if(m_bForceCleanupNow)debug("[Garbage collector]: Ops...I've left some undeleted stuff!"); + triggerCleanup(5000); // retry in 5 sec + } else { +// debug("[Garbage collector cleanup]: Completed"); + // nothing left to delete + if(m_pCleanupTimer) + { + delete m_pCleanupTimer; + m_pCleanupTimer = 0; + } + } +} + diff --git a/src/kvilib/ext/kvi_garbage.h b/src/kvilib/ext/kvi_garbage.h new file mode 100644 index 00000000..6bb75641 --- /dev/null +++ b/src/kvilib/ext/kvi_garbage.h @@ -0,0 +1,51 @@ +#ifndef _KVI_GARBAGE_H_ +#define _KVI_GARBAGE_H_ +// +// File : kvi_garbage.h +// Creation date : Mon Dec 3 16:49:13 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" + +#include <qobject.h> +#include "kvi_pointerlist.h" +#include <qtimer.h> + + +class KVILIB_API KviGarbageCollector : public QObject +{ + Q_OBJECT +public: + KviGarbageCollector(); + ~KviGarbageCollector(); +protected: + KviPointerList<QObject> * m_pGarbageList; + QTimer * m_pCleanupTimer; + bool m_bForceCleanupNow; +public: + void collect(QObject * g); +protected: + void triggerCleanup(int iTimeout); +protected slots: + void cleanup(); + void garbageSuicide(); +}; + +#endif //_KVI_GARBAGE_H_ diff --git a/src/kvilib/ext/kvi_imagelib.cpp b/src/kvilib/ext/kvi_imagelib.cpp new file mode 100644 index 00000000..10835b25 --- /dev/null +++ b/src/kvilib/ext/kvi_imagelib.cpp @@ -0,0 +1,138 @@ +//============================================================================= +// +// File : kvi_imagelib.cpp +// Creation date : Wed Jul 21 1999 16:41:26 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include <qnamespace.h> + +#include "kvi_imagelib.h" +#include "kvi_fileutils.h" +#include "kvi_locale.h" +#include "kvi_memmove.h" + +#include <qpixmap.h> + + +//KviImageLibrary::KviImageLibrary(const QPixmap &pixmap,int imageWidth,int imageHeight) +//{ +// if(pixmap.isNull())m_pLibrary=0; +// else m_pLibrary=new QPixmap(pixmap); +// setImageSize(imageWidth,imageHeight); +//} + +KviImageLibrary::KviImageLibrary(const QString &path,int imageWidth,int imageHeight) +{ + m_pLibrary=0; + loadLibrary(path); + setImageSize(imageWidth,imageHeight); +} + +KviImageLibrary::KviImageLibrary(const QString &path1,const QString &path2,int imageWidth,int imageHeight) +{ + m_pLibrary=0; + if(KviFileUtils::fileExists(path1)) + { + loadLibrary(path1); + if(m_pLibrary==0)loadLibrary(path2); + } else loadLibrary(path2); + setImageSize(imageWidth,imageHeight); +} + + +KviImageLibrary::~KviImageLibrary() +{ + unloadLibrary(); +} + +void KviImageLibrary::unloadLibrary() +{ + if(m_pLibrary)delete m_pLibrary; + m_pLibrary=0; +} + +bool KviImageLibrary::setImageSize(int imageWidth,int imageHeight) +{ + m_iWidth=((imageWidth>0) ? imageWidth : 16); + m_iHeight=((imageHeight>0) ? imageHeight : 16); + return true; +} + +bool KviImageLibrary::loadLibrary(const QString &path) +{ + if(m_pLibrary)delete m_pLibrary; + m_pLibrary=new QImage(path); + if(m_pLibrary->isNull()) + { + delete m_pLibrary; + m_pLibrary=0; + debug("WARNING : Can not load image library %s",KviQString::toUtf8(path).data()); + } + return (m_pLibrary != 0); +} + +int KviImageLibrary::imageCount() +{ + if(!m_pLibrary)return 0; + if((m_iWidth<1)||(m_iHeight<1))return 0; + int nRows=m_pLibrary->width()/m_iWidth; + return ( nRows * (m_pLibrary->height()/m_iHeight)); +} + +QPixmap KviImageLibrary::getImage(int zeroBasedIndex) +{ + if((zeroBasedIndex >= imageCount())||(zeroBasedIndex < 0)||(m_pLibrary->depth() < 8)) + { + QPixmap image(32,32); + image.fill(); //White fill + return image; + } + + // Im per row is not zero...because imageCount returned non zero. + int imPerRow=(m_pLibrary->width() / m_iWidth); + int xOffset=(zeroBasedIndex % imPerRow) * m_iWidth; + int yOffset=(zeroBasedIndex / imPerRow) * m_iHeight; + +#ifdef COMPILE_USE_QT4 + QImage image(m_iWidth,m_iHeight,m_pLibrary->format()); +#else + QImage image(m_iWidth,m_iHeight,m_pLibrary->depth()); +#endif + + int d = image.depth() / 8; +#ifndef COMPILE_USE_QT4 + if(d == 4)image.setAlphaBuffer(true); // Qt 4.x should manage it automagically +#endif + //Copy the image data + //bitBlt(&image,0,0,m_pLibrary,xOffset,yOffset,m_iWidth,m_iHeight,Qt::CopyROP,false); + + for(int i=0;i<m_iHeight;i++) + kvi_memmove(image.scanLine(i),m_pLibrary->scanLine(i + yOffset) + (xOffset * d),m_iWidth * d); + +#ifdef COMPILE_USE_QT4 + QPixmap p = QPixmap::fromImage(image); +#else + QPixmap p(image); +#endif + return p; +} diff --git a/src/kvilib/ext/kvi_imagelib.h b/src/kvilib/ext/kvi_imagelib.h new file mode 100644 index 00000000..d78c8d19 --- /dev/null +++ b/src/kvilib/ext/kvi_imagelib.h @@ -0,0 +1,73 @@ +#ifndef _KVI_IMAGELIB_H_ +#define _KVI_IMAGELIB_H_ + +// +// File : kvi_imagelib.h +// Creation date : Wed Jul 21 1999 16:41:26 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +// +// A class to manage multiple image libraries. +// The library is in fact a big image that contains +// several rows of other smaller images of the same size. +// The images inside the 'library' are indexed in the following way: +// +// ------------- +// |...|...|...| +// |.0.|.1.|.2.| +// ------------- +// |...|...|...| +// |.3.|.4.|.5.| +// ------------- +// |...|...|...| +// +// The 'library' image should have the size that is a multiple +// of the single image size. If not , the remaining part is ignored. +// The first image starts always in the left upper corner. +// + +// WARNING: This class will be removed in the near future. Don't use it. + +#include "kvi_settings.h" + +#include <qimage.h> + +class KVILIB_API KviImageLibrary +{ +public: // Consruction & Destruction +// KviImageLibrary(const QPixmap &pixmap,int imageWidth,int imageHeight); + KviImageLibrary(const QString &path,int imageWidth,int imageHeight); + KviImageLibrary(const QString &path1,const QString &path2,int imageWidth,int imageHeight); + ~KviImageLibrary(); +public: // Fields + QImage *m_pLibrary; + int m_iWidth; + int m_iHeight; +public: // Methods + bool loadLibrary(const QString &path); + void unloadLibrary(); + int imageCount(); + bool libraryLoaded(){ return (m_pLibrary != 0); }; + QImage *getLibrary(){ return m_pLibrary; }; + QPixmap getImage(int zeroBasedIndex); + bool setImageSize(int imageWidth,int imageHeight); +}; + +#endif //_KVI_IMAGELIB_H_INCLUDED_ diff --git a/src/kvilib/ext/kvi_md5.cpp b/src/kvilib/ext/kvi_md5.cpp new file mode 100644 index 00000000..cbf01500 --- /dev/null +++ b/src/kvilib/ext/kvi_md5.cpp @@ -0,0 +1,298 @@ +// +// File : kvi_md5.cpp +// Creation date : Wed Sep 4 22:16:45 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + + +/* + ###################################################################### + + MD5Sum - MD5 Message Digest Algorithm. + + This code implements the MD5 message-digest algorithm. The algorithm is + due to Ron Rivest. This code was written by Colin Plumb in 1993, no + copyright is claimed. This code is in the public domain; do with it what + you wish. + + Equivalent code is available from RSA Data Security, Inc. This code has + been tested against that, and is equivalent, except that you don't need to + include two pages of legalese with every copy. + + To compute the message digest of a chunk of bytes, instantiate the class, + and repeatedly call one of the Add() members. When finished the Result + method will return the Hash and finalize the value. + + Changed so as no longer to depend on Colin Plumb's `usual.h' header + definitions; now uses stuff from dpkg's config.h. + - Ian Jackson <ijackson@nyx.cs.du.edu>. + + Changed into a C++ interface and made work with APT's config.h. + - Jason Gunthorpe <jgg@gpu.srv.ualberta.ca> + + Interface adapted to the KVIrc irc client + - Szymon Stefanek <pragma at kvirc dot net> + + The classes use arrays of char that are a specific size. We cast those + arrays to uint8_t's and go from there. This allows us to advoid using + the uncommon inttypes.h in a public header or internally newing memory. + In theory if C9x becomes nicely accepted + + ##################################################################### */ + +#include "kvi_md5.h" +#include "kvi_settings.h" +#include "kvi_bswap.h" +#include "kvi_memmove.h" + +/* Swap n 32 bit longs in given buffer */ +#ifdef BIG_ENDIAN_MACHINE_BYTE_ORDER + static void byteSwap(kvi_u32_t *buf,unsigned int words) + { +// kvi_u8_t *p = (kvi_u8_t *)buf; +// do +// { +// *buf++ = (kvi_u32_t)((unsigned)p[3] << 8 | p[2]) << 16 | ((unsigned)p[1] << 8 | p[0]); +// p += 4; +// } while (--words); + do { + *buf = kvi_swap32(*buf); + buf++; + } while(--words); + } +#else + #define byteSwap(buf,words) +#endif + +/* The core of the MD5 algorithm, this alters an existing MD5 hash to + reflect the addition of 16 longwords of new data. Add blocks + the data and converts bytes into longwords for this routine. */ + +// The four core functions - F1 is optimized somewhat +// #define F1(x, y, z) (x & y | ~x & z) +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +// This is the central step in the MD5 algorithm. +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +static void MD5Transform(kvi_u32_t buf[4],const kvi_u32_t in[16]) +{ + register kvi_u32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +KviMd5::KviMd5() +{ + kvi_u32_t *buf = (kvi_u32_t *)m_pBuf; + kvi_u32_t *bytes = (kvi_u32_t *)m_pBytes; + + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + bytes[0] = 0; + bytes[1] = 0; + + m_bDone = false; +} + +KviMd5::~KviMd5() +{ +} + +bool KviMd5::add(const unsigned char *data,unsigned long len) +{ + if(m_bDone)return false; + + kvi_u32_t *buf = (kvi_u32_t *)m_pBuf; + kvi_u32_t *bytes = (kvi_u32_t *)m_pBytes; + kvi_u32_t *in = (kvi_u32_t *)m_pIn; + + // Update byte count and carry (this could be done with a long long?) + kvi_u32_t t = bytes[0]; + + if ((bytes[0] = t + len) < t)bytes[1]++; + + // Space available (at least 1) + t = 64 - (t & 0x3f); + if (t > len) + { + kvi_fastmove((unsigned char *)in + 64 - t,data,len); + return true; + } + + // First chunk is an odd size + kvi_fastmove((unsigned char *)in + 64 - t,data,t); + byteSwap(in, 16); + + MD5Transform(buf,in); + data += t; + len -= t; + + // Process data in 64-byte chunks + while (len >= 64) + { + kvi_fastmove(in,data,64); + byteSwap(in,16); + MD5Transform(buf,in); + data += 64; + len -= 64; + } + + // Handle any remaining bytes of data. + kvi_memmove(in,data,len); + + return true; +} + + +// --------------------------------------------------------------------- +/* Because this must add in the last bytes of the series it prevents anyone + from calling add after. */ + +KviStr KviMd5::result() +{ + kvi_u32_t *buf = (kvi_u32_t *)m_pBuf; + kvi_u32_t *bytes = (kvi_u32_t *)m_pBytes; + kvi_u32_t *in = (kvi_u32_t *)m_pIn; + + if(!m_bDone) + { + // Number of bytes in In + int count = bytes[0] & 0x3f; + unsigned char *p = (unsigned char *)in + count; + + // Set the first char of padding to 0x80. There is always room. + *p++ = 0x80; + + // Bytes of padding needed to make 56 bytes (-8..55) + count = 56 - 1 - count; + + // Padding forces an extra block + if (count < 0) + { + kvi_memset(p,0,count + 8); + byteSwap(in, 16); + MD5Transform(buf,in); + p = (unsigned char *)in; + count = 56; + } + + kvi_memset(p, 0, count); + byteSwap(in, 14); + + // Append length in bits and transform + in[14] = bytes[0] << 3; + in[15] = bytes[1] << 3 | bytes[0] >> 29; + MD5Transform(buf,in); + byteSwap(buf,4); + m_bDone = true; + } + + // m_pBuf now contains the md5 sum + KviStr ret; + ret.bufferToHex((char *)m_pBuf,16); + + return ret; +} diff --git a/src/kvilib/ext/kvi_md5.h b/src/kvilib/ext/kvi_md5.h new file mode 100644 index 00000000..113c3a7c --- /dev/null +++ b/src/kvilib/ext/kvi_md5.h @@ -0,0 +1,68 @@ +#ifndef _KVI_MD5_H_ +#define _KVI_MD5_H_ +// +// File : kvi_md5.h +// Creation date : Wed Sep 4 22:16:44 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + + + +/* ###################################################################### + + MD5SumValue - Storage for a MD5Sum + MD5Summation - MD5 Message Digest Algorithm. + + This is a C++ interface to a set of MD5Sum functions. The class can + store a MD5Sum in 16 bytes of memory. + + A MD5Sum is used to generate a (hopefully) unique 16 byte number for a + block of data. This can be used to gaurd against corruption of a file. + MD5 should not be used for tamper protection, use SHA or something more + secure. + + There are two classes because computing a MD5 is not a continual + operation unless 64 byte blocks are used. Also the summation requires an + extra 18*4 bytes to operate. + + ##################################################################### */ + +#include "kvi_settings.h" +#include "kvi_inttypes.h" +#include "kvi_string.h" + +class KviMd5 +{ +public: + KviMd5(); + ~KviMd5(); +protected: + unsigned char m_pBuf[4*4]; + unsigned char m_pBytes[2*4]; + unsigned char m_pIn[16*4]; + bool m_bDone; + +public: + bool add(const unsigned char *Data,unsigned long Size); + + KviStr result(); +}; + + +#endif //_KVI_MD5_H_ diff --git a/src/kvilib/ext/kvi_mediatype.cpp b/src/kvilib/ext/kvi_mediatype.cpp new file mode 100644 index 00000000..87c7926d --- /dev/null +++ b/src/kvilib/ext/kvi_mediatype.cpp @@ -0,0 +1,541 @@ +// +// File : kvi_mediatype.cpp +// Creation date : Mon Aug 21 2000 17:51:56 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +//#define _KVI_DEBUG_CHECK_RANGE_ + + + +#include "kvi_debug.h" +#include "kvi_mediatype.h" +#include "kvi_config.h" +#include "kvi_fileutils.h" +#include "kvi_locale.h" +#include "kvi_file.h" + +#include "kvi_settings.h" + +#include <qregexp.h> +#include <qdir.h> + +#include <sys/types.h> +#include <sys/stat.h> + + +#ifndef COMPILE_ON_WINDOWS + #include <unistd.h> + #include "kvi_malloc.h" +#endif + + + +#ifndef S_ISDIR +#define S_ISDIR(__f) (__f & _S_IFDIR) +#endif + +#ifndef S_ISFIFO +#define S_ISFIFO(__f) (__f & _S_IFIFO) +#endif + +#ifndef S_ISREG +#define S_ISREG(__f) (__f & _S_IFREG) +#endif + +#ifndef S_ISCHR +#define S_ISCHR(__f) (__f & _S_IFCHR) +#endif + +#ifndef COMPILE_ON_WINDOWS + #include <dirent.h> +#else + #include "kvi_malloc.h" +#endif + + + + +KviMediaManager::KviMediaManager() +: KviMutex() +{ + m_pMediaTypeList = new KviPointerList<KviMediaType>; + m_pMediaTypeList->setAutoDelete(true); +} + +KviMediaManager::~KviMediaManager() +{ + delete m_pMediaTypeList; +} + +KviMediaType * KviMediaManager::findMediaTypeByIanaType(const char * ianaType) +{ + __range_valid(locked()); + for(KviMediaType * mt = m_pMediaTypeList->first();mt;mt = m_pMediaTypeList->next()) + { + if(kvi_strEqualCI(mt->szIanaType.ptr(),ianaType))return mt; + } + + return 0; +} + +KviMediaType * KviMediaManager::findMediaTypeByFileMask(const char * filemask) +{ + __range_valid(locked()); + for(KviMediaType * mt = m_pMediaTypeList->first();mt;mt = m_pMediaTypeList->next()) + { +// FIXME: #warning "Should this be case sensitive ?" + if(kvi_strEqualCI(mt->szFileMask.ptr(),filemask))return mt; + } + + return 0; +} + +void KviMediaManager::copyMediaType(KviMediaType * dst,KviMediaType * src) +{ + dst->szFileMask = src->szFileMask; + dst->szMagicBytes = src->szMagicBytes; + dst->szIanaType = src->szIanaType; + dst->szDescription = src->szDescription; + dst->szSavePath = src->szSavePath; + dst->szCommandline = src->szCommandline; + dst->szRemoteExecCommandline = src->szRemoteExecCommandline; + dst->szIcon = src->szIcon; +} + + +void KviMediaManager::insertMediaType(KviMediaType * m) +{ + __range_valid(locked()); + int iWildCount = m->szFileMask.occurences('*'); + int iNonWildCount = m->szFileMask.len() - iWildCount; + + // The masks with no wildcards go first in the list + // then we insert the ones with more non-wild chars + + int index = 0; + for(KviMediaType * mt = m_pMediaTypeList->first();mt;mt = m_pMediaTypeList->next()) + { + if(iWildCount) + { + // the new mask has wildcards... if the current one has none, skip it + int iWildCountExisting = mt->szFileMask.occurences('*'); + if(iWildCountExisting) + { + // the one in the list has wildcards too... + // the ones with more non-wild chars go first... + int iNonWildCountExisting = mt->szFileMask.len() - iWildCountExisting; + if(iNonWildCountExisting < iNonWildCount) + { + // ok...the new one has more non-wildcards , insert + m_pMediaTypeList->insert(index,m); + return; + } else { + if(iNonWildCount == iNonWildCountExisting) + { + // the same number of non-wildcards + // let the number of wildcards decide (it will be eventually equal) + if(iWildCount < iWildCountExisting) + { + // the new one has less wildcards... goes first + m_pMediaTypeList->insert(index,m); + return; + } // else the same number of wildcards and non-wildcards...skip + } // else the existing one has more non-wildcards...skip + } + } // else the current has no wildcards...skip + } else { + // the new mask has no wildcards.... + if(mt->szFileMask.contains('*')) + { + // current one has wildcards...insert + m_pMediaTypeList->insert(index,m); + return; + } + // the current one has no wildcards... + // the longer masks go first.... + if(mt->szFileMask.len() < m->szFileMask.len()) + { + // the current one is shorter than the new one...insert + m_pMediaTypeList->insert(index,m); + return; + } // else current one is longer...skip + } + index++; + } + m_pMediaTypeList->append(m); + +/* + // the masks with no wildcards go first + // longer masks go first + + bool bHasWildcards = m->szFileMask.contains('*'); + int index = 0; + for(KviMediaType * mt = m_pMediaTypeList->first();mt;mt = m_pMediaTypeList->next()) + { + if(bHasWildcards) + { + if(mt->szFileMask.len() < m->szFileMask.len()) + { + m_pMediaTypeList->insert(index,m); + return; + } else if(mt->szFileMask.len() == m->szFileMask.len()) + { + if(mt->szMagicBytes.len() < m->szMagicBytes.len()) + { + m_pMediaTypeList->insert(index,m); + return; + } + } + } else { + if(mt->szFileMask.contains('*')) + { + m_pMediaTypeList->insert(index,m); + return; + } else { + if(mt->szFileMask.len() < m->szFileMask.len()) + { + m_pMediaTypeList->insert(index,m); + return; + } else if(mt->szFileMask.len() == m->szFileMask.len()) + { + if(mt->szMagicBytes.len() < m->szMagicBytes.len()) + { + m_pMediaTypeList->insert(index,m); + return; + } + } + } + } + index++; + } + m_pMediaTypeList->append(m); +*/ +} + + +KviMediaType * KviMediaManager::findMediaType(const char * filename,bool bCheckMagic) +{ + // FIXME: This should be ported at least to QString.... + __range_valid(locked()); + + KviStr szFullPath = filename; + if(!kvi_isAbsolutePath(szFullPath.ptr())) + { +#ifdef COMPILE_USE_QT4 + KviStr tmp = QDir::currentPath(); +#else + KviStr tmp = QDir::currentDirPath(); +#endif + tmp.ensureLastCharIs('/'); + szFullPath.prepend(tmp); + } + + KviStr szFile = filename; + szFile.cutToLast('/',true); + + + // first of all , lstat() the file +#ifdef COMPILE_ON_WINDOWS + struct _stat st; + if(_stat(szFullPath.ptr(),&st) != 0) +#else + struct stat st; + if(lstat(szFullPath.ptr(),&st) != 0) +#endif + { + //debug("Problems while stating file %s",szFullPath.ptr()); + // We do just the pattern matching + // it's better to avoid magic checks + // if the file is a device , we would be blocked while attempting to read data + return findMediaTypeForRegularFile(szFullPath.ptr(),szFile.ptr(),false); + } else { + // If it is a link , stat() the link target +#ifndef COMPILE_ON_WINDOWS + if(S_ISLNK(st.st_mode)) + { + if(stat(szFullPath.ptr(),&st) != 0) + { + debug("Problems while stating() target for link %s",szFullPath.ptr()); + // Same as above + return findMediaTypeForRegularFile(szFullPath.ptr(),szFile.ptr(),false); + } + } +#endif + } + + + if(S_ISDIR(st.st_mode)) + { + // Directory : return default media type + KviMediaType * mtd = findMediaTypeByIanaType("inode/directory"); + if(!mtd) + { + // Add it + mtd = new KviMediaType; + mtd->szIanaType = "inode/directory"; + mtd->szDescription = __tr("Directory"); + mtd->szCommandline = "dirbrowser.open -m $0"; + mtd->szIcon = "kvi_dbfolder.png"; // hardcoded ? + insertMediaType(mtd); + } + return mtd; + } + + +#ifndef COMPILE_ON_WINDOWS + if(S_ISSOCK(st.st_mode)) + { + // Socket : return default media type + KviMediaType * mtd = findMediaTypeByIanaType("inode/socket"); + if(!mtd) + { + // Add it + mtd = new KviMediaType; + mtd->szIanaType = "inode/socket"; + mtd->szDescription = __tr("Socket"); + mtd->szIcon = "kvi_dbsocket.png"; // hardcoded ? + insertMediaType(mtd); + } + return mtd; + } +#endif + + if(S_ISFIFO(st.st_mode)) + { + // Fifo: return default media type + KviMediaType * mtd = findMediaTypeByIanaType("inode/fifo"); + if(!mtd) + { + // Add it + mtd = new KviMediaType; + mtd->szIanaType = "inode/fifo"; + mtd->szDescription = __tr("Fifo"); + mtd->szIcon = "kvi_dbfifo.png"; // hardcoded ? + insertMediaType(mtd); + } + return mtd; + } + +#ifndef COMPILE_ON_WINDOWS + if(S_ISBLK(st.st_mode)) + { + // Block device: return default media type + KviMediaType * mtd = findMediaTypeByIanaType("inode/blockdevice"); + if(!mtd) + { + // Add it + mtd = new KviMediaType; + mtd->szIanaType = "inode/blockdevice"; + mtd->szDescription = __tr("Block device"); + mtd->szIcon = "kvi_dbblockdevice.png"; // hardcoded ? + insertMediaType(mtd); + } + return mtd; + } +#endif + + if(S_ISCHR(st.st_mode)) + { + // Char device: return default media type + KviMediaType * mtd = findMediaTypeByIanaType("inode/chardevice"); + if(!mtd) + { + // Add it + mtd = new KviMediaType; + mtd->szIanaType = "inode/chardevice"; + mtd->szDescription = __tr("Char device"); + mtd->szIcon = "kvi_dbchardevice.png"; // hardcoded ? + insertMediaType(mtd); + } + return mtd; + } + + + // this is a regular file (or at least it looks like one) + return findMediaTypeForRegularFile(szFullPath.ptr(),szFile.ptr(),bCheckMagic); +} + +KviMediaType * KviMediaManager::findMediaTypeForRegularFile(const char * szFullPath,const char * szFileName,bool bCheckMagic) +{ + char buffer[17]; + int len = 0; + + if(bCheckMagic) + { + QString szTmp=QString::fromUtf8(szFullPath); + KviFile f(szTmp); + if(f.openForReading()) + { + len = f.readBlock(buffer,16); + if(len > 0) + { + buffer[len] = '\0'; + if(buffer[0] == 0)len = 0; // no way to match it + } + f.close(); + } + } + + for(KviMediaType * m = m_pMediaTypeList->first();m;m = m_pMediaTypeList->next()) + { +// FIXME: #warning "Should this be case sensitive ?" + if(kvi_matchWildExpr(m->szFileMask.ptr(),szFileName)) + { + if(len && m->szMagicBytes.hasData()) + { + QRegExp re(m->szMagicBytes.ptr()); + // It looks like they can't decide the name for this function :D + // ... well, maybe the latest choice is the best one. +#ifdef COMPILE_USE_QT4 + if(re.indexIn(buffer) > -1)return m; // matched! +#else + #if QT_VERSION >= 300 + if(re.search(buffer) > -1)return m; // matched! + #else + if(re.find(buffer,0) > -1)return m; // matched! + #endif +#endif + // else magic failed...not a match + } else return m; // matched! (no magic check) + } + } + + KviMediaType * mtd = findMediaTypeByIanaType("application/octet-stream"); + if(!mtd) + { + // Add it + mtd = new KviMediaType; + mtd->szIanaType = "application/octet-stream"; + mtd->szDescription = __tr("Octet stream (unknown)"); + mtd->szCommandline = "editor.open $0"; + mtd->szIcon = "kvi_dbunknown.png"; // hardcoded ? + insertMediaType(mtd); + } + + return mtd; +} + +typedef struct _KviDefaultMediaType +{ + const char * filemask; + const char * magicbytes; + const char * ianatype; + const char * description; + const char * commandline; +} KviDefaultMediaType; + + +// FIXME : default handlers for windows ? + +static KviDefaultMediaType g_defMediaTypes[]= +{ + { "*.jpg","^\\0330\\0377","image/jpeg","JPEG image","run kview $0" }, + { "*.jpeg","^\\0330\\0377","image/jpeg","JPEG image","run kview $0" }, + { "*.png","","image/png","PNG image","run kview $0" }, + { "*.mp3","","audio/mpeg","MPEG audio","run xmms -e $0" }, + { "*.gif","","image/gif","GIF image","run kvirc $0" }, + { "*.mpeg","","video/mpeg","MPEG video","run xanim $0" }, + { "*.exe","","application/x-executable-file","Executable file","run $0" }, + { "*.zip","^PK\\0003\\0004","application/zip","ZIP archive","run ark $0" }, + { "*.tar.gz","","application/x-gzip","GZipped tarball","run ark $0" }, + { "*.tar.bz2","","applicatoin/x-bzip2","BZipped tarball","run ark $0" }, + { "*.tgz","","application/x-gzip","GZipped tarball","run ark $0" }, + { "*.wav","","audio/wav","Wave audio","run play $0" }, + { 0,0,0,0,0 } +}; + +void KviMediaManager::load(const char * filename) +{ + __range_valid(locked()); + + KviConfig cfg(filename,KviConfig::Read); + cfg.setGroup("MediaTypes"); + unsigned int nEntries = cfg.readUIntEntry("NEntries",0); + for(unsigned int i = 0; i < nEntries;i++) + { + KviMediaType * m = new KviMediaType; + KviStr tmp(KviStr::Format,"%dFileMask",i); + m->szFileMask = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%dMagicBytes",i); + m->szMagicBytes = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%dIanaType",i); + m->szIanaType = cfg.readEntry(tmp.ptr(),"application/unknown"); + tmp.sprintf("%dDescription",i); + m->szDescription = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%dSavePath",i); + m->szSavePath = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%dCommandline",i); + m->szCommandline = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%dRemoteExecCommandline",i); + m->szRemoteExecCommandline = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%dIcon",i); + m->szIcon = cfg.readEntry(tmp.ptr(),""); + insertMediaType(m); + } + + for(int u = 0;g_defMediaTypes[u].filemask;u++) + { + if(!findMediaTypeByFileMask(g_defMediaTypes[u].filemask)) + { + KviMediaType * m = new KviMediaType; + m->szFileMask = g_defMediaTypes[u].filemask; + m->szMagicBytes = g_defMediaTypes[u].magicbytes; + m->szIanaType = g_defMediaTypes[u].ianatype; + m->szDescription = g_defMediaTypes[u].description; + m->szCommandline = g_defMediaTypes[u].commandline; + insertMediaType(m); + } + } + +} + +void KviMediaManager::save(const char * filename) +{ + __range_valid(locked()); + KviConfig cfg(filename,KviConfig::Write); + + cfg.clear(); + cfg.setGroup("MediaTypes"); + cfg.writeEntry("NEntries",m_pMediaTypeList->count()); + int index = 0; + for(KviMediaType * m= m_pMediaTypeList->first();m;m = m_pMediaTypeList->next()) + { + KviStr tmp(KviStr::Format,"%dFileMask",index); + cfg.writeEntry(tmp.ptr(),m->szFileMask.ptr()); + tmp.sprintf("%dMagicBytes",index); + cfg.writeEntry(tmp.ptr(),m->szMagicBytes.ptr()); + tmp.sprintf("%dIanaType",index); + cfg.writeEntry(tmp.ptr(),m->szIanaType.ptr()); + tmp.sprintf("%dDescription",index); + cfg.writeEntry(tmp.ptr(),m->szDescription.ptr()); + tmp.sprintf("%dSavePath",index); + cfg.writeEntry(tmp.ptr(),m->szSavePath.ptr()); + tmp.sprintf("%dCommandline",index); + cfg.writeEntry(tmp.ptr(),m->szCommandline.ptr()); + tmp.sprintf("%dRemoteExecCommandline",index); + cfg.writeEntry(tmp.ptr(),m->szRemoteExecCommandline.ptr()); + tmp.sprintf("%dIcon",index); + cfg.writeEntry(tmp.ptr(),m->szIcon.ptr()); + ++index; + } +} diff --git a/src/kvilib/ext/kvi_mediatype.h b/src/kvilib/ext/kvi_mediatype.h new file mode 100644 index 00000000..77e96594 --- /dev/null +++ b/src/kvilib/ext/kvi_mediatype.h @@ -0,0 +1,83 @@ +#ifndef _KVI_MEDIATYPE_H_ +#define _KVI_MEDIATYPE_H_ +// +// File : kvi_mediatype.h +// Creation date : Mon Aug 21 2000 17:19:56 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_string.h" +#include "kvi_thread.h" + +#include "kvi_pointerlist.h" + + +// +// IANA media-types matching subsystem +// +// WARNING: This class is used in multiple threads +// Thus every usage of the classes and structures defined +// in this file MUST be protected by calls +// to KviMediaManager::lock() and KviMediaManager::unlock() +// + + +class KVILIB_API KviMediaType : public KviHeapObject +{ +public: + KviMediaType(){}; + ~KviMediaType(){}; +public: + KviStr szFileMask; + KviStr szMagicBytes; + KviStr szIanaType; + KviStr szDescription; + KviStr szSavePath; + KviStr szCommandline; + KviStr szRemoteExecCommandline; + KviStr szIcon; +}; + +class KVILIB_API KviMediaManager : public KviMutex +{ +public: + KviMediaManager(); + ~KviMediaManager(); +protected: + KviPointerList<KviMediaType> * m_pMediaTypeList; +private: + KviMediaType * findMediaTypeForRegularFile(const char * szFullPath,const char * szFileName,bool bCheckMagic); +public: + KviPointerList<KviMediaType> * mediaTypeList(){ return m_pMediaTypeList; }; + KviMediaType * findMediaTypeByFileMask(const char * filemask); + KviMediaType * findMediaTypeByIanaType(const char * ianaType); + bool removeMediaType(KviMediaType * t){ return m_pMediaTypeList->removeRef(t); }; + void clear(){ m_pMediaTypeList->clear(); }; + void insertMediaType(KviMediaType * t); + KviMediaType * findMediaType(const char * filename,bool bCheckMagic = true); + static void copyMediaType(KviMediaType * dst,KviMediaType * src); + + void load(const char * filename); + void save(const char * filename); +}; + + +#endif //_KVI_MEDIATYPE_H_ diff --git a/src/kvilib/ext/kvi_miscutils.cpp b/src/kvilib/ext/kvi_miscutils.cpp new file mode 100644 index 00000000..184345ed --- /dev/null +++ b/src/kvilib/ext/kvi_miscutils.cpp @@ -0,0 +1,86 @@ +//============================================================================= +// +// File : kvi_miscutils.cpp +// Created on Mon 08 Jan 2007 04:07:31 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2007 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_miscutils.h" + +#include <qstringlist.h> + +namespace KviMiscUtils +{ + int compareVersions(const QString &szVersion1,const QString &szVersion2) + { +#ifdef COMPILE_USE_QT4 + QStringList sl1 = szVersion1.split("."); + QStringList sl2 = szVersion2.split("."); +#else + QStringList sl1 = QStringList::split(".",szVersion1); + QStringList sl2 = QStringList::split(".",szVersion2); +#endif + + QStringList::Iterator it1 = sl1.begin(); + QStringList::Iterator it2 = sl2.begin(); + while((it1 != sl1.end()) && (it2 != sl2.end())) + { + bool bOk; + int i1 = (*it1).toInt(&bOk); + if(!bOk)return 1; + int i2 = (*it2).toInt(&bOk); + if(!bOk)return -1; + if(i1 != i2) + { + // field not equal + if(i1 > i2)return -1; + else return 1; + } + it1++; + it2++; + } + // both are equal until now + if(it1 != sl1.end())return -1; // 1 has at least one field more + if(it2 != sl2.end())return 1; // 2 has at least one field more + // both are equal also in length + return 0; + } + + bool isValidVersionString(const QString &szVersion) + { +#ifdef COMPILE_USE_QT4 + QStringList sl = szVersion.split("."); +#else + QStringList sl = QStringList::split(".",szVersion); +#endif + if(sl.isEmpty())return false; + // must all be numbers + for(QStringList::Iterator it = sl.begin();it != sl.end();++it) + { + bool bOk; + int i = (*it).toInt(&bOk); + if(!bOk)return false; + if(i < 0)return false; + } + return true; + } + +}; diff --git a/src/kvilib/ext/kvi_miscutils.h b/src/kvilib/ext/kvi_miscutils.h new file mode 100644 index 00000000..f09d63a7 --- /dev/null +++ b/src/kvilib/ext/kvi_miscutils.h @@ -0,0 +1,44 @@ +#ifndef _KVI_MISCUTILS_H_ +#define _KVI_MISCUTILS_H_ +//============================================================================= +// +// File : kvi_miscutils.h +// Created on Mon 08 Jan 2007 04:07:31 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2007 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" + +// this is the namespace for single function stuff that doesn't really fit anywhere else + +namespace KviMiscUtils +{ + // Compare two x.y.z... version strings. + // The function behaves like strcmp: it returns 0 when the versions + // are equal, -1 if the szVersion1 is greater and 1 if szVersion2 is greater + extern KVILIB_API int compareVersions(const QString &szVersion1,const QString &szVersion2); + + // Check if the argument string is a valid x.y.z.... version string + extern KVILIB_API bool isValidVersionString(const QString &szVersion); + +}; + +#endif //!_KVI_MISCUTILS_H_ diff --git a/src/kvilib/ext/kvi_msgtype.cpp b/src/kvilib/ext/kvi_msgtype.cpp new file mode 100644 index 00000000..d79a6220 --- /dev/null +++ b/src/kvilib/ext/kvi_msgtype.cpp @@ -0,0 +1,68 @@ +// +// File : kvi_msgtype.cpp +// Creation date : Fri 30 24 2000 13:53:21 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#define _KVI_DEBUG_CHECK_RANGE_ + +#include "kvi_debug.h" +#include "kvi_msgtype.h" + +KviMsgType::KviMsgType(const char * type,int pixId,unsigned char fore,unsigned char back,bool bLog,int iLevel) +{ + m_szType = type; + m_iPixId = pixId; + m_cForeColor = fore; + m_cBackColor = back; + m_bLogEnabled = bLog; + if((iLevel < KVI_MSGTYPE_MINLEVEL) || (iLevel > KVI_MSGTYPE_MAXLEVEL))iLevel = 1; + m_iLevel = iLevel; +} + +KviMsgType::KviMsgType(const KviMsgType &msg) +{ + m_szType = msg.m_szType; + m_iPixId = msg.m_iPixId; + m_cForeColor = msg.m_cForeColor; + m_cBackColor = msg.m_cBackColor; + m_bLogEnabled = msg.m_bLogEnabled; + m_iLevel = msg.m_iLevel; +} + +KviMsgType::~KviMsgType() +{ +} + + + +KviMsgType & KviMsgType::operator=(const KviMsgType &msg) +{ + //if(m_szType.ptr() == msg.m_szType.ptr())return (*this); // self assignment (!!!) + m_szType = msg.m_szType; + m_iPixId = msg.m_iPixId; + m_cForeColor = msg.m_cForeColor; + m_cBackColor = msg.m_cBackColor; + m_bLogEnabled = msg.m_bLogEnabled; + m_iLevel = msg.m_iLevel; + return (*this); +} diff --git a/src/kvilib/ext/kvi_msgtype.h b/src/kvilib/ext/kvi_msgtype.h new file mode 100644 index 00000000..ca4553ef --- /dev/null +++ b/src/kvilib/ext/kvi_msgtype.h @@ -0,0 +1,74 @@ +#ifndef _KVI_MSGTYPE_H_ +#define _KVI_MSGTYPE_H_ + +// +// File : kvi_msgtype.h +// Creation date : Fri Jun 30 2000 13:50:11 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_string.h" + +#define KVI_MSGTYPE_MINLEVEL 0 +#define KVI_MSGTYPE_LEVEL_0 0 +#define KVI_MSGTYPE_LEVEL_1 1 +#define KVI_MSGTYPE_LEVEL_2 2 +#define KVI_MSGTYPE_LEVEL_3 3 +#define KVI_MSGTYPE_LEVEL_4 4 +#define KVI_MSGTYPE_LEVEL_5 5 +#define KVI_MSGTYPE_MAXLEVEL 5 + +// 1 : Common activity +// 2 : People talking +// 3 : Response messages (whois , dns) +// 4 : +// 5 : Highlighted text + +// FIXME: Check the message ranges!!! + +class KVILIB_API KviMsgType +{ +public: + KviMsgType(const char * type,int pixId,unsigned char fore,unsigned char back,bool bLog,int iLevel); + KviMsgType(const KviMsgType &msg); + ~KviMsgType(); +public: + const char * m_szType; + int m_iPixId; + unsigned char m_cForeColor; + unsigned char m_cBackColor; + bool m_bLogEnabled; + int m_iLevel; +public: + void setBack(char back){ m_cBackColor = back; }; + void setFore(char fore){ m_cForeColor = fore; }; + int pixId(){ return m_iPixId; }; + int level(){ return m_iLevel; }; + void setLevel(int iLevel){ if((iLevel < KVI_MSGTYPE_MINLEVEL) || (iLevel > KVI_MSGTYPE_MAXLEVEL))m_iLevel = 1; else m_iLevel = iLevel; }; + void setPixId(int pixId){ m_iPixId = pixId; }; + unsigned char back(){ return m_cBackColor; }; + unsigned char fore(){ return m_cForeColor; }; + bool logEnabled(){ return m_bLogEnabled; }; + void enableLogging(bool bEnable){ m_bLogEnabled = bEnable; }; + const char * type(){ return m_szType; }; + KviMsgType & operator=(const KviMsgType &msg); // deep copy +}; + +#endif //_KVI_MSGTYPE_H_ diff --git a/src/kvilib/ext/kvi_osinfo.cpp b/src/kvilib/ext/kvi_osinfo.cpp new file mode 100644 index 00000000..51037a48 --- /dev/null +++ b/src/kvilib/ext/kvi_osinfo.cpp @@ -0,0 +1,510 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// File : kvi_osinfo.cpp +// Creation date : 19 Jan 2006 GMT by Alexey Uzhva +// +// This toolbar is part of the KVirc irc client distribution +// Copyright (C) 2006 Alexey Uzhva +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +/////////////////////////////////////////////////////////////////////////////// + +#define __KVILIB__ + +#include "kvi_osinfo.h" +#include "kvi_locale.h" +#include "kvi_qstring.h" + +#ifndef COMPILE_ON_WINDOWS + #include <sys/utsname.h> + #include <stdlib.h> + #include <unistd.h> +#endif + +#ifdef COMPILE_ON_WINDOWS +#include <windows.h> + +typedef enum QueryInfo +{ + Os_Release, + Os_Version, + Os_Type +}; +typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); +typedef BOOL (WINAPI *PGETPRODUCTINFO)(DWORD,DWORD,DWORD,DWORD,PDWORD); + +#define SM_SERVERR2 89 +#define BUFSIZE 1024 + +//Vista :/ + +#define PRODUCT_BUSINESS 0x00000006 +#define PRODUCT_BUSINESS_N 0x00000010 +#define PRODUCT_CLUSTER_SERVER 0x00000012 +#define PRODUCT_DATACENTER_SERVER 0x00000008 +#define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C +#define PRODUCT_ENTERPRISE 0x00000004 +#define PRODUCT_ENTERPRISE_SERVER 0x0000000A +#define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E +#define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F +#define PRODUCT_HOME_BASIC 0x00000002 +#define PRODUCT_HOME_BASIC_N 0x00000005 +#define PRODUCT_HOME_PREMIUM 0x00000003 +#define PRODUCT_HOME_SERVER 0x00000013 +#define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018 +#define PRODUCT_SMALLBUSINESS_SERVER 0x00000009 +#define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x00000019 +#define PRODUCT_STANDARD_SERVER 0x00000007 +#define PRODUCT_STANDARD_SERVER_CORE 0x0000000D +#define PRODUCT_STARTER 0x0000000B +#define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017 +#define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014 +#define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015 +#define PRODUCT_STORAGE_WORKGROUP_SERVER 0x00000016 +#define PRODUCT_UNDEFINED 0x00000000 +#define PRODUCT_ULTIMATE 0x00000001 +#define PRODUCT_WEB_SERVER 0x00000011 + +static QString queryWinInfo( QueryInfo info) +{ + QString szVersion; + OSVERSIONINFOEX osvi; + SYSTEM_INFO si; + PGNSI pGNSI; + BOOL bOsVersionInfoEx; + + ZeroMemory(&si, sizeof(SYSTEM_INFO)); + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + // If that fails, try using the OSVERSIONINFO structure. + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) ) + { + osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) + return FALSE; + } + + // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. + + pGNSI = (PGNSI) GetProcAddress( + GetModuleHandle(TEXT("kernel32.dll")), + "GetNativeSystemInfo"); + if(NULL != pGNSI) + pGNSI(&si); + else GetSystemInfo(&si); + + switch (osvi.dwPlatformId) + { + // Test for the Windows NT product family. + + case VER_PLATFORM_WIN32_NT: + + // Test for the specific product. + + if ( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0 ) + { + if( osvi.wProductType == VER_NT_WORKSTATION ) + szVersion+= "Windows Vista "; + else szVersion+="Windows Server \"Longhorn\" "; + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) + { + if( GetSystemMetrics(SM_SERVERR2) ) + szVersion+="Windows Server 2003 \"R2\" "; + else if( osvi.wProductType == VER_NT_WORKSTATION && + si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) + { + szVersion+="Windows XP Professional x64 Edition "; + } + else szVersion+="Windows Server 2003, "; + } + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) + szVersion+="Windows XP "; + + if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) + szVersion+="Windows 2000 "; + + if ( osvi.dwMajorVersion <= 4 ) + szVersion+="Windows NT "; + + PGETPRODUCTINFO pGetProductInfo; + pGetProductInfo = (PGETPRODUCTINFO) GetProcAddress( + GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo"); + // Test for specific product on Windows NT 4.0 SP6 and later. + if( bOsVersionInfoEx ) + { + DWORD dwPlatformInfo; + if(NULL != pGetProductInfo) + if(pGetProductInfo(osvi.dwMajorVersion,osvi.dwMinorVersion, + osvi.wServicePackMajor,osvi.wServicePackMinor,&dwPlatformInfo)) + { + switch(dwPlatformInfo) + { + case PRODUCT_BUSINESS: + szVersion+="Business Edition"; + break; + case PRODUCT_BUSINESS_N: + szVersion+="Business N Edition"; + break; + case PRODUCT_CLUSTER_SERVER: + szVersion+="Cluster Server Edition"; + break; + case PRODUCT_DATACENTER_SERVER: + szVersion+="Server Datacenter Edition (full installation)"; + break; + case PRODUCT_DATACENTER_SERVER_CORE: + szVersion+="Server Datacenter Edition (core installation)"; + break; + case PRODUCT_ENTERPRISE: + szVersion+="Enterprise Edition"; + break; + case PRODUCT_ENTERPRISE_SERVER: + szVersion+="Server Enterprise Edition (full installation)"; + break; + case PRODUCT_ENTERPRISE_SERVER_CORE: + szVersion+="Server Enterprise Edition (core installation)"; + break; + case PRODUCT_ENTERPRISE_SERVER_IA64: + szVersion+="Server Enterprise Edition for Itanium-based Systems"; + break; + case PRODUCT_HOME_BASIC: + szVersion+="Home Basic Edition"; + break; + case PRODUCT_HOME_BASIC_N: + szVersion+="Home Basic N Edition"; + break; + case PRODUCT_HOME_PREMIUM: + szVersion+="Home Premium Edition"; + break; + case PRODUCT_HOME_SERVER: + szVersion+="Home Server Edition"; + break; + case PRODUCT_SERVER_FOR_SMALLBUSINESS: + szVersion+="Server for Small Business Edition"; + break; + case PRODUCT_SMALLBUSINESS_SERVER: + szVersion+="Small Business Server"; + break; + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: + szVersion+="Small Business Server Premium Edition"; + break; + case PRODUCT_STANDARD_SERVER: + szVersion+="Server Standard Edition (full installation)"; + break; + case PRODUCT_STANDARD_SERVER_CORE: + szVersion+="Server Standard Edition (core installation)"; + break; + case PRODUCT_STARTER: + szVersion+="Starter Edition"; + break; + case PRODUCT_STORAGE_ENTERPRISE_SERVER: + szVersion+="Storage Server Enterprise Edition"; + break; + case PRODUCT_STORAGE_EXPRESS_SERVER: + szVersion+="Storage Server Express Edition"; + break; + case PRODUCT_STORAGE_STANDARD_SERVER: + szVersion+="Storage Server Standard Edition"; + break; + case PRODUCT_STORAGE_WORKGROUP_SERVER: + szVersion+="Storage Server Workgroup Edition"; + break; + case PRODUCT_UNDEFINED: + szVersion+="An unknown product"; + break; + case PRODUCT_ULTIMATE: + szVersion+="Ultimate Edition"; + break; + case PRODUCT_WEB_SERVER: + szVersion+="Web Server Edition"; + break; + + } + szVersion+=" "; + if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) + { + szVersion+="(x64) "; + } + } else { + // Test for the workstation type. + if ( osvi.wProductType == VER_NT_WORKSTATION && + si.wProcessorArchitecture!=PROCESSOR_ARCHITECTURE_AMD64) + { + if( osvi.dwMajorVersion == 4 ) + szVersion+= "Workstation 4.0 " ; + else if( osvi.wSuiteMask & VER_SUITE_PERSONAL ) + szVersion+= "Home Edition " ; + else szVersion+= "Professional " ; + } + + // Test for the server type. + else if ( osvi.wProductType == VER_NT_SERVER || + osvi.wProductType == VER_NT_DOMAIN_CONTROLLER ) + { + if(osvi.dwMajorVersion==5 && osvi.dwMinorVersion==2) + { + if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 ) + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + szVersion+= "Datacenter Edition for Itanium-based Systems" ; + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + szVersion+= "Enterprise Edition for Itanium-based Systems" ; + } + + else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + szVersion+= "Datacenter x64 Edition " ; + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + szVersion+= "Enterprise x64 Edition " ; + else szVersion+= "Standard x64 Edition " ; + } + + else + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + szVersion+= "Datacenter Edition " ; + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + szVersion+= "Enterprise Edition " ; + else if ( osvi.wSuiteMask == VER_SUITE_BLADE ) + szVersion+= "Web Edition " ; + else szVersion+= "Standard Edition " ; + } + } + else if(osvi.dwMajorVersion==5 && osvi.dwMinorVersion==0) + { + if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) + szVersion+= "Datacenter Server " ; + else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + szVersion+= "Advanced Server " ; + else szVersion+= "Server " ; + } + else // Windows NT 4.0 + { + if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) + szVersion+="Server 4.0, Enterprise Edition " ; + else szVersion+= "Server 4.0 " ; + } + } + } + } + // Test for specific product on Windows NT 4.0 SP5 and earlier + else + { + HKEY hKey; + TCHAR szProductType[BUFSIZE]; + DWORD dwBufLen=BUFSIZE*sizeof(TCHAR); + LONG lRet; + + lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"), + 0, KEY_QUERY_VALUE, &hKey ); + if( lRet != ERROR_SUCCESS ) + return FALSE; + + lRet = RegQueryValueEx( hKey, TEXT("ProductType"), NULL, NULL, + (LPBYTE) szProductType, &dwBufLen); + RegCloseKey( hKey ); + + if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE*sizeof(TCHAR)) ) + return FALSE; + + if ( lstrcmpi( TEXT("WINNT"), szProductType) == 0 ) + szVersion+= "Workstation " ; + if ( lstrcmpi( TEXT("LANMANNT"), szProductType) == 0 ) + szVersion+= "Server " ; + if ( lstrcmpi( TEXT("SERVERNT"), szProductType) == 0 ) + szVersion+= "Advanced Server " ; + } + + + // Display service pack (if any) and build number. + + if( osvi.dwMajorVersion == 4 && + lstrcmpi( osvi.szCSDVersion, TEXT("Service Pack 6") ) == 0 ) + { + HKEY hKey; + LONG lRet; + + // Test for SP6 versus SP6a. + lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), + 0, KEY_QUERY_VALUE, &hKey ); + if( lRet == ERROR_SUCCESS ) + szVersion+= QString("Service Pack 6a (Build %1)").arg( osvi.dwBuildNumber & 0xFFFF ); + else // Windows NT 4.0 prior to SP6a + { + szVersion+= QString( "%1 (Build %2)").arg( osvi.szCSDVersion).arg( osvi.dwBuildNumber & 0xFFFF); + } + + RegCloseKey( hKey ); + } + else // not Windows NT 4.0 + { + szVersion+= QString( "%1 (Build %2)").arg( osvi.szCSDVersion).arg( osvi.dwBuildNumber & 0xFFFF); + } + + break; + + // Test for the Windows Me/98/95. + case VER_PLATFORM_WIN32_WINDOWS: + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) + { + szVersion+="Windows 95 "; + if (osvi.szCSDVersion[1]=='C' || osvi.szCSDVersion[1]=='B') + szVersion+="OSR2 "; + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) + { + szVersion+="Windows 98 "; + if ( osvi.szCSDVersion[1]=='A' || osvi.szCSDVersion[1]=='B') + szVersion+="SE "; + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) + { + szVersion+="Windows Millennium Edition"; + } + break; + + case VER_PLATFORM_WIN32s: + + szVersion+="Win32s"; + break; + } + if(info==Os_Release) + { + unsigned long major = osvi.dwMajorVersion; + unsigned long minor = osvi.dwMinorVersion; + unsigned long release = osvi.dwBuildNumber; + QString szMajor, szMinor, szRelease, szVersion; + szMajor.setNum(major); + szMinor.setNum(minor); + szRelease.setNum(release); + szVersion = "Release : "+szMajor +"."+ szMinor +"."+ szRelease; + return szVersion; + } + if(info==Os_Type) + { + if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) return " NT "; + if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) return " Windows "; + if(osvi.dwPlatformId == VER_PLATFORM_WIN32s) return " Win32s "; + return __tr2qs("Unknown "); + } + if(info==Os_Version) + { + return szVersion; + } + + return "what's wrong? o.O"; +} +#endif + + +namespace KviOsInfo +{ + QString type() + { +#ifdef COMPILE_ON_WINDOWS + return queryWinInfo(Os_Type); +#else + #ifdef Q_OS_MACX + return "macosx"; + #else + return "unix"; + #endif +#endif + } + + QString name() + { +#ifdef COMPILE_ON_WINDOWS + return "windows"; +#else + struct utsname uts; + if(uname(&uts) == 0) + return QString::fromLocal8Bit(uts.sysname); + return KviQString::empty; +#endif + } + + QString version() + { +#ifdef COMPILE_ON_WINDOWS + return queryWinInfo(Os_Version); +#else + struct utsname uts; + if(uname(&uts) == 0) + return QString::fromLocal8Bit(uts.version); + return KviQString::empty; +#endif + } + + QString release() + { +#ifdef COMPILE_ON_WINDOWS + return queryWinInfo(Os_Release); +#else + struct utsname uts; + if(uname(&uts) == 0) + return QString::fromLocal8Bit(uts.release); + return KviQString::empty; +#endif + } + + QString machine() + { +#ifdef COMPILE_ON_WINDOWS + QString mach = getenv("PROCESSOR_IDENTIFIER"); + return mach.section(",",0,0); +#else + struct utsname uts; + if(uname(&uts) == 0) + return QString::fromLocal8Bit(uts.machine); + return KviQString::empty; +#endif + } + + QString nodename() + { +#ifdef COMPILE_ON_WINDOWS + return "windows"; +#else + struct utsname uts; + if(uname(&uts) == 0) + return QString::fromLocal8Bit(uts.nodename); + return KviQString::empty; +#endif + } + + QString hostname() + { + char hbuffer[1024]; + if(gethostname(hbuffer,1024) == 0) + return QString::fromLocal8Bit(hbuffer); + else + return KviQString::empty; + } +} + diff --git a/src/kvilib/ext/kvi_osinfo.h b/src/kvilib/ext/kvi_osinfo.h new file mode 100644 index 00000000..9df4a990 --- /dev/null +++ b/src/kvilib/ext/kvi_osinfo.h @@ -0,0 +1,43 @@ +#ifndef _KVI_OSINFO_H_ +#define _KVI_OSINFO_H_ + +/////////////////////////////////////////////////////////////////////////////// +// +// File : kvi_osinfo.h +// Creation date : 19 Jan 2006 GMT by Alexey Uzhva +// +// This toolbar is part of the KVirc irc client distribution +// Copyright (C) 2006 Alexey Uzhva +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "kvi_settings.h" + +#include <qstring.h> + +namespace KviOsInfo +{ + extern KVILIB_API QString type(); + extern KVILIB_API QString name(); + extern KVILIB_API QString version(); + extern KVILIB_API QString release(); + extern KVILIB_API QString machine(); + extern KVILIB_API QString nodename(); + extern KVILIB_API QString hostname(); +}; + +#endif //!_KVI_OSINFO_H_ diff --git a/src/kvilib/ext/kvi_parameterlist.cpp b/src/kvilib/ext/kvi_parameterlist.cpp new file mode 100644 index 00000000..318cd3d1 --- /dev/null +++ b/src/kvilib/ext/kvi_parameterlist.cpp @@ -0,0 +1,254 @@ +// +// File : kvi_parameterlist.cpp +// Creation date : Tue Sep 12 2000 18:14:01 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#include "kvi_parameterlist.h" + +KviParameterList::KviParameterList() +: KviPointerList<KviStr>() +{ + setAutoDelete(true); +} + +KviParameterList::KviParameterList(KviStr *p1) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + append(p1); +} + +KviParameterList::KviParameterList(KviStr *p1,KviStr *p2) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + append(p1); + append(p2); +} + +KviParameterList::KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + append(p1); + append(p2); + append(p3); +} + +KviParameterList::KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + append(p1); + append(p2); + append(p3); + append(p4); +} + +KviParameterList::KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4,KviStr *p5) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + append(p1); + append(p2); + append(p3); + append(p4); + append(p5); +} + +KviParameterList::KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4,KviStr *p5,KviStr *p6) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + append(p1); + append(p2); + append(p3); + append(p4); + append(p5); + append(p6); +} + + +KviParameterList::KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4,KviStr *p5,KviStr *p6,KviStr *p7) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + append(p1); + append(p2); + append(p3); + append(p4); + append(p5); + append(p6); + append(p7); +} + +KviParameterList::KviParameterList(const char *paramBuffer) +: KviPointerList<KviStr>() +{ + setAutoDelete(true); + while(*paramBuffer) + { + KviStr * pStr = new KviStr(); + paramBuffer = kvi_extractToken(*pStr,paramBuffer); + append(pStr); + } +} + +KviParameterList::~KviParameterList() +{ +} + +KviStr * KviParameterList::safeFirst() +{ + KviStr * f= first(); + return f ? f : &m_szEmpty; +} + +KviStr * KviParameterList::safeNext() +{ + KviStr * f = next(); + return f ? f : &m_szEmpty; +} + + +bool KviParameterList::getBool() +{ + KviStr * par = current(); + (void)next(); + if(par) + { + if(kvi_strEqualCS(par->ptr(),"0"))return false; + } + return true; // default +} + +int KviParameterList::getInt(bool * bOk) +{ + KviStr * par = current(); + (void)next(); + if(par) + { + return par->toInt(bOk); + } + if(bOk)*bOk = false; + return 0; +} + +unsigned int KviParameterList::getUInt(bool * bOk) +{ + KviStr * par = current(); + (void)next(); + if(par) + { + return par->toUInt(bOk); + } + if(bOk)*bOk = false; + return 0; +} + +QRect KviParameterList::getRect(bool * bOk) +{ + int val[4]; + for(int i=0;i<4;i++) + { + KviStr * pszv = current(); + (void)next(); + if(!pszv) + { + if(bOk)*bOk = false; + return QRect(); // invalid + } + bool mybOk; + val[i] = pszv->toInt(&mybOk); + if(!mybOk) + { + if(bOk)*bOk = false; + return QRect(); // invalid + } + } + if(bOk)*bOk = true; + return QRect(val[0],val[1],val[2],val[3]); +} + +QPoint KviParameterList::getPoint(bool * bOk) +{ + int val[2]; + for(int i=0;i<2;i++) + { + KviStr * pszv = current(); + (void)next(); + if(!pszv) + { + if(bOk)*bOk = false; + return QPoint(); // invalid + } + bool mybOk; + val[i] = pszv->toInt(&mybOk); + if(!mybOk) + { + if(bOk)*bOk = false; + return QPoint(); // invalid + } + } + if(bOk)*bOk = true; + return QPoint(val[0],val[1]); +} + +QSize KviParameterList::getSize(bool * bOk) +{ + int val[2]; + for(int i=0;i<2;i++) + { + KviStr * pszv = current(); + (void)next(); + if(!pszv) + { + if(bOk)*bOk = false; + return QSize(); // invalid + } + bool mybOk; + val[i] = pszv->toInt(&mybOk); + if(!mybOk) + { + if(bOk)*bOk = false; + return QSize(); // invalid + } + } + if(bOk)*bOk = true; + return QSize(val[0],val[1]); +} + +//#ifdef COMPILE_ON_WINDOWS +// +// #include "kvi_malloc.h" +// +// void * KviParameterList::operator new(size_t tSize) +// { +// return kvi_malloc(tSize); +// } +// +// void KviParameterList::operator delete(void * p) +// { +// kvi_free(p); +// } +//#endif diff --git a/src/kvilib/ext/kvi_parameterlist.h b/src/kvilib/ext/kvi_parameterlist.h new file mode 100644 index 00000000..51c573e0 --- /dev/null +++ b/src/kvilib/ext/kvi_parameterlist.h @@ -0,0 +1,72 @@ +#ifndef _KVI_PARAMETERLIST_H_ +#define _KVI_PARAMETERLIST_H_ + +// +// File : kvi_parameterlist.h +// Creation date : Tue Sep 12 2000 18:00:01 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_string.h" + +#include "kvi_pointerlist.h" +#include <qrect.h> +#include <qpoint.h> +#include <qsize.h> + +class KVILIB_API KviParameterList : public KviPointerList<KviStr>, public KviHeapObject +{ +public: + KviParameterList(); + KviParameterList(KviStr *p1); + KviParameterList(KviStr *p1,KviStr *p2); + KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3); + KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4); + KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4,KviStr *p5); + KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4,KviStr *p5,KviStr *p6); + KviParameterList(KviStr *p1,KviStr *p2,KviStr *p3,KviStr *p4,KviStr *p5,KviStr *p6,KviStr *p7); + KviParameterList(const char * paramBuffer); + virtual ~KviParameterList(); +private: + KviStr m_szEmpty; +public: + void init(){ (void)first(); }; + // These functions have to be called when the + // current() points to the FIRST item that has + // to be interpreted as Bool,Int,UInt,Rect etc... + // At the call exit the current() points + // to the first item that was NOT used by the call + bool getBool(); + int getInt(bool * bOk = 0); + unsigned int getUInt(bool * bOk = 0); + QRect getRect(bool * bOk = 0); + QPoint getPoint(bool * bOk = 0); + QSize getSize(bool * bOk = 0); + KviStr * safeFirst(); + KviStr * safeNext(); + const char * safeFirstParam(){ return safeFirst()->ptr(); }; + const char * safeNextParam(){ return safeNext()->ptr(); }; + +}; + + + +#endif //_KVI_PARAMETERLIST_H_ diff --git a/src/kvilib/ext/kvi_pixmap.cpp b/src/kvilib/ext/kvi_pixmap.cpp new file mode 100644 index 00000000..f22b03ef --- /dev/null +++ b/src/kvilib/ext/kvi_pixmap.cpp @@ -0,0 +1,180 @@ +//============================================================================= +// +// File : kvi_pixmap.cpp +// Creation date : Sat Jun 24 2000 14:00:27 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + + +#define __KVILIB__ + + +#include "kvi_debug.h" +#include "kvi_pixmap.h" +#include "kvi_qstring.h" + +#include <qpainter.h> + +KviPixmap::KviPixmap() +{ + m_pPix = 0; +} + +KviPixmap::KviPixmap(const char * path) +{ + m_pPix = 0; + load(path); +} + +KviPixmap::KviPixmap(const KviPixmap &pix) +{ + m_pPix = 0; + m_szPath = pix.path(); + + if(!m_szPath.isEmpty()) + { + if(pix.pixmap()) + { + m_pPix = new QPixmap(*(pix.pixmap())); + } + } +} + +KviPixmap::~KviPixmap() +{ + if(m_pPix)delete m_pPix; + m_pPix = 0; // just to be sure :) +} + +bool KviPixmap::load(const char * path) +{ + if(m_pPix)delete m_pPix; + m_pPix = 0; + m_szPath = path; + if(m_szPath.isEmpty())return false; + + m_pPix = new QPixmap(m_szPath); + + if(m_pPix->isNull()) + { + delete m_pPix; + m_pPix = 0; + m_szPath = ""; + return false; + } + return true; +} + +bool KviPixmap::load(const QString& path) +{ + if(m_pPix)delete m_pPix; + m_pPix = 0; + m_szPath = path; + if(m_szPath.isEmpty())return false; + + m_pPix = new QPixmap(m_szPath); + + if(m_pPix->isNull()) + { + delete m_pPix; + m_pPix = 0; + m_szPath = ""; + return false; + } + return true; +} + +void KviPixmap::set(const QPixmap &pix,const QString &szPath) +{ + if(pix.isNull()) + { + setNull(); + return; + } + + if(m_pPix)delete m_pPix; + m_pPix = new QPixmap(pix); + m_szPath = szPath; +} + + +void KviPixmap::setNull() +{ + if(m_pPix)delete m_pPix; + m_pPix = 0; + m_szPath = ""; +} + +KviPixmap & KviPixmap::operator=(const KviPixmap &pix) +{ + if(m_pPix == pix.m_pPix)return (*this); // self assignment (!!!) + if(KviQString::equalCI(m_szPath,pix.path()))return (*this); // same pix + + if(m_pPix)delete m_pPix; + m_pPix = 0; + m_szPath = pix.path(); + + if(!m_szPath.isEmpty()) + { + if(pix.pixmap()) + { + m_pPix = new QPixmap(*(pix.pixmap())); + } + } + return (*this); +} + + +void KviPixmapUtils::drawPixmapWithPainter(QPainter* p,QPixmap * pix,int flags,const QRect& paintRect,int iWidgetWidth,int iWidgetHeight,int dx,int dy) +{ + if(!pix)return; + if(!flags) + { + p->drawTiledPixmap(paintRect.left(),paintRect.top(),paintRect.width(),paintRect.height(),*pix,dx,dy); + return; + } + + int iPixWidth=pix->width(); + int iPixHeight=pix->height(); + int x=0; + int y=0; + + if( !(flags & Qt::AlignHorizontal_Mask )) + x=-1; + else if ( flags & Qt::AlignRight ) + x=iWidgetWidth - iPixWidth; + else if( flags & Qt::AlignHCenter ) + x=(iWidgetWidth - iPixWidth)/2; + + if( !(flags & Qt::AlignVertical_Mask )) + y=-1; + else if ( flags & Qt::AlignBottom ) + y=iWidgetHeight - iPixHeight; + else if( flags & Qt::AlignVCenter ) + y=(iWidgetHeight - iPixHeight)/2; + + if(x==-1) { + p->drawTiledPixmap(paintRect.left(),y,paintRect.width(),iPixHeight,*pix,dx,dy); + } else if(y==-1) { + p->drawTiledPixmap(x,paintRect.top(),iPixWidth,paintRect.height(),*pix,dx,dy); + } else { + p->drawPixmap(x,y,*pix); + } +} diff --git a/src/kvilib/ext/kvi_pixmap.h b/src/kvilib/ext/kvi_pixmap.h new file mode 100644 index 00000000..7ba91cec --- /dev/null +++ b/src/kvilib/ext/kvi_pixmap.h @@ -0,0 +1,61 @@ +#ifndef _KVI_PIXMAP_H_ +#define _KVI_PIXMAP_H_ + +//============================================================================= +// +// File : kvi_pixmap.h +// Creation date : Sat Jun 24 2000 13:59:04 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + + +#include "kvi_settings.h" +#include "kvi_string.h" +#include <qpixmap.h> + +class KVILIB_API KviPixmap +{ +public: + KviPixmap(); + KviPixmap(const char * path); + KviPixmap(const KviPixmap &pix); + ~KviPixmap(); +private: + QPixmap * m_pPix; + QString m_szPath; +public: + bool isNull(){ return m_pPix == 0; }; + bool load(const char * path); + bool load(const QString& path); + const QString& path() const { return m_szPath; }; + QPixmap * pixmap() const { return m_pPix; }; + void set(const QPixmap &pix,const QString &szPath); + KviPixmap & operator=(const KviPixmap &pix); // deep copy + void setNull(); +}; + +namespace KviPixmapUtils +{ + extern KVILIB_API void drawPixmapWithPainter(QPainter* p,QPixmap * pix,int flags,const QRect& paintRect,int iWidgetWidth,int iWidgetHeight,int dx,int dy); + inline void drawPixmapWithPainter(QPainter* p,QPixmap * pix,int flags,const QRect& paintRect,int iWidgetWidth,int iWidgetHeight) + { KviPixmapUtils::drawPixmapWithPainter(p,pix,flags,paintRect,iWidgetWidth,iWidgetHeight,paintRect.left(),paintRect.top()); }; +}; + +#endif //_KVI_PIXMAP_H_ diff --git a/src/kvilib/ext/kvi_proxydb.cpp b/src/kvilib/ext/kvi_proxydb.cpp new file mode 100644 index 00000000..917795c3 --- /dev/null +++ b/src/kvilib/ext/kvi_proxydb.cpp @@ -0,0 +1,192 @@ +// +// File : kvi_proxydb.cpp +// Creation date : Sat Jul 22 2000 18:23:23 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#include "kvi_proxydb.h" +#include "kvi_config.h" + + +KviProxy::KviProxy() +{ + m_szHostname = "proxy.example.net"; + m_uPort = 1080; + m_protocol = Socks4; + m_bIsIpV6 = false; +} + +KviProxy::KviProxy(const KviProxy &prx) +{ + m_szHostname = prx.m_szHostname; + m_szIp = prx.m_szIp; + m_szUser = prx.m_szUser; + m_szPass = prx.m_szPass; + m_uPort = prx.m_uPort; + m_protocol = prx.m_protocol; + m_bIsIpV6 = prx.m_bIsIpV6; +} + +KviProxy::~KviProxy() +{ +} + +static const char * proxy_protocols_table[3]= { "SOCKSv4", "SOCKSv5", "HTTP" }; + +const char * KviProxy::protocolName() const +{ + switch(m_protocol) + { + case Socks5: return proxy_protocols_table[1]; break; + case Http: return proxy_protocols_table[2]; break; + default: return proxy_protocols_table[0]; break; + } + + return proxy_protocols_table[0]; +} + +void KviProxy::setNamedProtocol(const char * proto) +{ + if(kvi_strEqualCI(proto,"SOCKSv5"))m_protocol = KviProxy::Socks5; + else if(kvi_strEqualCI(proto,"HTTP"))m_protocol = KviProxy::Http; + else m_protocol = KviProxy::Socks4; +} + +void KviProxy::getSupportedProtocolNames(QStringList & buf) +{ + for(int i=0;i<3;i++)buf.append(QString(proxy_protocols_table[i])); +} + +void KviProxy::normalizeUserAndPass() +{ + m_szUser.stripWhiteSpace(); + m_szPass.stripWhiteSpace(); +} + +KviProxyDataBase::KviProxyDataBase() +{ + m_pProxyList = new KviPointerList<KviProxy>; + m_pProxyList->setAutoDelete(true); + m_pCurrentProxy = 0; +} + +KviProxyDataBase::~KviProxyDataBase() +{ + delete m_pProxyList; +} + +void KviProxyDataBase::updateProxyIp(const char * proxy,const char * ip) +{ + for(KviProxy * prx = m_pProxyList->first();prx;prx = m_pProxyList->next()) + { + if(kvi_strEqualCI(proxy,prx->m_szHostname.ptr())) + { + prx->m_szIp = ip; + return; + } + } +} + +void KviProxyDataBase::clear() +{ + delete m_pProxyList; + m_pProxyList = new KviPointerList<KviProxy>; + m_pProxyList->setAutoDelete(true); + m_pCurrentProxy = 0; +} + +void KviProxyDataBase::load(const char * filename) +{ + clear(); + KviConfig cfg(filename,KviConfig::Read); + + unsigned int nEntries = cfg.readUIntEntry("Entries",0); + + for(unsigned int i=0;i<nEntries;i++) + { + KviProxy * p = new KviProxy(); + KviStr tmp(KviStr::Format,"%u_Hostname",i); + p->m_szHostname = cfg.readEntry(tmp.ptr(),"proxy.example.net"); + tmp.sprintf("%u_Port",i); + p->m_uPort = cfg.readUIntEntry(tmp.ptr(),7000); + tmp.sprintf("%u_Ip",i); + p->m_szIp = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%u_User",i); + p->m_szUser = cfg.readEntry(tmp.ptr(),""); + tmp.sprintf("%u_Pass",i); + p->m_szPass = cfg.readEntry(tmp.ptr(),""); + + tmp.sprintf("%u_Protocol",i); + KviStr type = cfg.readEntry(tmp.ptr(),"SOCKSv4"); + p->setNamedProtocol(type.ptr()); + + tmp.sprintf("%u_IsIpV6",i); + p->m_bIsIpV6 = cfg.readBoolEntry(tmp.ptr(),false); + tmp.sprintf("%u_Current",i); + if(cfg.readBoolEntry(tmp.ptr(),false))m_pCurrentProxy = p; + m_pProxyList->append(p); + } + + if(!m_pCurrentProxy)m_pCurrentProxy = m_pProxyList->first(); +} + +void KviProxyDataBase::save(const char * filename) +{ + KviConfig cfg(filename,KviConfig::Write); + + cfg.clear(); + + cfg.writeEntry("Entries",m_pProxyList->count()); + + + int i=0; + + for(KviProxy * p=m_pProxyList->first();p;p=m_pProxyList->next()) + { + KviStr tmp(KviStr::Format,"%u_Hostname",i); + cfg.writeEntry(tmp.ptr(),p->m_szHostname.ptr()); + tmp.sprintf("%u_Port",i); + cfg.writeEntry(tmp.ptr(),p->m_uPort); + tmp.sprintf("%u_Ip",i); + cfg.writeEntry(tmp.ptr(),p->m_szIp.ptr()); + tmp.sprintf("%u_User",i); + cfg.writeEntry(tmp.ptr(),p->m_szUser.ptr()); + tmp.sprintf("%u_Pass",i); + cfg.writeEntry(tmp.ptr(),p->m_szPass.ptr()); + + tmp.sprintf("%u_Protocol",i); + KviStr type; + switch(p->m_protocol) + { + case KviProxy::Socks5: type = "SOCKSv5"; break; + case KviProxy::Http: type = "HTTP"; break; + default: type = "SOCKSv4"; break; + } + cfg.writeEntry(tmp.ptr(),type.ptr()); + + tmp.sprintf("%u_IsIpV6",i); + cfg.writeEntry(tmp.ptr(),p->m_bIsIpV6); + tmp.sprintf("%u_Current",i); + if(m_pCurrentProxy == p)cfg.writeEntry(tmp.ptr(),true); + i++; + } +} diff --git a/src/kvilib/ext/kvi_proxydb.h b/src/kvilib/ext/kvi_proxydb.h new file mode 100644 index 00000000..92fa2c44 --- /dev/null +++ b/src/kvilib/ext/kvi_proxydb.h @@ -0,0 +1,86 @@ +#ifndef _KVI_PROXYDB_H_ +#define _KVI_PROXYDB_H_ + +// +// File : kvi_proxydb.h +// Creation date : Sat Jul 22 2000 18:19:01 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" + +#include "kvi_string.h" +#include "kvi_inttypes.h" +#include "kvi_pointerlist.h" +#include <qstringlist.h> + +class KVILIB_API KviProxy +{ +public: + enum Protocol { Socks4 , Socks5 , Http }; + KviProxy(); + KviProxy(const KviProxy &prx); + ~KviProxy(); +public: + KviStr m_szHostname; + KviStr m_szIp; + KviStr m_szPass; + KviStr m_szUser; + kvi_u32_t m_uPort; + Protocol m_protocol; + bool m_bIsIpV6; +public: + bool isIpV6() const { return m_bIsIpV6; }; + Protocol protocol() const { return m_protocol; }; + const char * protocolName() const; + void setNamedProtocol(const char * proto); + kvi_u32_t port() const { return m_uPort; }; + const char * user() const { return m_szUser.ptr(); }; + const char * pass() const { return m_szPass.ptr(); }; + const char * ip() const { return m_szIp.ptr(); }; + const char * hostname() const { return m_szHostname.ptr(); }; + void normalizeUserAndPass(); + bool hasPass() const { return m_szPass.hasData(); }; + bool hasUser() const { return m_szUser.hasData(); }; + unsigned int passLen() const { return (unsigned int)m_szPass.len(); }; + unsigned int userLen() const { return (unsigned int)m_szUser.len(); }; + static void getSupportedProtocolNames(QStringList & buf); +}; + + +class KVILIB_API KviProxyDataBase +{ +public: + KviProxyDataBase(); + ~KviProxyDataBase(); +private: + KviPointerList<KviProxy> * m_pProxyList; + KviProxy * m_pCurrentProxy; +public: + void clear(); + KviPointerList<KviProxy> * proxyList(){ return m_pProxyList; }; + KviProxy * currentProxy(){ return m_pCurrentProxy; }; + void updateProxyIp(const char * proxy,const char * ip); + void setCurrentProxy(KviProxy * prx){ m_pCurrentProxy = prx; }; + void insertProxy(KviProxy * prx){ m_pProxyList->append(prx); }; + void load(const char * filename); + void save(const char * filename); +}; + +#endif //_KVI_PROXYDB_H_ diff --git a/src/kvilib/ext/kvi_regchan.cpp b/src/kvilib/ext/kvi_regchan.cpp new file mode 100644 index 00000000..a26c5969 --- /dev/null +++ b/src/kvilib/ext/kvi_regchan.cpp @@ -0,0 +1,181 @@ +//============================================================================= +// +// File : kvi_regchan.cpp +// Creation date : Sat Jun 29 01:01:16 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include "kvi_regchan.h" +#include "kvi_config.h" +#include "kvi_qstring.h" + +KviRegisteredChannel::KviRegisteredChannel(const KviStr &name,const KviStr &netmask) +{ + m_szName = name; + m_szNetMask = netmask; + m_pPropertyDict = new KviPointerHashTable<const char *,KviStr>(7,false,true); + m_pPropertyDict->setAutoDelete(true); +} + +KviRegisteredChannel::~KviRegisteredChannel() +{ + delete m_pPropertyDict; +} + + + +KviRegisteredChannelDataBase::KviRegisteredChannelDataBase() +{ + m_pChannelDict = new KviPointerHashTable<const char *,KviRegisteredChannelList>(17,false,true); + m_pChannelDict->setAutoDelete(true); +} + +KviRegisteredChannelDataBase::~KviRegisteredChannelDataBase() +{ + delete m_pChannelDict; +} + +void KviRegisteredChannelDataBase::load(const char * filename) +{ + KviConfig cfg(filename,KviConfig::Read); + m_pChannelDict->clear(); + KviConfigIterator it(*(cfg.dict())); + while(KviConfigGroup * d = it.current()) + { + KviStr szMask = it.currentKey(); + KviStr szChan = szMask.leftToLast('@'); + szMask.cutToLast('@'); + KviRegisteredChannel * c = new KviRegisteredChannel(szChan,szMask); + add(c); + KviConfigGroupIterator sit(*d); + while(QString * s = sit.current()) + { + c->setProperty(KviQString::toUtf8(sit.currentKey()).data(),new KviStr(*s)); + ++sit; + } + ++it; + } +} + +void KviRegisteredChannelDataBase::save(const char * filename) +{ + KviConfig cfg(filename,KviConfig::Write); + cfg.clear(); + + KviPointerHashTableIterator<const char *,KviRegisteredChannelList> it(*m_pChannelDict); + while(KviRegisteredChannelList * l = it.current()) + { + for(KviRegisteredChannel * c = l->first();c;c = l->next()) + { + KviStr szGrp(KviStr::Format,"%s@%s",c->name().ptr(),c->netMask().ptr()); + cfg.setGroup(szGrp.ptr()); + KviPointerHashTableIterator<const char *,KviStr> pit(*(c->propertyDict())); + while(KviStr * s = pit.current()) + { + cfg.writeEntry(pit.currentKey(),s->ptr()); + ++pit; + } + } + ++it; + } +} + +KviRegisteredChannel * KviRegisteredChannelDataBase::find(const char * name,const char * net) +{ + KviRegisteredChannelList * l = m_pChannelDict->find(name); + if(!l)return 0; + for(KviRegisteredChannel * c = l->first();c;c = l->next()) + { + if(kvi_matchString(c->netMask().ptr(),net))return c; + } + + return 0; +} + +KviRegisteredChannel * KviRegisteredChannelDataBase::findExact(const char * name,const char * netmask) +{ + KviRegisteredChannelList * l = m_pChannelDict->find(name); + if(!l)return 0; + for(KviRegisteredChannel * c = l->first();c;c = l->next()) + { + if(kvi_strEqualCI(c->netMask().ptr(),netmask))return c; + } + return 0; +} + +void KviRegisteredChannelDataBase::remove(KviRegisteredChannel * c) +{ + KviRegisteredChannelList * l = m_pChannelDict->find(c->name().ptr()); + if(!l)return; + for(KviRegisteredChannel * ch = l->first();ch;ch = l->next()) + { + if(ch == c) + { + if(l->count() <= 1) + { + m_pChannelDict->remove(c->name().ptr()); + } else { + l->removeRef(c); + } + return; + } + } +} + + +void KviRegisteredChannelDataBase::add(KviRegisteredChannel * c) +{ + KviRegisteredChannel * old = findExact(c->name().ptr(),c->netMask().ptr()); + if(old) + { + KviPointerHashTableIterator<const char *,KviStr> pit(*(old->propertyDict())); + while(KviStr *s = pit.current()) + { + if(!c->property(pit.currentKey())) + c->setProperty(pit.currentKey(),new KviStr(*s)); + ++pit; + } + remove(old); + } + KviRegisteredChannelList * l = m_pChannelDict->find(c->name().ptr()); + if(!l) + { + l = new KviRegisteredChannelList; + l->setAutoDelete(true); + m_pChannelDict->insert(c->name().ptr(),l); + } + // insert where there are less wildcards + int o = c->netMask().occurences('*'); + int idx = 0; + for(KviRegisteredChannel * rc = l->first();rc;rc = l->next()) + { + if(rc->netMask().occurences('*') > o) + { + // the existing has more wildcards , insert here! + l->insert(idx,c); + return; + } + idx++; + } + l->append(c); +} + diff --git a/src/kvilib/ext/kvi_regchan.h b/src/kvilib/ext/kvi_regchan.h new file mode 100644 index 00000000..f447c313 --- /dev/null +++ b/src/kvilib/ext/kvi_regchan.h @@ -0,0 +1,74 @@ +#ifndef _KVI_REGCHAN_H_ +#define _KVI_REGCHAN_H_ +//============================================================================= +// +// File : kvi_regchan.h +// Creation date : Sat Jun 29 01:01:15 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_string.h" +#include "kvi_pointerlist.h" + +#include "kvi_pointerhashtable.h" + +class KVILIB_API KviRegisteredChannel : public KviHeapObject +{ + friend class KviRegisteredChannelDataBase; +public: + KviRegisteredChannel(const KviStr &name,const KviStr &netmask); + ~KviRegisteredChannel(); +protected: + KviStr m_szName; + KviStr m_szNetMask; + KviPointerHashTable<const char *,KviStr> * m_pPropertyDict; +public: + KviPointerHashTable<const char *,KviStr> * propertyDict(){ return m_pPropertyDict; }; + const KviStr & name(){ return m_szName; }; + const KviStr & netMask(){ return m_szNetMask; }; + KviStr * property(const char * name){ return m_pPropertyDict->find(name); }; + // val must be allocated with NEW! + void setProperty(const char * name,KviStr * val){ m_pPropertyDict->replace(name,val); }; + void removeProperty(const char * name){ m_pPropertyDict->remove(name); }; +}; + +typedef KVILIB_API KviPointerList<KviRegisteredChannel> KviRegisteredChannelList; + +class KVILIB_API KviRegisteredChannelDataBase +{ +public: + KviRegisteredChannelDataBase(); + ~KviRegisteredChannelDataBase(); +protected: + KviPointerHashTable<const char *,KviRegisteredChannelList> * m_pChannelDict; +public: + KviPointerHashTable<const char *,KviRegisteredChannelList> * channelDict(){ return m_pChannelDict; }; + KviRegisteredChannel * find(const char * name,const char * net); + KviRegisteredChannel * findExact(const char * name,const char * netmask); + void remove(KviRegisteredChannel * c); + void add(KviRegisteredChannel * c); + void load(const char * filename); + void save(const char * filename); +}; + + +#endif //_KVI_REGCHAN_H_ diff --git a/src/kvilib/ext/kvi_regusersdb.cpp b/src/kvilib/ext/kvi_regusersdb.cpp new file mode 100644 index 00000000..6d36c975 --- /dev/null +++ b/src/kvilib/ext/kvi_regusersdb.cpp @@ -0,0 +1,743 @@ +//================================================================================================= +// +// File : kvi_regusersdb.cpp +// Creation date : Sat Sep 09 2000 15:46:12 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//================================================================================================= + + +#define __KVILIB__ + +#include "kvi_debug.h" + +#define _KVI_REGUSERDB_CPP_ +#include "kvi_regusersdb.h" + +#include "kvi_config.h" +#include "kvi_locale.h" + +/* + @doc: registered_users + @title: + Registered users + @type: + generic + @short: + Registration of users in KVIrc + @keyterms: + registered users, registration mask, registered user properties, + user properties, notify property, avatar property + @body: + [big]Introduction[/big][br] + The "registered user database" is basically a set of users with associated + [doc:irc_masks]irc-masks[/doc] and properties.[br] + It is used to recognize users on IRC and associate properties to them.[br] + This works more or less like the IRC ban list, K-Line list, or invite list.[br] + [big]User entry[/big][br] + A registered user database entry is identified by an [b]unique[/b] name.[br] + It may be the nickname of the user that you want to match, or the real name (if you know it) + or any other string (even with spaces). The name is an "internal identifier" for the user entry: + each name maps to a single entry and each entry has a single name.[br] + Each entry has a set of registration [doc:irc_masks]irc-masks[/doc]: these masks + are used to recognize the user on irc.[br] + [br] + [big]Registration masks[/big][br] + The masks have the common IRC mask format: [b]<nick>!<user>@<host>[/b][br] + The masks may contain '*' and '?' wildcards that match any portion of text.[br] + [b]*!*@*[/b][br] + [b]Pragma!*@*[/b][br] + [b]*!~daemon@*[/b][br] + [b]Pragma!*daemon@*.it[/b][br] + [b]Pragma!?daemon@some*.it[/b][br] + [b]Pragma!~daemon@some.host.it[/b][br] + Are examples of valid registration masks.[br] + The masks with wildcards can actually match more than a single user.[br] + For example the mask *!root@*.host.com will match all the users + having root as username and coming from the host.com domain.[br] + For this reason putting wildcards in nicknames could become a problem + if not used carefully (but may also be used to achieve interesting tricks).[br] + If you don't use wildcards in nicknames you are sure that + in a single irc connection , a mask will always refer to a single user.[br] + You will commonly use the following format:[br] + <nick>!*<username>@*.<host>.<top>[br] + or[br] + <nick>!*<username>@<number>.<number>.<number>.*[br] + In this way you can be 95% sure that the mask will really match the correct user.[br] + [br] + [big]Example of registration and lookups[/big] + Assume that you want to registere a friend of yours: Derek Riggs.[br] + Derek often uses "Eddie" as his nickname + "stranger" as username and has a dial-up connection that makes his IP address appear as + <variable-number>.somewhere.in.time.org.[br] + You will add an entry with name "Derek Riggs" and a registration mask like the following: + Eddie!stranger@*.somewhere.in.time.org.[br] + If the IRC servers keep adding strange characters ([doc:irc_masks]prefixes[/doc]) at the beginning of his username you may use + Eddie!*stranger@*.somewhere.in.time.org.[br] + If Eddie also often connects from the wasted.years.org domain and gets 'eddie' as username there, you might add a second registration mask as follows: + Eddie!*eddie@*.wasted.years.org.[br] + An alternative could be use only one mask with *.org as domain and allow any username (Eddie!*@*.org) but this + could become dangerous since it could match the users that you don't want to.[br] + On the other hand, if you dislike the users with the nickname Eddie that come from .org + and you're implementing an auto-kick system, the correct mask to register is "Eddie!*@*.org".[br] + [br] + KVirc ties to be smart , and always find the most correct match for an user: + If you have two masks registered: Pragma!*xor@*.myisp.it and *!*@*.myisp.it, + kvirc will match Pragma!~xor@233-dyn.myisp.it with the first one even if the second + one matches too; the firs one is a best match.[br] + [br] + [big]Properties[/big][br] + A registered user has an (eventually empty) set of properties + defined by name/value pairs. (In versions prior to 3.0.0 flags were used instead, + but revealed to be insufficient).[br] + KVirc recognizes some of these proprietes and associates semantic actions to it; other properties + are left for scripting extension. Property names are case insensitive.[br] + One of the recognized properties is the "[doc:notify_list]notify[/doc]" property. + When an user is found to have this property set to a special value + KVIrc will attempt to track the user presence on IRC. + Another one is the [doc:avatar]avatar[/doc] property. Its value should be the + name of the "default" [doc:avatar]avatar image file[/doc] for the specified user.[br] + The "ignore" property should be set to "1" (or "true") for users that have to be ignored (:D).[br] + [br] + [big]The interface to the database[/big][br] + The [module:reguser]reguser module[/module] is the interface to the "registered users database".[br] + It provides a set of commands for adding and removing masks and manipulating properties.[br] +*/ + +//============================================================================================================ +// +// KviRegisteredMask +// + +KVILIB_API KviRegisteredUserDataBase* g_pRegisteredUserDataBase = 0; + +KviRegisteredMask::KviRegisteredMask(KviRegisteredUser * u,KviIrcMask * m) +{ + m_pUser = u; + m_pMask = m; + m_iMaskNonWildChars = m_pMask->nonWildChars(); +} + +//============================================================================================================ +// +// KviRegisteredUser +// + + +KviRegisteredUser::KviRegisteredUser(const QString & name) +{ + m_iIgnoreFlags =0; + m_bIgnoreEnabled=false; + m_szName = name; + m_pPropertyDict = 0; + m_pMaskList = new KviPointerList<KviIrcMask>; + m_pMaskList->setAutoDelete(true); +} + +KviRegisteredUser::~KviRegisteredUser() +{ + if(m_pPropertyDict)delete m_pPropertyDict; + delete m_pMaskList; +} + +bool KviRegisteredUser::isIgnoreEnabledFor(IgnoreFlags flag) +{ + if(!m_bIgnoreEnabled) return false; + return m_iIgnoreFlags & flag; +} + +KviIrcMask * KviRegisteredUser::findMask(const KviIrcMask &mask) +{ + for(KviIrcMask * m = m_pMaskList->first();m;m = m_pMaskList->next()) + { + if(*m == mask)return m; + } + return 0; +} + +bool KviRegisteredUser::addMask(KviIrcMask * mask) +{ + if(findMask(*mask)) + { + delete mask; + mask = 0; + return false; + } + m_pMaskList->append(mask); + return true; +} + +bool KviRegisteredUser::removeMask(KviIrcMask * mask) +{ + if(!mask)return false; + return m_pMaskList->removeRef(mask); +} + +bool KviRegisteredUser::matches(const KviIrcMask &mask) +{ + for(KviIrcMask * m = m_pMaskList->first();m;m = m_pMaskList->next()) + { + if(m->matches(mask))return true; + } + return false; +} + +bool KviRegisteredUser::matchesFixed(const KviIrcMask &mask) +{ + for(KviIrcMask * m = m_pMaskList->first();m;m = m_pMaskList->next()) + { + if(m->matchesFixed(mask))return true; + } + return false; +} + +bool KviRegisteredUser::matchesFixed(const QString & nick,const QString & user,const QString & host) +{ + for(KviIrcMask * m = m_pMaskList->first();m;m = m_pMaskList->next()) + { + if(m->matchesFixed(nick,user,host))return true; + } + return false; +} + +void KviRegisteredUser::setProperty(const QString &name,bool value) +{ + setProperty(name,value ? QString("true") : QString("false")); +} + +void KviRegisteredUser::setProperty(const QString & name,const QString & value) +{ + if(!value.isEmpty()) + { + if(!m_pPropertyDict) + { + m_pPropertyDict = new KviPointerHashTable<QString,QString>(7,false); + m_pPropertyDict->setAutoDelete(true); + } +#ifdef COMPILE_USE_QT4 + QString * val = new QString(value.trimmed()); +#else + QString * val = new QString(value.stripWhiteSpace()); +#endif + if(!val->isEmpty()) + { + m_pPropertyDict->replace(name,val); + } else { + delete val; + val = 0; + } + } else { + if(m_pPropertyDict)m_pPropertyDict->remove(name); + } +} + +bool KviRegisteredUser::getProperty(const QString & name,QString &value) +{ + if(!m_pPropertyDict)return false; + if(name.isEmpty()) return false; + QString * pValue = m_pPropertyDict->find(name); + if(pValue)value = *pValue; + else return false; + return true; +} + +const QString & KviRegisteredUser::getProperty(const QString & name) +{ + if(!m_pPropertyDict)return KviQString::empty; + if(name.isEmpty())return KviQString::empty; + QString * pValue = m_pPropertyDict->find(name); + if(pValue)return *pValue; + return KviQString::empty; +} + +bool KviRegisteredUser::getBoolProperty(const QString & name,bool def) +{ + if(!m_pPropertyDict)return def; + if(name.isEmpty()) return def; + QString * pValue = m_pPropertyDict->find(name); + if(pValue) + { + // be flexible , allow more "true" values (pragma) + if(KviQString::equalCS(*pValue,"1"))return true; + if(KviQString::equalCI(*pValue,"true"))return true; + if(KviQString::equalCI(*pValue,"yes"))return true; + //if(KviQString::equalCI(*pValue,"yeah"))return true; + //if(KviQString::equalCI(*pValue,"sure"))return true; + //if(KviQString::equalCI(*pValue,"sureashell"))return true; + } + return def; +} + +//============================================================================================================ +// +// KviRegisteredUserGroup +// + +KviRegisteredUserGroup::KviRegisteredUserGroup(const QString &name) +{ + setName(name); +} + +KviRegisteredUserGroup::~KviRegisteredUserGroup() +{ +} + + +//============================================================================================================ +// +// KviRegisteredUserDb +// + +KviRegisteredUserDataBase::KviRegisteredUserDataBase() +{ + m_pUserDict = new KviPointerHashTable<QString,KviRegisteredUser>(31,false); // do not copy keys + m_pUserDict->setAutoDelete(true); + + m_pWildMaskList = new KviRegisteredMaskList; + m_pWildMaskList->setAutoDelete(true); + + m_pMaskDict = new KviPointerHashTable<QString,KviRegisteredMaskList>(49,false); // copy keys here! + m_pMaskDict->setAutoDelete(true); + + m_pGroupDict = new KviPointerHashTable<QString,KviRegisteredUserGroup>(5,false); // copy keys here! + m_pGroupDict->setAutoDelete(true); +} + +KviRegisteredUserDataBase::~KviRegisteredUserDataBase() +{ + emit(databaseCleared()); + delete m_pUserDict; + delete m_pWildMaskList; + delete m_pMaskDict; + delete m_pGroupDict; +} + +KviRegisteredUser * KviRegisteredUserDataBase::addUser(const QString & name) +{ + if(name.isEmpty()) return false; + if(m_pUserDict->find(name))return 0; + KviRegisteredUser * u = new KviRegisteredUser(name); + m_pUserDict->replace(u->name(),u); //u->name() because we're NOT copying keys! + emit(userAdded(name)); + return u; +} + +KviRegisteredUserGroup * KviRegisteredUserDataBase::addGroup(const QString & name) +{ + if(name.isEmpty()) return false; + if(m_pGroupDict->find(name))return 0; + KviRegisteredUserGroup * pGroup = new KviRegisteredUserGroup(name); + m_pGroupDict->replace(pGroup->name(),pGroup); //u->name() because we're NOT copying keys! + return pGroup; +} + +KviRegisteredUser * KviRegisteredUserDataBase::getUser(const QString & name) +{ + if(name.isEmpty()) return 0; + KviRegisteredUser * u = m_pUserDict->find(name); + if(!u) + { + u = new KviRegisteredUser(name); + m_pUserDict->replace(u->name(),u); //u->name() because we're NOT copying keys! + } + return u; +} + +static void append_mask_to_list(KviRegisteredMaskList *l,KviRegisteredUser *u,KviIrcMask *mask) +{ + KviRegisteredMask * newMask = new KviRegisteredMask(u,mask); + int idx = 0; + for(KviRegisteredMask * m = l->first();m;m = l->next()) + { + if(m->nonWildChars() < newMask->nonWildChars()) + { + l->insert(idx,newMask); + return; + } + idx++; + } + l->append(newMask); +} + +KviRegisteredUser * KviRegisteredUserDataBase::addMask(KviRegisteredUser * u,KviIrcMask * mask) +{ + if(!u || !mask) return 0; + __range_valid(u == m_pUserDict->find(u->name())); + + KviRegisteredMaskList * l; + if(mask->hasWildNick()) + { + for(KviRegisteredMask * m = m_pWildMaskList->first();m;m = m_pWildMaskList->next()) + { + if(*(m->mask()) == *mask) + { + delete mask; + mask = 0; + return m->user(); + } + } + // not found ...ok... add it + // masks with more info go first in the list + l = m_pWildMaskList; + } else { + l = m_pMaskDict->find(mask->nick()); + if(l) + { + // FIXME: #warning "Here we could compare the host and username only: nick matches for sure" + for(KviRegisteredMask * m = l->first();m;m = l->next()) + { + if(*(m->mask()) == *mask) + { + delete mask; + mask = 0; + return m->user(); + } + } + // not found ...ok... add it + } else { + // not found ...ok... add it + // this is the first mask in the list + l = new KviRegisteredMaskList; + l->setAutoDelete(true); + if(!u->addMask(mask)) + { + debug(" Ops...got an incoherent regusers action...recovered ?"); + delete l; + l = 0; + } else { + append_mask_to_list(l,u,mask); + m_pMaskDict->insert(mask->nick(),l); + } + return 0; + } + } + // Ok...add it + if(!u->addMask(mask)) + { + debug("ops...got an incoherent regusers action...recovered ?"); + return 0; // ops...already there ? + } + append_mask_to_list(l,u,mask); + return 0; +} + +void KviRegisteredUserDataBase::copyFrom(KviRegisteredUserDataBase * db) +{ + m_pUserDict->clear(); + m_pWildMaskList->clear(); + m_pMaskDict->clear(); + m_pGroupDict->clear(); + emit(databaseCleared()); + + KviPointerHashTableIterator<QString,KviRegisteredUser> it(*(db->m_pUserDict)); + + while(KviRegisteredUser * theCur = it.current()) + { + KviRegisteredUser * u = getUser(theCur->name()); + // copy masks + KviPointerList<KviIrcMask> * l = theCur->maskList(); + for(KviIrcMask * m=l->first();m;m = l->next()) + { + KviIrcMask * m2 = new KviIrcMask(*m); + addMask(u,m2); + } + // copy properties + KviPointerHashTable<QString,QString> * pd = theCur->propertyDict(); + if(pd) + { + KviPointerHashTableIterator<QString,QString> pdi(*pd); + while(pdi.current()) + { + u->setProperty(pdi.currentKey(),*(pdi.current())); + ++pdi; + } + } + u->m_iIgnoreFlags=theCur->m_iIgnoreFlags; + u->m_bIgnoreEnabled=theCur->m_bIgnoreEnabled; + u->setGroup(theCur->group()); + ++it; + } + + KviPointerHashTableIterator<QString,KviRegisteredUserGroup> git(*db->m_pGroupDict); + while(git.current()) + { + addGroup(git.currentKey()); + ++git; + } +} + + +bool KviRegisteredUserDataBase::removeUser(const QString & name) +{ + if(name.isEmpty()) return false; + KviRegisteredUser * u = m_pUserDict->find(name); + if(!u)return false; + while(KviIrcMask * mask = u->maskList()->first()) + { + if(!removeMaskByPointer(mask)) + debug("Ops... removeMaskByPointer(%s) failed ?",KviQString::toUtf8(name).data()); + } + emit(userRemoved(name)); + m_pUserDict->remove(name); + return true; +} +bool KviRegisteredUserDataBase::removeGroup(const QString & name) +{ + if(name.isEmpty()) return false; + m_pGroupDict->remove(name); + return true; +} + +bool KviRegisteredUserDataBase::removeMask(const KviIrcMask &mask) +{ + // find the mask pointer + KviRegisteredMask * m = findExactMask(mask); + // and remove it + if(m){ + if(removeMaskByPointer(m->mask())) + { + return true; + } + } + return 0; +} + +bool KviRegisteredUserDataBase::removeMaskByPointer(KviIrcMask * mask) +{ + if(!mask) return 0; + if(mask->hasWildNick()) + { + // remove from the wild list + for(KviRegisteredMask * m = m_pWildMaskList->first();m;m = m_pWildMaskList->next()) + { + if(m->mask() == mask) + { + // ok..got it, remove from the list and from the user struct (user struct deletes it!) + emit(userChanged(mask->nick())); + m->user()->removeMask(mask); // this one deletes m->mask() + m_pWildMaskList->removeRef(m); // this one deletes m + return true; + } + } + // not found ...opz :) + } else { + KviRegisteredMaskList * l = m_pMaskDict->find(mask->nick()); + if(l) + { + // FIXME: #warning "Here we could compare the host and username only: nick matches for sure" + for(KviRegisteredMask * m = l->first();m;m = l->next()) + { + if(m->mask() == mask) + { + QString nick = mask->nick(); + emit(userChanged(nick)); + m->user()->removeMask(mask); // this one deletes m->mask() (or mask) + l->removeRef(m); // this one deletes m + if(l->count() == 0)m_pMaskDict->remove(nick); + return true; + } + } + // not found ...opz + } + } + // not found... + return false; +} + + + +/* +KviRegisteredUser * KviRegisteredUserDataBase::findMatchingUser(const KviIrcMask &mask) +{ + // first lookup the nickname in the maskDict + KviRegisteredMaskList * l = m_pMaskDict->find(mask.nick()); + if(l) + { + for(KviRegisteredMask *m = l->first();m;m = l->next()) + { + if(m->mask()->matchesFixed(0,mask.user(),mask.host()))return m->user(); + } + } + // not found....lookup the wild ones + for(KviRegisteredMask * m = m_pWildMaskList->first();m;m = m_pWildMaskList->next()) + { + if(m->mask()->matchesFixed(mask))return m->user(); + } + return 0; // no match at all +} +*/ +KviRegisteredUser * KviRegisteredUserDataBase::findMatchingUser(const QString & nick,const QString &user,const QString & host) +{ + KviRegisteredMask * m = findMatchingMask(nick,user,host); + if(m)return m->user(); + return 0; // no match at all +} + +KviRegisteredMask * KviRegisteredUserDataBase::findMatchingMask(const QString & nick,const QString &user,const QString & host) +{ + // first lookup the nickname in the maskDict + if(nick.isEmpty()) return false; + KviRegisteredMaskList * l = m_pMaskDict->find(nick); + if(l) + { + for(KviRegisteredMask *m = l->first();m;m = l->next()) + { + if(m->mask()->matchesFixed(nick,user,host))return m; + } + } + // not found....lookup the wild ones + for(KviRegisteredMask * m = m_pWildMaskList->first();m;m = m_pWildMaskList->next()) + { + if(m->mask()->matchesFixed(nick,user,host))return m; + } + return 0; // no match at all +} + +KviRegisteredUser * KviRegisteredUserDataBase::findUserWithMask(const KviIrcMask &mask) +{ + KviRegisteredMask * m = findExactMask(mask); + if(m)return m->user(); + return 0; +} + +KviRegisteredMask * KviRegisteredUserDataBase::findExactMask(const KviIrcMask &mask) +{ + // first lookup the nickname in the maskDict + if(mask.nick()=="") return 0; + KviRegisteredMaskList * l = m_pMaskDict->find(mask.nick()); + if(l) + { + for(KviRegisteredMask *m = l->first();m;m = l->next()) + { + if(*(m->mask()) == mask)return m; + } + } + // not found....lookup the wild ones + for(KviRegisteredMask * m = m_pWildMaskList->first();m;m = m_pWildMaskList->next()) + { + if(*(m->mask()) == mask)return m; + } + return 0; // no match at all +} +/* +bool KviRegisteredUserDataBase::isIgnoredUser(const QString & nick,const QString & user,const QString & host) +{ + KviRegisteredUser * u = findMatchingUser(nick,user,host); + if(u)return u->getBoolProperty("IGNORE"); + else return false; +} +*/ +void KviRegisteredUserDataBase::load(const QString & filename) +{ + QString szCurrent; + KviConfig cfg(filename,KviConfig::Read); + + KviConfigIterator it(*cfg.dict()); + while(it.current()) + { + cfg.setGroup(it.currentKey()); + szCurrent=it.currentKey(); + if(KviQString::equalCSN("#Group ",szCurrent,7)) + { + szCurrent.remove(0,7); + addGroup(szCurrent); + } else { + KviRegisteredUser * u = addUser(szCurrent); + + if(u) + { + u->setIgnoreEnabled(cfg.readBoolEntry("IgnoreEnabled",false)); + u->setIgnoreFlags(cfg.readIntEntry("IgnoreFlags",0)); + KviConfigGroupIterator sdi(*(it.current())); + while(sdi.current()) + { + QString tmp = sdi.currentKey(); + if(KviQString::equalCSN("prop_",tmp,5)) + { + tmp.remove(0,5); + u->setProperty(tmp,*(sdi.current())); + } else if(KviQString::equalCSN("mask_",tmp,5)) + { + KviIrcMask * mask = new KviIrcMask(*(sdi.current())); + addMask(u,mask); + } else if(KviQString::equalCI(tmp,"Group")) + { + u->setGroup(*(sdi.current())); + } + ++sdi; + } + } + } + ++it; + } + if(!m_pGroupDict->find(__tr("Default"))) + addGroup(__tr("Default")); +} + + +void KviRegisteredUserDataBase::save(const QString & filename) +{ + KviConfig cfg(filename,KviConfig::Write); + cfg.clear(); + cfg.preserveEmptyGroups(true); + + KviPointerHashTableIterator<QString,KviRegisteredUser> it(*m_pUserDict); + + while(it.current()) + { + cfg.setGroup(it.current()->name()); + // Write properties + cfg.writeEntry("IgnoreEnabled",it.current()->ignoreEnagled()); + cfg.writeEntry("IgnoreFlags",it.current()->ignoreFlags()); + if(it.current()->propertyDict()) + { + KviPointerHashTableIterator<QString,QString> pit(*(it.current()->propertyDict())); + while(pit.current()) + { + QString tmp = "prop_"; + tmp.append(pit.currentKey()); + cfg.writeEntry(tmp,*(pit.current())); + ++pit; + } + } + // Write masks + int idx = 0; + for(KviIrcMask * m = it.current()->maskList()->first();m;m = it.current()->maskList()->next()) + { + QString tmp; + KviQString::sprintf(tmp,"mask_%d",idx); + QString mask; + m->mask(mask,KviIrcMask::NickUserHost); + cfg.writeEntry(tmp,mask); + ++idx; + } + cfg.writeEntry("Group",it.current()->group()); + ++it; + } + + KviPointerHashTableIterator<QString,KviRegisteredUserGroup> git(*m_pGroupDict); + QString szTmp; + while(git.current()) + { + KviQString::sprintf(szTmp,"#Group %Q",&(git.current()->name())); + cfg.setGroup(szTmp); + ++git; + } + +} diff --git a/src/kvilib/ext/kvi_regusersdb.h b/src/kvilib/ext/kvi_regusersdb.h new file mode 100644 index 00000000..06152f24 --- /dev/null +++ b/src/kvilib/ext/kvi_regusersdb.h @@ -0,0 +1,201 @@ +#ifndef _KVI_REGUSERSDB_H_ +#define _KVI_REGUSERSDB_H_ +//================================================================================================= +// +// File : kvi_regusersdb.h +// Creation date : Sat Sep 09 2000 15:30:56 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//================================================================================================= + +// +// REGISTERED USERS +// +// Here we manage users resigered by mask and their (generic!) properties +// + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_qstring.h" +#include "kvi_ircmask.h" +#include "kvi_debug.h" + +#include "kvi_pointerlist.h" +#include "kvi_pointerhashtable.h" +#include <qobject.h> + +class KviRegisteredUserDataBase; + +#ifndef _KVI_REGUSERDB_CPP_ + extern KVILIB_API KviRegisteredUserDataBase * g_pRegisteredUserDataBase; +#endif //!_KVI_REGUSERDB_CPP_ + +//================================================================================================= +// +// KviRegisteredUser +// + +class KVILIB_API KviRegisteredUser : public KviHeapObject +{ + friend class KviRegisteredUserDataBase; +public: + enum IgnoreFlags { + Channel=1, + Query=2, + Notice=4, + Ctcp=8, + Invite=16, + Dcc=32 + }; + + KviRegisteredUser(const QString &name); + ~KviRegisteredUser(); +private: + int m_iIgnoreFlags; + bool m_bIgnoreEnabled; + QString m_szName; + QString m_szGroup; + KviPointerHashTable<QString,QString> * m_pPropertyDict; // owned properties + KviPointerList<KviIrcMask> * m_pMaskList; // owned masks +protected: + // mask ownership is transferred! (always!) returns false if the mask was already there + bool addMask(KviIrcMask * mask); + bool removeMask(KviIrcMask * mask); + KviIrcMask * findMask(const KviIrcMask &mask); +public: + int ignoreFlags() { return m_iIgnoreFlags; }; + void setIgnoreFlags(int flags) {m_iIgnoreFlags=flags; }; + bool ignoreEnagled() { return m_bIgnoreEnabled; }; + void setIgnoreEnabled(bool enabled) {m_bIgnoreEnabled=enabled;}; + bool isIgnoreEnabledFor(IgnoreFlags flag); + + const QString &name(){ return m_szName; }; + bool matches(const KviIrcMask &mask); + bool matchesFixed(const KviIrcMask &mask); + bool matchesFixed(const QString &nick,const QString &user,const QString &host); + + void setProperty(const QString &name,const QString &value); + void setProperty(const QString &name,bool value); + + void setGroup(const QString &name) { m_szGroup=name; }; + const QString &group(){ return m_szGroup; }; + + const QString & getProperty(const QString &name); // returns 0 if the property is not there + bool getProperty(const QString &name,QString &value); // returns false if the property is not there + bool getBoolProperty(const QString &name,bool def=FALSE); // returns true if the property is there and is true + // the propertyDict may be 0! + KviPointerHashTable<QString,QString> * propertyDict(){ return m_pPropertyDict; }; + // this is never zero (but may contain no masks) + KviPointerList<KviIrcMask> * maskList(){ return m_pMaskList; }; +}; + +//============================================================================================================ +// +// KviRegisteredUserGroup +// + +class KVILIB_API KviRegisteredUserGroup : public KviHeapObject +{ + friend class KviRegisteredUserDataBase; +public: + KviRegisteredUserGroup(const QString &name); + ~KviRegisteredUserGroup(); + + void setName(const QString &name) { m_szName=name; }; + const QString &name(){ return m_szName; }; +private: + QString m_szName; +}; +//============================================================================================================ +// +// KviRegisteredMask +// + +class KVILIB_API KviRegisteredMask +{ +private: + KviRegisteredUser * m_pUser; // pointer , not owned! + KviIrcMask * m_pMask; // pointer , not owned! + int m_iMaskNonWildChars; +public: + KviRegisteredMask(KviRegisteredUser * u,KviIrcMask * m); + ~KviRegisteredMask(){}; +public: + int nonWildChars(){ return m_iMaskNonWildChars; }; + KviRegisteredUser * user(){ return m_pUser; }; + KviIrcMask * mask(){ return m_pMask; }; +}; + +typedef KviPointerList<KviRegisteredMask> KviRegisteredMaskList; + +//================================================================================================= +// +// KviRegisteredUsersDb +// +// Manages a set of KviRegisteredUser instances stored in the m_pUserDict dictionary +// The users are identified by masks stored in m_pMaskDict and m_pWildMaskList +// m_pMaskDict contains lists of non wild-nick KviRegisteredMask that point to users +// m_pWildMaskList is a list of wild-nick KviRegisteredMask that point to users +// + +class KVILIB_API KviRegisteredUserDataBase : public QObject +{ + Q_OBJECT +public: + KviRegisteredUserDataBase(); + ~KviRegisteredUserDataBase(); +private: + KviPointerHashTable<QString,KviRegisteredUser> * m_pUserDict; // unique namespace, owns the objects, does not copy keys + KviPointerHashTable<QString,KviRegisteredMaskList> * m_pMaskDict; // owns the objects, copies the keys + KviRegisteredMaskList * m_pWildMaskList; // owns the objects + KviPointerHashTable<QString,KviRegisteredUserGroup>* m_pGroupDict; +public: + void copyFrom(KviRegisteredUserDataBase * db); + KviRegisteredUser * addUser(const QString &name); // returns 0 if already there + KviRegisteredUser * getUser(const QString &name); // returns existing or adds + bool removeUser(const QString &name); + bool removeGroup(const QString &name); + KviRegisteredUser * findUserByName(const QString &name){ return m_pUserDict->find(name); }; + // mask must be allocated on the heap and the ownership is transferred! + // returns non zero if there is already an user with this mask (returns the pointer to it!) + KviRegisteredUser * addMask(KviRegisteredUser * u,KviIrcMask * mask); + bool removeMaskByPointer(KviIrcMask * mask); + bool removeMask(const KviIrcMask &mask); + KviRegisteredUser * findMatchingUser(const QString &nick,const QString &user,const QString &host); + KviRegisteredUser * findUserWithMask(const KviIrcMask &mask); + KviRegisteredMask * findExactMask(const KviIrcMask &mask); + KviRegisteredMask * findMatchingMask(const QString &nick,const QString &user,const QString &host); + //Only used in few places (actually one) of the code, but lot of times;perfect for inlining... + //bool isIgnoredUser(const char * nick,const char * user,const char * host); + void load(const QString &filename); + void save(const QString &filename); + + KviPointerHashTable<QString,KviRegisteredUser> * userDict(){ return m_pUserDict; }; + KviPointerHashTable<QString,KviRegisteredUserGroup>* groupDict() { return m_pGroupDict; }; + + KviRegisteredUserGroup* addGroup(const QString &name); +signals: + void userRemoved(const QString&); + void userChanged(const QString&); + void userAdded (const QString&); + void databaseCleared(); +}; + + +#endif //_KVI_REGUSERSDB_H_ diff --git a/src/kvilib/ext/kvi_sharedfiles.cpp b/src/kvilib/ext/kvi_sharedfiles.cpp new file mode 100644 index 00000000..65ce0d69 --- /dev/null +++ b/src/kvilib/ext/kvi_sharedfiles.cpp @@ -0,0 +1,391 @@ +//============================================================================= +// +// File : kvi_filetrader.cpp +// Creation date : Wed Aug 27 2000 10:33:11 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_sharedfiles.h" + +#include "kvi_config.h" +#include "kvi_fileutils.h" + +#include <qfileinfo.h> + +// TODO: Match servers that the file requests come from +// TODO: Max number of downloads ? + +// FIXME: MD5SUM ? + +/* + @doc: shared_files + @title: + Sharing files with KVIrc + @type: + generic + @short: + Automatically sharing your files with other IRC users + @keyterms: + file sharing + @body: + [big]What is this ?[/big] + The "file offers" are a simple way to share your files with other IRC users.[br] + Basically , you setup an offer by selecting a local file, choosing a "visible name" for it. + Remote users will be able to request you the file and download it automatically by + issuing a simple DCC GET request.[br] + [big]Details[/big] + Each offer refers to an existing file on one of your locally mounted file systems. + The offer is given a visible name that the remote users will effectively request. + To share the file /usr/arch/mp3/SonataArctica_SingInSilence_Live.mp3 you will add a file offer + with /usr/arch/mp3/SonataArctica_SingInSilence_Live.mp3 as real file path , something like + "SonataArctica_SingInSilence.mp3". A remote user will then request you a DCC GET SonataArctica_SingInSilence.mp3 + and KVIrc will automatically send the file.[br] + Each file offer has an "user mask" that the requesting remote users must match to + obtain the file: *!*@* matches any user, Pragma!*@* matches any user with nickname pragma, + *!*@*.omnikron.net matches any user coming from the omnikron.net domain.[br] + Each offer can have an expire time: the offer will be automatically removed after + a defined number of seconds. An expire time of '0' seconds means that the offer should never expire.[br] + If you have two file offers with the same name and different file, the remote user can + use an additional "size" parameter in the DCC GET request.[br] + [big]Security issues[/big] + This is a nice but unsecure method of sharing files.[br] + The user mask is a good protection but you have to use it properly!.[br] + Setting the user mask to Nick!*@* can be easily exploited (just by making an user disconnect + in one of the well known ways and then by using his nickname).[br] + On the other side, the remote end must know exactly the visible name of the offer to request + and noone but you will tell him that name.[br] + In sum:[br] + Don't share any really important files: this *might* be like putting it on your webpage :D[br] + Please don't send complains if someone stoles your /etc/passwd : it is because you have permitted that.[br] +*/ + +KviSharedFile::KviSharedFile(const QString &szName,const QString &szAbsPath,const QString &szUserMask,time_t expireTime,unsigned int uFileSize) +{ + m_szName = szName; + m_szAbsFilePath = szAbsPath; + m_szUserMask = szUserMask; + m_expireTime = expireTime; + m_uFileSize = uFileSize; +#ifdef COMPILE_USE_QT4 + // QT4ROX: Because they have finally moved the functionality of QString::contains() to QString::count(), and QString::contains() now does the right job + m_uWildCount = m_szUserMask.count('*'); +#else + m_uWildCount = m_szUserMask.contains('*'); +#endif + m_uNonWildCount = m_szUserMask.length() - m_uWildCount; +} + +KviSharedFile::~KviSharedFile() +{ +} + + +KviSharedFilesManager::KviSharedFilesManager() +: QObject() +{ + m_pSharedListDict = new KviPointerHashTable<QString,KviSharedFileList>(); + m_pSharedListDict->setAutoDelete(true); + m_pCleanupTimer = new QTimer(); + connect(m_pCleanupTimer,SIGNAL(timeout()),this,SLOT(cleanup())); +} + +KviSharedFilesManager::~KviSharedFilesManager() +{ + if(m_pCleanupTimer->isActive())m_pCleanupTimer->stop(); + delete m_pCleanupTimer; + delete m_pSharedListDict; +} + +void KviSharedFilesManager::cleanup() +{ + KviPointerHashTableIterator<QString,KviSharedFileList> it(*m_pSharedListDict); + time_t curTime = time(0); + + bool bOtherStuffToCleanup = false; + //bool bChanged = false; + + KviPointerList<QString> lDying; + lDying.setAutoDelete(true); + + while(KviSharedFileList * l = it.current()) + { + KviPointerList<KviSharedFile> tmp; + tmp.setAutoDelete(false); + for(KviSharedFile * o = l->first();o;o = l->next()) + { + if(o->expireTime() > 0) + { + if(((int)o->expireTime()) <= ((int)curTime)) + { + tmp.append(o); + //bChanged = true; + } else { + bOtherStuffToCleanup = true; + } + } + } + for(KviSharedFile * fo = tmp.first();fo;fo = tmp.next()) + { + l->removeRef(fo); + emit sharedFileRemoved(fo); + } + if(l->count() == 0) + lDying.append(new QString(it.currentKey())); + + ++it; + } + + for(QString * pDyingKey = lDying.first();pDyingKey;pDyingKey = lDying.next()) + m_pSharedListDict->remove(*pDyingKey); + + if(!bOtherStuffToCleanup)m_pCleanupTimer->stop(); + //if(bChanged)emit sharedFilesChanged(); +} + +void KviSharedFilesManager::clear() +{ + m_pSharedListDict->clear(); + emit sharedFilesChanged(); +} + +void KviSharedFilesManager::doInsert(KviSharedFileList * l, KviSharedFile * o) +{ + int index = 0; + for(KviSharedFile * fo =l->first();fo;fo = l->next()) + { + if(o->wildcardCount() > 0) + { + // the new mask has wildcards... if the current one has none, skip it + if(fo->wildcardCount() > 0) + { + // the one in the list has wildcards too... + // the ones with more non-wild chars go first... + if(fo->nonWildcardCount() < o->nonWildcardCount()) + { + // ok...the new one has more non-wildcards , insert + l->insert(index,o); + return; + } else { + if(o->nonWildcardCount() == fo->nonWildcardCount()) + { + // the same number of non-wildcards + // let the number of wildcards decide (it will be eventually equal) + if(o->wildcardCount() < fo->wildcardCount()) + { + // the new one has less wildcards... goes first + l->insert(index,o); + return; + } // else the same number of wildcards and non-wildcards...skip + } // else the existing one has more non-wildcards...skip + } + } // else the current has no wildcards...skip + } else { + // the new mask has no wildcards.... + if(fo->wildcardCount() > 0) + { + // current one has wildcards...insert + l->insert(index,o); + return; + } + // the current one has no wildcards... + // the longer masks go first.... + if(fo->maskLength() < o->maskLength()) + { + // the current one is shorter than the new one...insert + l->insert(index,o); + return; + } // else current one is longer...skip + } + index++; + } + l->append(o); +} + +void KviSharedFilesManager::addSharedFile(KviSharedFile * f) +{ + // First find the list + KviSharedFileList * l = m_pSharedListDict->find(f->name()); + if(!l) + { + l = new KviSharedFileList; + l->setAutoDelete(true); + m_pSharedListDict->replace(f->name(),l); + } + + doInsert(l,f); + + if(((int)f->expireTime()) > 0) + { + if(!m_pCleanupTimer->isActive())m_pCleanupTimer->start(60000); + } + + emit sharedFileAdded(f); +} + +KviSharedFile * KviSharedFilesManager::addSharedFile(const QString &szName,const QString &szAbsPath,const QString &szMask,int timeoutInSecs) +{ + QFileInfo inf(szAbsPath); + if(inf.exists() && inf.isFile() && inf.isReadable() && (inf.size() > 0)) + { + // First find the list + KviSharedFileList * l = m_pSharedListDict->find(szName); + if(!l) + { + l = new KviSharedFileList; + l->setAutoDelete(true); + m_pSharedListDict->replace(szName,l); + } + + // Now insert + KviSharedFile * o = new KviSharedFile(szName,szAbsPath,szMask,timeoutInSecs > 0 ? (((int)(time(0))) + timeoutInSecs) : 0,inf.size()); + + doInsert(l,o); + + if(((int)o->expireTime()) > 0) + { + if(!m_pCleanupTimer->isActive())m_pCleanupTimer->start(60000); + } + + emit sharedFileAdded(o); + + return o; + } else { + debug("File %s unreadable: can't add offer",KviQString::toUtf8(szAbsPath).data()); + return 0; + } +} + +KviSharedFile * KviSharedFilesManager::lookupSharedFile(const QString &szName,KviIrcMask * mask,unsigned int uFileSize) +{ + KviSharedFileList * l = m_pSharedListDict->find(szName); + if(!l)return 0; + + for(KviSharedFile * o = l->first();o;o = l->next()) + { + bool bMatch; + if(mask) + { + KviIrcMask umask(o->userMask()); + bMatch = mask->matchedBy(umask); + } else bMatch = KviQString::equalCS(o->userMask(),"*!*@*"); + if(bMatch) + { + if(uFileSize > 0) + { + if(uFileSize == o->fileSize())return o; + } else return o; + } + } + + return 0; +} +bool KviSharedFilesManager::removeSharedFile(const QString &szName,const QString &szMask,unsigned int uFileSize) +{ + KviSharedFileList * l = m_pSharedListDict->find(szName); + if(!l)return false; + for(KviSharedFile * o = l->first();o;o = l->next()) + { + if(KviQString::equalCI(szMask,o->userMask())) + { + bool bMatch = uFileSize > 0 ? uFileSize == o->fileSize() : true; + if(bMatch) + { + QString save = szName; // <-- szName MAY Be a pointer to o->name() + l->removeRef(o); + if(l->count() == 0)m_pSharedListDict->remove(save); + emit sharedFileRemoved(o); + return true; + } + } + } + return false; +} + +bool KviSharedFilesManager::removeSharedFile(const QString &szName,KviSharedFile * off) +{ + KviSharedFileList * l = m_pSharedListDict->find(szName); + if(!l)return false; + for(KviSharedFile * o = l->first();o;o = l->next()) + { + if(off == o) + { + QString save = szName; // <-- szName MAY Be a pointer to o->name() + l->removeRef(o); + if(l->count() == 0)m_pSharedListDict->remove(save); + emit sharedFileRemoved(off); + return true; + } + } + return false; +} + + +void KviSharedFilesManager::load(const QString &filename) +{ + KviConfig cfg(filename,KviConfig::Read); + //cfg.clear(); + cfg.setGroup("PermanentFileOffers"); + int num = cfg.readIntEntry("NEntries",0); + for(int idx=0;idx<num;idx++) + { + QString tmp; + KviQString::sprintf(tmp,"%dFName",idx); + QString szName = cfg.readQStringEntry(tmp,""); + KviQString::sprintf(tmp,"%dFilePath",idx); + QString szPath = cfg.readQStringEntry(tmp,""); + KviQString::sprintf(tmp,"%dUserMask",idx); + QString szMask = cfg.readQStringEntry(tmp,""); + if(!szMask.isEmpty() && !szPath.isEmpty() && !szName.isEmpty()) + addSharedFile(szName,szPath,szMask,0); + } +} + +void KviSharedFilesManager::save(const QString &filename) +{ + KviConfig cfg(filename,KviConfig::Write); + cfg.clear(); + cfg.setGroup("PermanentFileOffers"); + + KviPointerHashTableIterator<QString,KviSharedFileList> it(*m_pSharedListDict); + int idx = 0; + while(KviSharedFileList * l = it.current()) + { + for(KviSharedFile * o = l->first();o;o = l->next()) + { + if(((int)(o->expireTime())) == 0) + { + QString tmp; + KviQString::sprintf(tmp,"%dFName",idx); + cfg.writeEntry(tmp,it.currentKey()); + KviQString::sprintf(tmp,"%dFilePath",idx); + cfg.writeEntry(tmp,o->absFilePath()); + KviQString::sprintf(tmp,"%dUserMask",idx); + cfg.writeEntry(tmp,o->userMask()); + ++idx; + } + } + ++it; + } + cfg.writeEntry("NEntries",idx); +} + diff --git a/src/kvilib/ext/kvi_sharedfiles.h b/src/kvilib/ext/kvi_sharedfiles.h new file mode 100644 index 00000000..3a6d2239 --- /dev/null +++ b/src/kvilib/ext/kvi_sharedfiles.h @@ -0,0 +1,133 @@ +#ifndef _KVI_FILETRADER_H_ +#define _KVI_FILETRADER_H_ +//============================================================================= +// +// File : kvi_filetrader.h +// Creation date : Wed Aug 27 2000 10:28:51 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_string.h" +#include "kvi_ircmask.h" +#include "kvi_pointerlist.h" +#include "kvi_qstring.h" + +#include "kvi_pointerhashtable.h" + +#include <time.h> +#include <qtimer.h> + + +class KVILIB_API KviSharedFile : public KviHeapObject +{ +public: + KviSharedFile(const QString &szName,const QString &szAbsPath,const QString &szUserMask,time_t expireTime,unsigned int uFileSize); + ~KviSharedFile(); +private: + QString m_szName; + QString m_szAbsFilePath; + time_t m_expireTime; + QString m_szUserMask; + unsigned int m_uFileSize; + unsigned int m_uWildCount; + unsigned int m_uNonWildCount; +public: + const QString &name(){ return m_szName; }; + + const QString &absFilePath(){ return m_szAbsFilePath; }; + + const QString &userMask(){ return m_szUserMask; }; + + time_t expireTime(){ return m_expireTime; }; + bool expires(){ return (m_expireTime != 0); }; + + unsigned int fileSize(){ return m_uFileSize; }; + + unsigned int wildcardCount(){ return m_uWildCount; }; + unsigned int nonWildcardCount(){ return m_uNonWildCount; }; + int maskLength(){ return m_szUserMask.length(); }; +}; + + +typedef KviPointerList<KviSharedFile> KviSharedFileList; + + +class KVILIB_API KviSharedFilesManager : public QObject +{ + Q_OBJECT +public: + KviSharedFilesManager(); + ~KviSharedFilesManager(); +private: + QTimer * m_pCleanupTimer; + KviPointerHashTable<QString,KviSharedFileList> * m_pSharedListDict; +public: + void addSharedFile(KviSharedFile * f); + KviSharedFile * addSharedFile(const QString &szName,const QString &szAbsPath,const QString &szMask,int timeoutInSecs); + KviSharedFile * lookupSharedFile(const QString &szName,KviIrcMask * mask,unsigned int uFileSize = 0); + bool removeSharedFile(const QString &szName,const QString &szMask,unsigned int uFileSize); + bool removeSharedFile(const QString &szName,KviSharedFile * off); + void load(const QString &filename); + void save(const QString &filename); + void clear(); + KviPointerHashTable<QString,KviSharedFileList> * sharedFileListDict(){ return m_pSharedListDict; }; +private: + void doInsert(KviSharedFileList * l, KviSharedFile * o); +private slots: + void cleanup(); +signals: + void sharedFilesChanged(); // emitted when the list is cleared at once + void sharedFileAdded(KviSharedFile * f); + void sharedFileRemoved(KviSharedFile * f); +}; + + +/* +class KviSharedFile +{ + KviSharedFile(); + KviSharedFile(const KviStr &filePath,const KviStr &userMask); + ~KviSharedFile(); +protected: + KviStr m_szFilePath; + KviStr m_szVisibleName; + KviStr m_szMd5Sum; + KviStr m_szUserMask; + unsigned short int m_uWildCount; + unsigned short int m_uNonWildCount; + + unsigned int m_uFileSize; + time_t m_tExpireTime; +public: + void setFilePath(const KviStr &filePath); + void setUserMask(const KviStr &userMask); + void setVisibleName(const KviStr &visibleName); + void setMd5Sum(const KviStr &md5Sum); + void setFileSize(unsigned int uFileSize); + void setExpireTime(time_t expireTime); + void doNotExpire(){ setExpireTime((time_t)0); }; + + void computeMd5Sum(); +}; +*/ + +#endif //_KVI_FILETRADER_H_ diff --git a/src/kvilib/ext/kvi_stringconversion.cpp b/src/kvilib/ext/kvi_stringconversion.cpp new file mode 100644 index 00000000..3d0255cc --- /dev/null +++ b/src/kvilib/ext/kvi_stringconversion.cpp @@ -0,0 +1,277 @@ +//============================================================================= +// +// File : kvi_stringconversion.cpp +// Creation date : Thu Oct 20 2000 14:12:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#define _KVI_STRINGCONVERSION_CPP_ +#include "kvi_stringconversion.h" + +#include "kvi_qstring.h" +#include <stdio.h> + +QString g_szGlobalDir; +QString g_szLocalDir; + +namespace KviStringConversion +{ + + void init(const QString& szGlobalDir,const QString& szLocalDir) + { + g_szGlobalDir=szGlobalDir; + g_szLocalDir=szLocalDir; + } + + void encodePath(QString& buffer) + { + if(!buffer.isEmpty()) + { + if(!g_szLocalDir.isEmpty()) + { + if(KviQString::find(buffer,g_szLocalDir)==0) + { + buffer.remove(0,g_szLocalDir.length()); + buffer.prepend("local://"); + } + } + if(!g_szGlobalDir.isEmpty()) + { + if(KviQString::find(buffer,g_szGlobalDir)==0) + { + buffer.remove(0,g_szGlobalDir.length()); + buffer.prepend("global://"); + } + } + } + } + + void decodePath(QString& buffer) + { + if(!buffer.isEmpty()) + { + if(!g_szLocalDir.isEmpty()) + { + if(KviQString::find(buffer,"local://")==0) + { + buffer.remove(0,8); + buffer.prepend(g_szLocalDir); + } + } + if(!g_szGlobalDir.isEmpty()) + { + if(KviQString::find(buffer,"global://")==0) + { + buffer.remove(0,9); + buffer.prepend(g_szGlobalDir); + } + } + } + } + + void encodePath(QStringList& buffer) + { + for ( QStringList::Iterator it = buffer.begin(); it != buffer.end(); ++it ) + { + encodePath(*it); + } + } + + void decodePath(QStringList& buffer) + { + for ( QStringList::Iterator it = buffer.begin(); it != buffer.end(); ++it ) + { + decodePath(*it); + } + } + + void toString(const bool bValue,QString &buffer) + { + buffer = bValue ? '1' : '0'; + } + + bool fromString(const QString & szValue,bool &buffer) + { + if(szValue.isEmpty())buffer = false; + else buffer = !((KviQString::equalCS(szValue,"0")) || (KviQString::equalCI(szValue,"false"))); + return true; + } + + void toString(const int iValue,QString &buffer) + { + buffer.setNum(iValue); + } + + bool fromString(const QString &szValue,int &buffer) + { + bool bOk; + buffer = szValue.toInt(&bOk); + return bOk; + } + + void toString(const unsigned int uValue,QString &buffer) + { + buffer.setNum(uValue); + } + + bool fromString(const QString & szValue,unsigned int &buffer) + { + bool bOk; + buffer= szValue.toUInt(&bOk); + return bOk; + } + + void toString(const QRect &rValue,QString &buffer) + { + buffer.sprintf("%d,%d,%d,%d",rValue.x(),rValue.y(),rValue.width(),rValue.height()); + } + + bool fromString(const QString & szValue,QRect &buffer) + { + KviQCString tmp = KviQString::toUtf8(szValue); + const char * c = tmp.data(); + if(!c)return false; + int l,t,w,h; + if(sscanf(c,"%d,%d,%d,%d",&l,&t,&w,&h) != 4)return false; + buffer.setRect(l,t,w,h); + return true; + } + + void toString(const QString &szValue,QString &buffer) + { + buffer = szValue; + } + + bool fromString(const QString & szValue,QString &buffer) + { + buffer = szValue; + return true; + } + + void toString(const KviPixmap &pValue,QString &buffer) + { + buffer=pValue.path(); + encodePath(buffer); + } + + bool fromString(const QString & szValue,KviPixmap &buffer) + { + QString szPath(szValue); + decodePath(szPath); + if(szPath.isEmpty()) { + buffer.setNull(); + return true; + } else { + return buffer.load(szPath); + } + } + + void toString(const KviMsgType &mValue,QString &buffer) + { + buffer.sprintf("%d,%u,%u,%d,%d",mValue.m_iPixId,mValue.m_cForeColor,mValue.m_cBackColor,mValue.m_bLogEnabled,mValue.m_iLevel); + } + + bool fromString(const QString & szValue,KviMsgType &buffer) + { + int iId,iLog,iLevel; + unsigned int uFore,uBack; + KviQCString tmp = KviQString::toUtf8(szValue); + char * cx = tmp.data(); + if(!cx)return false; + if(sscanf(cx,"%d,%u,%u,%d,%d",&iId,&uFore,&uBack,&iLog,&iLevel) != 5)return false; + buffer = KviMsgType(buffer.m_szType,iId,uFore,uBack,iLog,iLevel); + return true; + } + + void toString(const QColor &cValue,QString &buffer) + { + buffer = cValue.name(); + } + + bool fromString(const QString & szValue,QColor &buffer) + { + buffer.setNamedColor(szValue); return true; + } + + void toString(const QFont &fValue,QString &buffer) + { + QString family(fValue.family()); + buffer.sprintf("%s,%d,%d,%d",KviQString::toUtf8(family).data(),fValue.pointSize(),fValue.styleHint(),fValue.weight()); + QString options; + if(fValue.bold())options.append('b'); + if(fValue.italic())options.append('i'); + if(fValue.underline())options.append('u'); + if(fValue.strikeOut())options.append('s'); + if(fValue.fixedPitch())options.append('f'); + + if(!options.isEmpty()) + { + buffer.append(','); + buffer.append(options); + } + } + + bool fromString(const QString & szValue,QFont &buffer) + { + KviStr str = szValue; + KviStr family,pointSize,styleHint,weight,options; + str.getToken(family,','); + str.getToken(pointSize,','); + str.getToken(styleHint,','); + str.getToken(weight,','); + if(!family.isEmpty())buffer.setFamily(family.ptr()); + int i; + bool bOk; + i = pointSize.toInt(&bOk); + if(bOk && (i > 0))buffer.setPointSize(i); + i = styleHint.toInt(&bOk); + if(bOk && (i >= 0))buffer.setStyleHint((QFont::StyleHint)i); + i = weight.toInt(&bOk); + if(bOk && (i >= 0))buffer.setWeight(i); + if(!str.isEmpty()) + { + buffer.setBold(str.contains("b")); + buffer.setItalic(str.contains("i")); + buffer.setUnderline(str.contains("u")); + buffer.setStrikeOut(str.contains("s")); + buffer.setFixedPitch(str.contains("f")); + } + return true; + } + + void toString(const QStringList &sValue,QString &buffer) + { + buffer = sValue.join(","); + } + + bool fromString(const QString & szValue,QStringList &buffer) + { +#ifdef COMPILE_USE_QT4 + buffer = szValue.split(","); +#else + buffer = QStringList::split(",",szValue); +#endif + return true; + } + +} diff --git a/src/kvilib/ext/kvi_stringconversion.h b/src/kvilib/ext/kvi_stringconversion.h new file mode 100644 index 00000000..78f8d417 --- /dev/null +++ b/src/kvilib/ext/kvi_stringconversion.h @@ -0,0 +1,91 @@ +#ifndef _KVI_STRINGCONVERSION_H_ +#define _KVI_STRINGCONVERSION_H_ + +//============================================================================= +// +// File : kvi_stringconversion.h +// Creation date : Thu Oct 20 2000 13:27:12 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_string.h" +#include "kvi_pixmap.h" +#include "kvi_msgtype.h" + +#include <qrect.h> +#include <qcolor.h> +#include <qfont.h> +#include <qstringlist.h> +#include <qstring.h> + + +namespace KviStringConversion +{ + extern KVILIB_API void init(const QString& szGlobalDir,const QString& szLocalDir); + + extern KVILIB_API void encodePath(QString& buffer); + extern KVILIB_API void decodePath(QString& buffer); + + extern KVILIB_API void encodePath(QStringList& buffer); + extern KVILIB_API void decodePath(QStringList& buffer); + + // bool <-> + extern KVILIB_API void toString(const bool bValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,bool &buffer); + + // int <-> QString + extern KVILIB_API void toString(const int iValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,int &buffer); + + // uint <-> QString + extern KVILIB_API void toString(const unsigned int uValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,unsigned int &buffer); + + // QRect <-> QString + extern KVILIB_API void toString(const QRect &rValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,QRect &buffer); + + // QString <-> QString (Null conversion) + extern KVILIB_API void toString(const QString &szValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,QString &buffer); + + // KviPixmap <-> QString + extern KVILIB_API void toString(const KviPixmap &pValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,KviPixmap &buffer); + + // QFont <-> QString + extern KVILIB_API void toString(const QFont &fValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,QFont &buffer); + + // KviMsgType <-> QString + extern KVILIB_API void toString(const KviMsgType &mValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,KviMsgType &buffer); + + // QColor <-> QString + extern KVILIB_API void toString(const QColor &cValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,QColor &buffer); + + // QStringList <-> QString + extern KVILIB_API void toString(const QStringList &sValue,QString &buffer); + extern KVILIB_API bool fromString(const QString &szValue,QStringList &buffer); +}; + +#endif //!_KVI_STRINGCONVERSION_H_ diff --git a/src/kvilib/ext/kvi_xlib.h b/src/kvilib/ext/kvi_xlib.h new file mode 100644 index 00000000..ef6ca177 --- /dev/null +++ b/src/kvilib/ext/kvi_xlib.h @@ -0,0 +1,45 @@ +#ifndef _KVI_XLIB_H_ +#define _KVI_XLIB_H_ +//============================================================================= +// +// File : kvi_xlib.h +// Creation date : Tue Aug 14 18:17:21 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2005 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifndef COMPILE_NO_X + + #ifdef Bool + // Someone has defined Bool ? + #undef Bool + #endif + + #include <X11/Xlib.h> + + // Too bad that X11/Xlib.h defines Bool, Error and Success... this basically + // SUX since we can't use them anywhere in the source! + // this breaks, enums in Qt, enums in KVIrc and other stuff all around... + // Shame on you Xlib.h author :D + +#endif // !COMPILE_NO_X + +#endif //_KVI_XLIB_H_ diff --git a/src/kvilib/ext/moc_kvi_crypt.cpp b/src/kvilib/ext/moc_kvi_crypt.cpp new file mode 100644 index 00000000..89c29d46 --- /dev/null +++ b/src/kvilib/ext/moc_kvi_crypt.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** KviCryptEngine meta object code from reading C++ file 'kvi_crypt.h' +** +** Created: Sun Mar 23 20:56:10 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_crypt.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviCryptEngine::className() const +{ + return "KviCryptEngine"; +} + +QMetaObject *KviCryptEngine::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviCryptEngine( "KviCryptEngine", &KviCryptEngine::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviCryptEngine::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviCryptEngine", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviCryptEngine::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviCryptEngine", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviCryptEngine::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + metaObj = QMetaObject::new_metaobject( + "KviCryptEngine", parentObject, + 0, 0, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviCryptEngine.setMetaObject( metaObj ); + return metaObj; +} + +void* KviCryptEngine::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviCryptEngine" ) ) + return this; + if ( !qstrcmp( clname, "KviHeapObject" ) ) + return (KviHeapObject*)this; + return QObject::qt_cast( clname ); +} + +bool KviCryptEngine::qt_invoke( int _id, QUObject* _o ) +{ + return QObject::qt_invoke(_id,_o); +} + +bool KviCryptEngine::qt_emit( int _id, QUObject* _o ) +{ + return QObject::qt_emit(_id,_o); +} +#ifndef QT_NO_PROPERTIES + +bool KviCryptEngine::qt_property( int id, int f, QVariant* v) +{ + return QObject::qt_property( id, f, v); +} + +bool KviCryptEngine::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/ext/moc_kvi_garbage.cpp b/src/kvilib/ext/moc_kvi_garbage.cpp new file mode 100644 index 00000000..0c1a98ef --- /dev/null +++ b/src/kvilib/ext/moc_kvi_garbage.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** KviGarbageCollector meta object code from reading C++ file 'kvi_garbage.h' +** +** Created: Sun Mar 23 20:56:12 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_garbage.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviGarbageCollector::className() const +{ + return "KviGarbageCollector"; +} + +QMetaObject *KviGarbageCollector::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviGarbageCollector( "KviGarbageCollector", &KviGarbageCollector::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviGarbageCollector::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviGarbageCollector", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviGarbageCollector::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviGarbageCollector", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviGarbageCollector::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUMethod slot_0 = {"cleanup", 0, 0 }; + static const QUMethod slot_1 = {"garbageSuicide", 0, 0 }; + static const QMetaData slot_tbl[] = { + { "cleanup()", &slot_0, QMetaData::Protected }, + { "garbageSuicide()", &slot_1, QMetaData::Protected } + }; + metaObj = QMetaObject::new_metaobject( + "KviGarbageCollector", parentObject, + slot_tbl, 2, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviGarbageCollector.setMetaObject( metaObj ); + return metaObj; +} + +void* KviGarbageCollector::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviGarbageCollector" ) ) + return this; + return QObject::qt_cast( clname ); +} + +bool KviGarbageCollector::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: cleanup(); break; + case 1: garbageSuicide(); break; + default: + return QObject::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool KviGarbageCollector::qt_emit( int _id, QUObject* _o ) +{ + return QObject::qt_emit(_id,_o); +} +#ifndef QT_NO_PROPERTIES + +bool KviGarbageCollector::qt_property( int id, int f, QVariant* v) +{ + return QObject::qt_property( id, f, v); +} + +bool KviGarbageCollector::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/ext/moc_kvi_regusersdb.cpp b/src/kvilib/ext/moc_kvi_regusersdb.cpp new file mode 100644 index 00000000..092add9f --- /dev/null +++ b/src/kvilib/ext/moc_kvi_regusersdb.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** KviRegisteredUserDataBase meta object code from reading C++ file 'kvi_regusersdb.h' +** +** Created: Sun Mar 23 20:56:14 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_regusersdb.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviRegisteredUserDataBase::className() const +{ + return "KviRegisteredUserDataBase"; +} + +QMetaObject *KviRegisteredUserDataBase::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviRegisteredUserDataBase( "KviRegisteredUserDataBase", &KviRegisteredUserDataBase::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviRegisteredUserDataBase::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviRegisteredUserDataBase", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviRegisteredUserDataBase::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviRegisteredUserDataBase", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviRegisteredUserDataBase::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUParameter param_signal_0[] = { + { 0, &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod signal_0 = {"userRemoved", 1, param_signal_0 }; + static const QUParameter param_signal_1[] = { + { 0, &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod signal_1 = {"userChanged", 1, param_signal_1 }; + static const QUParameter param_signal_2[] = { + { 0, &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod signal_2 = {"userAdded", 1, param_signal_2 }; + static const QUMethod signal_3 = {"databaseCleared", 0, 0 }; + static const QMetaData signal_tbl[] = { + { "userRemoved(const QString&)", &signal_0, QMetaData::Public }, + { "userChanged(const QString&)", &signal_1, QMetaData::Public }, + { "userAdded(const QString&)", &signal_2, QMetaData::Public }, + { "databaseCleared()", &signal_3, QMetaData::Public } + }; + metaObj = QMetaObject::new_metaobject( + "KviRegisteredUserDataBase", parentObject, + 0, 0, + signal_tbl, 4, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviRegisteredUserDataBase.setMetaObject( metaObj ); + return metaObj; +} + +void* KviRegisteredUserDataBase::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviRegisteredUserDataBase" ) ) + return this; + return QObject::qt_cast( clname ); +} + +// SIGNAL userRemoved +void KviRegisteredUserDataBase::userRemoved( const QString& t0 ) +{ + activate_signal( staticMetaObject()->signalOffset() + 0, t0 ); +} + +// SIGNAL userChanged +void KviRegisteredUserDataBase::userChanged( const QString& t0 ) +{ + activate_signal( staticMetaObject()->signalOffset() + 1, t0 ); +} + +// SIGNAL userAdded +void KviRegisteredUserDataBase::userAdded( const QString& t0 ) +{ + activate_signal( staticMetaObject()->signalOffset() + 2, t0 ); +} + +// SIGNAL databaseCleared +void KviRegisteredUserDataBase::databaseCleared() +{ + activate_signal( staticMetaObject()->signalOffset() + 3 ); +} + +bool KviRegisteredUserDataBase::qt_invoke( int _id, QUObject* _o ) +{ + return QObject::qt_invoke(_id,_o); +} + +bool KviRegisteredUserDataBase::qt_emit( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->signalOffset() ) { + case 0: userRemoved((const QString&)static_QUType_QString.get(_o+1)); break; + case 1: userChanged((const QString&)static_QUType_QString.get(_o+1)); break; + case 2: userAdded((const QString&)static_QUType_QString.get(_o+1)); break; + case 3: databaseCleared(); break; + default: + return QObject::qt_emit(_id,_o); + } + return TRUE; +} +#ifndef QT_NO_PROPERTIES + +bool KviRegisteredUserDataBase::qt_property( int id, int f, QVariant* v) +{ + return QObject::qt_property( id, f, v); +} + +bool KviRegisteredUserDataBase::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/ext/moc_kvi_sharedfiles.cpp b/src/kvilib/ext/moc_kvi_sharedfiles.cpp new file mode 100644 index 00000000..83ea82a4 --- /dev/null +++ b/src/kvilib/ext/moc_kvi_sharedfiles.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** KviSharedFilesManager meta object code from reading C++ file 'kvi_sharedfiles.h' +** +** Created: Sun Mar 23 20:56:15 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_sharedfiles.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviSharedFilesManager::className() const +{ + return "KviSharedFilesManager"; +} + +QMetaObject *KviSharedFilesManager::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviSharedFilesManager( "KviSharedFilesManager", &KviSharedFilesManager::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviSharedFilesManager::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviSharedFilesManager", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviSharedFilesManager::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviSharedFilesManager", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviSharedFilesManager::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUMethod slot_0 = {"cleanup", 0, 0 }; + static const QMetaData slot_tbl[] = { + { "cleanup()", &slot_0, QMetaData::Private } + }; + static const QUMethod signal_0 = {"sharedFilesChanged", 0, 0 }; + static const QUParameter param_signal_1[] = { + { "f", &static_QUType_ptr, "KviSharedFile", QUParameter::In } + }; + static const QUMethod signal_1 = {"sharedFileAdded", 1, param_signal_1 }; + static const QUParameter param_signal_2[] = { + { "f", &static_QUType_ptr, "KviSharedFile", QUParameter::In } + }; + static const QUMethod signal_2 = {"sharedFileRemoved", 1, param_signal_2 }; + static const QMetaData signal_tbl[] = { + { "sharedFilesChanged()", &signal_0, QMetaData::Private }, + { "sharedFileAdded(KviSharedFile*)", &signal_1, QMetaData::Private }, + { "sharedFileRemoved(KviSharedFile*)", &signal_2, QMetaData::Private } + }; + metaObj = QMetaObject::new_metaobject( + "KviSharedFilesManager", parentObject, + slot_tbl, 1, + signal_tbl, 3, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviSharedFilesManager.setMetaObject( metaObj ); + return metaObj; +} + +void* KviSharedFilesManager::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviSharedFilesManager" ) ) + return this; + return QObject::qt_cast( clname ); +} + +// SIGNAL sharedFilesChanged +void KviSharedFilesManager::sharedFilesChanged() +{ + activate_signal( staticMetaObject()->signalOffset() + 0 ); +} + +#include <qobjectdefs.h> +#include <qsignalslotimp.h> + +// SIGNAL sharedFileAdded +void KviSharedFilesManager::sharedFileAdded( KviSharedFile* t0 ) +{ + if ( signalsBlocked() ) + return; + QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 1 ); + if ( !clist ) + return; + QUObject o[2]; + static_QUType_ptr.set(o+1,t0); + activate_signal( clist, o ); +} + +// SIGNAL sharedFileRemoved +void KviSharedFilesManager::sharedFileRemoved( KviSharedFile* t0 ) +{ + if ( signalsBlocked() ) + return; + QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 2 ); + if ( !clist ) + return; + QUObject o[2]; + static_QUType_ptr.set(o+1,t0); + activate_signal( clist, o ); +} + +bool KviSharedFilesManager::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: cleanup(); break; + default: + return QObject::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool KviSharedFilesManager::qt_emit( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->signalOffset() ) { + case 0: sharedFilesChanged(); break; + case 1: sharedFileAdded((KviSharedFile*)static_QUType_ptr.get(_o+1)); break; + case 2: sharedFileRemoved((KviSharedFile*)static_QUType_ptr.get(_o+1)); break; + default: + return QObject::qt_emit(_id,_o); + } + return TRUE; +} +#ifndef QT_NO_PROPERTIES + +bool KviSharedFilesManager::qt_property( int id, int f, QVariant* v) +{ + return QObject::qt_property( id, f, v); +} + +bool KviSharedFilesManager::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/file/Makefile.am b/src/kvilib/file/Makefile.am new file mode 100644 index 00000000..c84487eb --- /dev/null +++ b/src/kvilib/file/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.cpp *.h diff --git a/src/kvilib/file/kvi_file.cpp b/src/kvilib/file/kvi_file.cpp new file mode 100644 index 00000000..8ab1e739 --- /dev/null +++ b/src/kvilib/file/kvi_file.cpp @@ -0,0 +1,256 @@ +//============================================================================= +// +// File : kvi_file.cpp +// Creation date : Mon Dec 17 2001 00:04:12 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_file.h" +#include "kvi_byteorder.h" + + +KviFile::KviFile() +: QFile() +{ +} + +KviFile::KviFile(const QString &name) +: QFile(name) +{ +} + +KviFile::~KviFile() +{ +} + +bool KviFile::openForReading() +{ +#ifdef COMPILE_USE_QT4 + return open(QFile::ReadOnly); +#else + return open(IO_ReadOnly); +#endif +} + +bool KviFile::openForWriting(bool bAppend) +{ +#ifdef COMPILE_USE_QT4 + return open(QFile::WriteOnly | (bAppend ? QFile::Append : QFile::Truncate)); +#else + return open(IO_WriteOnly | (bAppend ? IO_Append : IO_Truncate)); +#endif +} + + +bool KviFile::save(const QByteArray &bData) +{ + if(!save((kvi_u32_t)(bData.size())))return false; + return (writeBlock(bData.data(),bData.size()) == ((int)(bData.size()))); +} + +bool KviFile::load(QByteArray &bData) +{ + kvi_u32_t iLen; + if(!load(iLen))return false; + bData.resize(iLen); // it is automatically null terminated in Qt 4.x... BLEAH :D + if(readBlock((char *)(bData.data()),iLen) != iLen)return false; + return true; +} + +#ifndef COMPILE_USE_QT4 + +bool KviFile::save(const KviQCString &szData) +{ + if(!save((kvi_u32_t)(szData.length())))return false; + return (writeBlock(szData.data(),szData.length()) == ((int)(szData.length()))); +} + +bool KviFile::load(KviQCString &szData) +{ + kvi_u32_t iLen; + if(!load(iLen))return false; + szData.resize(iLen + 1); // this would allocate one extra byte with Qt 4.x... + if(readBlock((char *)(szData.data()),iLen) != iLen)return false; + *(szData.data() + iLen) = 0; + return true; +} + +#endif + + +bool KviFile::save(const QString &szData) +{ + KviQCString c = KviQString::toUtf8(szData); + if(!save((kvi_u32_t)(c.length())))return false; + return (writeBlock(c.data(),c.length()) == ((int)(c.length()))); +} + +bool KviFile::load(QString &szData) +{ + kvi_u32_t iLen; + if(!load(iLen))return false; + KviQCString tmp; + tmp.resize(iLen + 1); + if(readBlock((char *)(tmp.data()),iLen) != iLen)return false; + *(tmp.data() + iLen) = 0; + szData = QString::fromUtf8(tmp.data()); + return true; +} + +bool KviFile::save(const KviStr &szData) +{ + if(!save((kvi_u32_t)(szData.len())))return false; + return (writeBlock(szData.ptr(),szData.len()) == (int) szData.len()); +} + +bool KviFile::load(KviStr &szData) +{ + kvi_u32_t iLen; + if(!load(iLen))return false; + szData.setLength(iLen); + return (readBlock((char *)(szData.ptr()),iLen) == iLen); +} + +bool KviFile::save(kvi_u32_t t) +{ +#ifndef LOCAL_CPU_LITTLE_ENDIAN + t = kvi_localCpuToLittleEndian32(t); +#endif + return (writeBlock((const char *)(&t),sizeof(kvi_u32_t)) == sizeof(kvi_u32_t)); +} + +bool KviFile::load(kvi_u32_t &t) +{ + if(!(readBlock((char *)(&t),sizeof(kvi_u32_t)) == sizeof(kvi_u32_t)))return false; +#ifndef LOCAL_CPU_LITTLE_ENDIAN + t = kvi_littleEndianToLocalCpu32(t); +#endif + return true; +} + +bool KviFile::save(kvi_u64_t t) +{ +#ifndef LOCAL_CPU_LITTLE_ENDIAN + t = kvi_localCpuToLittleEndian64(t); +#endif + return (writeBlock((const char *)(&t),sizeof(kvi_u64_t)) == sizeof(kvi_u64_t)); +} + +bool KviFile::load(kvi_u64_t &t) +{ + if(!(readBlock((char *)(&t),sizeof(kvi_u32_t)) == sizeof(kvi_u32_t)))return false; +#ifndef LOCAL_CPU_LITTLE_ENDIAN + t = kvi_littleEndianToLocalCpu32(t); +#endif + return true; +} + + +bool KviFile::save(kvi_u16_t t) +{ +#ifndef LOCAL_CPU_LITTLE_ENDIAN + t = kvi_localCpuToLittleEndian16(t); +#endif + return (writeBlock((const char *)(&t),sizeof(kvi_u16_t)) == sizeof(kvi_u16_t)); +} + +bool KviFile::load(kvi_u16_t &t) +{ + if(!(readBlock((char *)(&t),sizeof(kvi_u16_t)) == sizeof(kvi_u16_t)))return false; +#ifndef LOCAL_CPU_LITTLE_ENDIAN + t = kvi_littleEndianToLocalCpu16(t); +#endif + return true; +} + +bool KviFile::save(kvi_u8_t t) +{ + return (writeBlock((const char *)(&t),sizeof(kvi_u8_t)) == sizeof(kvi_u8_t)); +} + +bool KviFile::load(kvi_u8_t &t) +{ + return (readBlock((char *)(&t),sizeof(kvi_u8_t)) == sizeof(kvi_u8_t)); +} + + +bool KviFile::save(KviPointerList<KviStr> * pData) +{ + if(!save((int)(pData->count())))return false; + for(KviStr * s = pData->first();s;s = pData->next()) + { + if(!save(*s))return false; + } + return true; +} + +bool KviFile::load(KviPointerList<KviStr> * pData) +{ + pData->clear(); + int iCount; + if(!load(iCount))return false; + for(int i=0;i<iCount;i++) + { + KviStr * s = new KviStr(); + if(!load(*s)) + { + delete s; + s = 0; + return false; + } + pData->append(s); + } + return true; +} + +bool KviFile::skipFirst(char t,unsigned int maxdist) +{ + while(maxdist > 0) + { + char c; + if(!getChar(&c))return false; + if(((char)c) == t)return true; + maxdist--; + } + return false; +} + +bool KviFile::skipFirst(const KviStr &t,unsigned int maxdist) +{ + char * ptr = t.ptr(); + while(maxdist > 0) + { + char c; + if(!getChar(&c))return false; + if(c == *ptr) + { + ptr++; + if(!*ptr)return true; + } else { + ptr = t.ptr(); + } + maxdist--; + } + return false; +} + diff --git a/src/kvilib/file/kvi_file.h b/src/kvilib/file/kvi_file.h new file mode 100644 index 00000000..188a9dad --- /dev/null +++ b/src/kvilib/file/kvi_file.h @@ -0,0 +1,120 @@ +#ifndef _KVI_FILE_H_ +#define _KVI_FILE_H_ + +//============================================================================= +// +// File : kvi_file.h +// Creation date : Mon Dec 17 2001 00:05:04 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_qstring.h" +#include "kvi_string.h" +#include "kvi_pointerlist.h" +#include "kvi_inttypes.h" +#include "kvi_qcstring.h" + +#include <qfile.h> +#include <time.h> + +#ifdef COMPILE_USE_QT4 + #define kvi_file_offset_t qlonglong +#else + #define kvi_file_offset_t QFile::Offset +#endif + + +class KVILIB_API KviFile : public QFile, public KviHeapObject +{ +public: + KviFile(); + KviFile(const QString &name); + ~KviFile(); +public: + // Wrappers portable across Qt 3.x and Qt 4.x + bool openForReading(); + bool openForWriting(bool bAppend = false); + +#ifndef COMPILE_USE_QT4 + // Functions present in Qt 4.x but not Qt 3.x + bool putChar(char c){ return putch(c) != -1; }; + bool ungetChar(char c){ return ungetch(c) != -1; }; + bool getChar(char * c){ *c = getch(); return *c != -1; }; + bool seek(kvi_file_offset_t o){ return at(o); }; + kvi_file_offset_t pos(){ return at(); }; +#endif + +#ifdef COMPILE_USE_QT4 + // Missing functions in Qt 4.x + quint64 writeBlock(const char * data,quint64 uLen){ return write(data,uLen); }; + quint64 readBlock(char * data,quint64 uLen){ return read(data,uLen); }; +#endif + + // This stuff loads and saves LITTLE ENDIAN DATA! + bool save(kvi_u64_t t); + bool load(kvi_u64_t &t); + + bool save(kvi_i64_t t){ return save((kvi_u64_t)t); }; + bool load(kvi_i64_t &t){ return load((kvi_u64_t &)t); }; + + bool save(kvi_u32_t t); + bool load(kvi_u32_t &t); + + bool save(kvi_i32_t t){ return save((kvi_u32_t)t); }; + bool load(kvi_i32_t &t){ return load((kvi_u32_t &)t); }; + + bool save(kvi_u16_t t); + bool load(kvi_u16_t &t); + + bool save(kvi_i16_t t){ return save((kvi_u16_t)t); }; + bool load(kvi_i16_t &t){ return load((kvi_u16_t &)t); }; + + bool save(kvi_u8_t t); + bool load(kvi_u8_t &t); + + bool save(kvi_i8_t t){ return save((kvi_u8_t)t); }; + bool load(kvi_i8_t &t){ return load((kvi_u8_t &)t); };; + + bool save(const KviStr &szData); + bool load(KviStr &szData); + +#ifndef COMPILE_USE_QT4 + // Under Qt 4.x these collide with QByteArray + bool save(const KviQCString &szData); + bool load(KviQCString &szData); +#endif + + bool save(const QByteArray &bData); + bool load(QByteArray &bData); + + bool save(const QString &szData); + bool load(QString &szData); + + bool skipFirst(char t,unsigned int maxdist = 0xffffffff); + bool skipFirst(const KviStr &t,unsigned int maxdist = 0xffffffff); + + bool save(KviPointerList<KviStr> * pData); + bool load(KviPointerList<KviStr> * pData); +}; + + +#endif //_KVI_FILE_H_ diff --git a/src/kvilib/file/kvi_fileutils.cpp b/src/kvilib/file/kvi_fileutils.cpp new file mode 100644 index 00000000..648d9125 --- /dev/null +++ b/src/kvilib/file/kvi_fileutils.cpp @@ -0,0 +1,505 @@ +//============================================================================= +// +// File : kvi_fileutils.cpp +// Creation date : Fri Dec 25 1998 18:26:48 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1998-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#define _KVI_FILEUTLIS_CPP_ +#include "kvi_fileutils.h" +#include "kvi_qstring.h" +#include "kvi_file.h" +#include "kvi_malloc.h" + +#include <qdir.h> +#include <qfileinfo.h> +#include <qglobal.h> +#include <qtextcodec.h> +#include <qtextstream.h> + + +namespace KviFileUtils +{ + /* + WORKING CODE BUT UNUSED FOR NOW + bool readLine(QFile * f,QString &szBuffer,bool bClearBuffer) + { + // FIXME: Should this assume UTF8 encoding ? + char tmp_buf[256]; + int cur_len = 0; + //char *cur_ptr = tmp_buf; + if(bClearBuffer)szBuffer = ""; + int ch = f->getch(); + + while((ch != -1)&&(ch != '\n')&&(ch != 0)) + { + tmp_buf[cur_len] = ch; + cur_len++; + if(cur_len > 255) + { + if(tmp_buf[255] == '\r')cur_len--; //Ignore CR... + int lastlen = szBuffer.length(); + szBuffer.setLength(lastlen + cur_len); + QChar *p1 = szBuffer.unicode() + lastlen; + char * p2 = tmp_buf; + for(int i=0;i<cur_len;i++)*p1++ = *p2++; + cur_len = 0; + } + ch = f->getch(); + } + if(ch == 0) + { + debug("Warning : %s is not an ascii file",f->name().latin1()); + } + if(cur_len > 0) + { + if(tmp_buf[cur_len - 1] == '\r')cur_len--; //Ignore CR... + int lastlen = szBuffer.length(); + szBuffer.setLength(lastlen + cur_len); + QChar *p1 = szBuffer.unicode() + lastlen; + char * p2 = tmp_buf; + for(int i=0;i<cur_len;i++)*p1++ = *p2++; + } + return (ch == '\n'); //more data to read else a broken file or EOF + } + + bool loadFileStripCR(const QString &szPath,QString &szBuffer) + { + QFile f(szPath); + if(!f.open(IO_ReadOnly))return false; + szBuffer = ""; + while(readLine(&f,szBuffer,false)) + { + szBuffer.append('\n'); // readLine returned true...last char was a newline + } + // readLine returned false , no ending newline encountered + return true; + } + */ + + bool makeDir(const QString &szPath) + { + QDir d; + QString dir = KviQString::trimmed(szPath); + adjustFilePath(dir); + QString createdDir; + +#ifdef COMPILE_ON_WINDOWS +#ifdef COMPILE_USE_QT4 + int idx = dir.indexOf(':'); +#else + int idx = dir.find(':'); +#endif + if(idx == 1) + { + createdDir = dir.left(2); + dir.remove(0,2); + } +#endif + + KviQString::stripLeft(dir,KVI_PATH_SEPARATOR_CHAR); + while(!dir.isEmpty()) + { + createdDir += KVI_PATH_SEPARATOR; + createdDir += KviQString::getToken(dir,KVI_PATH_SEPARATOR_CHAR); + if(!directoryExists(createdDir)) + { + if(!d.mkdir(createdDir)) + { + debug("Can't create directory %s",KviQString::toUtf8(createdDir).data()); + return false; + } + } + KviQString::stripLeft(dir,KVI_PATH_SEPARATOR_CHAR); + } + return true; + } + + bool makeDir(const char* path) + { + QString szPath=QString::fromUtf8(path); + return makeDir(szPath); + } + + bool renameFile(const QString &szSrc,const QString &szDst) + { + QDir d; + return d.rename(szSrc,szDst); + } + + bool renameFile(const char* path,const char* path2) + { + QString szPath=QString::fromUtf8(path); + QString szPath2=QString::fromUtf8(path2); + return renameFile(szPath,szPath2); + } + + bool copyFile(const QString &szSrc,const QString &szDst) + { + KviFile f1(szSrc); + if(!f1.openForReading())return false; + KviFile f2(szDst); + if(!f2.openForWriting()) + { + f1.close(); + return false; + } + char buffer[1024]; + while(!f1.atEnd()) + { + int len = f1.readBlock(buffer,1024); + if(len <= 0) + { + f1.close(); + f2.close(); + return false; //"serious error" + } + f2.writeBlock(buffer,len); + } + f1.close(); + f2.close(); + return true; + } + + bool copyFile(const char* path,const char* path2) + { + QString szPath=QString::fromUtf8(path); + QString szPath2=QString::fromUtf8(path2); + return copyFile(szPath,szPath2); + } + + bool loadFile(const QString &szPath,QString &szBuffer,bool bUtf8) + { + KviFile f(szPath); + if(!f.openForReading())return false; + if(bUtf8) + { + QByteArray ba = f.readAll(); + szBuffer = QString::fromUtf8(ba.data(),ba.size()); + //debug("BUFFERLEN: %d",szBuffer.length()); + } else { + szBuffer = QString(f.readAll()); + } + return true; + } + + bool loadFile(const char* path,QString &szBuffer,bool bUtf8) + { + QString szPath=QString::fromUtf8(path); + return loadFile(szPath,szBuffer,bUtf8); + } + + void adjustFilePath(QString &szPath) + { +#ifdef COMPILE_ON_WINDOWS + szPath.replace('/',"\\"); +#ifdef COMPILE_USE_QT4 + szPath.replace("\\\\","\\"); +#else + while(szPath.find("\\\\") != -1)szPath.replace("\\\\","\\"); +#endif + // FIXME: Use the default drive here ? + if(szPath.startsWith("\\"))szPath.prepend("C:"); +#else + szPath.replace('\\',"/"); +#ifdef COMPILE_USE_QT4 + szPath.replace("//","/"); +#else + while(KviQString::find(szPath,"//") != -1)szPath.replace("//","/"); +#endif + // deal with windows paths + if((szPath.length() > 2) && (szPath.at(0) != QChar('/'))) + { + if((szPath.at(1) == QChar(':')) && (szPath.at(2) == QChar('/'))) + { + szPath.remove(0,2); + } + } +#ifdef COMPILE_USE_QT4 + szPath=QDir::cleanPath(szPath); +#else + szPath=QDir::cleanDirPath(szPath); +#endif +#endif + + } + + bool directoryExists(const QString &szPath) + { + QFileInfo f(szPath); + return (f.exists() && f.isDir()); + } + + bool directoryExists(const char* path) + { + QString szPath=QString::fromUtf8(path); + QFileInfo f(szPath); + return (f.exists() && f.isDir()); + } + + bool fileExists(const QString &szPath) + { + QFileInfo f(szPath); + return (f.exists() && f.isFile()); + } + + bool fileExists(const char* path) + { + QString szPath=QString::fromUtf8(path); + return fileExists(szPath); + } + + bool removeFile(const QString &szPath) + { + QDir d; + return d.remove(szPath); + } + + bool removeFile(const char* path) + { + QString szPath=QString::fromUtf8(path); + return removeFile(szPath); + } + + bool removeDir(const QString &szPath) + { + QDir d; + return d.rmdir(szPath); + } + + bool removeDir(const char* path) + { + QString szPath=QString::fromUtf8(path); + return removeDir(szPath); + } + + bool deleteDir(const QString &szPath) + { + QDir d(szPath); + QStringList sl = d.entryList(QDir::Dirs); + QStringList::Iterator it; + for(it=sl.begin();it != sl.end();it++) + { + QString szSubdir = *it; + if(!(KviQString::equalCS(szSubdir,"..") || KviQString::equalCS(szSubdir,"."))) + { + QString szSubPath = szPath; + KviQString::ensureLastCharIs(szSubPath,QChar(KVI_PATH_SEPARATOR_CHAR)); + szSubPath += szSubdir; + if(!KviFileUtils::deleteDir(szSubPath)) + return false; + } + } + + sl = d.entryList(QDir::Files); + for(it=sl.begin();it != sl.end();it++) + { + QString szFilePath = szPath; + KviQString::ensureLastCharIs(szFilePath,QChar(KVI_PATH_SEPARATOR_CHAR)); + szFilePath += *it; + if(!KviFileUtils::removeFile(szFilePath)) + return false; + } + + return KviFileUtils::removeDir(szPath); + } + + bool writeFile(const QString &szPath,const QString &szData,bool bAppend) + { + KviFile f(szPath); + if(!f.openForWriting(bAppend))return false; + KviQCString szTmp = KviQString::toUtf8(szData); + if(!szTmp.data())return true; + if(f.writeBlock(szTmp.data(),szTmp.length()) != ((int)(szTmp.length())))return false; + return true; + } + + bool writeFile(const char* path,const QString &szData,bool bAppend) + { + QString szPath=QString::fromUtf8(path); + return writeFile(szPath,szData,bAppend); + } + + bool writeFileLocal8Bit(const QString &szPath,const QString &szData,bool bAppend) + { + KviFile f(szPath); + if(!f.openForWriting(bAppend))return false; + KviQCString szTmp = QTextCodec::codecForLocale()->fromUnicode(szData); + if(!szTmp.data())return true; + if(f.writeBlock(szTmp.data(),szTmp.length()) != ((int)(szTmp.length())))return false; + return true; + } + + bool writeFileLocal8Bit(const char* path,const QString &szData,bool bAppend) + { + QString szPath=QString::fromUtf8(path); + return writeFileLocal8Bit(szPath,szData,bAppend); + } + + bool readFile(const QString &szPath,QString &szBuffer,unsigned int uMaxSize) + { + KviFile f(szPath); + if(!f.openForReading())return false; + if(f.size() < 1) + { + szBuffer = ""; + f.close(); + return true; + } + if(f.size() > uMaxSize)return false; + char * buf = new char[f.size() + 1]; + if(f.readBlock(buf,f.size()) != ((long int)f.size())) + { + delete buf; + buf = 0; + return false; + } + buf[f.size()] = '\0'; + szBuffer = QString::fromUtf8(buf); + delete[] buf; + return true; + } + + bool readFile(const char* path,QString &szBuffer,unsigned int uMaxSize) + { + QString szPath=QString::fromUtf8(path); + return readFile(szPath,szBuffer,uMaxSize); + } + + + QString extractFileName(const QString &szFileNameWithPath) + { + return QFileInfo(szFileNameWithPath).fileName(); + } + + QString extractFilePath(const QString &szFileNameWithPath) + { + return QFileInfo(szFileNameWithPath).dirPath(true); + } + + bool readLine(QFile * f,QString &szBuffer,bool bUtf8) + { + QTextStream stream(f); + stream.setEncoding(bUtf8 ? QTextStream::UnicodeUTF8 : QTextStream::Locale); + szBuffer=stream.readLine(); + return !szBuffer.isNull(); + } + + bool readLines(QFile * f,QStringList &buffer,int iStartLine, int iCount, bool bUtf8) + { + QTextStream stream( f ); + stream.setEncoding(bUtf8 ? QTextStream::UnicodeUTF8 : QTextStream::Locale); + for(int i=0;i<iStartLine;i++) + stream.readLine(); + + if(iCount>0) + { + for(; (iCount>0 && !stream.atEnd()) ; iCount-- ) + buffer.append(stream.readLine()); + } else { + while(!stream.atEnd()) { + buffer.append(stream.readLine()); + } + } + return buffer.count()!= 0; + } + + bool isReadable(const QString &szFname) + { + QFileInfo f(szFname); + return (f.exists() && f.isFile() && f.isReadable()); + } + + bool isReadable(const char* path) + { + QString szPath=QString::fromUtf8(path); + return isReadable(szPath); + } + + bool isAbsolutePath(const QString &szPath) + { + QFileInfo f(szPath); + return !f.isRelative(); + } +}; + +static char hexchars[16] = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' }; + + +void kvi_encodeFileName(KviStr & path) +{ + QString szPath(path.ptr()); + kvi_encodeFileName(szPath); + path=szPath; +} + +void kvi_encodeFileName(QString & path) +{ + QString src(path); + path=""; + for(int i=0;i<src.length();i++) + { + QChar cur=src[i]; + if( ! (cur.isLetter() || cur.isDigit() || cur==' ' || cur=='_' || cur=='.' || cur=='#' || cur=='%') ) + { + if(cur.row()!=0) + { + path+='%'; + path+=hexchars[cur.row() >> 4]; + path+=hexchars[cur.row() & 15]; + } + path+='%'; + path+=hexchars[cur.cell() >> 4]; + path+=hexchars[cur.cell() & 15]; + } else if (cur=='%') + { + path+="%%"; + } else { + path+=cur; + } + } +} + +//================ kvi_isAbsolutePath ===============// + +bool kvi_isAbsolutePath(const char *path) +{ + if(*path == '/')return true; + if(isalpha(*path)) + { + if((*(path + 1)) == ':')return true; + } + return false; +} + +//=================== kvi_readLine =====================// + +bool kvi_readLine(QFile *f,KviStr &str) +{ + QTextStream stream(f); + QString szBuff=stream.readLine(); + str=szBuff; + return szBuff.isNull() ? 1 : 0; +} + + diff --git a/src/kvilib/file/kvi_fileutils.h b/src/kvilib/file/kvi_fileutils.h new file mode 100644 index 00000000..dcead8ae --- /dev/null +++ b/src/kvilib/file/kvi_fileutils.h @@ -0,0 +1,112 @@ +#ifndef _KVI_FILEUTILS_H_ +#define _KVI_FILEUTILS_H_ + +// +// File : kvi_fileutils.h +// Creation date : Fri Dec 25 1998 18:27:04 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_string.h" + +#include <qfile.h> +#include <qstringlist.h> + +#include <time.h> + + +#ifdef COMPILE_ON_WINDOWS + #define KVI_PATH_SEPARATOR "\\" + #define KVI_PATH_SEPARATOR_CHAR '\\' +#else + #define KVI_PATH_SEPARATOR "/" + #define KVI_PATH_SEPARATOR_CHAR '/' +#endif + +// #warning "Add kvi_trashFile(const char * path) ? - is it needed in the whole app" +// #warning "or should it be availible only for dirbrowser module ?" +namespace KviFileUtils +{ + //extern KVILIB_API bool readLine(QFile * f,QString &szBuffer,bool bClearBuffer = true); + //extern KVILIB_API bool loadFileStripCR(const QString &szPath,QString &szBuffer); + + // loads the file at szPath to szBuffer eventually converting from utf8 + extern KVILIB_API bool loadFile(const QString &szPath,QString &szBuffer,bool bUtf8 = true); + extern KVILIB_API bool loadFile(const char* szPath,QString &szBuffer,bool bUtf8 = true); + // adjusts the file path to the current platform + extern KVILIB_API void adjustFilePath(QString &szPath); + // returns true if szPath points to an existing directory + extern KVILIB_API bool directoryExists(const QString &szPath); + extern KVILIB_API bool directoryExists(const char* path); + // returns true if szPath points to an existing file + extern KVILIB_API bool fileExists(const QString &szPath); + extern KVILIB_API bool fileExists(const char* szPath); + // removes a file + extern KVILIB_API bool removeFile(const QString &szPath); + extern KVILIB_API bool removeFile(const char* path); + // removes a dir (must be empty) + extern KVILIB_API bool removeDir(const QString &szPath); + extern KVILIB_API bool removeDir(const char* path); + // removes a dir recursively + extern KVILIB_API bool deleteDir(const QString &szPath); + // writes a complete file (utf8 version) + extern KVILIB_API bool writeFile(const QString &szPath,const QString &szData,bool bAppend = false); + extern KVILIB_API bool writeFile(const char* path,const QString &szData,bool bAppend = false); + // writes a complete file (local 8 bit version) + extern KVILIB_API bool writeFileLocal8Bit(const QString &szPath,const QString &szData,bool bAppend = false); + extern KVILIB_API bool writeFileLocal8Bit(const char* path,const QString &szData,bool bAppend = false); + // reads a complete file and puts it in the string szBuffer, if the file is smaller than uMaxSize bytes + extern KVILIB_API bool readFile(const QString &szPath,QString &szBuffer,unsigned int uMaxSize = 65535); + extern KVILIB_API bool readFile(const char* path,QString &szBuffer,unsigned int uMaxSize = 65535); + // extracts the filename from a complete path (strips leading path) + extern KVILIB_API QString extractFileName(const QString &szFileNameWithPath); + + extern KVILIB_API QString extractFilePath(const QString &szFileNameWithPath); + // cp -f + extern KVILIB_API bool copyFile(const QString &szSrc,const QString &szDst); + extern KVILIB_API bool copyFile(const char* src,const char* dst); + // mv + extern KVILIB_API bool renameFile(const QString &szSrc,const QString &szDst); + extern KVILIB_API bool renameFile(const char* src,const char* dst); + // mkdir + extern KVILIB_API bool makeDir(const QString &szPath); + extern KVILIB_API bool makeDir(const char* path); + // reads a text line, returns false if EOF is reached + extern KVILIB_API bool readLine(QFile * f,QString &szBuffer,bool bUtf8 = true); + extern KVILIB_API bool readLines(QFile * f,QStringList &buffer,int iStartLine = 0, int iCount = -1, bool bUtf8 = true); + extern KVILIB_API bool isReadable(const QString &szFname); + extern KVILIB_API bool isAbsolutePath(const QString &szPath); +}; + +// ALL THIS STUFF BELOW SHOULD DIE: IF YOU SEE IT, REPLACE WITH THE FUNCTIONS IN THE NAMESPACE ABOVE + +// Returns true if the path begins with '/' +KVILIB_API extern bool kvi_isAbsolutePath(const char *path); +// Translates ANY string into a valid filename (with no path!) +// There is NO way to come back to the original string +// the algo is one-way only +KVILIB_API extern void kvi_encodeFileName(KviStr & path); +KVILIB_API extern void kvi_encodeFileName(QString & path); + +// Reads a single line from the file and returns false if EOF was encountered. +KVILIB_API extern bool kvi_readLine(QFile *f,KviStr &str); +// Removes a file + +#endif //_KVI_FILEUTILS_H_INCLUDED_ diff --git a/src/kvilib/file/kvi_packagefile.cpp b/src/kvilib/file/kvi_packagefile.cpp new file mode 100644 index 00000000..3e7bcc17 --- /dev/null +++ b/src/kvilib/file/kvi_packagefile.cpp @@ -0,0 +1,1028 @@ +//============================================================================= +// +// File : kvi_packagefile.cpp +// Created on Tue 26 Dec 2006 05:33:33 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_packagefile.h" + +#include "kvi_file.h" +#include "kvi_fileutils.h" +#include "kvi_locale.h" +#include "kvi_inttypes.h" + +#include <qprogressdialog.h> +#include <qlabel.h> + +#include <qdir.h> + +#ifdef COMPILE_ZLIB_SUPPORT + #include <zlib.h> +#endif + +// +// A KVIrc Package File is basically a simple zip file with some additional meta-data. +// The package file has the following format +// + +// Field Type Bytes Description +//------------------------------------------------------------------------------- +// Package: +// PackageHeader +// PackageInfo +// PackageData + +// PackageHeader: +// Magic Bytes 4 'KVPF': Signature for the Kvirc Package File +// Version uint32 4 0x00000001: Version of this package file +// Flags uint32 4 0x00000000: Flags, in version 1 is reserved and must be zero +// + +// PackageInfo: +// InfoFieldCount uint32 4 Number of package info fields +// InfoField InfoField Variable A list of informational name-value pairs +// InfoField InfoField Variable A list of informational name-value pairs +// InfoField InfoField Variable A list of informational name-value pairs +// .... .... .... + +// PackageData: +// DataField DataField Variable A list of data fields with format defined below +// DataField DataField Variable A list of data fields with format defined below +// DataField DataField Variable A list of data fields with format defined below +// .... .... .... + +// InfoField: +// Name UniString Variable The "name" element of the info field +// ValueType uint32 4 The type of the following ValueData field +// ValueData ValueData Variable + +// ValueData for ValueType 1 (string field) +// Value UniString Variable The value element of type string of the the info field + +// ValueData for ValueType 2 (binary buffer field) +// BufferLen uint32 4 The length of the binary buffer +// BufferData Bytes Variable The data for the binary buffer + + +// UniString: +// StringLen uint32 4 The length of the string data in BYTES (null terminator NOT included) +// StringData Bytes StringLen An utf8 encoded string (do NOT write the NULL terminator) + +// Bytes: +// Byte uint8 1 A byte +// Byte uint8 1 A byte +// .... .... .... + +// DataField: +// FieldType uint32 4 The type of the field, see below for defined values +// FieldLen uint32 4 FieldData length in bytes (useful for skipping a field if unsupported) +// FieldData Variable FieldLen The data of the field, see below for defined values + +// FieldData for FieldType 1 (file field) +// Flags uint32 4 Bitmask. Bits: 1=FileIsDeflated +// Path UniString Variable A relative path expressed as utf8 string. \ AND / are considered to be separators +// Size uint32 4 Size of the following file data +// FilePayload Bytes Variable + +// Everything is stored in LITTLE ENDIAN byte order. + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Da Base Engine + +KviPackageIOEngine::KviPackageIOEngine() +{ + m_pProgressDialog = 0; + m_pStringInfoFields = new KviPointerHashTable<QString,QString>(); + m_pStringInfoFields->setAutoDelete(true); + m_pBinaryInfoFields = new KviPointerHashTable<QString,QByteArray>(); + m_pBinaryInfoFields->setAutoDelete(true); +} + +KviPackageIOEngine::~KviPackageIOEngine() +{ + if(m_pProgressDialog)delete m_pProgressDialog; + delete m_pStringInfoFields; + delete m_pBinaryInfoFields; +} + + +bool KviPackageIOEngine::updateProgress(int iProgress,const QString &szLabel) +{ + if(!m_pProgressDialog)return true; +#ifdef COMPILE_USE_QT4 + m_pProgressDialog->setValue(iProgress); +#else + m_pProgressDialog->setProgress(iProgress); +#endif + m_pProgressDialogLabel->setText(szLabel); + qApp->processEvents(); + if(m_pProgressDialog->wasCanceled()) + { + setLastError(__tr2qs("Operation cancelled")); + return false; + } + return true; +} + +void KviPackageIOEngine::showProgressDialog(const QString &szCaption,int iTotalSteps) +{ +#ifdef COMPILE_USE_QT4 + m_pProgressDialog = new QProgressDialog(QString(""),__tr2qs("Cancel"),0,iTotalSteps,0); + m_pProgressDialog->setModal(true); + m_pProgressDialog->setWindowTitle(szCaption); +#else + m_pProgressDialog = new QProgressDialog(QString(""),__tr2qs("Cancel"),iTotalSteps,0,"",true); + m_pProgressDialog->setCaption(szCaption); +#endif + m_pProgressDialogLabel = new QLabel(m_pProgressDialog); + m_pProgressDialogLabel->setMaximumSize(500,300); + m_pProgressDialog->setLabel(m_pProgressDialogLabel); +} + +void KviPackageIOEngine::hideProgressDialog() +{ + if(!m_pProgressDialog)return; + delete m_pProgressDialog; + m_pProgressDialog = 0; +} + +bool KviPackageIOEngine::writeError() +{ + setLastError(__tr2qs("File write error")); + return false; +} + +bool KviPackageIOEngine::readError() +{ + setLastError(__tr2qs("File read error")); + return false; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Da Writer + + +KviPackageWriter::KviPackageWriter() +: KviPackageIOEngine() +{ + m_pDataFields = new KviPointerList<DataField>(); + m_pDataFields->setAutoDelete(true); +} + +KviPackageWriter::~KviPackageWriter() +{ + delete m_pDataFields; +} + +void KviPackageWriter::addInfoField(const QString &szName,const QString &szValue) +{ + m_pStringInfoFields->replace(szName,new QString(szValue)); +} + +void KviPackageWriter::addInfoField(const QString &szName,QByteArray * pValue) +{ + m_pBinaryInfoFields->replace(szName,pValue); +} + +bool KviPackageWriter::addFile(const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags) +{ + QFileInfo fi(szLocalFileName); + return addFileInternal(&fi,szLocalFileName,szTargetFileName,uAddFileFlags); +} + +bool KviPackageWriter::addFileInternal(const QFileInfo * fi,const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags) +{ + if(!(fi->isFile() && fi->isReadable())) + return false; + + if(!(uAddFileFlags & FollowSymLinks)) + { + if(fi->isSymLink()) + return true; // do NOT add a symlink + } + + DataField * f = new DataField(); + f->m_uType = KVI_PACKAGE_DATAFIELD_TYPE_FILE; + f->m_bFileAllowCompression = !(uAddFileFlags & NoCompression); + f->m_szFileLocalName = szLocalFileName; + f->m_szFileTargetName = szTargetFileName; + m_pDataFields->append(f); + + return true; +} + +bool KviPackageWriter::addDirectory(const QString &szLocalDirectoryName,const QString &szTargetDirectoryPrefix,kvi_u32_t uAddFileFlags) +{ + QDir d(szLocalDirectoryName); +#ifdef COMPILE_USE_QT4 + QDir::Filters iFlags; +#else + int iFlags; +#endif + iFlags = QDir::Files | QDir::Readable; + if(!(uAddFileFlags & FollowSymLinks)) + iFlags |= QDir::NoSymLinks; + + // QT4SUX: Because the QDir::entryInfoList() breaks really a lot of code by returning an object that behaves in a _totally_ different way.. it's also much slower + +#ifdef COMPILE_USE_QT4 + int j; + QFileInfoList sl = d.entryInfoList(iFlags); + for(j=0;j<sl.size();j++) + { +#else + const QFileInfoList * sl = d.entryInfoList(iFlags); + if(!sl)return false; + QFileInfoListIterator it(*sl); + while(QFileInfo * fi = it.current()) + { +#endif + QString szSFileName = szLocalDirectoryName; + KviQString::ensureLastCharIs(szSFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); +#ifdef COMPILE_USE_QT4 + QFileInfo slowCopy = sl.at(j); + szSFileName += slowCopy.fileName(); +#else + szSFileName += fi->fileName(); +#endif + QString szDFileName = szTargetDirectoryPrefix; + KviQString::ensureLastCharIs(szDFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); +#ifdef COMPILE_USE_QT4 + szDFileName += slowCopy.fileName(); + if(!addFileInternal(&slowCopy,szSFileName,szDFileName,uAddFileFlags)) + return false; +#else + szDFileName += fi->fileName(); + if(!addFileInternal(fi,szSFileName,szDFileName,uAddFileFlags)) + return false; +#endif +#ifndef COMPILE_USE_QT4 + ++it; +#endif + } + iFlags = QDir::Dirs | QDir::Readable; + if(!(uAddFileFlags & FollowSymLinks)) + iFlags |= QDir::NoSymLinks; + sl = d.entryInfoList(iFlags); +#ifdef COMPILE_USE_QT4 + for(j=0;j<sl.size();j++) + { + QString szDir = sl.at(j).fileName(); +#else + if(!sl)return false; + QFileInfoListIterator it2(*sl); + while(QFileInfo * fi2 = it2.current()) + { + QString szDir = fi2->fileName(); +#endif + if(!KviQString::equalCS(szDir,"..") && !KviQString::equalCS(szDir,".")) + { + QString szSDirName = szLocalDirectoryName; + KviQString::ensureLastCharIs(szSDirName,QChar(KVI_PATH_SEPARATOR_CHAR)); + szSDirName += szDir; + QString szDDirName = szTargetDirectoryPrefix; + KviQString::ensureLastCharIs(szDDirName,QChar(KVI_PATH_SEPARATOR_CHAR)); + szDDirName += szDir; + if(!addDirectory(szSDirName,szDDirName,uAddFileFlags)) + return false; + } +#ifndef COMPILE_USE_QT4 + ++it2; +#endif + } + + return true; +} + + + +#define BUFFER_SIZE 32768 + +bool KviPackageWriter::packFile(KviFile * pFile,DataField * pDataField) +{ + QString szProgressText; + KviQString::sprintf(szProgressText,__tr2qs("Packaging file %Q"),&(pDataField->m_szFileLocalName)); + if(!updateProgress(m_iCurrentProgress,szProgressText)) + return false; // aborted + + + KviFile source(pDataField->m_szFileLocalName); + if(!source.openForReading()) + { + setLastError(__tr2qs("Failed to open a source file for reading")); + return false; + } + + kvi_u32_t uSize = source.size(); + + // Flags +#ifdef COMPILE_ZLIB_SUPPORT + kvi_u32_t uFlags = pDataField->m_bFileAllowCompression ? + (uSize > 64 ? KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE : 0) + : 0; +#else + kvi_u32_t uFlags = 0; +#endif + + if(!pFile->save(uFlags))return writeError(); + + KviQCString szTargetFileName = KviQString::toUtf8(pDataField->m_szFileTargetName); + + // Path + if(!pFile->save(szTargetFileName))return writeError(); + + kvi_file_offset_t savedSizeOffset = pFile->pos(); + + // Size : will update it if compression is requested + if(!pFile->save(uSize))return writeError(); + + pDataField->m_uWrittenFieldLength = 4 + 4 + 4 + szTargetFileName.length(); // sizeof(flags + uncompressed size + path len + path) + + // FilePayload +#ifdef COMPILE_ZLIB_SUPPORT + if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE) + { + unsigned char ibuffer[BUFFER_SIZE]; + unsigned char obuffer[BUFFER_SIZE]; + + kvi_i32_t iReaded = source.readBlock((char *)ibuffer,BUFFER_SIZE); + if(iReaded < 0) + return readError(); + + z_stream zstr; + zstr.zalloc = Z_NULL; + zstr.zfree = Z_NULL; + zstr.opaque = Z_NULL; + zstr.next_in = ibuffer; + zstr.avail_in = iReaded; + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + + if(deflateInit(&zstr,9) != Z_OK) + { + setLastError(__tr2qs("Compression library initialization error")); + return false; + } + + while(iReaded > 0) + { + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + + if(deflate(&zstr,Z_NO_FLUSH) != Z_OK) + { + setLastError(__tr2qs("Compression library error")); + return false; + } + + if(zstr.avail_out < BUFFER_SIZE) + { + int iCompressed = zstr.next_out - obuffer; + pDataField->m_uWrittenFieldLength += iCompressed; + if(pFile->writeBlock((char *)obuffer,iCompressed) != iCompressed) + { + deflateEnd(&zstr); + return writeError(); + } + } + + if(zstr.avail_in < BUFFER_SIZE) + { + int iDataToRead = BUFFER_SIZE - zstr.avail_in; + if(iDataToRead < BUFFER_SIZE) + { + if(ibuffer != zstr.next_in) + { + // hum, there is still some data in the buffer to be readed + // and it is not at the beginning...move it to the beginning of ibuffer + memmove(ibuffer,zstr.next_in,zstr.avail_in); + } + } + iReaded = source.readBlock((char *)(ibuffer + zstr.avail_in),iDataToRead); + if(iReaded < 0) + { + deflateEnd(&zstr); + return readError(); + } + zstr.avail_in += iReaded; + zstr.next_in = ibuffer; + + if((zstr.total_in % 2000000) == 0) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),zstr.total_in,uSize); + QString szPrg = szProgressText + szTmp; + if(!updateProgress(m_iCurrentProgress,szPrg)) + return false; // aborted + } + + + } + } + + // flush pending output + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + + int ret; + do + { + ret = deflate(&zstr,Z_FINISH); + + if((ret == Z_OK) || (ret == Z_STREAM_END)) + { + if(zstr.avail_out < BUFFER_SIZE) + { + int iCompressed = zstr.next_out - obuffer; + pDataField->m_uWrittenFieldLength += iCompressed; + if(pFile->writeBlock((char *)obuffer,iCompressed) != iCompressed) + { + deflateEnd(&zstr); + return writeError(); + } + } else { + deflateEnd(&zstr); + setLastError(__tr2qs("Compression library internal error")); + return false; + } + + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + } + + } while(ret == Z_OK); + + // store the compressed data size + kvi_file_offset_t here = pFile->pos(); + pFile->seek(savedSizeOffset); + uSize = zstr.total_out; + + deflateEnd(&zstr); + if(!pFile->save(uSize))return writeError(); + + if(ret != Z_STREAM_END) + { + setLastError(__tr2qs("Error while compressing a file stream")); + return false; + } + + pFile->seek(here); + } else { +#endif + unsigned char buffer[BUFFER_SIZE]; + int iTotalFileSize = 0; + kvi_i32_t iReaded = source.readBlock((char *)buffer,BUFFER_SIZE); + if(iReaded < 0) + return readError(); + while(iReaded > 0) + { + iTotalFileSize += iReaded; + if((iTotalFileSize % 1000000) == 0) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),iTotalFileSize,uSize); + QString szPrg = szProgressText + szTmp; + if(!updateProgress(m_iCurrentProgress,szPrg)) + return false; // aborted + } + pDataField->m_uWrittenFieldLength += iReaded; + if(pFile->writeBlock((char *)buffer,iReaded) != iReaded) + return writeError(); + iReaded = source.readBlock((char *)buffer,BUFFER_SIZE); + } +#ifdef COMPILE_ZLIB_SUPPORT + } +#endif + source.close(); + + return true; +} + +bool KviPackageWriter::pack(const QString &szFileName,kvi_u32_t uPackFlags) +{ + m_iCurrentProgress = 0; + if(!(uPackFlags & NoProgressDialog)) + { + showProgressDialog(__tr2qs("Creating package..."),100); + updateProgress(m_iCurrentProgress,__tr2qs("Writing package header")); + } + + bool bRet = packInternal(szFileName,uPackFlags); + + hideProgressDialog(); + return bRet; +} + +bool KviPackageWriter::packInternal(const QString &szFileName,kvi_u32_t uPackFlags) +{ + + KviFile f(szFileName); + if(!f.openForWriting()) + { + setLastError(__tr2qs("Can't open file for writing")); + return false; + } + + // write the PackageHeader + + // Magic + char magic[4]; + magic[0] = 'K'; + magic[1] = 'V'; + magic[2] = 'P'; + magic[3] = 'F'; + if(f.writeBlock(magic,4) != 4)return writeError(); + + // Version + kvi_u32_t uVersion = 0x1; + if(!f.save(uVersion))return writeError(); + + // Flags + kvi_u32_t uFlags = 0x0; + if(!f.save(uFlags))return writeError(); + + // write PackageInfo + + // InfoFieldCount + kvi_u32_t uCount = m_pStringInfoFields->count() + m_pBinaryInfoFields->count(); + if(!f.save(uCount))return writeError(); + + m_iCurrentProgress = 5; + if(!updateProgress(m_iCurrentProgress,__tr2qs("Writing informational fields"))) + return false; // aborted + + // InfoFields (string) + KviPointerHashTableIterator<QString,QString> it(*m_pStringInfoFields); + while(QString * s = it.current()) + { + if(!f.save(it.currentKey()))return writeError(); + kvi_u32_t uType = KVI_PACKAGE_INFOFIELD_TYPE_STRING; + if(!f.save(uType))return writeError(); + if(!f.save(*s))return writeError(); + ++it; + } + + // InfoFields (binary) + KviPointerHashTableIterator<QString,QByteArray> it2(*m_pBinaryInfoFields); + while(QByteArray * b = it2.current()) + { + if(!f.save(it2.currentKey()))return writeError(); + kvi_u32_t uType = KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER; + if(!f.save(uType))return writeError(); + if(!f.save(*b))return writeError(); + ++it2; + } + + m_iCurrentProgress = 10; + if(!updateProgress(m_iCurrentProgress,__tr2qs("Writing package data"))) + return false; // aborted + + // write PackageData + int iIdx = 0; + for(DataField * pDataField = m_pDataFields->first();pDataField;pDataField = m_pDataFields->next()) + { + kvi_u32_t uDataFieldType = pDataField->m_uType; + if(!f.save(uDataFieldType))return writeError(); + + kvi_file_offset_t savedLenOffset = f.pos(); + // here we will store the length of the field once it's written + if(!f.save(uDataFieldType))return writeError(); + + m_iCurrentProgress = 10 + ((90 * iIdx) / m_pDataFields->count()); + + switch(pDataField->m_uType) + { + case KVI_PACKAGE_DATAFIELD_TYPE_FILE: + if(!packFile(&f,pDataField)) + return false; + break; + default: + setLastError(__tr2qs("Internal error")); + return false; + break; + } + + kvi_file_offset_t savedEndOffset = f.pos(); + f.seek(savedLenOffset); + if(!f.save(pDataField->m_uWrittenFieldLength)) + return writeError(); + + f.seek(savedEndOffset); + iIdx++; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Da Reader + +KviPackageReader::KviPackageReader() +: KviPackageIOEngine() +{ +} + +KviPackageReader::~KviPackageReader() +{ +} + +bool KviPackageReader::readHeaderInternal(KviFile * pFile,const QString &szLocalFileName) +{ + // read the PackageHeader + + // Magic + char magic[4]; + + if(pFile->readBlock(magic,4) != 4)return readError(); + if((magic[0] != 'K') || (magic[1] != 'V') || (magic[2] != 'P') || (magic[3] != 'F')) + { + setLastError(__tr2qs("The file specified is not a valid KVIrc package")); + return false; + } + + // Version + kvi_u32_t uVersion; + if(!pFile->load(uVersion))return readError(); + if(uVersion != 0x1) + { + setLastError(__tr2qs("The package has an invalid version number, it might have been created by a newer KVIrc")); + return false; + } + + // Flags + kvi_u32_t uFlags; + if(!pFile->load(uFlags))return readError(); + // we ignore them at the moment + + // read PackageInfo + + // InfoFieldCount + kvi_u32_t uCount; + if(!pFile->load(uCount))return writeError(); + + m_pStringInfoFields->clear(); + m_pBinaryInfoFields->clear(); + + kvi_u32_t uIdx = 0; + while(uIdx < uCount) + { + QString szKey; + if(!pFile->load(szKey))return readError(); + kvi_u32_t uFieldType; + if(!pFile->load(uFieldType))return readError(); + switch(uFieldType) + { + case KVI_PACKAGE_INFOFIELD_TYPE_STRING: + { + QString szValue; + if(!pFile->load(szValue))return readError(); + m_pStringInfoFields->replace(szKey,new QString(szValue)); + } + break; + case KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER: + { + QByteArray * pbValue = new QByteArray(); + if(!pFile->load(*pbValue)) + { + delete pbValue; + return readError(); + } + m_pBinaryInfoFields->replace(szKey,pbValue); + } + break; + default: + setLastError(__tr2qs("Invalid info field: the package is probably corrupt")); + break; + } + uIdx++; + } + + return true; +} + + +bool KviPackageReader::readHeader(const QString &szLocalFileName) +{ + KviFile f(szLocalFileName); + if(!f.openForReading()) + { + setLastError(__tr2qs("Can't open file for reading")); + return false; + } + + return readHeaderInternal(&f,szLocalFileName); +} + +bool KviPackageReader::unpackFile(KviFile * pFile,const QString &szUnpackPath) +{ + // Flags + kvi_u32_t uFlags; + if(!pFile->load(uFlags))return readError(); + +#ifndef COMPILE_ZLIB_SUPPORT + if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE) + { + setLastError(__tr2qs("The package contains compressed data but this executable does not support compression")); + return false; + } +#endif + + // Path + QString szPath; + if(!pFile->load(szPath))return readError(); + + QString szFileName = szUnpackPath; + KviQString::ensureLastCharIs(szFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); + + szFileName += szPath; + + // no attacks please :) + szFileName.replace(QString("..\\"),QString("")); + szFileName.replace(QString("..//"),QString("")); + + KviFileUtils::adjustFilePath(szFileName); + + int idx = KviQString::findRev(szFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); + if(idx != -1) + { + QString szPrefixPath = szFileName.left(idx); + if(!KviFileUtils::makeDir(szPrefixPath)) + { + setLastError(__tr2qs("Failed to create the target directory")); + return false; + } + } + + KviFile dest(szFileName); + if(!dest.openForWriting()) + { + setLastError(__tr2qs("Failed to open a source file for reading")); + return false; + } + + QString szProgressText; + KviQString::sprintf(szProgressText,__tr2qs("Unpacking file %Q"),&szFileName); + if(!updateProgress(pFile->pos(),szProgressText)) + return false; // aborted + + // Size + kvi_u32_t uSize; + if(!pFile->load(uSize))return readError(); + + + // FilePayload +#ifdef COMPILE_ZLIB_SUPPORT + if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE) + { + int iRemainingSize = uSize; + unsigned char ibuffer[BUFFER_SIZE]; + unsigned char obuffer[BUFFER_SIZE]; + + int iToRead = iRemainingSize; + if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE; + int iReaded = pFile->readBlock((char *)ibuffer,iToRead); + iRemainingSize -= iReaded; + + z_stream zstr; + zstr.zalloc = Z_NULL; + zstr.zfree = Z_NULL; + zstr.opaque = Z_NULL; + zstr.next_in = ibuffer; + zstr.avail_in = iReaded; + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + + if(inflateInit(&zstr) != Z_OK) + { + setLastError(__tr2qs("Compression library initialization error")); + return false; + } + + while((iReaded > 0) && (iRemainingSize > 0)) + { + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + + if(inflate(&zstr,Z_NO_FLUSH) != Z_OK) + { + setLastError(__tr2qs("Compression library error")); + return false; + } + + if(zstr.avail_out < BUFFER_SIZE) + { + int iDecompressed = zstr.next_out - obuffer; + if(dest.writeBlock((char *)obuffer,iDecompressed) != iDecompressed) + { + inflateEnd(&zstr); + return writeError(); + } + } + + if(zstr.avail_in < BUFFER_SIZE) + { + int iDataToRead = BUFFER_SIZE - zstr.avail_in; + if(iDataToRead < BUFFER_SIZE) + { + if(ibuffer != zstr.next_in) + { + // hum, there is still some data in the buffer to be readed + // and it is not at the beginning...move it to the beginning of ibuffer + memmove(ibuffer,zstr.next_in,zstr.avail_in); + } + } + + if(iDataToRead > iRemainingSize) + iDataToRead = iRemainingSize; + + iReaded = pFile->readBlock((char *)(ibuffer + zstr.avail_in),iDataToRead); + if(iReaded < 0) + { + inflateEnd(&zstr); + return readError(); + } + + iRemainingSize -= iReaded; + zstr.avail_in += iReaded; + zstr.next_in = ibuffer; + + if((zstr.total_in % 2000000) == 0) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),zstr.total_in,uSize); + QString szPrg = szProgressText + szTmp; + if(!updateProgress(pFile->pos(),szPrg)) + return false; // aborted + } + } + } + + // flush pending output + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + + int ret; + + do { + ret = inflate(&zstr,Z_FINISH); + + if((ret == Z_OK) || (ret == Z_STREAM_END) || (ret == Z_BUF_ERROR)) + { + if(zstr.avail_out < BUFFER_SIZE) + { + int iDecompressed = zstr.next_out - obuffer; + if(dest.writeBlock((char *)obuffer,iDecompressed) != iDecompressed) + { + inflateEnd(&zstr); + return writeError(); + } + } /* else { THIS HAPPENS FOR ZERO SIZE FILES + debug("hum.... internal, rEWq (ret = %d) (avail_out = %d)",ret,zstr.avail_out); + + inflateEnd(&zstr); + setLastError(__tr2qs("Compression library internal error")); + return false; + } */ + zstr.next_out = obuffer; + zstr.avail_out = BUFFER_SIZE; + } + + } while((ret == Z_OK) || (ret == Z_BUF_ERROR)); + + inflateEnd(&zstr); + + if(ret != Z_STREAM_END) + { + setLastError(__tr2qs("Error in compressed file stream")); + return false; + } + + } else { +#endif + unsigned char buffer[BUFFER_SIZE]; + int iTotalFileSize = 0; + int iRemainingData = uSize; + int iToRead = iRemainingData; + if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE; + int iReaded = 1; + + while((iReaded > 0) && (iToRead > 0)) + { + iReaded = pFile->readBlock((char *)buffer,iToRead); + if(iReaded > 0) + { + iTotalFileSize += iReaded; + iRemainingData -= iReaded; + + if((iTotalFileSize % 3000000) == 0) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),iTotalFileSize,uSize); + QString szPrg = szProgressText + szTmp; + if(!updateProgress(pFile->pos(),szPrg)) + return false; // aborted + } + + if(dest.writeBlock((char *)buffer,iReaded) != iReaded) + return writeError(); + } + + int iToRead = iRemainingData; + if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE; + } +#ifdef COMPILE_ZLIB_SUPPORT + } +#endif + dest.close(); + + return true; +} + +bool KviPackageReader::getStringInfoField(const QString &szName,QString &szBuffer) +{ + QString * pVal = m_pStringInfoFields->find(szName); + if(!pVal)return false; + szBuffer = *pVal; + return true; +} + +bool KviPackageReader::unpack(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags) +{ + bool bRet = unpackInternal(szLocalFileName,szUnpackPath,uUnpackFlags); + hideProgressDialog(); + return bRet; +} + +bool KviPackageReader::unpackInternal(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags) +{ + + KviFile f(szLocalFileName); + if(!f.openForReading()) + { + setLastError(__tr2qs("Can't open file for reading")); + return false; + } + + kvi_file_offset_t size = f.size(); + + if(!(uUnpackFlags & NoProgressDialog)) + { + showProgressDialog(__tr2qs("Reading package..."),size); + updateProgress(0,__tr2qs("Reading package header")); + } + + + if(!readHeaderInternal(&f,szLocalFileName)) + return false; + + if(!updateProgress(f.pos(),__tr2qs("Reading package data"))) + return false; // aborted + + while(!f.atEnd()) + { + // DataFieldType + kvi_u32_t uDataFieldType; + if(!f.load(uDataFieldType))return readError(); + // DataFieldLen + kvi_u32_t uDataFieldLen; + if(!f.load(uDataFieldLen))return readError(); + + switch(uDataFieldType) + { + case KVI_PACKAGE_DATAFIELD_TYPE_FILE: + if(!unpackFile(&f,szUnpackPath)) + return false; + break; + default: + setLastError(__tr2qs("Invalid data field: the package is probably corrupt")); + return false; + break; + } + + } + + return true; +} + + + diff --git a/src/kvilib/file/kvi_packagefile.h b/src/kvilib/file/kvi_packagefile.h new file mode 100644 index 00000000..3e330554 --- /dev/null +++ b/src/kvilib/file/kvi_packagefile.h @@ -0,0 +1,142 @@ +#ifndef _KVI_PACKAGEFILE_H_ +#define _KVI_PACKAGEFILE_H_ +//============================================================================= +// +// File : kvi_packagefile.h +// Created on Tue 26 Dec 2006 05:33:33 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" +#include "kvi_pointerhashtable.h" +#include "kvi_qcstring.h" // QByteArray anyway +#include <qobject.h> +#include "kvi_pointerlist.h" + +class KviFile; +class QProgressDialog; +class QLabel; +class QFileInfo; + +// +// This class is used for creating KVIrc package files. +// You simply instantiate it, add some info fields, add some files and then call pack(). +// + +class KVILIB_API KviPackageIOEngine +{ +public: + KviPackageIOEngine(); + virtual ~KviPackageIOEngine(); +protected: + QString m_szLastError; + KviPointerHashTable<QString,QString> * m_pStringInfoFields; + KviPointerHashTable<QString,QByteArray> * m_pBinaryInfoFields; + QProgressDialog * m_pProgressDialog; + QLabel * m_pProgressDialogLabel; +public: + const QString & lastError(){ return m_szLastError; }; + void setLastError(const QString &szLastError){ m_szLastError = szLastError; }; + KviPointerHashTable<QString,QString> * stringInfoFields(){ return m_pStringInfoFields; }; + KviPointerHashTable<QString,QByteArray> * binaryInfoFields(){ return m_pBinaryInfoFields; }; +protected: + void showProgressDialog(const QString &szCaption,int iTotalSteps); + void hideProgressDialog(); + bool updateProgress(int iProgress,const QString &szLabel); + bool writeError(); + bool readError(); +}; + +#define KVI_PACKAGE_INFOFIELD_TYPE_STRING 1 +#define KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER 2 + +#define KVI_PACKAGE_DATAFIELD_TYPE_FILE 1 + +#define KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE 1 + +class KVILIB_API KviPackageWriter : public KviPackageIOEngine +{ +public: + KviPackageWriter(); + virtual ~KviPackageWriter(); +protected: + + class DataField + { + public: + kvi_u32_t m_uType; + // output length of the field + kvi_u32_t m_uWrittenFieldLength; + // data fields for the File DataFieldType + bool m_bFileAllowCompression; + QString m_szFileLocalName; + QString m_szFileTargetName; + }; + + KviPointerList<DataField> * m_pDataFields; + int m_iCurrentProgress; +public: + // Adds a file to the package. The file must be specified as absolute local + // path and as target path relative to the KVIrc local directory. + // ... more ? + enum AddFileFlags { + NoCompression = 1, + FollowSymLinks = 2 + }; + bool addFile(const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags = 0); + bool addDirectory(const QString &szLocalDirectoryName,const QString &szTargetDirectoryPrefix,kvi_u32_t uAddFileFlags = 0); + // Adds an info field as a name=value pair + void addInfoField(const QString &szName,const QString &szValue); + void addInfoField(const QString &szName,QByteArray * pArray); + // Attempts to pack everything and store it as the specified file. + // There is no mandatory extension but you *should* use KVI_FILEEXTENSION_THEMEPACKAGE for themes + // and KVI_FILEEXTENSION_ADDONPACKAGE for addons. See kvi_fileextension.h + enum PackFlags { + NoProgressDialog = 1 + }; + bool pack(const QString &szFileName,kvi_u32_t uPackFlags = 0); +private: + bool packInternal(const QString &szFileName,kvi_u32_t uPackFlags = 0); + bool packFile(KviFile * pFile,DataField * pDataField); + bool addFileInternal(const QFileInfo * fi,const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags = 0); +}; + +class KVILIB_API KviPackageReader : public KviPackageIOEngine +{ +public: + KviPackageReader(); + virtual ~KviPackageReader(); +public: + bool readHeader(const QString &szLocalFileName); + enum UnpackFlags { + NoProgressDialog = 1 + }; + bool getStringInfoField(const QString &szName,QString &szBuffer); + bool unpack(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags = 0); +private: + bool unpackInternal(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags = 0); + bool unpackFile(KviFile * pFile,const QString &szUnpackPath); + bool readHeaderInternal(KviFile * pFile,const QString &szLocalFileName); +}; + + + +#endif //!_KVI_PACKAGEFILE_H_ diff --git a/src/kvilib/include/Makefile.am b/src/kvilib/include/Makefile.am new file mode 100644 index 00000000..60838ee7 --- /dev/null +++ b/src/kvilib/include/Makefile.am @@ -0,0 +1,4 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + diff --git a/src/kvilib/irc/Makefile.am b/src/kvilib/irc/Makefile.am new file mode 100644 index 00000000..c84487eb --- /dev/null +++ b/src/kvilib/irc/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.cpp *.h diff --git a/src/kvilib/irc/kvi_avatar.cpp b/src/kvilib/irc/kvi_avatar.cpp new file mode 100644 index 00000000..1642560a --- /dev/null +++ b/src/kvilib/irc/kvi_avatar.cpp @@ -0,0 +1,165 @@ +//============================================================================= +// +// File : kvi_avatar.cpp +// Creation date : Fri Dec 01 2000 13:58:12 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= +#define __KVILIB__ + + +#include "kvi_avatar.h" +#include "kvi_qstring.h" + +#include <qimage.h> + + +/* + @doc: ctcp_avatar + @title: + The AVATAR idea + @short: + Extending IRC fun: the AVATAR idea + @body: + [big]Introduction[/big] + Starting from version 3.0.0 KVIrc supports the AVATAR protocol. + The AVATAR term dictionary definitions include:[br] + - Hindu mythology incarnation of a God[br] + - Embodiment of a concept or philosophy[br] + - In [b]cyberspace communities[/b], the rappresentation of an + user in a shared virtual reality.[br] + The AVATAR protocol attempts to improve the IRC communication + by adding a method for associating a graphical rappresentation + to an IRC user.[br] + Since this may involve binary data transfers between users, + the protocol is intended to be client based. + [big]The terms[/big] + The user that wants to offer a digital rappresentation of himself + will be called "source user". The ones that will receive the notification + will be called "target users". + Every irc user can be either a source user or target user. + [big]The idea[/big] + Every irc user has a client-side property called AVATAR. Let's say that there + are two users: A and B.[br] + When user A wants to see the B's avatar he simply sends a CTCP AVATAR request + to B (the request is sent through a PRIVMSG irc command).[br] + User B replies with a CTCP AVATAR notification (sent through a NOTICE irc command) + with the name or url of his avatar.[br] + The actual syntax for the notification is:[br] + [b]AVATAR <avatar_file> [<filesize>][/b] + The <avatar_file> may be either the name of a B's local image file or an url + pointing to an image on some web server.[br] + The optional <filesize> parameter is sent only if <avatar_file> is + stored on the B's machine and there will be more info on that later.[br] + Anyway, after A has received the notification he tries to locate the avatar + file in its local cache (yes, <filesize> may help here and more on this later). + If the file can be found + and loaded then it is simply displayed in some way near the B's nickname + otherwise A must download the avatar from some place. + If the <avatar_file> contains a leading url prefix (http://) then + A fetches the image from the specified url and after that displays + it near the B's nickname. If the <avatar_file> does not contain the + leading url prefix then it is assumed that B offers this file for + downloading via DCC from his machine. In this case A may also avoid + requesting the file if the <filesize> is too large and the transfer + would occupy too much bandwidth (for example). + The DCC download is initiated by issuing a DCC GET <avatar_file> request to B. + B may then reply with a standard DCC SEND or a DCC RSEND (kvirc's extension).[br] + The implementation of the DCC GET protocol is defined by other documents here around :).[br] + [br] + The CTCP AVATAR messages can be sent to a single user , a set of users or a channel: + this depends only on the source user and how many clients he wants to reach. + [br] + There should be a convention on the image sizes: not a protocol limit. + For example, the convention could be that all the images should be smaller than + 129x129 pixels. The preferred image format is "png" (Portable Network Graphics) + since it allows good compression rates without compromising the image quality. + Other formats may be accepted as well (Theoretically this protocol could be + extended to allow movies or 3D images). + The "preferred" image size may grow with time, as the network transmission speed grows. +*/ + +KviAvatar::KviAvatar(const QString &szLocalPath,const QString &szName,QPixmap * pix) +{ + m_pPixmap = pix; + m_pScaledPixmap = 0; + if(m_pPixmap == 0)m_pPixmap = new QPixmap(32,32); // cool memory map :) + + m_bRemote = KviQString::equalCIN("http://",szName,7); + + m_szLocalPath = szLocalPath; + m_szName = szName; +} + +KviAvatar::~KviAvatar() +{ + delete m_pPixmap; + if(m_pScaledPixmap)delete m_pScaledPixmap; +} + +QPixmap * KviAvatar::scaledPixmap(unsigned int w,unsigned int h) +{ + if(((unsigned int)(m_pPixmap->width())) == w) + { + if(((unsigned int)(m_pPixmap->height())) == h) + return m_pPixmap; + } + + if(m_pScaledPixmap) + { + if((m_uLastScaleWidth == w) && (m_uLastScaleHeight == h))return m_pScaledPixmap; + delete m_pScaledPixmap; + m_pScaledPixmap = 0; + } + + int curW = m_pPixmap->width(); + int curH = m_pPixmap->height(); + + if(curW < 1)curW = 1; + if(curH < 1)curH = 1; + + m_uLastScaleWidth = w; + m_uLastScaleHeight = h; + + int scaleW = w; + int scaleH; + + /* We want to maintain the aspect of the image instead simply set + height and width. The first step is trying to adapt the image size + by "w" vaule */ + + scaleH = (curH * scaleW) / curW; + + /* Now check the resized image size. If it is too wide or too tall, + resize it again by "h" value */ + if(scaleH > h) { + scaleH = h; + scaleW = (scaleH * curW) / curH; + } + +#ifdef COMPILE_USE_QT4 + m_pScaledPixmap = new QPixmap(m_pPixmap->scaled(scaleW,scaleH)); +#else + QImage img = m_pPixmap->convertToImage(); + + m_pScaledPixmap = new QPixmap(); + m_pScaledPixmap->convertFromImage(img.smoothScale(scaleW,scaleH)); +#endif + return m_pScaledPixmap; +} diff --git a/src/kvilib/irc/kvi_avatar.h b/src/kvilib/irc/kvi_avatar.h new file mode 100644 index 00000000..ba8edbc5 --- /dev/null +++ b/src/kvilib/irc/kvi_avatar.h @@ -0,0 +1,83 @@ +#ifndef _KVI_AVATAR_H_ +#define _KVI_AVATAR_H_ + +//============================================================================= +// +// File : kvi_avatar.h +// Creation date : Fri Dec 01 2000 13:54:04 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_string.h" +#include "kvi_heapobject.h" +#include "kvi_settings.h" + +#include <qpixmap.h> + +class KVILIB_API KviAvatar : public KviHeapObject +{ +public: + KviAvatar(const QString &szLocalPath,const QString &szName,QPixmap * pix); + ~KviAvatar(); +private: + QString m_szLocalPath; + QString m_szName; + bool m_bRemote; + + QPixmap * m_pPixmap; + QPixmap * m_pScaledPixmap; + + unsigned int m_uLastScaleWidth; + unsigned int m_uLastScaleHeight; +public: + QPixmap * pixmap(){ return m_pPixmap; }; + QPixmap * scaledPixmap(unsigned int w,unsigned int h); + + bool isRemote(){ return m_bRemote; }; + + const QString &localPath(){ return m_szLocalPath; }; + const QString &name(){ return m_szName; }; + + // string that uniquely identifies this avatar + // for remote avatars that have name starting with http:// + // the name is used. + // for local avatars the localPath is used instead + const QString &identificationString(){ return m_bRemote ? m_szName : m_szLocalPath; }; + + + // if name is http://xxxx + // then identification is the name + // if name is xxx.png + // then identification is the local path + + + // name : visible name of the avatar : url or filename + // ex: http://www.kvirc.net/img/pragma.png + // ex: pragma.png + // local path : local path + // ex: /home/pragma/.kvirc/avatars/http.www.kvirc.net.img.pragma.png + // ex: /home/pragma/.kvirc/avatars/pragma.png + + // local path->name : strip leading path informations + // name->local path : replace : / and + +}; + +#endif //_KVI_AVATAR_H_ diff --git a/src/kvilib/irc/kvi_avatarcache.cpp b/src/kvilib/irc/kvi_avatarcache.cpp new file mode 100644 index 00000000..d24562ea --- /dev/null +++ b/src/kvilib/irc/kvi_avatarcache.cpp @@ -0,0 +1,250 @@ +//============================================================================= +// +// File : kvi_avatarcache.cpp +// Created on Sat 27 Dec 2003 21:19:47 by Szymon Stefanek +// +// This file is part of the KVIrc IRC client distribution +// Copyright (C) 2003 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= +#define __KVILIB__ + + +#include "kvi_avatarcache.h" +#include "kvi_pointerlist.h" +#include "kvi_config.h" + +// this level triggers a cleanup +#define MAX_AVATARS_IN_CACHE 100 +// this is the level that has be reached by a cleanup +#define CACHE_GUARD_LEVEL 85 +// dictionary size +#define CACHE_DICT_SIZE 101 +// keep the unaccessed avatars for 30 days +#define MAX_UNACCESSED_TIME (3600 * 24 * 30) + + +KviAvatarCache * KviAvatarCache::m_pAvatarCacheInstance = 0; + +void KviAvatarCache::init() +{ + if(m_pAvatarCacheInstance) + { + debug("WARNING: trying to initialize the avatar cache twice"); + return; + } + + m_pAvatarCacheInstance = new KviAvatarCache(); +} + +void KviAvatarCache::done() +{ + if(!m_pAvatarCacheInstance) + { + debug("WARNING: trying to destroy an uninitialized avatar cache"); + return; + } + + delete m_pAvatarCacheInstance; + m_pAvatarCacheInstance = 0; +} + + +KviAvatarCache::KviAvatarCache() +{ + m_pAvatarDict = new KviPointerHashTable<QString,KviAvatarCacheEntry>(CACHE_DICT_SIZE,false); + m_pAvatarDict->setAutoDelete(true); +} + +KviAvatarCache::~KviAvatarCache() +{ + delete m_pAvatarDict; +} + + +void KviAvatarCache::replace(const QString &szIdString,const KviIrcMask &mask,const QString &szNetwork) +{ + QString szKey; + + mask.mask(szKey,KviIrcMask::NickCleanUserSmartNet); + szKey.append(QChar('+')); + szKey.append(szNetwork); + + KviAvatarCacheEntry * e = new KviAvatarCacheEntry; + e->szIdString = szIdString; + e->tLastAccess = kvi_unixTime(); + + m_pAvatarDict->replace(szKey,e); + + if(m_pAvatarDict->count() > MAX_AVATARS_IN_CACHE) + { + cleanup(); + } +} + +void KviAvatarCache::remove(const KviIrcMask &mask,const QString &szNetwork) +{ + QString szKey; + + mask.mask(szKey,KviIrcMask::NickCleanUserSmartNet); + szKey.append(QChar('+')); + szKey.append(szNetwork); + + m_pAvatarDict->remove(szKey); +} + + + +const QString & KviAvatarCache::lookup(const KviIrcMask &mask,const QString &szNetwork) +{ + QString szKey; + + mask.mask(szKey,KviIrcMask::NickCleanUserSmartNet); + szKey.append(QChar('+')); + szKey.append(szNetwork); + + KviAvatarCacheEntry * e = m_pAvatarDict->find(szKey); + if(!e)return KviQString::empty; + e->tLastAccess = kvi_unixTime(); + return e->szIdString; +} + +void KviAvatarCache::load(const QString &szFileName) +{ + m_pAvatarDict->clear(); + + KviConfig cfg(szFileName,KviConfig::Read); + + kvi_time_t tNow = kvi_unixTime(); + + KviConfigIterator it(*(cfg.dict())); + + int cnt = 0; + + while(it.current()) + { + cfg.setGroup(it.currentKey()); + + kvi_time_t tLastAccess = cfg.readUIntEntry("LastAccess",0); + if((tNow - tLastAccess) < MAX_UNACCESSED_TIME) + { + QString szIdString = cfg.readQStringEntry("Avatar",""); + + if(!szIdString.isEmpty()) + { + KviAvatarCacheEntry * e = new KviAvatarCacheEntry; + e->tLastAccess = tLastAccess; + e->szIdString = szIdString; + m_pAvatarDict->replace(it.currentKey(),e); + cnt++; + if(cnt >= MAX_AVATARS_IN_CACHE)return; // done + } + } + ++it; + } +} + +void KviAvatarCache::save(const QString &szFileName) +{ + KviConfig cfg(szFileName,KviConfig::Write); +// cfg.clear(); // not needed with KviConfig::Write + + KviPointerHashTableIterator<QString,KviAvatarCacheEntry> it(*m_pAvatarDict); + + while(KviAvatarCacheEntry * e = it.current()) + { + if(e->tLastAccess) + { + cfg.setGroup(it.currentKey()); + cfg.writeEntry("Avatar",e->szIdString); + cfg.writeEntry("LastAccess",((unsigned int)(e->tLastAccess))); + } + ++it; + } +} + +void KviAvatarCache::cleanup() +{ + // first do a quick run deleting the avatars really too old + KviPointerHashTableIterator<QString,KviAvatarCacheEntry> it(*m_pAvatarDict); + + kvi_time_t tNow = kvi_unixTime(); + + KviPointerList<QString> l; + l.setAutoDelete(false); + + KviAvatarCacheEntry * e; + + while((e = it.current())) + { + if((tNow - e->tLastAccess) > MAX_UNACCESSED_TIME) + { + l.append(new QString(it.currentKey())); + } + ++it; + } + + for(QString *s = l.first();s;s = l.next())m_pAvatarDict->remove(*s); + + if(m_pAvatarDict->count() < CACHE_GUARD_LEVEL)return; + + // not done.. need to kill the last accessed :/ + + it.toFirst(); + + KviPointerList<KviAvatarCacheEntry> ll; + ll.setAutoDelete(true); + + // here we use the cache entries in another way + // szAvatar is the KEY instead of the avatar name + + while((e = it.current())) + { + KviAvatarCacheEntry * current = ll.first(); + unsigned int idx = 0; + while(current) + { + // if the current is newer than the inserted one + // then stop searching and insert it just before + if(current->tLastAccess > e->tLastAccess)break; + // otherwise the current is older and the inserted + // one goes after + current = ll.next(); + idx++; + } + + KviAvatarCacheEntry * xx = new KviAvatarCacheEntry; + xx->szIdString = it.currentKey(); + xx->tLastAccess = e->tLastAccess; + + if(current)ll.insert(idx,xx); + else ll.append(xx); + ++it; + } + + // the oldest keys are at the beginning + int uRemove = ll.count() - CACHE_GUARD_LEVEL; + if(uRemove < 1)return; // huh ? + + // remember that szAvatar contains the key! + for(e = ll.first();e && (uRemove > 0);e = ll.next()) + { + m_pAvatarDict->remove(e->szIdString); + uRemove--; + } + // now we should be ok +} diff --git a/src/kvilib/irc/kvi_avatarcache.h b/src/kvilib/irc/kvi_avatarcache.h new file mode 100644 index 00000000..7d715256 --- /dev/null +++ b/src/kvilib/irc/kvi_avatarcache.h @@ -0,0 +1,69 @@ +#ifndef _KVI_AVATARCACHE_H_ +#define _KVI_AVATARCACHE_H_ +//============================================================================= +// +// File : kvi_avatarcache.h +// Created on Sat 27 Dec 2003 21:19:47 by Szymon Stefanek +// +// This file is part of the KVIrc IRC client distribution +// Copyright (C) 2003 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" +#include "kvi_time.h" +#include "kvi_ircmask.h" + +#include "kvi_pointerhashtable.h" + + +typedef struct _KviAvatarCacheEntry +{ + QString szIdString; + kvi_time_t tLastAccess; +} KviAvatarCacheEntry; + + + +class KVILIB_API KviAvatarCache +{ +protected: + KviAvatarCache(); + ~KviAvatarCache(); +public: + KviPointerHashTable<QString,KviAvatarCacheEntry> * m_pAvatarDict; +protected: + static KviAvatarCache * m_pAvatarCacheInstance; +public: + static void init(); + static void done(); + + static KviAvatarCache * instance(){ return m_pAvatarCacheInstance; }; + + void replace(const QString &szIdString,const KviIrcMask &mask,const QString &szNetwork); + void remove(const KviIrcMask &mask,const QString &szNetwork); + const QString & lookup(const KviIrcMask &mask,const QString &szNetwork); + + void cleanup(); + + void load(const QString &szFileName); + void save(const QString &szFileName); +}; + + +#endif //!_KVI_AVATARCACHE_H_ diff --git a/src/kvilib/irc/kvi_ircmask.cpp b/src/kvilib/irc/kvi_ircmask.cpp new file mode 100644 index 00000000..dbdc1b6c --- /dev/null +++ b/src/kvilib/irc/kvi_ircmask.cpp @@ -0,0 +1,760 @@ +//============================================================================= +// +// File : kvi_ircuser.cpp +// Creation date : Fri Jan 8 1999 20:56:07 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_debug.h" +#include "kvi_ircmask.h" + +/* + @doc: irc_masks + @title: + Irc masks + @type: + generic + @short: + Decription of the standard IRC masks + @keyterms: + irc masks , nickname , username , hostname , wildcard + @body: + [big]Simple masks[/big][br] + An irc mask is a string in a special format that identifies an user on irc.[br] + The standard basic format is:[br] + [b]<nick>!<username>@<host>[/b][br] + The <nick> part contains the nickname with that the user is widely known across the network.[br] + The nickname format is generally restricted by the irc network rules: usually it has a maximum + length (9 on actual IrcNet servers for example), and can contain only a defined set of characters. + Just as example, the character '!' obviously can't be included in a nickname.[br] + The <username> part is the machine username of the remote user: this is usually + retrieved by the irc server at connect time by contacting the ident service on the user's machine. + Some IRC servers allow specifying this username inside the login messages and do not connect + to the ident service at all.[br] + The <username> often has a special prefix character added by the irc server:[br] + this is rather server specific protocol , but the prefixes are somewhat standardized and + the common meanings of them are:[br] + noprefix: I line with ident[br] + ^: I line with OTHER type ident[br] + ~: I line, no ident[br] + +: i line with ident[br] + =: i line with OTHER type ident[br] + -: i line, no ident[br] + So finally you can find <username> strings like "~pragma" or "^pragma", where "pragma" + is the system username of the irc-user and ~ and ^ are prefixes.[br] + The <host> part is the hostname of the remote user.[br] + In most cases it is the human-readable format of the host name, but sometimes + it happens to be an IP-address (when the host has no reverse dns entry).[br] + The IP address can be either in IPV4 format or in IPV6 format.[br] + Some (weird from my point of view) servers hide certain parts of the IP address to + prevent attacks to the user's machine.[br] + Here are some examples of full irc-masks:[br] + Pragma!^pragma@staff.kvirc.net[br] + [jazz]!~jazz@jazz.myhome.com[br] + luke!=skywalker@212.213.41.12[br] + HAN!^solo@ff0f:a0a0:1011::ea80:1[br] + Darth!vader@210.11.12.XXX[br] + The irc-masks are [b]case insensitive[/b].[br] + [br] + [big]Wildcard masks[/big][br] + In some contexts the irc-masks can contain '*' and '?' wildcards.[br] + The wild masks are used to "match" an user within a set of them.[br] + '*' matches any sequence (eventually empty) of characters and '?' matches a single character.[br] + Wildcards are allowed only in the <nick> , <user> and <host> part: so the + "wildest" mask possible is:[br] + [b]*!*@*[/b][br] + that designates "any nickname, any username on any host".[br] + Here are some examples of wild masks:[br] + Pragma!*pragma@212.101.102.*: matches any user with nickname "Pragma" , username that ends with "pragma" and + coming from any machine on the 212.101.102 network.[br] + *!solo@*.starwars.org: matches any nick with username solo (no prefix!) coming from any machine in + the starwars.org domain.[br] + Pragma!*@*: matches any user with nickname "Pragma".[br] +*/ + +/* +const char * KviIrcMask::setMask(const char *szMask,char c) +{ + __range_valid(szMask); + //nick!username@host.top + //0123456789 + register const char *p=szMask; + //Run over nick.... + while(*p && (*p != '!'))p++; + int len = p - szMask; + if(len > 0){ + m_nick_ptr = (char *)kvi_realloc(m_nick_ptr,len+1); + kvi_memmove((void *)m_nick_ptr,(void *)szMask,len); + } else { //Empty nick...set it to "*" + len = 1; + m_nick_ptr = (char *)kvi_realloc(m_nick_ptr,len+1); + kvi_memmove((void *)m_nick_ptr,(void *)"*",len); + } + *(m_nick_ptr+len) = '\0'; //With zero length nick it will be just an empty-string + if(!(*p)){ + setHost("*"); + setUsername("*"); + return p; + } + szMask = ++p; + //The username + while(*p && (*p != '@'))p++; + len = p - szMask; + if(len > 0){ + m_user_ptr = (char *)kvi_realloc(m_user_ptr,len+1); + kvi_memmove((void *)m_user_ptr,(void *)szMask,len); + } else { + len = 1; + m_user_ptr = (char *)kvi_realloc(m_user_ptr,len+1); + kvi_memmove((void *)m_user_ptr,(void *)"*",len); + } + *(m_user_ptr+len) = '\0'; + if(!(*p)){ + setHost("*"); + return p; + } + szMask = ++p; + //And finally the host + while(*p && (*p != c))p++; + len = p - szMask; + if(len > 0){ + m_host_ptr = (char *)kvi_realloc(m_host_ptr,len+1); + kvi_memmove((void *)m_host_ptr,(void *)szMask,len); + } else { + len = 1; + m_host_ptr = (char *)kvi_realloc(m_host_ptr,len+1); + kvi_memmove((void *)m_host_ptr,(void *)"*",len); + } + *(m_host_ptr+len) = '\0'; + return p; +} + +const char * KviIrcMask::setUserhostMask(const char *szMask) +{ + __range_valid(szMask); + //nick[*]=<+!->username@host.top + //0123456789 + register const char *p=szMask; + // Run over nick.... + while(*p && (*p != '*') && (*p != '=') && (!isspace(*p)))p++; + // extract it + int len = p - szMask; + if(len > 0){ + m_nick_ptr = (char *)kvi_realloc(m_nick_ptr,len+1); + kvi_memmove((void *)m_nick_ptr,(void *)szMask,len); + } else { //Empty nick...set it to "*" + len = 1; + m_nick_ptr = (char *)kvi_realloc(m_nick_ptr,len+1); + kvi_memmove((void *)m_nick_ptr,(void *)"*",len); + } + *(m_nick_ptr+len) = '\0'; //With zero length nick it will be just an empty-string + // now skip all the flags + while(*p && ((*p=='*')||(*p=='=')||(*p=='+')||(*p=='-')) && (!isspace(*p)))p++; + // check... + if((!(*p)) || isspace(*p)){ + // ooops , finished or isspace + setHost("*"); + setUsername("*"); + while(*p && isspace(*p))p++; + return p; + } + + szMask = p; + //The username + while(*p && (*p != '@') && (!isspace(*p)))p++; + len = p - szMask; + if(len > 0){ + m_user_ptr = (char *)kvi_realloc(m_user_ptr,len+1); + kvi_memmove((void *)m_user_ptr,(void *)szMask,len); + } else { + len = 1; + m_user_ptr = (char *)kvi_realloc(m_user_ptr,len+1); + kvi_memmove((void *)m_user_ptr,(void *)"*",len); + } + *(m_user_ptr+len) = '\0'; + + if((!(*p))||isspace(*p)){ + // oops finished or isspace + setHost("*"); + while(*p && isspace(*p))p++; + return p; + } + szMask = ++p; + //And finally the host + while(*p && (!isspace(*p)))p++; + len = p - szMask; + if(len > 0){ + m_host_ptr = (char *)kvi_realloc(m_host_ptr,len+1); + kvi_memmove((void *)m_host_ptr,(void *)szMask,len); + } else { + len = 1; + m_host_ptr = (char *)kvi_realloc(m_host_ptr,len+1); + kvi_memmove((void *)m_host_ptr,(void *)"*",len); + } + *(m_host_ptr+len) = '\0'; + while(*p && isspace(*p))p++; + return p; +} + +*/ + +KviIrcMask::KviIrcMask() +{ + m_szHost = m_szWild; + m_szUser = m_szWild; + m_szNick = m_szWild; +} + +KviIrcMask::KviIrcMask(const QString &szMask) +{ + static QString szWild("*"); + const QChar * b = KviQString::nullTerminatedArray(szMask); + if(b) + { + const QChar * p = b; + while(p->unicode() && (p->unicode() != '!'))p++; + if(p->unicode()) + { + if(p != b) + { + m_szNick.setUnicode(b,p-b); + } else { + m_szNick = szWild; // ??? + } + } else { + if(p != b)m_szNick.setUnicode(b,p-b); + else m_szNick = szWild; // ??? + m_szUser = szWild; + m_szHost = szWild; + return; + } + p++; + b = p; + while(p->unicode() && (p->unicode() != '@'))p++; + if(p->unicode()) + { + if(p != b) + { + m_szUser.setUnicode(b,p-b); + } else { + m_szUser = szWild; // ??? + } + } else { + if(p != b)m_szUser.setUnicode(b,p-b); + else m_szUser = szWild; // ??? + m_szHost = szWild; + return; + } + p++; + b=p; + while(p->unicode())p++; + if(p != b) + { + m_szHost.setUnicode(b,p-b); + } else { + m_szHost = szWild; // ??? + } + + } else { + m_szUser = szWild; + m_szHost = szWild; + m_szNick = szWild; + } +} + +QString KviIrcMask::m_szWild("*"); + +bool KviIrcMask::hasNumericHost() const +{ + const QChar * p = KviQString::nullTerminatedArray(m_szHost); + if(!p)return false; + int nPoints = 0; + int nDoublePoints = 0; + unsigned short uc; + while((uc = p->unicode())) + { + if(uc == '.')nPoints++; // ipv6 masks can contain dots too! + else { + if(uc == ':')nDoublePoints++; + else { + if((uc < '0') || (uc > '9')) + { +#ifdef COMPILE_USE_QT4 + uc = p->toUpper().unicode(); +#else + uc = p->upper().unicode(); +#endif + if((uc < 'A') || (uc > 'F'))return false; + } + } + } + p++; + } + return ((nPoints == 3) || (nDoublePoints > 1)); +} + + +/** +* Retuns in szMask the specified (if possible) mask of this user.<br> +* If the host or username are not known , the mask may contain less information +* than requested.<br> +* Mask types:<br> +* 0 : nick!user@machine.host.top (nick!user@XXX.XXX.XXX.XXX) (default)<br> +* 1 : nick!user@*.host.top (nick!user@XXX.XXX.XXX.*)<br> +* 2 : nick!user@*<br> +* 3 : nick!*@machine.host.top (nick!user@XXX.XXX.XXX.XXX)<br> +* 4 : nick!*@*.host.top (nick!user@XXX.XXX.XXX.*)<br> +* 5 : nick!*@*<br> +* 6 : *!user@machine.host.top (*!user@XXX.XXX.XXX.XX)<br> +* 7 : *!user@*.host.top (*!user@XXX.XXX.XXX.*)<br> +* 8 : *!user@*<br> +* 9 : *!*@machine.host.top (*!*@XXX.XXX.XXX.XXX)<br> +* 10: *!*@*.host.top (*!*@XXX.XXX.XXX.*)<br> +* 11: nick!*user@machine.host.top (nick!*user@machine.host.top)<br> +* 12: nick!*user@*.host.top (nick!*user@*.host.top)<br> +* 13: nick!*user@*<br> +* 14: *!*user@machine.host.top (*!*user@machine.host.top)<br> +* 15: *!*user@*.host.top (*!*user@*.host.top)<br> +* 16: *!*user@*<br> +* 17: nick!~user@*.host.top (nick!~user@XXX.XXX.*) +* 18: nick!*@*.host.top (nick!*@XXX.XXX.*) +* 19: *!~user@*.host.top (*!~user@XXX.XXX.*) +* 20: nick!*user@*.host.top (nick!*user@XXX.XXX.*) +* 21: *!*user@*.host.top (*!user@*XXX.XXX.*) +* smart versions of the masks 17-21 that try take care of masked ip addresses +* in the form xxx.xxx.INVALID-TOP-MASK +* 22: nick!~user@*.host.top (nick!~user@XXX.XXX.*) +* 23: nick!*@*.host.top (nick!*@XXX.XXX.*) +* 24: *!~user@*.host.top (*!~user@XXX.XXX.*) +* 25: nick!*user@*.host.top (nick!*user@XXX.XXX.*) +* 26: *!*user@*.host.top (*!user@*XXX.XXX.*) +* If some data is missing , these types may change:<br> +* For example , if hostname is missing , the mask type 3 or 4 may be reduced to type 5 +*/ + +/* +** ident is fun.. ahem +** prefixes used: +** none I line with ident +** ^ I line with OTHER type ident +** ~ I line, no ident +** + i line with ident +** = i line with OTHER type ident +** - i line, no ident +*/ + +static unsigned char maskTable[27][3] = { + { 0 , 0 , 0 }, //0 means normal block + { 0 , 0 , 2 }, //2 in the third field means type *.abc.host.top (or XXX.XXX.XXX.*) host mask + { 0 , 0 , 1 }, //2 in the second field means *user (strip prefixes) + { 0 , 1 , 0 }, //1 means * + { 0 , 1 , 2 }, //3 in the third field means type *.host.top (or XXX.XXX.*) host mask + { 0 , 1 , 1 }, //4 in the third field is like 3 but tries to detect masked ip addresses too + { 1 , 0 , 0 }, + { 1 , 0 , 2 }, + { 1 , 0 , 1 }, + { 1 , 1 , 0 }, + { 1 , 1 , 2 }, + { 0 , 2 , 0 }, + { 0 , 2 , 2 }, + { 0 , 2 , 1 }, + { 1 , 2 , 0 }, + { 1 , 2 , 2 }, + { 1 , 2 , 1 }, + { 0 , 0 , 3 }, + { 0 , 1 , 3 }, + { 1 , 0 , 3 }, + { 0 , 2 , 3 }, + { 1 , 2 , 3 }, + { 0 , 0 , 4 }, + { 0 , 1 , 4 }, + { 1 , 0 , 4 }, + { 0 , 2 , 4 }, + { 1 , 2 , 4 } +}; + +void KviIrcMask::mask(QString &szMask,MaskType eMaskType) const +{ + if((((int)eMaskType) > 26)||(((int)eMaskType) < 0))eMaskType = NickUserHost; + szMask = maskTable[((int)eMaskType)][0] ? m_szWild : m_szNick; + szMask.append("!"); + switch(maskTable[((int)eMaskType)][1]) + { + case 0: + szMask.append(m_szUser); + break; + case 1: + szMask.append(m_szWild); + break; + default: + if (m_szUser.length() > 0) { + if(m_szUser[0].unicode() != '*') + szMask.append(m_szWild); + if ((m_szUser[0].unicode() == '~') || + (m_szUser[0].unicode() == '^') || + (m_szUser[0].unicode() == '+') || + (m_szUser[0].unicode() == '-') || + (m_szUser[0].unicode() == '='))szMask.append(m_szUser.right(m_szUser.length() - 1)); + else + szMask.append(m_szUser); + } + break; + } + szMask.append('@'); + switch(maskTable[((int)eMaskType)][2]) + { + case 0: + szMask.append(m_szHost); + break; + case 1: + szMask.append(m_szWild); + break; + case 2: + if(m_szHost != m_szWild) + { + if(hasNumericHost()) + { + QString szHost(m_szHost.left(getIpDomainMaskLen())); + szMask.append(szHost); + szMask.append(m_szWild); + } else { + szMask.append(m_szWild); + szMask.append(getHostDomainMask()); + } + } else { + szMask.append(m_szWild); + } + break; + case 3: + if(m_szHost != m_szWild) + { + if(hasNumericHost()) + { + QString szHost(m_szHost.left(getLargeIpDomainMaskLen())); + szMask.append(szHost); + szMask.append(m_szWild); + } else { + szMask.append(m_szWild); + szMask.append(getLargeHostDomainMask()); + } + } else { + szMask.append(m_szWild); + } + break; + default: // case 4 and others + if(m_szHost != m_szWild) + { + if(hasNumericHost() || hasMaskedIp()) + { + QString szHost(m_szHost.left(getLargeIpDomainMaskLen())); + szMask.append(szHost); + szMask.append(m_szWild); + } else { + szMask.append(m_szWild); + szMask.append(getLargeHostDomainMask()); + } + } else { + szMask.append(m_szWild); + } + break; + } +} + + +/* +bool KviIrcMask::matches(const char *szMask) +{ + const char * ret1; + const char * ret2; + + if(kvi_matchWildExprWithTerminator(szMask,m_nick_ptr,'!',&ret1,&ret2)) + { + if(*ret1 == '!') + { + ret1++; + if(kvi_matchWildExprWithTerminator(ret1,m_user_ptr,'@',&ret1,&ret2)) + { + if(*ret1 == '@') + { + ret1++; + return kvi_matchWildExpr(ret1,m_host_ptr); + } + } + } + } + return false; +} +*/ + +/* +bool KviIrcMask::matchesFixed(const char *szMask) const +{ + const char * ret1; + const char * ret2; + + if(kvi_matchStringWithTerminator(m_nick_ptr,szMask,'!',&ret1,&ret2)) + { + if(*ret2 == '!') + { + ret2++; + if(kvi_matchStringWithTerminator(m_user_ptr,ret2,'@',&ret1,&ret2)) + { + if(*ret2 == '@') + { + ret2++; + return kvi_matchString(m_host_ptr,ret2); + } + } + } + } + return false; +} +*/ + +/* +bool KviIrcMask::matchedBy(const QString &szMask) const +{ + const char * ret1; + const char * ret2; + + if(kvi_matchStringWithTerminator(szMask,m_nick_ptr,'!',&ret1,&ret2)) + { + if(*ret1 == '!') + { + ret1++; + if(kvi_matchStringWithTerminator(ret1,m_user_ptr,'@',&ret1,&ret2)) + { + if(*ret1 == '@') + { + ret1++; + return kvi_matchString(ret1,m_host_ptr); + } + } + } + } + return false; +} +*/ + +bool KviIrcMask::matches(const KviIrcMask &mask) const +{ + if(KviQString::matchWildExpressionsCI(m_szNick,mask.m_szNick)) + { + if(KviQString::matchWildExpressionsCI(m_szUser,mask.m_szUser)) + { + if(KviQString::matchWildExpressionsCI(m_szHost,mask.m_szHost))return true; + } + } + return false; +} + +bool KviIrcMask::matchesFixed(const KviIrcMask &mask) const +{ + if(KviQString::matchStringCI(m_szNick,mask.m_szNick,0,1)) + { + if(KviQString::matchStringCI(m_szUser,mask.m_szUser,0,1)) + { + if(KviQString::matchStringCI(m_szHost,mask.m_szHost,0,1))return true; + } + } + return false; +} + +/* +bool KviIrcMask::matches(const char * nick,const char * user,const char * host) +{ + if(nick) + { + if(!kvi_matchWildExpr(m_nick_ptr,nick))return false; + } + + if(user) + { + if(!kvi_matchWildExpr(m_user_ptr,user))return false; + } + + if(host) + { + if(!kvi_matchWildExpr(m_host_ptr,host))return false; + } + return true; +} +*/ + +bool KviIrcMask::matchesFixed(const QString &nick,const QString &user,const QString &host) const +{ + if(!KviQString::matchStringCI(m_szNick,nick,0,1))return false; + if(!KviQString::matchStringCI(m_szUser,user,0,1))return false; + if(!KviQString::matchStringCI(m_szHost,host,0,1))return false; + return true; +} + +//Internals for mask() + +int KviIrcMask::getIpDomainMaskLen() const +{ + int len = m_szHost.length(); + const QChar *p = m_szHost.unicode(); + const QChar *b = p; + p += len; + if(b < p) + { + p--; + while((b < p) && (p->unicode() != '.') && (p->unicode() != ':'))p--; + } + // 000.000.000.000 + // p + // + return (p == b) ? 0 : ((p-b) + 1); +} + + +int KviIrcMask::getLargeIpDomainMaskLen() const +{ + int len = m_szHost.length(); + const QChar *p = m_szHost.unicode(); + const QChar *b = p; + p += len; + if(b < p) + { + p--; + while((b < p) && (p->unicode() != '.') && (p->unicode() != ':'))p--; + if(b < p) + { + p--; + while((b < p) && (p->unicode() != '.') && (p->unicode() != ':'))p--; + } + } + // 000.000.000.000 + // p + // + return (p == b) ? 0 : ((p-b) + 1); +} + +QString KviIrcMask::getHostDomainMask() const +{ + int len = m_szHost.length(); + const QChar *p=KviQString::nullTerminatedArray(m_szHost); + if(!p)return QString::null; + const QChar *b = p; + while(p->unicode() && p->unicode() != '.')p++; + QString ret(p,len - (p - b)); + return ret; +} + + +QString KviIrcMask::getLargeHostDomainMask() const +{ + int len = m_szHost.length(); + const QChar *p = m_szHost.unicode(); + const QChar *b = p; + p += len; + + if(b < p) + { + p--; + while((b < p) && (p->unicode() != '.'))p--; + if(b < p) + { + p--; + while((b < p) && (p->unicode() != '.'))p--; + } + } + + // xyz.klm.abc.host.top + // p + + QString ret(p,len - (p - b)); + return ret; +} + +// this is just a GUESS and must be called AFTER making sure that it is NOT a plain numeric IP +bool KviIrcMask::hasMaskedIp() const +{ + int len = m_szHost.length(); + const QChar *p = m_szHost.unicode(); + const QChar *b = p; + if(len == 0)return false; + //run to the end + p += len; + const QChar *e = p; + p--; + while((b < p) && (p->unicode() != '.'))p--; + return ((e - p) > 4); // at the moment 4 should be enough : the largest top part is "name" +} + + +bool KviIrcMask::operator==(const KviIrcMask &user) +{ + if(KviQString::equalCI(m_szNick,user.m_szNick)) + { + if(KviQString::equalCI(m_szUser,user.m_szUser)) + { + if(KviQString::equalCI(m_szHost,user.m_szHost))return true; + } + } + return false; +} + +bool KviIrcMask::hasWildNick() +{ + const QChar * aux = KviQString::nullTerminatedArray(m_szNick); + if(!aux)return false; + unsigned short uc; + while((uc = aux->unicode())) + { + if((uc == '*') || (uc == '?'))return true; + aux++; + } + return false; +} + +int KviIrcMask::nonWildChars() +{ + int iCnt = 0; + const QChar * aux = KviQString::nullTerminatedArray(m_szNick); + if(!aux)return 0; + unsigned short uc; + + while((uc = aux->unicode())) + { + if((uc != '*') && (uc != '?'))iCnt++; + aux++; + } + + aux = KviQString::nullTerminatedArray(m_szUser); + while((uc = aux->unicode())) + { + if((uc != '*') && (uc != '?'))iCnt++; + aux++; + } + + + aux = KviQString::nullTerminatedArray(m_szHost); + while((uc = aux->unicode())) + { + if((uc != '*') && (uc != '?'))iCnt++; + aux++; + } + return iCnt; +} diff --git a/src/kvilib/irc/kvi_ircmask.h b/src/kvilib/irc/kvi_ircmask.h new file mode 100644 index 00000000..3c9ccf5d --- /dev/null +++ b/src/kvilib/irc/kvi_ircmask.h @@ -0,0 +1,164 @@ +#ifndef _KVI_IRCMASK_H_ +#define _KVI_IRCMASK_H_ + +//============================================================================= +// +// File : kvi_ircmask.h +// Creation date : Fri Jan 8 1999 19:50:35 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +// originally this file was named kvi_ircuser.h and the class was KviIrcUser +// ported to UNICODE on 2004.10.28 1:50 am + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_qstring.h" + +//============================================================================= +// Irc user mask abstraction +//============================================================================= + +class KVILIB_API KviIrcMask : public KviHeapObject +{ + friend class KviIrcUserList; + friend class KviIrcUserChanList; +private: + QString m_szNick; + QString m_szUser; + QString m_szHost; + static QString m_szWild; +public: + // Sets the nick for this user.<br> + // If szNick is NULL or it points to an empty string the nick is set to "*".<br> + void setNick(const QString &szNick){ m_szNick = szNick.isEmpty() ? m_szWild : szNick; }; + // Sets the username for this user.<br> + // If szUsername is NULL or it points to an empty string the username is set to "*".<br> + void setUsername(const QString &szUser){ m_szUser = szUser.isEmpty() ? m_szWild : szUser; }; + void setUser(const QString &szUser){ m_szUser = szUser.isEmpty() ? m_szWild : szUser; }; + // Sets the host for this user.<br> + // If szHost is NULL or it points to an empty string the host is set to "*".<br> + void setHost(const QString &szHost){ m_szHost = szHost.isEmpty() ? m_szWild : szHost; }; + // Sets the host , nick and username extracting it from an irc mask:<br> + // nick!user@host<br> + // The mask is terminated by end-of string null character or a character equal to c in the string.<br> + // Returns the pointer to the end of the mask in the szMask string.(c or null-terminator)<br> + //const char * setMask(const QString &szMask,char c=' '); + // Sets the host , nick and username extracting it from an userhost mask:<br> + // nick[*]=<+|->user@host<br> + // The mask is terminated by end-of string null char or a space character.<br> + // Returns the pointer to the next non-space char in the szMask string or to the null-terminator<br> + // If there are no more masks avaiable. + // WARNING : the szMask pointer can NOT be NULL + //const char *setUserhostMask(const QString &szMask); + // Returns the nick of this user.<br> + // In the worst case you get a string == "*"<br> + const QString &nick() const { return m_szNick; }; + // DEPRECATED! + const QString &username() const { return m_szUser; }; + const QString &user() const { return m_szUser; }; + const QString &host() const { return m_szHost; }; + + bool hasUser() const { return !(m_szUser.isEmpty() || (m_szUser == m_szWild)); }; + bool hasHost() const { return !(m_szHost.isEmpty() || (m_szHost == m_szWild)); }; + + bool hasNumericHost() const; + // Retuns in szMask the specified (if possible) mask of this user.<br> + // If the host or username are not known , the mask may contain less information + // than requested.<br> + + enum MaskType + { + NickUserHost = 0, // nick!~user@machine.host.top (nick!~user@XXX.XXX.XXX.XXX) (default) + NickUserNet = 1, // 1 : nick!~user@*.abc.host.top (nick!~user@XXX.XXX.XXX.*) + NickUser = 2, // 2 : nick!~user@* + NickHost = 3, // 3 : nick!*@machine.host.top (nick!*@XXX.XXX.XXX.XXX) + NickNet = 4, // 4 : nick!*@*.abc.host.top (nick!*@XXX.XXX.XXX.*) + Nick = 5, // 5 : nick!*@* + UserHost = 6, // 6 : *!~user@machine.host.top (*!~user@XXX.XXX.XXX.XXX) + UserNet = 7, // 7 : *!~user@*.abc.host.top (*!~user@XXX.XXX.XXX.*) + User = 8, // 8 : *!~user@* + Host = 9, // 9 : *!*@machine.host.top (*!*@XXX.XXX.XXX.XXX) + Net = 10, // 10: *!*@*.abc.host.top (*!*@XXX.XXX.XXX.*) + NickCleanUserHost = 11, // 11 : nick!*user@machine.host.top (nick!*user@XXX.XXX.XXX.XXX) + NickCleanUserNet = 12, // 12 : nick!*user@*.abc.host.top (nick!*user@XXX.XXX.XXX.*) + NickCleanUser = 13, // 13 : nick!*user@* + CleanUserHost = 14, // 14 : *!*user@machine.host.top (*!user@*XXX.XXX.XXX.XXX) + CleanUserNet = 15, // 15 : *!*user@*.abc.host.top (*!user@*XXX.XXX.XXX.*) + CleanUser = 16, // 16 : *!*user@* + NickUserLargeNet = 17, // 17 : nick!~user@*.host.top (nick!~user@XXX.XXX.*) + NickLargeNet = 18, // 18 : nick!*@*.host.top (nick!*@XXX.XXX.*) + UserLargeNet = 19, // 19 : *!~user@*.host.top (*!~user@XXX.XXX.*) + NickCleanUserLargeNet = 20, // 20 : nick!*user@*.host.top (nick!*user@XXX.XXX.*) + CleanUserLargeNet = 21, // 21 : *!*user@*.host.top (*!user@*XXX.XXX.*) + // smart versions of the masks 17-21 that try take care of masked ip addresses + // in the form xxx.xxx.INVALID-TOP-MASK + NickUserSmartNet = 22, // 22 : nick!~user@*.host.top (nick!~user@XXX.XXX.*) + NickSmartNet = 23, // 23 : nick!*@*.host.top (nick!*@XXX.XXX.*) + UserSmartNet = 24, // 24 : *!~user@*.host.top (*!~user@XXX.XXX.*) + NickCleanUserSmartNet = 25, // 25 : nick!*user@*.host.top (nick!*user@XXX.XXX.*) + CleanUserSmartNet = 26 // 26 : *!*user@*.host.top (*!user@*XXX.XXX.*) + }; + + void mask(QString &szMask,MaskType eMaskType = NickCleanUserHost) const; + bool hasWildNick(); + + // Wild external matches (this and external are wild) + +// bool matches(const char *szMask); +// // passing 0 as one of params here means that it is a match by default +// bool matches(const char *nick,const char *user,const char *host); + bool matches(const KviIrcMask &mask) const; + + + // Fixed external matches (this is wild , external is fixed) + bool matchesFixed(const QString &nick,const QString &user,const QString &host) const; +// bool matchesFixed(const QString &szMask) const; + bool matchesFixed(const KviIrcMask &mask) const; + + // Fixed internal matches (this is fixed , external is wild) + //bool matchedBy(const QString &szMask) const; + bool matchedBy(const KviIrcMask &mask) const { return mask.matchesFixed(*this); }; + + int nonWildChars(); + bool operator==(const KviIrcMask &user); +public: + // Constructs an empty mask (*!*@*) + KviIrcMask(); + // Constructs this KviIrcMask object from a string mask + KviIrcMask(const QString &szMask); + // Carbon copy + KviIrcMask(const KviIrcMask &ircUser) + : m_szNick(ircUser.m_szNick), m_szUser(ircUser.m_szUser), m_szHost(ircUser.m_szHost) {}; + KviIrcMask(const QString &nick,const QString &user,const QString &host) + : m_szNick(nick), m_szUser(user), m_szHost(host) {}; +private: + int getIpDomainMaskLen() const; + QString getHostDomainMask() const; + int getLargeIpDomainMaskLen() const; + QString getLargeHostDomainMask() const; + // this is just a GUESS and must be called AFTER making sure that it is NOT a plain numeric IP + bool hasMaskedIp() const; +}; + + + + +#endif //_KVI_IRCMASK_H_ diff --git a/src/kvilib/irc/kvi_ircserver.cpp b/src/kvilib/irc/kvi_ircserver.cpp new file mode 100644 index 00000000..5f03fb5e --- /dev/null +++ b/src/kvilib/irc/kvi_ircserver.cpp @@ -0,0 +1,373 @@ +//============================================================================= +// +// File : kvi_ircserver.cpp +// Creation date : Mon Jul 10 2000 03:42:59 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include "kvi_ircserver.h" +#include "kvi_malloc.h" + +#include "kvi_config.h" +#include "kvi_nickserv.h" +#include "kvi_time.h" +#include "kvi_proxydb.h" +#include <stdlib.h> + +// This is not allowed on windows unless we force the symbol to be undefined +// It works on linux since gcc allows undefined symbols by default +// but it is also "theoretically" wrong: +// kvilib is not linked to kvirc: it's kvirc being linked to kvilib +// thus kvilib should not depend on symbols defined in the kvirc core. +// We must find another way to do that (like having just the id and finding +// the proxy in the kvirc core, or just passing the pointer to the db from outside). +// Pragma + +//extern KVIRC_API KviProxyDataBase * g_pProxyDataBase; + +// FIXME: This should be renamed to KviServer or sth like that +KviIrcServer::KviIrcServer() +{ + m_pReconnectInfo=0; + m_uFlags = 0; + m_uPort = 6667; + m_pChannelList = 0; + m_bAutoConnect = false; + m_iProxy = -1; +} + +KviProxy* KviIrcServer::proxyServer(KviProxyDataBase * pDb) +{ + int i=0; + if(proxy()<0) return 0; + KviPointerList<KviProxy> * proxylist = pDb->proxyList(); + for(KviProxy * p = proxylist->first();p;p = proxylist->next()) + { + if(i==proxy()) return p; + i++; + } + return 0; +} + +KviIrcServer::KviIrcServer(const KviIrcServer &serv) +{ + m_pReconnectInfo = 0; + m_szHostname = serv.m_szHostname; + m_szIp = serv.m_szIp; + m_szDescription = serv.m_szDescription; + m_szUser = serv.m_szUser; + m_szPass = serv.m_szPass; + m_uPort = serv.m_uPort; + m_szNick = serv.m_szNick; + m_szRealName = serv.m_szRealName; + m_szEncoding = serv.m_szEncoding; + m_uFlags = serv.m_uFlags; + m_szInitUMode = serv.m_szInitUMode; + m_szOnConnectCommand = serv.m_szOnConnectCommand; + m_szOnLoginCommand = serv.m_szOnLoginCommand; + m_szLinkFilter = serv.m_szLinkFilter; + m_szId = serv.m_szId; + m_iProxy = serv.m_iProxy; + m_szUserIdentityId = serv.m_szUserIdentityId; + if(serv.m_pChannelList) + m_pChannelList = new QStringList(*(serv.m_pChannelList)); + else m_pChannelList = 0; + m_bAutoConnect = serv.m_bAutoConnect; +} + +void KviIrcServer::operator=(const KviIrcServer &serv) +{ + m_szHostname = serv.m_szHostname; + m_szIp = serv.m_szIp; + m_szDescription = serv.m_szDescription; + m_szUser = serv.m_szUser; + m_szPass = serv.m_szPass; + m_uPort = serv.m_uPort; + m_szNick = serv.m_szNick; + m_szRealName = serv.m_szRealName; + m_szEncoding = serv.m_szEncoding; + m_uFlags = serv.m_uFlags; + m_szInitUMode = serv.m_szInitUMode; + m_szOnConnectCommand = serv.m_szOnConnectCommand; + m_szOnLoginCommand = serv.m_szOnLoginCommand; + m_szLinkFilter = serv.m_szLinkFilter; + m_szId = serv.m_szId; + m_szUserIdentityId = serv.m_szUserIdentityId; + m_iProxy = serv.m_iProxy; + if(m_pChannelList)delete m_pChannelList; + if(serv.m_pChannelList) + m_pChannelList = new QStringList(*(serv.m_pChannelList)); + else m_pChannelList = 0; + m_bAutoConnect = serv.m_bAutoConnect; +} + + +KviIrcServer::~KviIrcServer() +{ + if(m_pChannelList)delete m_pChannelList; + if(m_pReconnectInfo) delete m_pReconnectInfo; +} + +void KviIrcServer::generateUniqueId() +{ + struct timeval tv; + kvi_gettimeofday(&tv,0); + KviQString::sprintf(m_szId,"myserver%d%d%d",tv.tv_usec,rand() % 1000,rand() % 1000); +} + +QString KviIrcServer::ircUri() +{ + QString uri("irc"); + if(useSSL())uri += "s"; + if(isIpV6())uri += "6"; + uri += "://"; + uri += m_szHostname; + + if(m_uPort!=6667) + { + uri += ":"; + QString num; + num.setNum(m_uPort); + uri += num; + } + return uri; +} + +void KviIrcServer::setAutoJoinChannelList(QStringList * pNewChannelList) +{ + if(m_pChannelList)delete m_pChannelList; + m_pChannelList = pNewChannelList; +} + + +bool KviIrcServer::load(KviConfig * cfg,const QString &prefix) +{ + QString tmp; + KviQString::sprintf(tmp,"%QHostname",&prefix); + m_szHostname = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QIp",&prefix); + m_szIp = cfg->readQStringEntry(tmp); + if(m_szHostname.isEmpty() && m_szIp.isEmpty())return false; + KviQString::sprintf(tmp,"%QDescription",&prefix); + m_szDescription = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QUser",&prefix); + m_szUser = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QPass",&prefix); + m_szPass = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QNick",&prefix); + m_szNick = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QRealName",&prefix); + m_szRealName = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QInitUmode",&prefix); + m_szInitUMode = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QAutoJoinChannels",&prefix); + QStringList l = cfg->readStringListEntry(tmp,QStringList()); + if(l.count() > 0)setAutoJoinChannelList(new QStringList(l)); + KviQString::sprintf(tmp,"%QAutoConnect",&prefix); + m_bAutoConnect = cfg->readBoolEntry(tmp,false); + KviQString::sprintf(tmp,"%QEncoding",&prefix); + m_szEncoding = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QOnConnectCommand",&prefix); + m_szOnConnectCommand = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QOnLoginCommand",&prefix); + m_szOnLoginCommand = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QLinkFilter",&prefix); + m_szLinkFilter = cfg->readQStringEntry(tmp); + KviQString::sprintf(tmp,"%QPort",&prefix); + m_uPort = cfg->readUIntEntry(tmp,6667); + KviQString::sprintf(tmp,"%QId",&prefix); + m_szId = cfg->readQStringEntry(tmp); + if(m_szId.isEmpty())generateUniqueId(); + KviQString::sprintf(tmp,"%QIpV6",&prefix); + setIpV6(cfg->readBoolEntry(tmp,false)); + KviQString::sprintf(tmp,"%QCacheIp",&prefix); + setCacheIp(cfg->readBoolEntry(tmp,false)); // true ? + KviQString::sprintf(tmp,"%QSSL",&prefix); + setUseSSL(cfg->readBoolEntry(tmp,false)); + KviQString::sprintf(tmp,"%QProxy",&prefix); + setProxy(cfg->readIntEntry(tmp,-2)); + KviQString::sprintf(tmp,"%QUserIdentityId",&prefix); + m_szUserIdentityId = cfg->readQStringEntry(tmp); + return true; +} + +void KviIrcServer::save(KviConfig * cfg,const QString &prefix) +{ + QString tmp; + KviQString::sprintf(tmp,"%QHostname",&prefix); + cfg->writeEntry(tmp,m_szHostname); + KviQString::sprintf(tmp,"%QId",&prefix); + cfg->writeEntry(tmp,m_szId); + if(!m_szIp.isEmpty()) + { + KviQString::sprintf(tmp,"%QIp",&prefix); + cfg->writeEntry(tmp,m_szIp); + } + if(!m_szDescription.isEmpty()) + { + KviQString::sprintf(tmp,"%QDescription",&prefix); + cfg->writeEntry(tmp,m_szDescription); + } + if(!m_szUser.isEmpty()) + { + KviQString::sprintf(tmp,"%QUser",&prefix); + cfg->writeEntry(tmp,m_szUser); + } + if(!m_szPass.isEmpty()) + { + KviQString::sprintf(tmp,"%QPass",&prefix); + cfg->writeEntry(tmp,m_szPass); + } + if(!m_szNick.isEmpty()) + { + KviQString::sprintf(tmp,"%QNick",&prefix); + cfg->writeEntry(tmp,m_szNick); + } + if(!m_szRealName.isEmpty()) + { + KviQString::sprintf(tmp,"%QRealName",&prefix); + cfg->writeEntry(tmp,m_szRealName); + } + if(!m_szInitUMode.isEmpty()) + { + KviQString::sprintf(tmp,"%QInitUMode",&prefix); + cfg->writeEntry(tmp,m_szInitUMode); + } + if(autoJoinChannelList()) + { + KviQString::sprintf(tmp,"%QAutoJoinChannels",&prefix); + cfg->writeEntry(tmp,*(autoJoinChannelList())); + } + if(autoConnect()) // otherwise it defaults to false anyway + { + KviQString::sprintf(tmp,"%QAutoConnect",&prefix); + cfg->writeEntry(tmp,autoConnect()); + } + if(!m_szEncoding.isEmpty()) + { + KviQString::sprintf(tmp,"%QEncoding",&prefix); + cfg->writeEntry(tmp,m_szEncoding); + } + if(!m_szOnConnectCommand.isEmpty()) + { + KviQString::sprintf(tmp,"%QOnConnectCommand",&prefix); + cfg->writeEntry(tmp,m_szOnConnectCommand); + } + if(!m_szOnLoginCommand.isEmpty()) + { + KviQString::sprintf(tmp,"%QOnLoginCommand",&prefix); + cfg->writeEntry(tmp,m_szOnLoginCommand); + } + if(!m_szLinkFilter.isEmpty()) + { + KviQString::sprintf(tmp,"%QLinkFilter",&prefix); + cfg->writeEntry(tmp,m_szLinkFilter); + } + if(m_uPort != 6667) + { + KviQString::sprintf(tmp,"%QPort",&prefix); + cfg->writeEntry(tmp,m_uPort); + } + if(isIpV6()) + { + KviQString::sprintf(tmp,"%QIpV6",&prefix); + cfg->writeEntry(tmp,isIpV6()); + } + if(cacheIp()) + { + KviQString::sprintf(tmp,"%QCacheIp",&prefix); + cfg->writeEntry(tmp,cacheIp()); + } + if(useSSL()) + { + KviQString::sprintf(tmp,"%QSSL",&prefix); + cfg->writeEntry(tmp,useSSL()); + } + if(proxy()!=-2) + { + KviQString::sprintf(tmp,"%QProxy",&prefix); + cfg->writeEntry(tmp,proxy()); + } + if(!m_szUserIdentityId.isEmpty()) + { + KviQString::sprintf(tmp,"%QUserIdentityId",&prefix); + cfg->writeEntry(tmp,m_szUserIdentityId); + } +} + + + +KviIrcNetwork::KviIrcNetwork(const KviIrcNetwork &src) +{ + m_pChannelList = 0; + m_pNickServRuleSet = 0; + copyFrom(src); +} + +KviIrcNetwork::KviIrcNetwork(const QString &name) +{ + m_szName = name; + m_pChannelList = 0; + m_pNickServRuleSet = 0; + m_bAutoConnect = false; + // m_szEncoding = QString::null; // set by default +} + +KviIrcNetwork::~KviIrcNetwork() +{ + if(m_pChannelList)delete m_pChannelList; + if(m_pNickServRuleSet)delete m_pNickServRuleSet; +} + +void KviIrcNetwork::setAutoJoinChannelList(QStringList * pNewChannelList) +{ + if(m_pChannelList)delete m_pChannelList; + m_pChannelList = pNewChannelList; +} + +void KviIrcNetwork::setNickServRuleSet(KviNickServRuleSet * s) +{ + if(m_pNickServRuleSet)delete m_pNickServRuleSet; + m_pNickServRuleSet = s; +} + + +void KviIrcNetwork::copyFrom(const KviIrcNetwork &src) +{ + m_szName = src.m_szName; + m_szEncoding = src.m_szEncoding; + m_szDescription = src.m_szDescription; + m_szNickName = src.m_szNickName; + m_szRealName = src.m_szRealName; + m_szUserName = src.m_szUserName; + m_bAutoConnect = src.m_bAutoConnect; + m_szUserIdentityId = src.m_szUserIdentityId; + m_szOnConnectCommand = src.m_szOnConnectCommand; + m_szOnLoginCommand = src.m_szOnLoginCommand; + if(m_pChannelList)delete m_pChannelList; + if(src.m_pChannelList)m_pChannelList = new QStringList(*(src.m_pChannelList)); + else m_pChannelList = 0; + if(m_pNickServRuleSet)delete m_pNickServRuleSet; + if(src.m_pNickServRuleSet)m_pNickServRuleSet = new KviNickServRuleSet(*(src.m_pNickServRuleSet)); + else m_pNickServRuleSet = 0; +} + diff --git a/src/kvilib/irc/kvi_ircserver.h b/src/kvilib/irc/kvi_ircserver.h new file mode 100644 index 00000000..4c0ca54d --- /dev/null +++ b/src/kvilib/irc/kvi_ircserver.h @@ -0,0 +1,206 @@ +#ifndef _KVI_IRCSERVER_H_ +#define _KVI_IRCSERVER_H_ + +//============================================================================= +// +// File : kvi_ircserver.h +// Creation date : Mon Jul 10 2000 03:24:11 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_qstring.h" +#include "kvi_pointerlist.h" + +#include <qstringlist.h> + +class KviConfig; +class KviNickServRuleSet; +class KviProxy; +class KviProxyDataBase; +class KviIrcServer; + +#define KVI_IRCSERVER_FLAG_IPV6 1 +#define KVI_IRCSERVER_FLAG_CACHEIP 2 +#define KVI_IRCSERVER_FLAG_SSL 4 + +class KVILIB_API KviIrcServerReconnectInfo { +public: + QString m_szNick; + QString m_szAwayReason; + QString m_szJoinChannels; + QStringList m_szOpenQueryes; + bool m_bIsAway; +}; + +class KVILIB_API KviIrcServer : public KviHeapObject +{ +public: + KviIrcServer(); + KviIrcServer(const KviIrcServer &serv); + ~KviIrcServer(); +public: + KviIrcServerReconnectInfo *m_pReconnectInfo; + QString m_szHostname; // the server hostname (or ip eventually) + QString m_szIp; // the server's cached ip (if we're caching) + QString m_szDescription; // the server description + kvi_u32_t m_uPort; // the server's port + unsigned short int m_uFlags; // flags + + // Extended data + QString m_szUserIdentityId; // The user identity to use for this server: if empty + // Then use the network identity instead + + QString m_szUser; // special username + QString m_szPass; // special password + QString m_szNick; // special nickname + QString m_szRealName; // special real name + QString m_szInitUMode; // special user mode + QString m_szOnConnectCommand; // the command to run on connect + QString m_szOnLoginCommand; // the command to run after login + QString m_szLinkFilter; // the link filter object + QString m_szEncoding; // if empty, use network encoding + QStringList * m_pChannelList; // Channels to auto join + bool m_bAutoConnect; // autoconnect + QString m_szId; // the server's may-be-unique id, may be auto-generated + int m_iProxy; // proxy server's id +public: + int proxy() { return m_iProxy; }; + KviProxy* proxyServer(KviProxyDataBase * pDb); + + kvi_u32_t port() const { return m_uPort; }; + const QString & ipAddress() const { return m_szIp; }; + const QString & password() const { return m_szPass; }; + const QString & nickName() const { return m_szNick; }; + const QString & initUMode() const { return m_szInitUMode; }; + const QString & hostName() const { return m_szHostname; }; + const QString & ip() const { return m_szIp; }; + const QString & onLoginCommand() const { return m_szOnLoginCommand; }; + const QString & onConnectCommand() const { return m_szOnConnectCommand; }; + const QString & userName() const { return m_szUser; }; + const QString & realName() const { return m_szRealName; }; + const QString & linkFilter() const { return m_szLinkFilter; }; + const QString & description() const { return m_szDescription; }; + const QString & encoding() const { return m_szEncoding; }; + const QString & id() const { return m_szId; }; + const QString & userIdentityId() const { return m_szUserIdentityId; }; + bool autoConnect() const { return m_bAutoConnect; }; + QStringList* autoJoinChannelList(){ return m_pChannelList; }; + bool isIpV6() const { return (m_uFlags & KVI_IRCSERVER_FLAG_IPV6); }; + bool useSSL() const { return (m_uFlags & KVI_IRCSERVER_FLAG_SSL); }; + bool cacheIp() const { return (m_uFlags & KVI_IRCSERVER_FLAG_CACHEIP); }; + + void setProxy(int p){ m_iProxy = p; }; + void setIpAddress(const QString &a){ m_szIp = a; }; + void setPort(kvi_u32_t p){ m_uPort = p; }; + void setHostName(const QString &n){ m_szHostname = n; }; + void setDescription(const QString &d){ m_szDescription = d; }; + void setUserName(const QString &u){ m_szUser = u; }; + void setPassword(const QString &p){ m_szPass = p; }; + void setNickName(const QString &n){ m_szNick = n; }; + void setRealName(const QString &r){ m_szRealName = r; }; + void setEncoding(const QString &e){ m_szEncoding = e; }; + void setInitUMode(const QString &u){ m_szInitUMode = u; }; + void setOnConnectCommand(const QString &cmd){ m_szOnConnectCommand = cmd; }; + void setOnLoginCommand(const QString &cmd){ m_szOnLoginCommand = cmd; }; + void setLinkFilter(const QString &f){ m_szLinkFilter = f; }; + // the channel list must be allocated with new! + void setAutoJoinChannelList(QStringList * pNewChannelList); + void setAutoConnect(bool autoconnect) { m_bAutoConnect = autoconnect; }; + void setUserIdentityId(const QString &szUserIdentityId){ m_szUserIdentityId = szUserIdentityId; }; + void setIpV6(bool bSet) + { + if(bSet)m_uFlags |= KVI_IRCSERVER_FLAG_IPV6; + else m_uFlags &= ((unsigned short)~KVI_IRCSERVER_FLAG_IPV6); + }; + void setUseSSL(bool bSet) + { + if(bSet)m_uFlags |= KVI_IRCSERVER_FLAG_SSL; + else m_uFlags &= ((unsigned short)~KVI_IRCSERVER_FLAG_SSL); + }; + void setCacheIp(bool bSet) + { + if(bSet)m_uFlags |= KVI_IRCSERVER_FLAG_CACHEIP; + else m_uFlags &= ((unsigned short)~KVI_IRCSERVER_FLAG_CACHEIP); + }; + void operator =(const KviIrcServer &s); + + bool load(KviConfig * cfg,const QString &prefix); + void save(KviConfig * cfg,const QString &prefix); + + void generateUniqueId(); + void setId(const QString &szId){ m_szId = szId; if(m_szId.isEmpty())generateUniqueId(); }; + + QString ircUri(); +}; + +class KVILIB_API KviIrcNetwork : public KviHeapObject +{ + friend class KviIrcServerDataBase; +public: + KviIrcNetwork(const KviIrcNetwork &src); + KviIrcNetwork(const QString &name); + ~KviIrcNetwork(); +protected: + QString m_szName; + QString m_szDescription; + QString m_szEncoding; // if empty, use system default + QString m_szNickName; // preferred nick name + QString m_szUserName; // preferred user name + QString m_szRealName; // preferred real name + QString m_szOnConnectCommand; // the command to run on connect + QString m_szOnLoginCommand; // the command to run after login + QStringList * m_pChannelList; // Channels to auto join + KviNickServRuleSet * m_pNickServRuleSet; // set of nick serv rules + bool m_bAutoConnect; // autoconnect + QString m_szUserIdentityId; // The user identity to use for this server: if empty + // Then use the global primary identity +public: + const QString & name() const { return m_szName; }; + const QString & encoding() const { return m_szEncoding; }; + const QString & description() const { return m_szDescription; }; + const QString & nickName() const { return m_szNickName; }; + const QString & realName() const { return m_szRealName; }; + const QString & userName() const { return m_szUserName; }; + const QString & onLoginCommand() const { return m_szOnLoginCommand; }; + const QString & onConnectCommand() const { return m_szOnConnectCommand; }; + const QString & userIdentityId() const { return m_szUserIdentityId; }; + bool autoConnect() const { return m_bAutoConnect; }; + QStringList* autoJoinChannelList(){ return m_pChannelList; }; + KviNickServRuleSet * nickServRuleSet(){ return m_pNickServRuleSet; }; + void setNickServRuleSet(KviNickServRuleSet * s); + void copyFrom(const KviIrcNetwork &d); + void setName(const QString &szName){ m_szName = szName; }; + void setEncoding(const QString &szEncoding){ m_szEncoding = szEncoding; }; + void setDescription(const QString &szDescription){ m_szDescription = szDescription; }; + void setOnConnectCommand(const QString &cmd){ m_szOnConnectCommand = cmd; }; + void setOnLoginCommand(const QString &cmd){ m_szOnLoginCommand = cmd; }; + void setNickName(const QString &n){ m_szNickName = n; }; + void setRealName(const QString &r){ m_szRealName = r; }; + void setUserName(const QString &u){ m_szUserName = u; }; + void setAutoJoinChannelList(QStringList * pNewChannelList); + void setAutoConnect(bool bAutoConnect){ m_bAutoConnect = bAutoConnect; }; + void setUserIdentityId(const QString &szUserIdentityId){ m_szUserIdentityId = szUserIdentityId; }; +}; + + + +#endif //_KVI_IRCSERVER_H_ diff --git a/src/kvilib/irc/kvi_ircserverdb.cpp b/src/kvilib/irc/kvi_ircserverdb.cpp new file mode 100644 index 00000000..88198b12 --- /dev/null +++ b/src/kvilib/irc/kvi_ircserverdb.cpp @@ -0,0 +1,646 @@ +//============================================================================= +// +// File : kvi_ircserverdb.cpp +// Creation date : Mon Jul 10 2000 14:25:00 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include <qapplication.h> +#include <qlayout.h> +#include <qmessagebox.h> +#include <qcheckbox.h> + +#include "kvi_ircserverdb.h" +#include "kvi_config.h" +#include "kvi_locale.h" +#include "kvi_netutils.h" +#include "kvi_nickserv.h" + +KviIrcServerDataBaseRecord::KviIrcServerDataBaseRecord(KviIrcNetwork * n) +{ + m_pNetwork = n; + m_pServerList = new KviPointerList<KviIrcServer>; + m_pServerList->setAutoDelete(true); + m_pCurrentServer = 0; +} + +KviIrcServerDataBaseRecord::~KviIrcServerDataBaseRecord() +{ + delete m_pNetwork; + delete m_pServerList; +} + +void KviIrcServerDataBaseRecord::insertServer(KviIrcServer *srv) +{ + m_pServerList->append(srv); +} + +KviIrcServer * KviIrcServerDataBaseRecord::findServer(const KviIrcServer * pServer) +{ + for(KviIrcServer *s=m_pServerList->first();s;s=m_pServerList->next()) + { + if(KviQString::equalCI(s->m_szHostname,pServer->m_szHostname) && + (s->m_uPort == pServer->m_uPort) && + (s->useSSL() == pServer->useSSL()) && + (s->isIpV6() == pServer->isIpV6()))return s; + } + return 0; +} + +void KviIrcServerDataBaseRecord::setCurrentServer(KviIrcServer *srv) +{ + if(m_pServerList->findRef(srv) != -1)m_pCurrentServer = srv; +} + +KviIrcServer * KviIrcServerDataBaseRecord::currentServer() +{ + if(m_pCurrentServer)return m_pCurrentServer; + m_pCurrentServer = m_pServerList->first(); + return m_pCurrentServer; +} + + + + + + + + + + +KviIrcServerDataBase::KviIrcServerDataBase() +{ + m_pRecords = new KviPointerHashTable<QString,KviIrcServerDataBaseRecord>(17,false); + m_pRecords->setAutoDelete(true); + m_pAutoConnectOnStartupServers = 0; + m_pAutoConnectOnStartupNetworks = 0; +} + +KviIrcServerDataBase::~KviIrcServerDataBase() +{ + delete m_pRecords; + if(m_pAutoConnectOnStartupServers)delete m_pAutoConnectOnStartupServers; + if(m_pAutoConnectOnStartupNetworks)delete m_pAutoConnectOnStartupNetworks; +} + +void KviIrcServerDataBase::clearAutoConnectOnStartupServers() +{ + if(!m_pAutoConnectOnStartupServers)return; + delete m_pAutoConnectOnStartupServers; + m_pAutoConnectOnStartupServers = 0; +} + +void KviIrcServerDataBase::clearAutoConnectOnStartupNetworks() +{ + if(!m_pAutoConnectOnStartupNetworks)return; + delete m_pAutoConnectOnStartupNetworks; + m_pAutoConnectOnStartupNetworks = 0; +} + +void KviIrcServerDataBase::clear() +{ + m_pRecords->clear(); + m_szCurrentNetwork = ""; +} + +KviIrcServerDataBaseRecord * KviIrcServerDataBase::insertNetwork(KviIrcNetwork *n) +{ + KviIrcServerDataBaseRecord * r = new KviIrcServerDataBaseRecord(n); + m_pRecords->replace(n->name(),r); + return r; +} + +KviIrcServerDataBaseRecord * KviIrcServerDataBase::findRecord(const QString &szNetName) +{ + return m_pRecords->find(szNetName); +} + + +KviIrcNetwork * KviIrcServerDataBase::findNetwork(const QString &szName) +{ + KviIrcServerDataBaseRecord * r = m_pRecords->find(szName); + if(!r)return 0; + return r->network(); +} + +KviIrcServerDataBaseRecord * KviIrcServerDataBase::currentRecord() +{ + KviIrcServerDataBaseRecord * r = 0; + if(!m_szCurrentNetwork.isEmpty())r = m_pRecords->find(m_szCurrentNetwork); + if(r)return r; + + KviPointerHashTableIterator<QString,KviIrcServerDataBaseRecord> it(*m_pRecords); + r = it.current(); + if(!r)return 0; + m_szCurrentNetwork = r->network()->name(); + return r; +} + +void KviIrcServerDataBase::updateServerIp(KviIrcServer * pServer,const QString & ip) +{ + KviPointerHashTableIterator<QString,KviIrcServerDataBaseRecord> it(*m_pRecords); + while(KviIrcServerDataBaseRecord * r = it.current()) + { + KviIrcServer * srv = r->findServer(pServer); + if(srv) + { + srv->m_szIp = ip; + return; + } + ++it; + } +} + +bool KviIrcServerDataBase::makeCurrentBestServerInNetwork(const QString &szNetName,KviIrcServerDataBaseRecord * r,QString &szError) +{ + m_szCurrentNetwork = szNetName; + // find a round-robin server in that network + + if(r->m_pServerList->isEmpty()) + { + szError = __tr2qs("The specified network has no server entries"); + return false; + } + + for(KviIrcServer * s = r->m_pServerList->first();s;s = r->m_pServerList->next()) + { +#ifdef COMPILE_USE_QT4 + if(s->m_szDescription.contains("random",Qt::CaseInsensitive) || + (s->m_szDescription.contains("round",Qt::CaseInsensitive) && s->m_szDescription.contains("robin",Qt::CaseInsensitive))) +#else + if(s->m_szDescription.contains("random",false) || + (s->m_szDescription.contains("round",false) && s->m_szDescription.contains("robin",false))) +#endif + { + r->setCurrentServer(s); + return true; + } + } + + // no explicit round robin... try some common names + + QString tryAlso1,tryAlso2,tryAlso3; + + KviQString::sprintf(tryAlso1,"irc.%Q.org",&szNetName); + KviQString::sprintf(tryAlso2,"irc.%Q.net",&szNetName); + KviQString::sprintf(tryAlso3,"irc.%Q.com",&szNetName); + + for(KviIrcServer * ss = r->m_pServerList->first();ss;ss = r->m_pServerList->next()) + { + if(KviQString::equalCI(ss->m_szHostname,tryAlso1) || + KviQString::equalCI(ss->m_szHostname,tryAlso2) || + KviQString::equalCI(ss->m_szHostname,tryAlso3)) + { + r->setCurrentServer(ss); + return true; + } + } + + // a random one in this network + return true; +} + + +bool KviIrcServerDataBase::makeCurrentServer(KviIrcServerDefinition * d,QString &szError) +{ + KviIrcServer * pServer = 0; + + KviPointerHashTableIterator<QString,KviIrcServerDataBaseRecord> it(*m_pRecords); + KviIrcServerDataBaseRecord * r = 0; + KviIrcServer * srv; + + if(KviQString::equalCIN(d->szServer,"net:",4)) + { + // net:networkname form + QString szNet = d->szServer; + szNet.remove(0,4); + KviIrcServerDataBaseRecord * r = m_pRecords->find(szNet); + if(r)return makeCurrentBestServerInNetwork(szNet,r,szError); + szError = __tr2qs("The server specification seems to be in the net:<string> but the network couln't be found in the database"); + return false; + } + + if(KviQString::equalCIN(d->szServer,"id:",3)) + { + // id:serverid form + QString szId = d->szServer; + szId.remove(0,3); + + while((r = it.current())) + { + for(srv = r->serverList()->first();srv && (!pServer);srv = r->serverList()->next()) + { + if(KviQString::equalCI(srv->id(),szId)) + { + pServer = srv; + goto search_finished; + } + } + ++it; + } + szError = __tr2qs("The server specification seems to be in the id:<string> form but the identifier coulnd't be found in the database"); + return false; + } + + it.toFirst(); + + while((r = it.current())) + { + for(srv = r->serverList()->first();srv && (!pServer);srv = r->serverList()->next()) + { + if(KviQString::equalCI(srv->hostName(),d->szServer)) + { + if(d->bIpV6 == srv->isIpV6()) + { + if(d->bSSL == srv->useSSL()) + { + if(d->bPortIsValid) + { + // must match the port + if(d->uPort == srv->port()) + { + // port matches + if(!d->szLinkFilter.isEmpty()) + { + // must match the link filter + if(KviQString::equalCI(d->szLinkFilter,srv->linkFilter())) + { + // link filter matches + pServer = srv; + goto search_finished; + } // else link filter doesn't match + } else { + // no need to match the link filter + pServer = srv; + goto search_finished; + } + } // else port doesn't match + } else { + // no need to match the port + if(!d->szLinkFilter.isEmpty()) + { + // must match the link filter + if(KviQString::equalCI(d->szLinkFilter,srv->linkFilter())) + { + // link filter matches + pServer = srv; + goto search_finished; + } // else link filter doesn't match + } else { + // no need to match the link filter + pServer = srv; + goto search_finished; + } + } + } + } + } + } + ++it; + } + +search_finished: + + if(r && pServer) + { + if(!d->szNick.isEmpty())pServer->m_szNick = d->szNick; + if(!d->szPass.isEmpty())pServer->m_szPass = d->szPass; // don't clear the pass! + if(!d->szInitUMode.isEmpty())pServer->m_szInitUMode = d->szInitUMode; + + m_szCurrentNetwork = r->network()->name(); + r->setCurrentServer(pServer); + return true; + } + + // no such server: is it a valid ip address or hostname ? + bool bIsValidIpV4 = KviNetUtils::isValidStringIp(d->szServer); +#ifdef COMPILE_IPV6_SUPPORT + bool bIsValidIpV6 =KviNetUtils::isValidStringIp_V6(d->szServer); +#else + bool bIsValidIpV6 = false; +#endif + + if(!(bIsValidIpV4 || bIsValidIpV6)) + { + // is it a valid hostname ? (must contain at least one dot) +#ifdef COMPILE_USE_QT4 + if(!d->szServer.contains('.')) +#else + if(d->szServer.contains('.') < 1) +#endif + { + // assume it is a network name! + KviIrcServerDataBaseRecord * r = m_pRecords->find(d->szServer); + if(r)return makeCurrentBestServerInNetwork(d->szServer,r,szError); + // else probably not a network name + } + } + + // a valid hostname or ip address , not found in list : add it and make it current + + r = m_pRecords->find(__tr2qs("Standalone Servers")); + if(!r) + { + r = new KviIrcServerDataBaseRecord(new KviIrcNetwork(__tr2qs("Standalone Servers"))); + m_pRecords->replace(r->network()->name(),r); + } + + KviIrcServer * s = new KviIrcServer(); + s->m_szHostname = d->szServer; + if(bIsValidIpV4) + { + s->m_szIp = d->szServer; + s->setCacheIp(true); +#ifdef COMPILE_IPV6_SUPPORT + } else { + if(bIsValidIpV6) + { + s->m_szIp = d->szServer; + s->setCacheIp(true); + d->bIpV6 = true; + } + } +#else + } +#endif + s->m_uPort = d->bPortIsValid ? d->uPort : 6667; + s->setLinkFilter(d->szLinkFilter); + s->m_szPass= d->szPass; + s->m_szNick= d->szNick; + s->m_szInitUMode = d->szInitUMode; + s->setIpV6(d->bIpV6); + s->setUseSSL(d->bSSL); + r->insertServer(s); + m_szCurrentNetwork = r->network()->name(); + r->setCurrentServer(s); + + return true; +} + +void parseMircServerRecord(QString entry,QString& szNet, + QString& szDescription,QString& szHost,QString& szPort,bool& bSsl,kvi_u32_t& uPort) +{ + bSsl = false; + int idx = KviQString::find(entry,"SERVER:"); + if(idx != -1) + { + szDescription = entry.left(idx); + szNet=szDescription.section(':',0,0); + szDescription=szDescription.section(':',1,1); + + entry.remove(0,idx + 7); + idx = KviQString::find(entry,"GROUP:"); + if(idx != -1) + { + szHost = entry.left(idx); + } else { + szHost = entry; + } + + szPort = szHost.section(':',1,1); + if(szPort[0]=='+') + { + bSsl = true; + szPort.remove(0,1); + } + szHost = szHost.section(':',0,0); + + bool bOk; + uPort = szPort.toUInt(&bOk); + if(!bOk)uPort = 6667; + } +} + +void KviIrcServerDataBase::loadFromMircIni(const QString & filename, const QString & szMircIni, QStringList& recentServers) +{ + clear(); + recentServers.clear(); + QString szDefaultServer; + KviConfig mircCfg(szMircIni,KviConfig::Read,true); + if(mircCfg.hasGroup("mirc")) + { + mircCfg.setGroup("mirc"); + szDefaultServer = mircCfg.readQStringEntry("host"); + } + + KviConfig cfg(filename,KviConfig::Read,true); + int i = 0; + + QString entry; + QString key; + if(cfg.hasGroup("recent")) + { + cfg.setGroup("recent"); + do { + KviQString::sprintf(key,"n%d",i); + entry = cfg.readEntry(key); + if(!entry.isEmpty()) + { + QString szNet; + QString szDescription; + QString szHost; + QString szPort; + bool bSsl = false; + kvi_u32_t uPort = 0; + + parseMircServerRecord(entry,szNet, + szDescription,szHost,szPort,bSsl,uPort); + + recentServers << (bSsl ? "ircs://" : "irc://" ) +szHost+":"+szPort; + } + i++; + } while(!entry.isEmpty()); + } + + i = 0; + if(cfg.hasGroup("servers")) + { + cfg.setGroup("servers"); + do { + KviQString::sprintf(key,"n%d",i); + entry = cfg.readEntry(key); + if(!entry.isEmpty()) + { + bool bDefault = false; + QString szNet; + QString szDescription; + QString szHost; + QString szPort; + bool bSsl = false; + kvi_u32_t uPort = 0; + // <net>:<description>SERVER:<server:port>GROUP:<group???> + if(entry==szDefaultServer) + bDefault = true; + + parseMircServerRecord(entry,szNet, + szDescription,szHost,szPort,bSsl,uPort); + + KviIrcServerDataBaseRecord * r = findRecord(szNet); + + if(!r) { + KviIrcNetwork * n = new KviIrcNetwork(szNet); + r = insertNetwork(n); + } + + KviIrcServer *s = new KviIrcServer(); + s->m_szHostname = szHost; + s->m_szDescription = szDescription; + s->m_uPort = uPort; + + + r->m_pServerList->append(s); + if(bDefault) + { + m_szCurrentNetwork = szNet; + } + } + i++; + } while(!entry.isEmpty()); + } +} + + +void KviIrcServerDataBase::load(const QString & filename) +{ + clear(); + KviConfig cfg(filename,KviConfig::Read); + + KviConfigIterator it(*(cfg.dict())); + + QString tmp; + + while(it.current()) + { + if(it.current()->count() > 0) + { + KviIrcNetwork * n = new KviIrcNetwork(it.currentKey()); + KviIrcServerDataBaseRecord * r = insertNetwork(n); + cfg.setGroup(it.currentKey()); + n->m_szEncoding = cfg.readQStringEntry("Encoding"); + n->m_szDescription = cfg.readQStringEntry("Description"); + n->m_szNickName = cfg.readQStringEntry("NickName"); + n->m_szRealName = cfg.readQStringEntry("RealName"); + n->m_szUserName = cfg.readQStringEntry("UserName"); + n->m_szOnConnectCommand = cfg.readQStringEntry("OnConnectCommand"); + n->m_szOnLoginCommand = cfg.readQStringEntry("OnLoginCommand"); + n->m_pNickServRuleSet = KviNickServRuleSet::load(&cfg,QString::null); + n->m_bAutoConnect = cfg.readBoolEntry("AutoConnect",false); + n->m_szUserIdentityId = cfg.readQStringEntry("UserIdentityId"); + if(n->m_bAutoConnect) + { + if(!m_pAutoConnectOnStartupNetworks) + { + m_pAutoConnectOnStartupNetworks = new KviPointerList<KviIrcServerDataBaseRecord>; + m_pAutoConnectOnStartupNetworks->setAutoDelete(false); + } + m_pAutoConnectOnStartupNetworks->append(r); + } + QStringList l = cfg.readStringListEntry("AutoJoinChannels",QStringList()); + if(l.count() > 0)n->setAutoJoinChannelList(new QStringList(l)); + + if(cfg.readBoolEntry("Current",false))m_szCurrentNetwork = it.currentKey(); + + int nServers = cfg.readIntEntry("NServers",0); + for(int i=0;i < nServers;i++) + { + KviIrcServer *s = new KviIrcServer(); + KviQString::sprintf(tmp,"%d_",i); + if(s->load(&cfg,tmp)) + { + r->m_pServerList->append(s); + KviQString::sprintf(tmp,"%d_Current",i); + if(cfg.readBoolEntry(tmp,false))r->m_pCurrentServer = s; + if(s->autoConnect()) + { + if(!m_pAutoConnectOnStartupServers) + { + m_pAutoConnectOnStartupServers = new KviPointerList<KviIrcServer>; + m_pAutoConnectOnStartupServers->setAutoDelete(false); + } + m_pAutoConnectOnStartupServers->append(s); + } + } else delete s; + } + if(!r->m_pCurrentServer)r->m_pCurrentServer = r->m_pServerList->first(); + } + ++it; + } +} + +void KviIrcServerDataBase::save(const QString &filename) +{ + KviConfig cfg(filename,KviConfig::Write); + + cfg.clear(); // clear any old entry + + KviPointerHashTableIterator<QString,KviIrcServerDataBaseRecord> it(*m_pRecords); + + QString tmp; + + while(KviIrcServerDataBaseRecord * r = it.current()) + { + KviIrcNetwork * n = r->network(); + cfg.setGroup(n->m_szName); + cfg.writeEntry("NServers",r->m_pServerList->count()); + if(n->m_bAutoConnect) + cfg.writeEntry("AutoConnect",true); + if(!n->m_szEncoding.isEmpty()) + cfg.writeEntry("Encoding",n->m_szEncoding); + if(!n->m_szDescription.isEmpty()) + cfg.writeEntry("Description",n->m_szDescription); + if(!n->m_szNickName.isEmpty()) + cfg.writeEntry("NickName",n->m_szNickName); + if(!n->m_szRealName.isEmpty()) + cfg.writeEntry("RealName",n->m_szRealName); + if(!n->m_szUserName.isEmpty()) + cfg.writeEntry("UserName",n->m_szUserName); + if(!n->m_szOnConnectCommand.isEmpty()) + cfg.writeEntry("OnConnectCommand",n->m_szOnConnectCommand); + if(!n->m_szOnLoginCommand.isEmpty()) + cfg.writeEntry("OnLoginCommand",n->m_szOnLoginCommand); + if(n->m_pNickServRuleSet)n->m_pNickServRuleSet->save(&cfg,QString::null); + if(n->autoJoinChannelList()) + cfg.writeEntry("AutoJoinChannels",*(n->autoJoinChannelList())); + if(n->m_szName == m_szCurrentNetwork)cfg.writeEntry("Current",true); + if(!n->m_szUserIdentityId.isEmpty()) + cfg.writeEntry("UserIdentityId",n->m_szUserIdentityId); + int i=0; + for(KviIrcServer *s = r->m_pServerList->first();s;s = r->m_pServerList->next()) + { + KviQString::sprintf(tmp,"%d_",i); + s->save(&cfg,tmp); + + if(s == r->m_pCurrentServer) + { + KviQString::sprintf(tmp,"%d_Current",i); + cfg.writeEntry(tmp,true); + } + + i++; + } + ++it; + } +} + + + diff --git a/src/kvilib/irc/kvi_ircserverdb.h b/src/kvilib/irc/kvi_ircserverdb.h new file mode 100644 index 00000000..b5d55231 --- /dev/null +++ b/src/kvilib/irc/kvi_ircserverdb.h @@ -0,0 +1,116 @@ +#ifndef _KVI_IRCSERVERDB_H_ +#define _KVI_IRCSERVERDB_H_ +//============================================================================= +// +// File : kvi_ircserverdb.h +// Creation date : Mon Jul 10 2000 14:15:42 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" +#include "kvi_ircserver.h" + +#include "kvi_pointerhashtable.h" + +typedef struct _KviIrcServerDefinition +{ + QString szServer; + kvi_u32_t uPort; + bool bPortIsValid; + bool bIpV6; + bool bSSL; + QString szLinkFilter; + QString szPass; + QString szNick; + QString szInitUMode; +} KviIrcServerDefinition; + + + +class KVILIB_API KviIrcServerDataBaseRecord +{ + friend class KviIrcServerDataBase; +public: + KviIrcServerDataBaseRecord(KviIrcNetwork * n); + ~KviIrcServerDataBaseRecord(); +protected: + KviIrcNetwork * m_pNetwork; + KviPointerList<KviIrcServer> * m_pServerList; + + KviIrcServer * m_pCurrentServer; +public: + KviIrcNetwork * network(){ return m_pNetwork; }; + KviPointerList<KviIrcServer> * serverList(){ return m_pServerList; }; + KviIrcServer * currentServer(); + void insertServer(KviIrcServer *srv); + KviIrcServer * findServer(const KviIrcServer * pServer); + void setCurrentServer(KviIrcServer *srv); +}; + + + + + +class KVILIB_API KviIrcServerDataBase +{ +public: + KviIrcServerDataBase(); + ~KviIrcServerDataBase(); +private: + KviPointerHashTable<QString,KviIrcServerDataBaseRecord> * m_pRecords; + QString m_szCurrentNetwork; + // This list is computed when the data are loaded from disk + // during the startup and is used by KviApp to + // start the connections. + // The pointer is zero if there are no autoConnect servers + // The list is valid only during the startup phase + // because it contains shallow pointers to the servers + // really contained in the server/network list + // and it is never updated later + KviPointerList<KviIrcServer> * m_pAutoConnectOnStartupServers; + KviPointerList<KviIrcServerDataBaseRecord> * m_pAutoConnectOnStartupNetworks; +public: + void clear(); + KviPointerHashTable<QString,KviIrcServerDataBaseRecord> * recordDict(){ return m_pRecords; }; + KviPointerList<KviIrcServer> * autoConnectOnStartupServers(){ return m_pAutoConnectOnStartupServers; }; + KviPointerList<KviIrcServerDataBaseRecord> * autoConnectOnStartupNetworks(){ return m_pAutoConnectOnStartupNetworks; }; + void clearAutoConnectOnStartupServers(); + void clearAutoConnectOnStartupNetworks(); + void setCurrentNetwork(const QString &szNetName){ m_szCurrentNetwork = szNetName; }; + const QString & currentNetworkName(){ return m_szCurrentNetwork; }; + KviIrcServerDataBaseRecord * currentRecord(); + KviIrcServerDataBaseRecord * findRecord(const QString &szNetName); + KviIrcNetwork * findNetwork(const QString &name); + void loadFromMircIni(const QString & filename, const QString & szMircIni, QStringList& recentServers); + void load(const QString & filename); + void save(const QString & filename); + KviIrcServerDataBaseRecord * insertNetwork(KviIrcNetwork * n); + void updateServerIp(KviIrcServer * pServer,const QString &ip); + bool makeCurrentServer(KviIrcServerDefinition * d,QString &szError); + bool makeCurrentBestServerInNetwork(const QString &szNetName,KviIrcServerDataBaseRecord * d,QString &szError); +}; + + + + + + +#endif //_KVI_IRCSERVERDB_H_ diff --git a/src/kvilib/irc/kvi_ircuserdb.cpp b/src/kvilib/irc/kvi_ircuserdb.cpp new file mode 100644 index 00000000..38b52522 --- /dev/null +++ b/src/kvilib/irc/kvi_ircuserdb.cpp @@ -0,0 +1,285 @@ +//============================================================================= +// +// File : kvi_ircuserdb.cpp +// Creation date : Mon Jul 31 2000 21:23:22 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_debug.h" +#include "kvi_ircuserdb.h" +#include "kvi_mirccntrl.h" +#include "kvi_qstring.h" +#include "kvi_stringconversion.h" + +//static int cacheHit = 0; +//static int cacheMiss = 0; + +KviIrcUserEntry::KviIrcUserEntry(const QString &user,const QString &host) +{ + m_szUser = user; + m_szHost = host; + m_pAvatar = 0; + m_nRefs = 1; + m_iHops = -1; + m_bAway = false; + m_eGender = Unknown; + m_bBot = false; + m_bNotFoundRegUserLoockup=false; + m_bUseCustomColor=false; +} + +void KviIrcUserEntry::setRealName(const QString &rn) +{ + m_szRealName = rn; + m_szRealName = KviQString::trimmed(m_szRealName); + if(m_szRealName.length()>=3) + { + if( (m_szRealName[0].unicode()==KVI_TEXT_COLOR) && (m_szRealName[2].unicode()==KVI_TEXT_RESET) ) + { + switch(m_szRealName[1].unicode()) + { + case '1': // hum.. encoded as hidden color code eh ? publish is somewhere, so others might implement this... + setGender(Male); + break; + case '2': + setGender(Female); + break; + case '3': + setBot(true); + break; + } + m_szRealName.remove(0,3); + } + } +} + +KviIrcUserEntry::~KviIrcUserEntry() +{ + if(m_pAvatar)delete m_pAvatar; +} + +void KviIrcUserEntry::setAvatar(KviAvatar * av) +{ + if(m_pAvatar)delete m_pAvatar; + m_pAvatar = av; +} + +KviAvatar * KviIrcUserEntry::forgetAvatar() +{ + KviAvatar * ret = m_pAvatar; + m_pAvatar = 0; + return ret; +} + +KviIrcUserDataBase::KviIrcUserDataBase() +: QObject() +{ + // we expect a maximum of ~4000 users (= ~16 KB array on a 32 bit machine) + // ...after that we will loose in performance + // ... well...4000 users is a really big number...say 6-7 really big channels + // (4001 is prime) + // up to 12000 users we will have a reasonably fast access. + // the performance increase since kvirc versions < 3.0.0 + // is really big anyway (there was a linear list instead of a hash!!!) + + m_pDict = new KviPointerHashTable<QString,KviIrcUserEntry>(4001,false); + m_pDict->setAutoDelete(true); + setupConnectionWithReguserDb(); +} + +KviIrcUserDataBase::~KviIrcUserDataBase() +{ + delete m_pDict; +} + +bool KviIrcUserDataBase::haveCustomColor(const QString & nick) +{ + KviIrcUserEntry *u = find(nick); + if(!u) return false; + if( u->m_szLastRegisteredMatchNick!=nick) + registeredUser(nick); + if(!u->m_bNotFoundRegUserLoockup) + { + return u->m_bUseCustomColor; + } + return false; +} + +QColor* KviIrcUserDataBase::customColor(const QString & nick) +{ + KviIrcUserEntry *u = find(nick); + if(!u) return 0; + if( u->m_szLastRegisteredMatchNick!=nick) + registeredUser(nick); + + if(!u->m_bNotFoundRegUserLoockup) + { + return &(u->m_cachedColor); + } + return 0; +} + + +KviRegisteredUser* KviIrcUserDataBase::registeredUser(const QString & nick,const QString & user,const QString & host) +{ + if(nick.isEmpty()) return 0; + KviIrcUserEntry *u = find(nick); + if(!u) return g_pRegisteredUserDataBase->findMatchingUser(nick,user,host); + KviRegisteredUser* pUser=0; + + if(u->m_bNotFoundRegUserLoockup && u->m_szLastRegisteredMatchNick==nick) + { + //cacheHit++; + //debug("cache hits/miss = %i/%i",cacheHit,cacheMiss); + return 0; + } + + if(!u->m_szRegisteredUserName.isEmpty() && u->m_szLastRegisteredMatchNick==nick) + { + pUser = g_pRegisteredUserDataBase->getUser(u->m_szRegisteredUserName); + //if(pUser) cacheHit++; + } + + if(!pUser) { + //user renamed or it is a first loockup + if(u->hasHost() && u->hasUser()) + { + pUser=g_pRegisteredUserDataBase->findMatchingUser(nick,u->user(),u->host()); + //cacheMiss++; + if(pUser) { + u->m_szLastRegisteredMatchNick=nick; + u->m_szRegisteredUserName=pUser->name(); + + u->m_bUseCustomColor=pUser->getBoolProperty("useCustomColor"); + QString szTmp=pUser->getProperty("customColor"); + KviStringConversion::fromString(szTmp,u->m_cachedColor); + + u->m_bNotFoundRegUserLoockup=false; //to be shure + } else { + u->m_szLastRegisteredMatchNick=nick; + u->m_bNotFoundRegUserLoockup=true; + } + } + } + +// debug("cache hits/miss = %i/%i",cacheHit,cacheMiss); + return pUser; +} + +KviRegisteredUser* KviIrcUserDataBase::registeredUser(const QString & nick) +{ + if(nick.isEmpty()) return 0; + KviIrcUserEntry *u = find(nick); + if(!u) return 0; + return registeredUser(nick,u->user(),u->host()); +} + +void KviIrcUserDataBase::clear() +{ + delete m_pDict; + m_pDict = new KviPointerHashTable<QString,KviIrcUserEntry>(4001,false); + m_pDict->setAutoDelete(true); +} + +KviIrcUserEntry * KviIrcUserDataBase::insertUser(const QString &nick,const QString &user,const QString &hostname) +{ + KviIrcUserEntry * e = m_pDict->find(nick); + if(e) + { + e->m_nRefs++; + if(e->m_szUser.isEmpty()) + { + e->m_szUser = user; + e->m_szHost = hostname; + } + } else { + e = new KviIrcUserEntry(user,hostname); + m_pDict->insert(nick,e); + } + return e; +} + +void KviIrcUserDataBase::removeUser(const QString &nick,KviIrcUserEntry * e) +{ + e->m_nRefs--; + if(e->m_nRefs == 0)m_pDict->remove(nick); +} + +void KviIrcUserDataBase::setupConnectionWithReguserDb() +{ + connect(g_pRegisteredUserDataBase,SIGNAL(userRemoved(const QString&)),this,SLOT(registeredUserRemoved(const QString&))); + connect(g_pRegisteredUserDataBase,SIGNAL(userChanged(const QString&)),this,SLOT(registeredUserChanged(const QString&))); + connect(g_pRegisteredUserDataBase,SIGNAL(userAdded(const QString&)),this,SLOT(registeredUserAdded(const QString&))); + connect(g_pRegisteredUserDataBase,SIGNAL(databaseCleared()),this,SLOT(registeredDatabaseCleared())); + + +} + +void KviIrcUserDataBase::registeredUserRemoved(const QString& user) +{ + KviPointerHashTableIterator<QString,KviIrcUserEntry> it( *m_pDict ); + for( ; it.current(); ++it ) + { + if(it.current()->m_szRegisteredUserName==user) + { + it.current()->m_szRegisteredUserName=""; + it.current()->m_bNotFoundRegUserLoockup=false; + } + } +} + +void KviIrcUserDataBase::registeredUserChanged(const QString& user) +{ + //the same as above + KviPointerHashTableIterator<QString,KviIrcUserEntry> it( *m_pDict ); + for( ; it.current(); ++it ) + { + if(it.current()->m_szRegisteredUserName==user) + { + it.current()->m_szRegisteredUserName=""; + it.current()->m_bNotFoundRegUserLoockup=false; + } + } +} + +void KviIrcUserDataBase::registeredUserAdded(const QString& user) +{ + KviPointerHashTableIterator<QString,KviIrcUserEntry> it( *m_pDict ); + for( ; it.current(); ++it ) + { + if(it.current()->m_szRegisteredUserName.isEmpty()) + { + it.current()->m_bNotFoundRegUserLoockup=false; + } + } +} + +void KviIrcUserDataBase::registeredDatabaseCleared() +{ + KviPointerHashTableIterator<QString,KviIrcUserEntry> it( *m_pDict ); + for( ; it.current(); ++it ) + { + it.current()->m_szRegisteredUserName=""; + it.current()->m_bNotFoundRegUserLoockup=false; + } +} diff --git a/src/kvilib/irc/kvi_ircuserdb.h b/src/kvilib/irc/kvi_ircuserdb.h new file mode 100644 index 00000000..bdf7c51c --- /dev/null +++ b/src/kvilib/irc/kvi_ircuserdb.h @@ -0,0 +1,145 @@ +#ifndef _KVI_IRCUSERDB_H_ +#define _KVI_IRCUSERDB_H_ + +//============================================================================= +// +// File : kvi_ircuserdb.h +// Creation date : Mon Jul 31 2000 20:59:12 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include "kvi_pointerhashtable.h" + +#include "kvi_string.h" +#include "kvi_avatar.h" +#include "kvi_regusersdb.h" + +class KviIrcUserDataBase; + +class KVILIB_API KviIrcUserEntry +{ + friend class KviIrcUserDataBase; +public: + KviIrcUserEntry(const QString &user,const QString &host); + ~KviIrcUserEntry(); + + enum Gender { + Male = 0, + Female = 1, + Unknown = 3 + }; + +protected: + QString m_szUser; + QString m_szHost; + + QString m_szServer; + QString m_szRealName; + int m_iHops; + Gender m_eGender; + + bool m_bAway; + + KviAvatar * m_pAvatar; + + int m_nRefs; + bool m_bBot; + + bool m_bNotFoundRegUserLoockup; + QString m_szRegisteredUserName; + QString m_szLastRegisteredMatchNick; + + QColor m_cachedColor; + bool m_bUseCustomColor; +public: + Gender gender() { return m_eGender; }; + void setBot(bool bIsBot) { m_bBot = bIsBot; }; + bool isBot() { return m_bBot; }; + void setGender(Gender g) { m_eGender=g; }; + void setUser(const QString &user) { m_szUser = user; }; + bool hasUser() { return (!m_szUser.isEmpty()); }; + void setHost(const QString &host) { m_szHost = host; }; + bool hasHost() { return (!m_szHost.isEmpty()); }; + void setServer(const QString &serv) { m_szServer = serv; }; + void setRealName(const QString &rn); + void setHops(int hops) { m_iHops = hops; }; + const QString &user() { return m_szUser; }; + const QString &host() { return m_szHost; }; + bool hasServer() { return (!m_szServer.isEmpty()); }; + const QString &server() { return m_szServer; }; + bool hasRealName() { return (!m_szRealName.isEmpty()); }; + const QString &realName() { return m_szRealName; }; + bool hasHops() { return m_iHops >= 0; }; + int hops() { return m_iHops; }; + KviAvatar * avatar() { return m_pAvatar; }; + int nRefs() { return m_nRefs; }; + bool isAway() const { return m_bAway; }; + void setAway(bool bAway) { m_bAway = bAway; }; + // warning! the ownership passes to this class! + void setAvatar(KviAvatar * av = 0); + KviAvatar * forgetAvatar(); +}; + +// from least powerful to most powerful +#define KVI_USERFLAG_USEROP 1 +#define KVI_USERFLAG_VOICE 2 +#define KVI_USERFLAG_HALFOP 4 +#define KVI_USERFLAG_OP 8 +#define KVI_USERFLAG_CHANADMIN 16 +#define KVI_USERFLAG_CHANOWNER 32 + +// 1 | 2 | 4 | 8 | 16 | 32 +#define KVI_USERFLAG_MASK (KVI_USERFLAG_OP | KVI_USERFLAG_VOICE | KVI_USERFLAG_HALFOP | KVI_USERFLAG_CHANADMIN | KVI_USERFLAG_USEROP | KVI_USERFLAG_CHANOWNER) +// at the moment all the flags are usermodes +#define KVI_USERFLAG_MODEMASK KVI_USERFLAG_MASK + + +class KVILIB_API KviIrcUserDataBase : public QObject +{ + Q_OBJECT +public: + KviIrcUserDataBase(); + ~KviIrcUserDataBase(); +private: + KviPointerHashTable<QString,KviIrcUserEntry> * m_pDict; +public: + void clear(); + KviIrcUserEntry * insertUser(const QString &nick,const QString &user,const QString &hostname); + KviIrcUserEntry * find(const QString &nick){ return m_pDict->find(nick); }; + void removeUser(const QString &nick,KviIrcUserEntry * e); + KviPointerHashTable<QString,KviIrcUserEntry> * dict(){ return m_pDict; }; + + KviRegisteredUser* registeredUser(const QString & nick); + KviRegisteredUser* registeredUser(const QString & nick,const QString & user,const QString & host); + + bool haveCustomColor(const QString & nick); + QColor* customColor(const QString & nick); + + void setupConnectionWithReguserDb(); +protected slots: + void registeredUserRemoved(const QString&); + void registeredUserChanged(const QString&); + void registeredUserAdded (const QString&); + void registeredDatabaseCleared(); +}; + +#endif //_KVI_IRCUSERDB_H_ diff --git a/src/kvilib/irc/kvi_mirccntrl.cpp b/src/kvilib/irc/kvi_mirccntrl.cpp new file mode 100644 index 00000000..fbf3c2d3 --- /dev/null +++ b/src/kvilib/irc/kvi_mirccntrl.cpp @@ -0,0 +1,307 @@ +// +// File : kvi_mirccntrl.cpp +// Creation date : Sat Aug 31 17:07:36 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + +#define _KVI_MIRCCNTRL_CPP_ + +#include "kvi_mirccntrl.h" + +KVILIB_API const char * getColorBytes(const char *data_ptr,unsigned char *byte_1,unsigned char *byte_2) +{ + // + // Scans the data_ptr for a mIrc color code XX,XX + // and fills the color values in the two bytes + // + + //First we can have a digit or a coma + if(((*data_ptr >= '0') && (*data_ptr <='9'))) + { + //Something interesting ok. + (*byte_1)=(*data_ptr)-'0'; //store the code + data_ptr++; //and check the next + if(((*data_ptr >= '0') && (*data_ptr <= '9'))||(*data_ptr==',')) + { + //Yes we can understand it + if(*data_ptr==',') + { + //A coma , need to check for background + data_ptr++; + } else { + //A number + (*byte_1)=((((*byte_1)*10)+((*data_ptr)-'0'))%16); + data_ptr++; + if(*data_ptr==',') + { + //A coma , need to check for background + data_ptr++; + } else { + //Senseless return + (*byte_2)=KVI_NOCHANGE; + return data_ptr; + } + } + } else { + //Senseless character control code OK and return + (*byte_2)=KVI_NOCHANGE; + return data_ptr; + } + } else { + //Senseless character : only a CTRL+K code + (*byte_1)=KVI_NOCHANGE; + (*byte_2)=KVI_NOCHANGE; + return data_ptr; + } + + if((*data_ptr >= '0') && (*data_ptr <='9')) + { + //Background , a color code + (*byte_2)=(*data_ptr)-'0'; + data_ptr++; + if((*data_ptr >= '0') && (*data_ptr <='9')) + { + (*byte_2)=((((*byte_2)*10)+((*data_ptr)-'0'))%16); + data_ptr++; + } + return data_ptr; + } else { + (*byte_2)=KVI_NOCHANGE; + return data_ptr-1; + } +} + + +KVILIB_API const kvi_wchar_t * getColorBytesW(const kvi_wchar_t *data_ptr,unsigned char *byte_1,unsigned char *byte_2) +{ + // + // Scans the data_ptr for a mIrc color code XX,XX + // and fills the color values in the two bytes + // + + //First we can have a digit or a coma + if(((*data_ptr >= '0') && (*data_ptr <='9'))) + { + //Something interesting ok. + (*byte_1)=((*data_ptr)-'0'); //store the code + data_ptr++; //and check the next + if(((*data_ptr >= '0') && (*data_ptr <= '9'))||(*data_ptr==',')) + { + //Yes we can understand it + if(*data_ptr==',') + { + //A coma , need to check for background + data_ptr++; + } else { + //A number + //(*byte_1)=((((*byte_1)*10)+((*data_ptr)-'0'))%16); + (*byte_1)=((*byte_1)*10)+((*data_ptr)-'0'); + data_ptr++; + if(*data_ptr==',') + { + //A coma , need to check for background + data_ptr++; + } else { + //Senseless return + (*byte_2)=KVI_NOCHANGE; + return data_ptr; + } + } + } else { + //Senseless character control code OK and return + (*byte_2)=KVI_NOCHANGE; + return data_ptr; + } + } else { + //Senseless character : only a CTRL+K code + (*byte_1)=KVI_NOCHANGE; + (*byte_2)=KVI_NOCHANGE; + return data_ptr; + } + + if((*data_ptr >= '0') && (*data_ptr <='9')) + { + //Background , a color code + (*byte_2)=(*data_ptr)-'0'; + data_ptr++; + if((*data_ptr >= '0') && (*data_ptr <='9')) + { + //(*byte_2)=((((*byte_2)*10)+((*data_ptr)-'0'))%16); + (*byte_2)=((*byte_2)*10)+((*data_ptr)-'0'); + data_ptr++; + } + return data_ptr; + } else { + (*byte_2)=KVI_NOCHANGE; + return data_ptr-1; + } +} + +KVILIB_API unsigned int getUnicodeColorBytes(const QString &szData,unsigned int charIdx,unsigned char *byte_1,unsigned char *byte_2) +{ + // + // Scans the szData for a mIrc color code XX,XX + // and fills the color values in the two bytes + // + + if(charIdx >= szData.length()) + { + (*byte_1)=KVI_NOCHANGE; + (*byte_2)=KVI_NOCHANGE; + return charIdx; + } + + unsigned short c = szData[(int)charIdx].unicode(); + + //First we can have a digit or a coma + if(((c < '0') || (c > '9'))) + { + // senseless : only a CTRL+K code + (*byte_1)=KVI_NOCHANGE; + (*byte_2)=KVI_NOCHANGE; + return charIdx; + } + + //Something interesting ok. + (*byte_1)=c - '0'; //store the code + charIdx++; + if(charIdx >= szData.length()) + { + (*byte_2)=KVI_NOCHANGE; + return charIdx; + } + + c = szData[(int)charIdx].unicode(); + + if(((c < '0') || (c > '9')) && (c != ',')) + { + (*byte_2)=KVI_NOCHANGE; + return charIdx; + } + + + if((c >= '0') && (c <= '9')) + { + (*byte_1)=(((*byte_1)*10)+(c-'0'))%16; + charIdx++; + if(charIdx >= szData.length()) + { + (*byte_2)=KVI_NOCHANGE; + return charIdx; + } + c = szData[(int)charIdx].unicode(); + } + + if(c == ',') + { + charIdx++; + if(charIdx >= szData.length()) + { + (*byte_2)=KVI_NOCHANGE; + return charIdx; + } + c = szData[(int)charIdx].unicode(); + } else { + (*byte_2)=KVI_NOCHANGE; + return charIdx; + } + + if((c < '0') || (c > '9')) + { + (*byte_2)=KVI_NOCHANGE; + if(szData[(int)(charIdx-1)].unicode()==',') + return charIdx-1; + else + return charIdx; + } + + //Background , a color code + (*byte_2)=c-'0'; + charIdx++; + if(charIdx >= szData.length())return charIdx; + c = szData[(int)charIdx].unicode(); + + if((c >= '0') && (c <='9')) + { + (*byte_2)=(((*byte_2)*10)+(c-'0'))%16; + charIdx++; + } + + return charIdx; +} + + +namespace KviMircCntrl +{ + QString stripControlBytes(const QString &szData) + { + QString ret; + + int i = 0; + int l = szData.length(); + int begin = 0; + unsigned char b1; + unsigned char b2; + while(i < l) + { + switch(szData[i].unicode()) + { + case KVI_TEXT_UNDERLINE: + case KVI_TEXT_BOLD: + case KVI_TEXT_RESET: + case KVI_TEXT_REVERSE: + case KVI_TEXT_CRYPTESCAPE: + case KVI_TEXT_CTCP: + if(i != begin) + ret += szData.mid(begin,i - begin); + i++; + begin = i; + break; + case KVI_TEXT_COLOR: + if(i != begin) + ret += szData.mid(begin,i - begin); + i++; + i = getUnicodeColorBytes(szData,i,&b1,&b2); + begin = i; + break; + case KVI_TEXT_ICON: + if(i != begin) + ret += szData.mid(begin,i - begin); + i++; + while(i < l) + { + if(szData[i].unicode() == ' ')break; + else i++; + } + begin = i; + break; + default: + i++; + break; + } + } + if(i != begin) + ret += szData.mid(begin,i - begin); + return ret; + } +} + + diff --git a/src/kvilib/irc/kvi_mirccntrl.h b/src/kvilib/irc/kvi_mirccntrl.h new file mode 100644 index 00000000..c3028568 --- /dev/null +++ b/src/kvilib/irc/kvi_mirccntrl.h @@ -0,0 +1,163 @@ +#ifndef _KVI_MIRCCNTRL_H_ +#define _KVI_MIRCCNTRL_H_ + +//============================================================================= +// +// File : kvi_mirccntrl.h +// Creation date : Thu Jun 29 2000 21:06:55 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// This file contains non-customizable standards +// +// Better do not touch this :) +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_string.h" + +// +// mIrc color codes +// + +#define KVI_WHITE 0 +#define KVI_BLACK 1 +#define KVI_DARKBLUE 2 +#define KVI_DARKGREEN 3 +#define KVI_RED 4 +#define KVI_DARKRED 5 +#define KVI_DARKVIOLET 6 +#define KVI_ORANGE 7 +#define KVI_YELLOW 8 +#define KVI_LIGHTGREEN 9 +#define KVI_BLUEMARINE 10 +#define KVI_LIGHTBLUE 11 +#define KVI_BLUE 12 +#define KVI_LIGHTVIOLET 13 +#define KVI_DARKGRAY 14 +#define KVI_LIGHTGRAY 15 + +#define KVI_MIRCCOLOR_MAX_FOREGROUND 15 +#define KVI_MIRCCOLOR_MAX_BACKGROUND 15 + +// +// Non-standard color codes for KviIrcView +// +#define KVI_TRANSPARENT 100 +#define KVI_NOCHANGE 101 +// +// Internal control codes for KviIrcView +// +// (Totally artificial and internal to KviIrcView) +#define KVI_TEXT_ESCAPE 0x04 +#define KVI_TEXT_UNESCAPE 0x05 +#define KVI_TEXT_UNICON 0x06 +//#define KVI_TEXT_EMOTICON 0x07 + +// ASCII Stuff: the following defines are meant to be escape sequences +// that can go thru an IRC connection + +// The following table is a 30-minute analysis of the escape characters commonly used over the IRC protocol... +// created when looking for a good placement for the CRYPT escape char in KVirc. +// I guess that the best chars to be used were FS,GS,RS,US,DC1,DC2,DC3,DC4...they have the "less defined" +// meaning as ASCII control chars. +// mmmh... :) + +// ASCII IRC Meaning +// 000 NUL Null (Cannot be assigned) +// 001 SOH Start of heading ( CTCP Escape: only beginning of the message ) +// 002 STX Start of text ( Bold text ) +// 003 ETX End of text ( Color text escape sequence ) +// 004 EOT End of transmission ( Assigned internally (escape) ) +// 005 ENQ Enquiry (WRU: Who are you) ( Assigned internally (unescape) ) +// 006 ACK Acknowledge (Not so good, but can be used as last resource) +// 007 BEL Bell ( Recognized as bell by terminals and IRCII ) (Used also by some IRC servers) +// 008 BS Backspace (Should not be assigned: terminal control) +// 009 HT Horizontal tabulation (Should not be assigned: terminal control) +// 010 LF Line feed (Should not be assigned: terminal control) +// 011 VT Vertical tabulation (Should not be assigned: terminal control) +// 012 FF Form feed (Should not be assigned: terminal control) +// 013 CR Carriage return (Should not be assigned: terminal control) +// 014 SO Shift out (Should not be assigned: terminal control) +// 015 SI Shift in ( Resets Bold,Color,Underline and Reverse ) (Conflicting with terminal control) +// 016 DLE Data link escape (Decent , can be assigned) +// 017 DC1 Device control 1 (Good to be assigned) +// 018 DC2 Device control 2 (Good to be assigned) +// 019 DC3 Device control 3 (Good to be assigned) +// 020 DC4 Device control 4 (Good to be assigned) +// 021 NAK Negative acknowledge (Not so good, but could be used as last resource) +// 022 SYN Synchronous idle ( Reverse text ) +// 023 ETB End of transmission block (Decent , can be assigned) +// 024 CAN Cancel (Should not be assigned: terminal control) +// 025 EM End of medium (Decent , can be assigned) +// 026 SUB Substitute (Should not be assigned: terminal control) +// 027 ESC Escape (Should not be assigned: terminal control) +// 028 FS File separator (Excellent , should be used as first candidate) +// 029 GS Group separator ( ICONS Escape: beginning of a word ) +// 030 RS Record separator ( CRYPT Escape: only beginning of the message ) +// 031 US Unit separator ( Underline text ) + + +// +// mIrc control codes +// + +//31 (0001 1111) US (Unit separator) +#define KVI_TEXT_UNDERLINE 0x1f +//2 (0000 0010) STX (Start of text) +#define KVI_TEXT_BOLD 0x02 +//15 (0000 1111) SI (Shift in) +#define KVI_TEXT_RESET 0x0f +//22 (0001 0110) SYN (Synchronous idle) +#define KVI_TEXT_REVERSE 0x16 +//3 (0000 0011) ETX (End of text) +#define KVI_TEXT_COLOR 0x03 + +// +// Irc control codes +// +//1 (0000 0001) SOH (Start of heading) +#define KVI_TEXT_CTCP 0x01 + +// +// KVirc added control codes +// +//30 (0001 1110) RS (Record separator) +#define KVI_TEXT_CRYPTESCAPE 0x1e +//29 (0001 1101) GS (Group separator) +#define KVI_TEXT_ICON 0x1d + +#ifndef _KVI_MIRCCNTRL_CPP_ + extern KVILIB_API const char * getColorBytes(const char *data_ptr,unsigned char *byte_1,unsigned char *byte_2); + extern KVILIB_API const kvi_wchar_t * getColorBytesW(const kvi_wchar_t *data_ptr,unsigned char *byte_1,unsigned char *byte_2); + extern KVILIB_API unsigned int getUnicodeColorBytes(const QString &szData,unsigned int charIdx,unsigned char *byte_1,unsigned char *byte_2); + inline const QChar * getUnicodeColorBytes(const QChar *pData,unsigned char *byte_1,unsigned char *byte_2) + { return (QChar *)getColorBytesW((const kvi_wchar_t *)pData,byte_1,byte_2); }; + +#endif + +namespace KviMircCntrl +{ + KVILIB_API QString stripControlBytes(const QString &szData); +} + + +#endif //_KVI_MIRCCNTRL_H_ diff --git a/src/kvilib/irc/kvi_nickserv.cpp b/src/kvilib/irc/kvi_nickserv.cpp new file mode 100644 index 00000000..a1809f84 --- /dev/null +++ b/src/kvilib/irc/kvi_nickserv.cpp @@ -0,0 +1,312 @@ +//============================================================================= +// +// File : kvi_nickserv.cpp +// Creation date : Thu Aug 09 2001 17:44:56 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_nickserv.h" +#include "kvi_config.h" +#include "kvi_ircmask.h" + +#include <qregexp.h> + + + +/* + @doc: nickserv_proto + @title: + Authentication with NickServ + @keyterms: + NickServ, automatic authentication with NickServ + @type: + generic + @short: + Automatic authentication with NickServ + @body: + KVIrc supports automatic authentication with the NickServ service.[br] + This service is commonly implemented on major IRC networks: basically + it is a program that allows users to register their nickname and protect + it from being stolen by others.[br] The NickServ protocol is + not standardized (at the time that I'm writing this doc) and automatic + authentication is a pure experimental protocol.[br] + Once you get on IRC with a registered nickname , the NickServ will + ask you for identification by sending you a NOTICE.[br] + The message will look in a way similar to the following:[br] + <b>You're using a registered nickname: if this is your nick, + please type /msg NickServ IDENTIFY password, otherwise please + choose another nickname</b>.[br] + The message is often broken in two or three lines of text.[br] + Please note that many network policies suggest to avoid automatic authentication + with NickServ.[br]I have implemented it because I know that it works on the networks + that I'm usually on.[br]You have to check that this protocol works on your network and + then eventually use it at your own risk.[br] +*/ + + +// FIXME: The doc above is a bit outdated , fix it + +KviNickServRuleSet::KviNickServRuleSet() +: KviHeapObject() +{ + m_bEnabled = false; + m_pRules = 0; +} + +KviNickServRuleSet::KviNickServRuleSet(const KviNickServRuleSet &s) +{ + m_pRules = 0; + copyFrom(s); +} + + +KviNickServRuleSet::~KviNickServRuleSet() +{ + if(m_pRules)delete m_pRules; +} + +void KviNickServRuleSet::save(KviConfig * cfg,const QString &prefix) +{ + if(!m_pRules)return; // nothing to save + if(m_pRules->isEmpty())return; // should never happen anyway + QString tmp; + if(m_bEnabled) + { + KviQString::sprintf(tmp,"%QNSEnabled",&prefix); + cfg->writeEntry(tmp,m_bEnabled); + } + KviQString::sprintf(tmp,"%QNSRules",&prefix); + cfg->writeEntry(tmp,m_pRules->count()); + int idx = 0; + for(KviNickServRule * r = m_pRules->first();r;r = m_pRules->next()) + { + KviQString::sprintf(tmp,"%QNSRule%d_",&prefix,idx); + r->save(cfg,tmp); + idx++; + } +} + +KviNickServRuleSet * KviNickServRuleSet::load(KviConfig * cfg,const QString &prefix) +{ + QString tmp; + KviQString::sprintf(tmp,"%QNSRules",&prefix); + unsigned int cnt = cfg->readUIntEntry(tmp,0); + if(cnt == 0)return 0; + KviNickServRuleSet * s = new KviNickServRuleSet(); + if(s->loadPrivate(cfg,prefix,cnt))return s; + delete s; + return 0; +} + +void KviNickServRuleSet::load(const QString &szConfigFile) +{ + clear(); + KviConfig cfg(szConfigFile,KviConfig::Read); + + QString tmp; + KviQString::sprintf(tmp,"NSRules"); + unsigned int cnt = cfg.readUIntEntry(tmp,0); + if(cnt == 0)return; + loadPrivate(&cfg,QString(""),cnt); +} + +void KviNickServRuleSet::save(const QString &szConfigFile) +{ + KviConfig cfg(szConfigFile,KviConfig::Write); + cfg.clear(); + save(&cfg,QString("")); +} + +bool KviNickServRuleSet::loadPrivate(KviConfig * cfg,const QString &prefix,unsigned int nEntries) +{ + if(m_pRules)m_pRules->clear(); + else { + m_pRules = new KviPointerList<KviNickServRule>; + m_pRules->setAutoDelete(true); + } + + if(nEntries != 0) + { + QString tmp; + KviQString::sprintf(tmp,"%QNSEnabled",&prefix); + m_bEnabled = cfg->readBoolEntry(tmp,false); + for(unsigned int u=0;u<nEntries;u++) + { + KviQString::sprintf(tmp,"%QNSRule%u_",&prefix,u); + KviNickServRule * r = new KviNickServRule(); + if(!r->load(cfg,tmp))delete r; + else m_pRules->append(r); + } + } + + if(m_pRules->isEmpty()) + { + m_bEnabled = false; + delete m_pRules; + m_pRules = 0; + return false; + } + return true; +} + +void KviNickServRuleSet::clear() +{ + if(m_pRules) + { + delete m_pRules; + m_pRules = 0; + } + m_bEnabled = false; +} + +void KviNickServRuleSet::addRule(KviNickServRule * r) +{ + if(!m_pRules) + { + m_pRules = new KviPointerList<KviNickServRule>; + m_pRules->setAutoDelete(true); + } + m_pRules->append(r); +} + +KviNickServRuleSet * KviNickServRuleSet::createInstance() +{ + return new KviNickServRuleSet(); +} + + +KviNickServRule * KviNickServRuleSet::matchRule(const QString &szNick,const KviIrcMask *nickServ,const QString &szMsg,const QString &szServer) +{ + if(!m_pRules)return 0; + for(KviNickServRule *r = m_pRules->first();r;r = m_pRules->next()) + { + if(!KviQString::matchStringCI(r->registeredNick(),szNick,false,true)) continue; + if(!szServer.isEmpty()) + { +#ifdef COMPILE_USE_QT4 + QRegExp res(r->serverMask(),Qt::CaseInsensitive,QRegExp::Wildcard); +#else + QRegExp res(r->serverMask(),false,true); +#endif + if(!res.exactMatch(szServer))continue; + } + if(!nickServ->matchedBy(KviIrcMask(r->nickServMask())))continue; +#ifdef COMPILE_USE_QT4 + QRegExp re(r->messageRegexp(),Qt::CaseInsensitive,QRegExp::Wildcard); +#else + QRegExp re(r->messageRegexp(),false,true); +#endif + if(re.exactMatch(szMsg))return r; + } + return 0; +} + +void KviNickServRuleSet::copyFrom(const KviNickServRuleSet &src) +{ + if(src.m_pRules) + { + if(m_pRules)m_pRules->clear(); + else { + m_pRules = new KviPointerList<KviNickServRule>; + m_pRules->setAutoDelete(true); + } + for(KviNickServRule * r = src.m_pRules->first();r;r = src.m_pRules->next()) + { + KviNickServRule * c = new KviNickServRule(); + c->copyFrom(*r); + m_pRules->append(c); + } + if(m_pRules->isEmpty()) + { + m_bEnabled = false; + delete m_pRules; + m_pRules = 0; + } else { + m_bEnabled = src.m_bEnabled; + } + } else { + m_bEnabled = false; + if(m_pRules) + { + delete m_pRules; + m_pRules = 0; + } + } +} + + +void KviNickServRule::copyFrom(const KviNickServRule &src) +{ + m_szRegisteredNick = src.m_szRegisteredNick; + m_szNickServMask = src.m_szNickServMask; + m_szMessageRegexp = src.m_szMessageRegexp; + m_szIdentifyCommand = src.m_szIdentifyCommand; + m_szServerMask = src.m_szServerMask; +} + +void KviNickServRule::save(KviConfig * cfg,const QString &prefix) +{ + QString tmp; + KviQString::sprintf(tmp,"%QRegisteredNick",&prefix); + cfg->writeEntry(tmp,m_szRegisteredNick); + KviQString::sprintf(tmp,"%QNickServMask",&prefix); + cfg->writeEntry(tmp,m_szNickServMask); + KviQString::sprintf(tmp,"%QMessageRegexp",&prefix); + cfg->writeEntry(tmp,m_szMessageRegexp); + KviQString::sprintf(tmp,"%QIdentifyCommand",&prefix); + cfg->writeEntry(tmp,m_szIdentifyCommand); + KviQString::sprintf(tmp,"%QServerMask",&prefix); + cfg->writeEntry(tmp,m_szServerMask); +} + +bool KviNickServRule::load(KviConfig * cfg,const QString &prefix) +{ + QString tmp; + KviQString::sprintf(tmp,"%QRegisteredNick",&prefix); + m_szRegisteredNick = KviQString::trimmed(cfg->readQStringEntry(tmp)); + if(m_szRegisteredNick.isEmpty())return false; + KviQString::sprintf(tmp,"%QNickServMask",&prefix); + m_szNickServMask = cfg->readQStringEntry(tmp); + if(m_szNickServMask.isEmpty())return false; + KviQString::sprintf(tmp,"%QServerMask",&prefix); + m_szServerMask = cfg->readQStringEntry(tmp,QString::null); + KviQString::sprintf(tmp,"%QMessageRegexp",&prefix); + m_szMessageRegexp = cfg->readQStringEntry(tmp); + if(m_szMessageRegexp.isEmpty())return false; + KviQString::sprintf(tmp,"%QIdentifyCommand",&prefix); + m_szIdentifyCommand = cfg->readQStringEntry(tmp); + return !m_szIdentifyCommand.isEmpty(); +} + +KviNickServRule * KviNickServRule::createInstance(const QString &szRegisteredNick, + const QString &szNickServMask, + const QString &szMessageRegexp, + const QString &szIdentifyCommand, + const QString &szServerMask) +{ + return new KviNickServRule(szRegisteredNick,szNickServMask,szMessageRegexp,szIdentifyCommand,szServerMask); +} + + + + diff --git a/src/kvilib/irc/kvi_nickserv.h b/src/kvilib/irc/kvi_nickserv.h new file mode 100644 index 00000000..105eed1c --- /dev/null +++ b/src/kvilib/irc/kvi_nickserv.h @@ -0,0 +1,112 @@ +#ifndef _KVI_NICKSERV_H_ +#define _KVI_NICKSERV_H_ +//============================================================================= +// +// File : kvi_nickserv.h +// Creation date : Thu Aug 09 2001 16:43:56 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" +#include "kvi_heapobject.h" +#include "kvi_pointerlist.h" + +class KviConfig; +class KviIrcMask; + +class KVILIB_API KviNickServRule : public KviHeapObject +{ +protected: + QString m_szRegisteredNick; // my registered nickname + QString m_szNickServMask; // the NickServ service mask + QString m_szMessageRegexp; // the NickServ message regexp + QString m_szIdentifyCommand; // the IDENTIFY command to send to server + QString m_szServerMask; // the mask that the server must match (not used in per-network rules) +public: + KviNickServRule() : KviHeapObject() {}; + KviNickServRule( + const QString &szRegisteredNick, + const QString &szNickServMask, + const QString &szMessageRegexp, + const QString &szIdentifyCommand, + const QString &szServerMask = QString::null) + : KviHeapObject(), + m_szRegisteredNick(szRegisteredNick), + m_szNickServMask(szNickServMask), + m_szMessageRegexp(szMessageRegexp), + m_szIdentifyCommand(szIdentifyCommand), + m_szServerMask(szServerMask) + {}; +public: + const QString & registeredNick() const { return m_szRegisteredNick; }; + const QString & nickServMask() const { return m_szNickServMask; }; + const QString & messageRegexp() const { return m_szMessageRegexp; }; + const QString & identifyCommand() const { return m_szIdentifyCommand; }; + const QString & serverMask() const { return m_szServerMask; }; + void setRegisteredNick(const QString &szRegisteredNick){ m_szRegisteredNick = szRegisteredNick; }; + void setNickServMask(const QString &szNickServMask){ m_szNickServMask = szNickServMask; }; + void setMessageRegexp(const QString &szMessageRegexp){ m_szMessageRegexp = szMessageRegexp; }; + void setIdentifyCommand(const QString &szIdentifyCommand){ m_szIdentifyCommand = szIdentifyCommand; }; + void setServerMask(const QString &szServerMask){ m_szServerMask = szServerMask; }; +public: + // avoid crashes under windows + static KviNickServRule * createInstance(const QString &szRegisteredNick, + const QString &szNickServMask, + const QString &szMessageRegexp, + const QString &szIdentifyCommand, + const QString &szServerMask = QString::null); + + void save(KviConfig * cfg,const QString &prefix); + // returns false if the loaded data has no sense + bool load(KviConfig * cfg,const QString &prefix); + void copyFrom(const KviNickServRule &src); +}; + +class KVILIB_API KviNickServRuleSet : public KviHeapObject +{ +public: + KviNickServRuleSet(); + KviNickServRuleSet(const KviNickServRuleSet &s); + ~KviNickServRuleSet(); +protected: + KviPointerList<KviNickServRule> * m_pRules; // FIXME: Replace with KviPointerHashTable<QString,KviPointerList> + bool m_bEnabled; +public: + // avoid crashes under windows + static KviNickServRuleSet * createInstance(); + void clear(); + bool isEnabled(){ return m_bEnabled; }; + void setEnabled(bool bEnabled){ m_bEnabled = bEnabled; }; + bool isEmpty(){ return m_pRules ? m_pRules->isEmpty() : true; }; + void addRule(KviNickServRule * r); + KviNickServRule * matchRule(const QString &szNick,const KviIrcMask *nickServ,const QString &szMsg,const QString &szServer = QString::null); + void copyFrom(const KviNickServRuleSet &src); + void load(const QString &szConfigFile); + void save(const QString &szConfigFile); + void save(KviConfig * cfg,const QString &prefix); + KviPointerList<KviNickServRule> * rules(){ return m_pRules; }; + static KviNickServRuleSet * load(KviConfig * cfg,const QString &prefix); +protected: + bool loadPrivate(KviConfig * cfg,const QString &prefix,unsigned int nEntries); +}; + + +#endif // _KVI_NICKSERV_H_ diff --git a/src/kvilib/irc/kvi_useridentity.cpp b/src/kvilib/irc/kvi_useridentity.cpp new file mode 100644 index 00000000..d4791333 --- /dev/null +++ b/src/kvilib/irc/kvi_useridentity.cpp @@ -0,0 +1,252 @@ +//============================================================================= +// +// File : kvi_useridentity.cpp +// Created on Sun 21 Jan 2007 04:31:47 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2007 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + +#include "kvi_useridentity.h" +#include "kvi_locale.h" +#include "kvi_defaults.h" + +// FIXME: Put here also the default away message, default away nick, default ctcp replies etc ? + +bool KviUserIdentity::load(KviConfig &cfg) +{ + m_szId = cfg.group(); + m_szNickName = cfg.readQStringEntry("NickName"); + m_szAltNickName1 = cfg.readQStringEntry("AltNickName1"); + m_szAltNickName2 = cfg.readQStringEntry("AltNickName2"); + m_szAltNickName3 = cfg.readQStringEntry("AltNickName3"); + m_szUserName = cfg.readQStringEntry("UserName"); + // FIXME: At least scramble the pass ? + m_szPassword = cfg.readQStringEntry("Password"); + KviPixmap def; + m_pixAvatar = cfg.readPixmapEntry("Avatar",def); + m_szPartMessage = cfg.readQStringEntry("PartMessage"); + m_szQuitMessage= cfg.readQStringEntry("QuitMessage"); + m_szAge = cfg.readQStringEntry("Age"); + m_szGender = cfg.readQStringEntry("Gender"); + m_szLocation = cfg.readQStringEntry("Location"); + m_szLanguages = cfg.readQStringEntry("Languages"); + m_szOtherInfo = cfg.readQStringEntry("OtherInfo"); + m_szUserMode = cfg.readQStringEntry("UserMode"); + m_szOnConnectCommand = cfg.readQStringEntry("OnConnectCommand"); + m_szOnLoginCommand = cfg.readQStringEntry("OnLoginCommand"); + return !(m_szId.isEmpty() || m_szNickName.isEmpty()); +} + +bool KviUserIdentity::save(KviConfig &cfg) +{ + cfg.setGroup(m_szId); + cfg.writeEntry("NickName",m_szNickName); + cfg.writeEntry("AltNickName1",m_szAltNickName1); + cfg.writeEntry("AltNickName2",m_szAltNickName2); + cfg.writeEntry("AltNickName3",m_szAltNickName3); + cfg.writeEntry("UserName",m_szUserName); + // FIXME: At least scramble the pass ? + cfg.writeEntry("Password",m_szPassword); + cfg.writeEntry("Avatar",m_pixAvatar); + cfg.writeEntry("PartMessage",m_szPartMessage); + cfg.writeEntry("QuitMessage",m_szQuitMessage); + cfg.writeEntry("Age",m_szAge); + cfg.writeEntry("Gender",m_szGender); + cfg.writeEntry("Location",m_szLocation); + cfg.writeEntry("Languages",m_szLanguages); + cfg.writeEntry("OtherInfo",m_szOtherInfo); + cfg.writeEntry("UserMode",m_szUserMode); + cfg.writeEntry("OnConnectCommand",m_szOnConnectCommand); + cfg.writeEntry("OnLoginCommand",m_szOnLoginCommand); + return true; +} + +void KviUserIdentity::copyFrom(const KviUserIdentity &src) +{ + m_szId = src.m_szId; + m_szNickName = src.m_szNickName; + + m_szAltNickName1 = src.m_szAltNickName1; + m_szAltNickName2 = src.m_szAltNickName2; + m_szAltNickName3 = src.m_szAltNickName3; + + m_szUserName = src.m_szUserName; + m_szRealName = src.m_szRealName; + m_szPassword = src.m_szPassword; + + m_pixAvatar = src.m_pixAvatar; + + m_szUserName = src.m_szUserName; + m_szRealName = src.m_szRealName; + m_szPassword = src.m_szPassword; + + m_pixAvatar = src.m_pixAvatar; + + m_szPartMessage = src.m_szPartMessage; + m_szQuitMessage = src.m_szQuitMessage; + + m_szAge = src.m_szAge; + m_szGender = src.m_szGender; + m_szLocation = src.m_szLocation; + m_szLanguages = src.m_szLanguages; + m_szOtherInfo = src.m_szOtherInfo; + + m_szUserMode = src.m_szUserMode; + + m_szOnConnectCommand = src.m_szOnConnectCommand; + m_szOnLoginCommand = src.m_szOnLoginCommand; +} + + +KviUserIdentityManager * KviUserIdentityManager::m_pInstance = 0; + +KviUserIdentityManager::KviUserIdentityManager() +: KviHeapObject() +{ + m_pIdentityDict = new KviPointerHashTable<QString,KviUserIdentity>(); + m_pIdentityDict->setAutoDelete(true); +} + +KviUserIdentityManager::~KviUserIdentityManager() +{ + delete m_pIdentityDict; +} + +void KviUserIdentityManager::init() +{ + if(m_pInstance)return; + m_pInstance = new KviUserIdentityManager(); +} + +void KviUserIdentityManager::done() +{ + if(!m_pInstance)return; + delete m_pInstance; + m_pInstance = 0; +} + +const KviUserIdentity * KviUserIdentityManager::defaultIdentity() +{ + KviUserIdentity * ret; + if(!m_szDefaultIdentity.isEmpty()) + { + ret = m_pIdentityDict->find(m_szDefaultIdentity); + if(ret)return ret; + } + + // the default identity is borken :/ + // grab the first one + KviPointerHashTableIterator<QString,KviUserIdentity> it(*m_pIdentityDict); + ret = it.current(); + if(ret) + { + m_szDefaultIdentity = ret->id(); + return ret; + } + // no identities available: create the default + ret = new KviUserIdentity(); + + ret->setId(__tr2qs("Default")); + ret->setNickName(KVI_DEFAULT_NICKNAME1); + ret->setAltNickName1(KVI_DEFAULT_NICKNAME2); + ret->setAltNickName2(KVI_DEFAULT_NICKNAME3); + ret->setAltNickName3(KVI_DEFAULT_NICKNAME4); + ret->setUserName(KVI_DEFAULT_USERNAME); + ret->setRealName(KVI_DEFAULT_REALNAME); + ret->setPartMessage(KVI_DEFAULT_PART_MESSAGE); + ret->setQuitMessage(KVI_DEFAULT_QUIT_MESSAGE); + + m_pIdentityDict->replace(ret->id(),ret); + + return ret; +} + +void KviUserIdentityManager::load(const QString &szFileName) +{ + m_pIdentityDict->clear(); + + KviConfig cfg(szFileName,KviConfig::Read); + + cfg.setGroup("KVIrc"); + + m_szDefaultIdentity = cfg.readQStringEntry("DefaultIdentity",""); + + KviConfigIterator it(*(cfg.dict())); + while(KviConfigGroup * grp = it.current()) + { + if(!KviQString::equalCI(it.currentKey(),"KVIrc")) + { + cfg.setGroup(it.currentKey()); + + KviUserIdentity * id = new KviUserIdentity(); + if(id->load(cfg)) + m_pIdentityDict->replace(id->id(),id); + else + delete id; + } + ++it; + } +} + +void KviUserIdentityManager::save(const QString &szFileName) +{ + KviConfig cfg(szFileName,KviConfig::Write); + cfg.clear(); + + cfg.setGroup("KVIrc"); + + cfg.writeEntry("DefaultIdentity",m_szDefaultIdentity); + + KviPointerHashTableIterator<QString,KviUserIdentity> it(*m_pIdentityDict); + while(KviUserIdentity * id = it.current()) + { + id->save(cfg); + ++it; + } +} + +void KviUserIdentityManager::copyFrom(KviUserIdentityManager * pWorkingCopy) +{ + m_pIdentityDict->clear(); + m_szDefaultIdentity = pWorkingCopy->m_szDefaultIdentity; + KviPointerHashTableIterator<QString,KviUserIdentity> it(*(pWorkingCopy->m_pIdentityDict)); + while(KviUserIdentity * id = it.current()) + { + KviUserIdentity * pNew = new KviUserIdentity(); + pNew->copyFrom(*id); + m_pIdentityDict->replace(pNew->id(),pNew); + ++it; + } +} + +KviUserIdentityManager * KviUserIdentityManager::createWorkingCopy() +{ + KviUserIdentityManager * pCopy = new KviUserIdentityManager(); + pCopy->copyFrom(this); + return pCopy; +} + +void KviUserIdentityManager::releaseWorkingCopy(KviUserIdentityManager * pWorkingCopy) +{ + if(pWorkingCopy)delete pWorkingCopy; +} + + diff --git a/src/kvilib/irc/kvi_useridentity.h b/src/kvilib/irc/kvi_useridentity.h new file mode 100644 index 00000000..c1018f1a --- /dev/null +++ b/src/kvilib/irc/kvi_useridentity.h @@ -0,0 +1,145 @@ +#ifndef _KVI_USERIDENTITY_H_ +#define _KVI_USERIDENTITY_H_ +//============================================================================= +// +// File : kvi_useridentity.h +// Created on Sun 21 Jan 2007 04:31:47 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2007 Szymon Stefanek <pragma at kvirc dot net> +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_pixmap.h" +#include "kvi_config.h" +#include "kvi_pointerhashtable.h" + +class KVILIB_API KviUserIdentity : public KviHeapObject +{ + friend class KviUserIdentityManager; +public: + KviUserIdentity() + : KviHeapObject() + { + } + ~KviUserIdentity() + { + } +protected: + QString m_szId; // the identity set name + + QString m_szNickName; + + QString m_szAltNickName1; + QString m_szAltNickName2; + QString m_szAltNickName3; + + QString m_szUserName; + QString m_szRealName; + QString m_szPassword; + + KviPixmap m_pixAvatar; + + QString m_szPartMessage; + QString m_szQuitMessage; + + QString m_szAge; + QString m_szGender; + QString m_szLocation; + QString m_szLanguages; + QString m_szOtherInfo; + + QString m_szUserMode; + + QString m_szOnConnectCommand; + QString m_szOnLoginCommand; +public: + const QString & id() const { return m_szId; }; + const QString & nickName() const { return m_szNickName; }; + const QString & altNickName1() const { return m_szAltNickName1; }; + const QString & altNickName2() const { return m_szAltNickName2; }; + const QString & altNickName3() const { return m_szAltNickName3; }; + const QString & userName() const { return m_szUserName; }; + const QString & password() const { return m_szPassword; }; + const KviPixmap & avatar() const { return m_pixAvatar; }; + const QString & partMessage() const { return m_szPartMessage; }; + const QString & quitMessage() const { return m_szQuitMessage; }; + const QString & age() const { return m_szAge; }; + const QString & gender() const { return m_szGender; }; + const QString & location() const { return m_szLocation; }; + const QString & languages() const { return m_szLanguages; }; + const QString & otherInfo() const { return m_szOtherInfo; }; + const QString & userMode() const { return m_szUserMode; }; + const QString & onConnectCommand() const { return m_szOnConnectCommand; }; + const QString & onLoginCommand() const { return m_szOnLoginCommand; }; + void setId(const QString &szId){ m_szId = szId; }; + void setNickName(const QString &szNickName){ m_szNickName = szNickName; }; + void setAltNickName1(const QString &szNickName){ m_szAltNickName1 = szNickName; }; + void setAltNickName2(const QString &szNickName){ m_szAltNickName2 = szNickName; }; + void setAltNickName3(const QString &szNickName){ m_szAltNickName3 = szNickName; }; + void setUserName(const QString &szUserName){ m_szUserName = szUserName; }; + void setRealName(const QString &szRealName){ m_szRealName = szRealName; }; + void setPassword(const QString &szPassword){ m_szPassword = szPassword; }; + void setAvatar(const KviPixmap &pix){ m_pixAvatar = pix; }; + void setPartMessage(const QString &szMsg){ m_szPartMessage = szMsg; }; + void setQuitMessage(const QString &szMsg){ m_szQuitMessage = szMsg; }; + void setAge(const QString &szAge){ m_szAge = szAge; }; + void setGender(const QString &szGender){ m_szGender = szGender; }; + void setLocation(const QString &szLocation){ m_szLocation = szLocation; }; + void setLanguages(const QString &szLanguages){ m_szLanguages = szLanguages; }; + void setOtherInfo(const QString &szOtherInfo){ m_szOtherInfo = szOtherInfo; }; + void setUserMode(const QString &szUserMode){ m_szUserMode = szUserMode; }; + void setOnConnectCommand(const QString &szOnConnectCommand){ m_szOnConnectCommand = szOnConnectCommand; }; + void setOnLoginCommand(const QString &szOnLoginCommand){ m_szOnLoginCommand = szOnLoginCommand; }; +protected: + void copyFrom(const KviUserIdentity &src); + bool save(KviConfig &cfg); + bool load(KviConfig &cfg); +}; + +class KVILIB_API KviUserIdentityManager : public KviHeapObject +{ +protected: + KviUserIdentityManager(); + ~KviUserIdentityManager(); +protected: + static KviUserIdentityManager * m_pInstance; + KviPointerHashTable<QString,KviUserIdentity> * m_pIdentityDict; + QString m_szDefaultIdentity; +public: + static void init(); + static void done(); + static KviUserIdentityManager * instance(){ return m_pInstance; }; + + KviPointerHashTable<QString,KviUserIdentity> * identityDict(){ return m_pIdentityDict; }; + const KviUserIdentity * findIdentity(const QString &szId){ return m_pIdentityDict->find(szId); }; + // NEVER NULL + const KviUserIdentity * defaultIdentity(); + + void setDefaultIdentity(const QString &szIdentityId){ m_szDefaultIdentity = szIdentityId; }; + + KviUserIdentityManager * createWorkingCopy(); + void copyFrom(KviUserIdentityManager * pWorkingCopy); + void releaseWorkingCopy(KviUserIdentityManager * pWorkingCopy); + + void save(const QString &szFileName); + void load(const QString &szFileName); +}; + +#endif //!_KVI_USERIDENTITY_H_ diff --git a/src/kvilib/irc/moc_kvi_ircuserdb.cpp b/src/kvilib/irc/moc_kvi_ircuserdb.cpp new file mode 100644 index 00000000..2b4d1482 --- /dev/null +++ b/src/kvilib/irc/moc_kvi_ircuserdb.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** KviIrcUserDataBase meta object code from reading C++ file 'kvi_ircuserdb.h' +** +** Created: Sun Mar 23 20:56:18 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_ircuserdb.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviIrcUserDataBase::className() const +{ + return "KviIrcUserDataBase"; +} + +QMetaObject *KviIrcUserDataBase::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviIrcUserDataBase( "KviIrcUserDataBase", &KviIrcUserDataBase::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviIrcUserDataBase::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviIrcUserDataBase", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviIrcUserDataBase::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviIrcUserDataBase", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviIrcUserDataBase::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUParameter param_slot_0[] = { + { 0, &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod slot_0 = {"registeredUserRemoved", 1, param_slot_0 }; + static const QUParameter param_slot_1[] = { + { 0, &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod slot_1 = {"registeredUserChanged", 1, param_slot_1 }; + static const QUParameter param_slot_2[] = { + { 0, &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod slot_2 = {"registeredUserAdded", 1, param_slot_2 }; + static const QUMethod slot_3 = {"registeredDatabaseCleared", 0, 0 }; + static const QMetaData slot_tbl[] = { + { "registeredUserRemoved(const QString&)", &slot_0, QMetaData::Protected }, + { "registeredUserChanged(const QString&)", &slot_1, QMetaData::Protected }, + { "registeredUserAdded(const QString&)", &slot_2, QMetaData::Protected }, + { "registeredDatabaseCleared()", &slot_3, QMetaData::Protected } + }; + metaObj = QMetaObject::new_metaobject( + "KviIrcUserDataBase", parentObject, + slot_tbl, 4, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviIrcUserDataBase.setMetaObject( metaObj ); + return metaObj; +} + +void* KviIrcUserDataBase::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviIrcUserDataBase" ) ) + return this; + return QObject::qt_cast( clname ); +} + +bool KviIrcUserDataBase::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: registeredUserRemoved((const QString&)static_QUType_QString.get(_o+1)); break; + case 1: registeredUserChanged((const QString&)static_QUType_QString.get(_o+1)); break; + case 2: registeredUserAdded((const QString&)static_QUType_QString.get(_o+1)); break; + case 3: registeredDatabaseCleared(); break; + default: + return QObject::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool KviIrcUserDataBase::qt_emit( int _id, QUObject* _o ) +{ + return QObject::qt_emit(_id,_o); +} +#ifndef QT_NO_PROPERTIES + +bool KviIrcUserDataBase::qt_property( int id, int f, QVariant* v) +{ + return QObject::qt_property( id, f, v); +} + +bool KviIrcUserDataBase::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/net/Makefile.am b/src/kvilib/net/Makefile.am new file mode 100644 index 00000000..c84487eb --- /dev/null +++ b/src/kvilib/net/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.cpp *.h diff --git a/src/kvilib/net/kvi_dns.cpp b/src/kvilib/net/kvi_dns.cpp new file mode 100644 index 00000000..faa2e126 --- /dev/null +++ b/src/kvilib/net/kvi_dns.cpp @@ -0,0 +1,450 @@ +//============================================================================= +// +// File : kvi_dns.cpp +// Creation date : Sat Jul 21 2000 17:19:31 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2000-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= +#define __KVILIB__ + +#include "kvi_dns.h" +#include "kvi_error.h" +#include "kvi_netutils.h" + +#include <errno.h> + +#ifdef COMPILE_ON_WINDOWS + #include <winsock2.h> + + #ifdef COMPILE_IPV6_SUPPORT + #ifdef WIN2K + #include <ws2ip6.h> + #else + #include <ws2tcpip.h> + //#include <tpipv6.h> + #endif + #endif +#else + #include <sys/types.h> + #include <sys/socket.h> + #include <netdb.h> +#endif + +// this is for FreeBSD +#ifndef EAI_ADDRFAMILY + #define EAI_ADDRFAMILY EAI_FAMILY +#endif + +#ifndef EAI_NODATA + #define EAI_NODATA 0 +#endif + + + +KviDnsResult::KviDnsResult() +{ + m_iError = KviError_success; + m_pHostnameList = new KviPointerList<QString>; + m_pHostnameList->setAutoDelete(true); + m_pIpAddressList = new KviPointerList<QString>; + m_pIpAddressList->setAutoDelete(true); + +} + +KviDnsResult::~KviDnsResult() +{ + delete m_pHostnameList; + delete m_pIpAddressList; +} + +void KviDnsResult::appendHostname(const QString &host) +{ + m_pHostnameList->append(new QString(host)); +} + + +void KviDnsResult::appendAddress(const QString &addr) +{ + m_pIpAddressList->append(new QString(addr)); +} + + + +KviDnsThread::KviDnsThread(KviDns * pDns) +{ + m_pParentDns = pDns; +} + +KviDnsThread::~KviDnsThread() +{ +} + +int KviDnsThread::translateDnsError(int iErr) +{ +#if defined(COMPILE_IPV6_SUPPORT) || !defined(COMPILE_ON_WINDOWS) + + switch(iErr) + { + case EAI_FAMILY: return KviError_unsupportedAddressFamily; break; +#if !defined(COMPILE_ON_WINDOWS) && defined(EAI_ADDRFAMILY) && (EAI_ADDRFAMILY != EAI_FAMILY) + case EAI_ADDRFAMILY: return KviError_unsupportedAddressFamily; break; +#endif +// NOT FreeBSD ARE WE? +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) +// YARR + case EAI_NODATA: return KviError_validNameButNoIpAddress; break; +#endif + case EAI_FAIL: return KviError_unrecoverableNameserverError; break; + case EAI_AGAIN: return KviError_dnsTemporaneousFault; break; + // this should never happen + case EAI_BADFLAGS: return KviError_dnsInternalErrorBadFlags; break; + case EAI_MEMORY: return KviError_dnsInternalErrorOutOfMemory; break; + // got this when experimenting with protocols + case EAI_SERVICE: return KviError_dnsInternalErrorServiceNotSupported; break; +#ifndef COMPILE_ON_WINDOWS + case EAI_NONAME: return KviError_dnsNoName; break; +#endif + // got this when experimenting with protocols + case EAI_SOCKTYPE: return KviError_dnsInternalErrorUnsupportedSocketType; break; +#ifndef COMPILE_ON_WINDOWS + case EAI_SYSTEM: return -errno; +#endif + } + +#endif + return KviError_dnsQueryFailed; +} + +void KviDnsThread::postDnsError(KviDnsResult * dns,int iErr) +{ + dns->setError(iErr); + KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA); + e->setData(dns); + postEvent(m_pParentDns,e); +} + +void KviDnsThread::run() +{ + KviDnsResult * dns = new KviDnsResult(); + + dns->setQuery(m_szQuery); + + if(m_szQuery.isEmpty()) + { + postDnsError(dns,KviError_noHostToResolve); + return; + } + +#ifndef COMPILE_IPV6_SUPPORT + if(m_queryType != KviDns::IpV4) + { + if(m_queryType == KviDns::IpV6) + { + postDnsError(dns,KviError_noIpV6Support); + return; + } + m_queryType = KviDns::IpV4; + } +#endif + +#if defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_IPV6_SUPPORT) + + if(m_queryType == KviDns::IpV6) + { + postDnsError(dns,KviError_noIpV6Support); + return; + } + + // gethostbyaddr and gethostbyname are thread-safe on Windoze + struct in_addr inAddr; + struct hostent *pHostEntry = 0; + + + // DIE DIE!....I hope that this stuff will disappear sooner or later :) + + if(KviNetUtils::stringIpToBinaryIp(m_szQuery,&inAddr)) + { + pHostEntry = gethostbyaddr((const char *)&inAddr,sizeof(inAddr),AF_INET); + } else { + pHostEntry = gethostbyname(m_szQuery); + } + + if(!pHostEntry) + { + switch(h_errno) + { + case HOST_NOT_FOUND: dns->setError(KviError_hostNotFound); break; + case NO_ADDRESS: dns->setError(KviError_validNameButNoIpAddress); break; + case NO_RECOVERY: dns->setError(KviError_unrecoverableNameserverError); break; + case TRY_AGAIN: dns->setError(KviError_dnsTemporaneousFault); break; + default: dns->setError(KviError_dnsQueryFailed); break; + } + } else { + dns->appendHostname(pHostEntry->h_name); + QString szIp; + KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr)),szIp); + dns->appendAddress(szIp); + + int idx = 1; + while(pHostEntry->h_addr_list[idx]) + { + QString tmp; + KviNetUtils::binaryIpToStringIp(* ((struct in_addr*)(pHostEntry->h_addr_list[idx])),tmp); + if(tmp.hasData())dns->appendAddress(tmp); + ++idx; + } + if(pHostEntry->h_aliases[0]) + { + dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[0])); + if(pHostEntry->h_aliases[1])dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[1])); + } + } + + +#else //!COMPILE_ON_WINDOWS || COMPILE_IPV6_SUPPORT + + int retVal; + + +//#ifdef HAVE_GETNAMEINFO + struct sockaddr_in ipv4Addr; + +#ifdef COMPILE_IPV6_SUPPORT + struct sockaddr_in6 ipv6Addr; + bool bIsIpV6Ip = false; +#endif + + bool bIsIpV4Ip = KviNetUtils::stringIpToBinaryIp(m_szQuery,(struct in_addr *)&(ipv4Addr.sin_addr)); + +#ifdef COMPILE_IPV6_SUPPORT + if(!bIsIpV4Ip)bIsIpV6Ip = KviNetUtils::stringIpToBinaryIp_V6(m_szQuery,(struct in6_addr *)&(ipv6Addr.sin6_addr)); +#endif + +//#ifdef HAVE_GETNAMEINFO + +#ifdef COMPILE_IPV6_SUPPORT + if(bIsIpV4Ip || bIsIpV6Ip) + { +#else + if(bIsIpV4Ip) + { +#endif + // use getnameinfo... + char retname[1025]; // should be enough.... + +#ifdef COMPILE_IPV6_SUPPORT + if(bIsIpV4Ip) + { +#endif + ipv4Addr.sin_family = AF_INET; + ipv4Addr.sin_port = 0; + // NI_NAMEREQD as last param ? + retVal = getnameinfo((struct sockaddr *)&ipv4Addr,sizeof(ipv4Addr),retname,1025,0,0,NI_NAMEREQD); +#ifdef COMPILE_IPV6_SUPPORT + } else { + ipv6Addr.sin6_family = AF_INET6; + ipv6Addr.sin6_port = 0; + retVal = getnameinfo((struct sockaddr *)&ipv6Addr,sizeof(ipv6Addr),retname,1025,0,0,NI_NAMEREQD); + } +#endif + + if(retVal != 0)dns->setError(translateDnsError(retVal)); + else { + dns->appendHostname(retname); + dns->appendAddress(m_szQuery); + } + + } else { +//#endif //HAVE_GETNAMEINFO + + +//#ifdef COMPILE_IPV6_SUPPORT +// struct in6_addr in6Addr; +//#endif + struct addrinfo * pRet = 0; + struct addrinfo * pNext; + struct addrinfo hints; + hints.ai_flags = 0; //AI_CANONNAME; <-- for IPV6 it makes cannoname to point to the IP address! +#ifdef COMPILE_IPV6_SUPPORT + hints.ai_family = (m_queryType == KviDns::IpV6) ? PF_INET6 : ((m_queryType == KviDns::IpV4) ? PF_INET : PF_UNSPEC); +#else + hints.ai_family = PF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + hints.ai_addrlen = 0; + hints.ai_canonname = 0; + hints.ai_addr = 0; + hints.ai_next = 0; + + retVal = getaddrinfo(KviQString::toUtf8(m_szQuery).data(),0,&hints,&pRet); + + if(retVal != 0)dns->setError(translateDnsError(retVal)); + else { + dns->appendHostname(pRet->ai_canonname ? QString::fromUtf8(pRet->ai_canonname) : m_szQuery); + QString szIp; +#ifdef COMPILE_IPV6_SUPPORT + if(pRet->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pRet->ai_addr))->sin6_addr,szIp); + else { +#endif + KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pRet->ai_addr))->sin_addr,szIp); +#ifdef COMPILE_IPV6_SUPPORT + } +#endif + dns->appendAddress(szIp); + + pNext = pRet->ai_next; + while(pNext) + { + QString tmp; +#ifdef COMPILE_IPV6_SUPPORT + if(pNext->ai_family == PF_INET6)KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pNext->ai_addr))->sin6_addr,tmp); + else { +#endif + KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pNext->ai_addr))->sin_addr,tmp); +#ifdef COMPILE_IPV6_SUPPORT + } +#endif + if(!tmp.isEmpty())dns->appendAddress(tmp); + + if(pNext->ai_canonname) + { + // FIXME: only of not equal to other names ? + dns->appendHostname(QString::fromUtf8(pNext->ai_canonname)); + } + + pNext = pNext->ai_next; + + } + } + if(pRet)freeaddrinfo(pRet); +//#ifdef HAVE_GETNAMEINFO + } +//#endif //HAVE_GETNAMEINFO + +#endif // !COMPILE_ON_WINDOWS + + + KviThreadDataEvent<KviDnsResult> * e = new KviThreadDataEvent<KviDnsResult>(KVI_DNS_THREAD_EVENT_DATA); + e->setData(dns); + postEvent(m_pParentDns,e); +} + + + + +KviDns::KviDns() +: QObject() +{ + m_pSlaveThread = new KviDnsThread(this); + m_pDnsResult = new KviDnsResult(); + m_pAuxData = 0; + m_state = Idle; +} + +KviDns::~KviDns() +{ + if(m_pSlaveThread)delete m_pSlaveThread; // will eventually terminate it (but it will also block us!!!) + KviThreadManager::killPendingEvents(this); + if(m_pDnsResult)delete m_pDnsResult; + if(m_pAuxData)debug("You're leaking memory man! m_pAuxData is non 0!"); +} + + +bool KviDns::isRunning() const +{ + return (m_state == Busy); +}; + +bool KviDns::lookup(const QString &query,QueryType type) +{ + if(m_state == Busy)return false; + m_pSlaveThread->setQuery(KviQString::trimmed(query),type); + bool bStarted = m_pSlaveThread->start(); + m_state = bStarted ? Busy : Failure; + return bStarted; +} + +int KviDns::error() +{ + if(!m_pDnsResult)return KviError_dnsQueryFailed; + return m_pDnsResult->error(); +} + +KviDnsResult * KviDns::result() +{ + if(!m_pDnsResult)m_pDnsResult = new KviDnsResult(); + return m_pDnsResult; +} + +KviPointerList<QString> * KviDns::hostnameList() +{ + return result()->hostnameList(); +} + +KviPointerList<QString> * KviDns::ipAddressList() +{ + return result()->ipAddressList(); +} + +int KviDns::hostnameCount() +{ + return result()->hostnameList()->count(); +} + +int KviDns::ipAddressCount() +{ + return result()->ipAddressList()->count(); +} + +const QString & KviDns::firstHostname() +{ + QString * pStr = result()->hostnameList()->first(); + if(pStr)return *pStr; + return KviQString::empty; +} + +const QString & KviDns::firstIpAddress() +{ + QString * pStr = result()->ipAddressList()->first(); + if(pStr)return *pStr; + return KviQString::empty; +} + +const QString & KviDns::query() +{ + return result()->query(); +} + +bool KviDns::event(QEvent *e) +{ + if(e->type() == KVI_THREAD_EVENT) + { + if(((KviThreadEvent *)e)->id() == KVI_DNS_THREAD_EVENT_DATA) + { + if(m_pDnsResult)delete m_pDnsResult; + m_pDnsResult = ((KviThreadDataEvent<KviDnsResult> *)e)->getData(); + m_state = (m_pDnsResult->error() == KviError_success) ? Success : Failure; + emit lookupDone(this); + return true; + } // else ops... unknown thread event ? + } + return QObject::event(e); +} + diff --git a/src/kvilib/net/kvi_dns.h b/src/kvilib/net/kvi_dns.h new file mode 100644 index 00000000..3f423c24 --- /dev/null +++ b/src/kvilib/net/kvi_dns.h @@ -0,0 +1,142 @@ +#ifndef _KVI_DNS_H_ +#define _KVI_DNS_H_ + +//============================================================================= +// +// File : kvi_dns.h +// Creation date : Sat Jul 21 2000 13:59:11 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_thread.h" +#include "kvi_qstring.h" + + +class KviDnsThread; // not part of the API + + +class KVILIB_API KviDnsResult : public KviHeapObject +{ + friend class KviDns; + friend class KviDnsThread; +protected: + KviDnsResult(); +public: + ~KviDnsResult(); +protected: + int m_iError; + KviPointerList<QString> * m_pHostnameList; + KviPointerList<QString> * m_pIpAddressList; + QString m_szQuery; +public: + int error(){ return m_iError; }; + // never store nor delete these pointers! + // (these are NEVER 0) + KviPointerList<QString> * hostnameList(){ return m_pHostnameList; }; + KviPointerList<QString> * ipAddressList(){ return m_pIpAddressList; }; + const QString &query(){ return m_szQuery; }; +protected: + void setError(int iError){ m_iError = iError; }; + void setQuery(const QString &query){ m_szQuery = query; }; + void appendHostname(const QString &host); + void appendAddress(const QString &addr); +}; + + + +class KVILIB_API KviDns : public QObject, public KviHeapObject +{ + Q_OBJECT + Q_PROPERTY(bool blockingDelete READ isRunning) +public: + KviDns(); + ~KviDns(); +public: + enum QueryType { IpV4 , IpV6 , Any }; + enum State { Idle , Busy , Failure , Success }; +protected: + void * m_pAuxData; + KviDnsThread * m_pSlaveThread; + KviDnsResult * m_pDnsResult; + State m_state; +public: + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Public interface + // + + // Lookup start + bool lookup(const QString &szQuery,QueryType type); + + // Current object state + State state(){ return m_state; }; + + // Results (return always non null-data..but valid results only if state() == Success or Failure) + int error(); + const QString & firstHostname(); + const QString & firstIpAddress(); + int hostnameCount(); + int ipAddressCount(); + KviPointerList<QString> * hostnameList(); + KviPointerList<QString> * ipAddressList(); + const QString & query(); + bool isRunning() const; + + // Auxiliary data store + void setAuxData(void * pAuxData){ m_pAuxData = pAuxData; }; + void * releaseAuxData(){ void * pData = m_pAuxData; m_pAuxData = 0; return pData; }; +protected: + virtual bool event(QEvent *e); +private: + KviDnsResult * result(); +signals: + void lookupDone(KviDns *); +}; + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// INTERNAL CLASSES +// + +#define KVI_DNS_THREAD_EVENT_DATA (KVI_THREAD_USER_EVENT_BASE + 7432) + +class KviDnsThread : public KviThread +{ + friend class KviDns; +protected: + KviDnsThread(KviDns * pDns); + ~KviDnsThread(); +protected: + QString m_szQuery; + KviDns::QueryType m_queryType; + KviDns * m_pParentDns; +public: + void setQuery(const QString &query,KviDns::QueryType type){ m_szQuery = query; m_queryType = type; }; +protected: + virtual void run(); + int translateDnsError(int iErr); + void postDnsError(KviDnsResult * dns,int iErr); +}; + + +#endif //_KVI_DNS_H_ diff --git a/src/kvilib/net/kvi_http.cpp b/src/kvilib/net/kvi_http.cpp new file mode 100644 index 00000000..2e94abbe --- /dev/null +++ b/src/kvilib/net/kvi_http.cpp @@ -0,0 +1,1440 @@ +//============================================================================= +// +// File : kvi_http.cpp +// Creation date : Sat Aug 17 13:43:32 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include <qdir.h> +#include <qtimer.h> +//#include <zlib.h> + +#include "kvi_http.h" +#include "kvi_locale.h" +#include "kvi_netutils.h" +#include "kvi_dns.h" +#include "kvi_error.h" +#include "kvi_debug.h" +#include "kvi_socket.h" +#include "kvi_time.h" +#ifdef COMPILE_SSL_SUPPORT + #include "kvi_ssl.h" +#endif + + +#define KVI_HTTP_REQUEST_THREAD_EVENT_CONNECTED (KVI_THREAD_USER_EVENT_BASE + 0xCAFE) +#define KVI_HTTP_REQUEST_THREAD_EVENT_REQUESTSENT (KVI_THREAD_USER_EVENT_BASE + 0xCAFF) + +KviHttpRequest::KviHttpRequest() +: QObject() +{ + m_pDns = 0; + m_pThread = 0; + m_pFile = 0; + m_pPrivateData = 0; + m_bHeaderProcessed = false; + m_pBuffer = new KviDataBuffer(); + + resetStatus(); + resetData(); +} + +KviHttpRequest::~KviHttpRequest() +{ + resetInternalStatus(); + delete m_pBuffer; +} + +void KviHttpRequest::abort() +{ + resetInternalStatus(); + m_szLastError = __tr2qs("Aborted"); + emit terminated(false); +} + +void KviHttpRequest::resetInternalStatus() +{ + if(m_pThread)delete m_pThread; + if(m_pDns)delete m_pDns; + + m_pDns = 0; + m_pThread = 0; + + if(!m_pFile)return; + m_pFile->close(); + delete m_pFile; + m_pFile = 0; + + m_pBuffer->clear(); + m_bHeaderProcessed = false; + + KviThreadManager::killPendingEvents(this); +} + +void KviHttpRequest::resetStatus() +{ + m_szLastError = __tr2qs("No request"); + m_uTotalSize = 0; + m_uReceivedSize = 0; +} + +void KviHttpRequest::resetData() +{ + m_szFileName = ""; + m_eProcessingType = WholeFile; + m_eExistingFileAction = RenameIncoming; + m_url = ""; + m_uMaxContentLength = 0; + m_uContentOffset = 0; + m_bChunkedTransferEncoding = false; + m_bGzip = false; + m_bIgnoreRemainingData = false; + m_uRemainingChunkSize = 0; +} + +void KviHttpRequest::reset() +{ + resetStatus(); + resetData(); + resetInternalStatus(); +} + +bool KviHttpRequest::get(const KviUrl &u,ProcessingType p,const QString &szFileName) +{ + reset(); + setUrl(u); + setProcessingType(p); + setFileName(szFileName); + return start(); +} + +bool KviHttpRequest::start() +{ + // ensure that the file is closed + resetInternalStatus(); + resetStatus(); + + if(m_eProcessingType == StoreToFile) + { + if(m_szFileName.isEmpty()) + { + m_szLastError = __tr2qs("No filename specified for the \"StoreToFile\" processing type"); + return false; + } + + if((m_eExistingFileAction == Resume) && (m_uContentOffset == 0)) + { + // determine the content offset automatically + if(KviFile::exists(m_szFileName)) + { + // we check it + QFileInfo fi(m_szFileName); + m_uContentOffset = fi.size(); + } + } + } + + if(m_url.host().isEmpty()) + { + resetInternalStatus(); + m_szLastError = __tr2qs("Invalid URL: Missing hostname"); + return false; + } + + if((!kvi_strEqualCI(m_url.protocol().ptr(),"http")) && (!kvi_strEqualCI(m_url.protocol().ptr(),"https"))) + { + resetInternalStatus(); + m_szLastError=__tr2qs("Unsupported protocol %1").arg(m_url.protocol().ptr()); + return false; + } + + if(kvi_isValidStringIp(m_url.host().ptr())) + { + m_szIp = m_url.host(); + QTimer::singleShot(10,this,SLOT(haveServerIp())); + return true; + } + + return startDnsLookup(); +} + +bool KviHttpRequest::startDnsLookup() +{ + m_pDns = new KviDns(); + connect(m_pDns,SIGNAL(lookupDone(KviDns *)),this,SLOT(dnsLookupDone(KviDns *))); + + if(!m_pDns->lookup(m_url.host().ptr(),KviDns::IpV4)) + { + resetInternalStatus(); + m_szLastError = __tr2qs("Unable to start the DNS lookup"); + return false; + } + + QString tmp; + KviQString::sprintf(tmp,__tr2qs("Looking up host %s"),m_url.host().ptr()); + emit status(tmp); // FIXME + + emit resolvingHost(QString(m_url.host().ptr())); + + return true; +} + +void KviHttpRequest::dnsLookupDone(KviDns *d) +{ + if(d->state() == KviDns::Success) + { + m_szIp = d->firstIpAddress(); + delete m_pDns; + m_pDns = 0; + QString tmp; + KviQString::sprintf(tmp,__tr2qs("Host %s resolved to %Q"),m_url.host().ptr(),&m_szIp); + emit status(tmp); + haveServerIp(); + } else { + int iErr = d->error(); + resetInternalStatus(); + m_szLastError = KviError::getDescription(iErr); + emit terminated(false); + } +} + +void KviHttpRequest::haveServerIp() +{ + unsigned short uPort = m_url.port(); + if(uPort == 0)uPort = 80; + + QString tmp; + KviQString::sprintf(tmp,"%Q:%u",&m_szIp,uPort); + emit contactingHost(tmp); + + if(m_pThread)delete m_pThread; + + m_pThread = new KviHttpRequestThread( + this, + m_url.host().ptr(), + m_szIp, + uPort, + m_url.path().ptr(), + m_uContentOffset, + (m_eProcessingType == HeadersOnly) ? KviHttpRequestThread::Head : (m_szPostData.isEmpty() ? KviHttpRequestThread::Get : KviHttpRequestThread::Post), + m_szPostData, + kvi_strEqualCI(m_url.protocol().ptr(),"https")); + + if(!m_pThread->start()) + { + resetInternalStatus(); + m_szLastError = __tr2qs("Unable to start the request slave thread"); + emit terminated(false); + return; + } + + KviQString::sprintf(tmp,__tr2qs("Contacting host %Q on port %u"),&m_szIp,uPort); + emit status(tmp); +} + +bool KviHttpRequest::event(QEvent *e) +{ + if(e->type() == KVI_THREAD_EVENT) + { + switch(((KviThreadEvent *)e)->id()) + { + case KVI_THREAD_EVENT_BINARYDATA: + { + KviDataBuffer * b = ((KviThreadDataEvent<KviDataBuffer> *)e)->getData(); + processData(b); + delete b; + return true; + } + break; + case KVI_HTTP_REQUEST_THREAD_EVENT_CONNECTED: + emit connectionEstabilished(); + emit status(__tr2qs("Connection established, sending request")); + return true; + break; + case KVI_HTTP_REQUEST_THREAD_EVENT_REQUESTSENT: + { + QString * req = ((KviThreadDataEvent<QString> *)e)->getData(); +#ifdef COMPILE_USE_QT4 + QStringList sl = req->split("\r\n"); +#else + QStringList sl = QStringList::split("\r\n",*req); +#endif + emit requestSent(sl); + delete req; + return true; + } + break; + case KVI_THREAD_EVENT_SUCCESS: + if(!m_pThread && !m_bHeaderProcessed) + { + // the thread has already been deleted + // probably because the response was something like a 404 + // just ignore the event + return true; + } + switch(m_eProcessingType) + { + case WholeFile: + // happens always + emit binaryData(*m_pBuffer); + break; + case Blocks: + // an unprocessed block ?.. should never happend.. but well :D + if(m_pBuffer->size() > 0)emit binaryData(*m_pBuffer); + break; + case Lines: + if(m_pBuffer->size() > 0) + { + // something left in the buffer and has no trailing LF + KviStr tmp((const char *)(m_pBuffer->data()),m_pBuffer->size()); + emit data(tmp); + } + break; + case StoreToFile: + // same as above... should never happen.. but well :D + if(m_pFile && m_pBuffer->size() > 0)m_pFile->writeBlock((const char *)(m_pBuffer->data()),m_pBuffer->size()); + break; + default: + // nothing... just make gcc happy + break; + } + resetInternalStatus(); + m_szLastError = __tr2qs("Success"); + emit terminated(true); + return true; + break; + case KVI_THREAD_EVENT_ERROR: + { + KviStr * err = ((KviThreadDataEvent<KviStr> *)e)->getData(); + m_szLastError = __tr2qs_no_xgettext(err->ptr()); + delete err; + resetInternalStatus(); + emit terminated(false); + return true; + } + break; + case KVI_THREAD_EVENT_MESSAGE: + { + KviStr * msg = ((KviThreadDataEvent<KviStr> *)e)->getData(); + emit status(__tr2qs_no_xgettext(msg->ptr())); + delete msg; + return true; + } + break; + } + } + return QObject::event(e); +} + +void KviHttpRequest::emitLines(KviDataBuffer * pDataBuffer) +{ + int idx = pDataBuffer->find((const unsigned char *)"\n",1); + while(idx != -1) + { + KviStr tmp((const char *)(m_pBuffer->data()),idx); + tmp.stripRight('\r'); + pDataBuffer->remove(idx + 1); + idx = pDataBuffer->find((const unsigned char *)"\n",1); + emit data(tmp); + } +} + +// header += "Accept: "; +// QString acceptHeader = metaData("accept"); +// if (!acceptHeader.isEmpty()) +// header += acceptHeader; +// else +// header += DEFAULT_ACCEPT_HEADER; +// header += "\r\n"; +// +//#ifdef DO_GZIP +// if (m_request.allowCompressedPage) +// header += "Accept-Encoding: x-gzip, x-deflate, gzip, deflate, identity\r\n"; +//#endif +// +// if (!m_request.charsets.isEmpty()) +// header += "Accept-Charset: " + m_request.charsets + "\r\n"; +// +// if (!m_request.languages.isEmpty()) +// header += "Accept-Language: " + m_request.languages + "\r\n"; +// +// +// /* support for virtual hosts and required by HTTP 1.1 */ +// header += "Host: "; +// header += "Pragma: no-cache\r\n"; /* for HTTP/1.0 caches */ +// header += "Cache-control: no-cache\r\n"; /* for HTTP >=1.1 caches */ + +// header += "Referer: "; //Don't try to correct spelling! +// header += m_request.referrer; +// header += "\r\n"; +bool KviHttpRequest::openFile() +{ + if(m_eProcessingType != StoreToFile)return true; + + bool bAppend = false; + + // take action when the file is existing + if(KviFile::exists(m_szFileName)) + { + switch(m_eExistingFileAction) + { + case Resume: + { + bAppend = true; + } + break; + case RenameIncoming: + { + int i=0; + QString tmp = m_szFileName; + do { + i++; + m_szFileName = tmp + QString(".kvirnm-%1").arg(i); + } while(KviFile::exists(m_szFileName)); + } + break; + case RenameExisting: + { + int i=0; + QString tmp; + do { + i++; + tmp = m_szFileName + QString(".kvirnm-%1").arg(i); + } while(KviFile::exists(tmp)); + QDir d; + if(!d.rename(m_szFileName,tmp)) + { + // fail :( + resetInternalStatus(); + m_szLastError = __tr2qs("Failed to rename the existing file, please rename manually and retry"); + emit terminated(false); + return false; + } + } + break; + case Overwrite: + default: + // nothing + break; + } + } + + m_pFile = new KviFile(m_szFileName); + + if(!m_pFile->openForWriting(bAppend)) + { + resetInternalStatus(); + KviQString::sprintf(m_szLastError,__tr2qs("Can't open file \"%Q\" for writing"),&m_szFileName); + emit terminated(false); + return false; + } + + return true; +} + + + + + +bool KviHttpRequest::processHeader(KviStr &szHeader) +{ + int idx = szHeader.findFirstIdx("\r\n"); + KviStr szResponse; + if(idx != -1) + { + szResponse = szHeader.left(idx); + szHeader.cutLeft(idx + 2); + } else { + szResponse = szHeader; + szHeader = ""; + } + + szResponse.stripWhiteSpace(); + + bool bValid = false; + + unsigned int uStatus = 0; + + // check the response value + if(kvi_strEqualCSN(szResponse.ptr(),"HTTP",4)) + { + KviStr szR = szResponse; + szR.cutToFirst(' '); + szR.stripWhiteSpace(); + int idx = szR.findFirstIdx(' '); + KviStr szNumber; + if(idx != -1)szNumber = szR.left(idx); + else szNumber = szR; + bool bOk; + uStatus = szNumber.toUInt(&bOk); + if(bOk)bValid = true; + } + + if(!bValid) + { + // the response is invalid ? + resetInternalStatus(); + m_szLastError=__tr2qs("Invalid HTTP response: %s").arg(szResponse.ptr()); + emit terminated(false); + return false; + } + + QString tmp; + KviQString::sprintf(tmp,__tr2qs("Received HTTP response: %s"),szResponse.ptr()); + + emit status(tmp); + emit receivedResponse(QString(szResponse.ptr())); + + KviPointerList<KviStr> hlist; + hlist.setAutoDelete(true); + + idx = szHeader.findFirstIdx("\r\n"); + while(idx != -1) + { + if(idx > 0) + { + hlist.append(new KviStr(szHeader.ptr(),idx)); + szHeader.cutLeft(idx + 2); + } + idx = szHeader.findFirstIdx("\r\n"); + } + if(szHeader.hasData())hlist.append(new KviStr(szHeader)); + + KviPointerHashTable<const char *,KviStr> hdr(11,false,true); + hdr.setAutoDelete(true); + + for(KviStr * s = hlist.first();s;s = hlist.next()) + { + idx = s->findFirstIdx(":"); + if(idx != -1) + { + KviStr szName = s->left(idx); + s->cutLeft(idx + 1); + s->stripWhiteSpace(); + hdr.replace(szName.ptr(),new KviStr(*s)); + //debug("FOUND HEADER (%s)=(%s)",szName.ptr(),s->ptr()); + } + } + + KviStr * size = hdr.find("Content-length"); + if(size) + { + bool bOk; + m_uTotalSize = size->toUInt(&bOk); + if(!bOk)m_uTotalSize = 0; + } + + KviStr * contentEncoding = hdr.find("Content-encoding"); + if(contentEncoding) + { + m_bGzip = contentEncoding->equalsCI("gzip"); + } + + KviStr * transferEncoding = hdr.find("Transfer-Encoding"); + if(transferEncoding) + { + if(kvi_strEqualCI(transferEncoding->ptr(),"chunked")) + { + // be prepared to handle the chunked transfer encoding as required by HTTP/1.1 + m_bChunkedTransferEncoding = true; + m_uRemainingChunkSize = 0; + } + } + + emit header(&hdr); + + // check the status + + // case 200: // OK + // case 206: // Partial content + + // case 100: // Continue ?? + // case 101: // Switching protocols ??? + // case 201: // Created + // case 202: // Accepted + // case 203: // Non-Authoritative Information + // case 204: // No content + // case 205: // Reset content + // case 300: // Multiple choices + // case 301: // Moved permanently + // case 302: // Found + // case 303: // See Other + // case 304: // Not modified + // case 305: // Use Proxy + // case 306: // ??? + // case 307: // Temporary Redirect + // case 400: // Bad request + // case 401: // Unauthorized + // case 402: // Payment Required + // case 403: // Forbidden + // case 404: // Not found + // case 405: // Method not allowed + // case 406: // Not acceptable + // case 407: // Proxy authentication required + // case 408: // Request timeout + // case 409: // Conflict + // case 410: // Gone + // case 411: // Length required + // case 412: // Precondition failed + // case 413: // Request entity too large + // case 414: // Request-URI Too Long + // case 415: // Unsupported media type + // case 416: // Requested range not satisfiable + // case 417: // Expectation Failed + // case 500: // Internal server error + // case 501: // Not implemented + // case 502: // Bad gateway + // case 503: // Service unavailable + // case 504: // Gateway timeout + // case 505: // HTTP Version not supported + + if((uStatus != 200) && (uStatus != 206)) + { + // this is not "OK" and not "Partial content" + // Error , redirect or something confusing + if(m_eProcessingType != HeadersOnly) + { + // this is an error then + resetInternalStatus(); + m_szLastError = szResponse.ptr(); + emit terminated(false); + return false; + } // else the server will terminate (it was a HEAD request) + } + + if((m_uMaxContentLength > 0) && (m_uTotalSize > ((unsigned int)m_uMaxContentLength))) + { + resetInternalStatus(); + m_szLastError=__tr2qs("Stream exceeding maximum length"); + emit terminated(false); + return false; + } + + // fixme: could check for data type etc... + + return true; +} +#define BUFFER_SIZE 32768 + +void KviHttpRequest::processData(KviDataBuffer * data) +{ +// unsigned char obuffer[BUFFER_SIZE]; + if(m_bChunkedTransferEncoding && m_bIgnoreRemainingData) + { + // In chunked transfer encoding mode there may be additional headers + // after the last chunk of data. We simply ignore them. + return; + } + + if(!m_bHeaderProcessed) + { + // time to process the header + m_pBuffer->append(*data); + + int idx = m_pBuffer->find((const unsigned char *)"\r\n\r\n",4); + if(idx == -1) + { + // header not complete + if(m_pBuffer->size() > 4096) + { + resetInternalStatus(); + m_szLastError = __tr2qs("Header too long: exceeded 4096 bytes"); + emit terminated(false); + } + return; + } + KviStr szHeader((const char *)(m_pBuffer->data()),idx); + m_pBuffer->remove(idx + 4); + + if(!processHeader(szHeader))return; + m_bHeaderProcessed = true; + + if(m_eProcessingType == StoreToFile) + { + if(!openFile())return; + } + + m_uReceivedSize = m_pBuffer->size(); + + + // here the header is complete and the eventual remaining data is in m_pBuffer. data has been already used. + + } else { + // header already processed + m_uReceivedSize += data->size(); + + // here the header is complete and some data *might* be already in m_pBuffer. data is unused yet. + + // Optimisation: If the transfer is NOT chunked (so we don't have to parse it) + // and the requested processing type is either Blocks or StoreToFile + // then we just can avoid to copy the data to m_pBuffer. + // This is a good optimisation since for large files we can save allocating + // space for and moving megabytes of data... + + + if((!m_bChunkedTransferEncoding) && ((m_eProcessingType == Blocks) || (m_eProcessingType == StoreToFile))) + { + switch(m_eProcessingType) + { + case Blocks: + emit binaryData(*data); + break; + case StoreToFile: + m_pFile->writeBlock((const char *)(data->data()),data->size()); + break; + } + + if(((m_uTotalSize > 0) && (m_uReceivedSize > m_uTotalSize)) || ((m_uMaxContentLength > 0) && (m_uReceivedSize > m_uMaxContentLength))) + { + resetInternalStatus(); + m_szLastError=__tr2qs("Stream exceeded expected length"); + emit terminated(false); + } + + return; + } + + // need to append to m_pBuffer and process it + m_pBuffer->append(*data); + } + + // we're processing data in m_pBuffer here + if(m_bChunkedTransferEncoding) + { + // The transfer encoding is chunked: the buffer contains + // chunks of data with an initial header composed + // of a hexadecimal length, an optional bullshit and a single CRLF + // The transfer terminates when we read a last chunk of size 0 + // that may be followed by optional headers... + // This sux :) + while(m_pBuffer->size() > 0) // <-- note that we may exit from this loop also for other conditions (there is a goto below) + { + // we process chunks of parts of chunks at a time. + if(m_uRemainingChunkSize > 0) + { + // process the current chunk data + unsigned int uProcessSize = m_uRemainingChunkSize; + if(uProcessSize > m_pBuffer->size())uProcessSize = m_pBuffer->size(); + m_uRemainingChunkSize -= uProcessSize; + + switch(m_eProcessingType) + { + case Blocks: + if(m_pBuffer->size() == uProcessSize) + { + // avoid copying to a new buffer + emit binaryData(*m_pBuffer); + } else { + // must copy + KviDataBuffer tmp(uProcessSize,m_pBuffer->data()); + emit binaryData(tmp); + m_pBuffer->remove(uProcessSize); + } + break; + case Lines: + if(m_pBuffer->size() == uProcessSize) + { + // avoid copying to a new buffer + emitLines(m_pBuffer); + } else { + // must copy + KviDataBuffer tmp(uProcessSize,m_pBuffer->data()); + emitLines(&tmp); + m_pBuffer->remove(uProcessSize); + } + break; + case StoreToFile: + m_pFile->writeBlock((const char *)(m_pBuffer->data()),uProcessSize); + m_pBuffer->remove(uProcessSize); + break; + default: + // nothing.. just make gcc happy + break; + } + // now either the buffer is empty or there is another chunk header: continue looping + } else { + // We're looking for the beginning of a chunk now. + // Note that we might be at the end of a previous chunk that has a CRLF terminator + // we need to skip it. + int crlf = m_pBuffer->find((const unsigned char *)"\r\n",2); + if(crlf != -1) + { + if(crlf == 0) + { + // This is a plain CRLF at the beginning of the buffer BEFORE a chunk header. + // It comes from the previous chunk terminator. Skip it. + m_pBuffer->remove(2); + } else { + // got a chunk header + KviStr szHeader((const char *)(m_pBuffer->data()),crlf); + szHeader.cutFromFirst(' '); + // now szHeader should contain a hexadecimal chunk length... (why the hell it is hex and not decimal ????) + QString szHexHeader = szHeader.ptr(); + bool bOk; + m_uRemainingChunkSize = szHexHeader.toLong(&bOk,16); + if(!bOk) + { + resetInternalStatus(); + m_szLastError = __tr2qs("Protocol error: invalid chunk size"); + emit terminated(false); + return; + } + m_pBuffer->remove(crlf+2); + if(m_uRemainingChunkSize == 0) + { + // this is the last chunk of data. It may be followed by optional headers + // but we actually don't need them (since we're surely not in HEAD mode) + m_bIgnoreRemainingData = true; + m_pBuffer->clear(); + goto check_stream_length; + } + } + // the rest is valid data of a non-zero chunk: continue looping + } else { + // chunk header not complete + if(m_pBuffer->size() > 4096) + { + resetInternalStatus(); + m_szLastError = __tr2qs("Chunk header too long: exceeded 4096 bytes"); + emit terminated(false); + return; + } + goto check_stream_length; + } + } + } + } else { + // the transfer encoding is not chunked: m_pBuffer contains only valid data + switch(m_eProcessingType) + { + case Blocks: + if(m_pBuffer->size() > 0)emit binaryData(*m_pBuffer); + m_pBuffer->clear(); + break; + case Lines: + if(m_pBuffer->size() > 0)emitLines(m_pBuffer); + break; + case StoreToFile: + m_pFile->writeBlock((const char *)(m_pBuffer->data()),m_pBuffer->size()); + m_pBuffer->clear(); + break; + default: + // nothing.. just make gcc happy + break; + } + } + +check_stream_length: + + if(((m_uTotalSize > 0) && (m_uReceivedSize > m_uTotalSize)) || ((m_uMaxContentLength > 0) && (m_uReceivedSize > m_uMaxContentLength))) + { + resetInternalStatus(); + m_szLastError=__tr2qs("Stream exceeded expected length"); + emit terminated(false); + } + return; +} + + + + + + + + + + + + + + + + +KviHttpRequestThread::KviHttpRequestThread( + KviHttpRequest * r, + const QString &szHost, + const QString &szIp, + unsigned short uPort, + const QString & szPath, + unsigned int uContentOffset, + RequestMethod m, + const QString &szPostData, + bool bUseSSL +) : KviSensitiveThread() +{ + m_pRequest = r; + m_szHost = szHost; + m_szIp = szIp; + m_szPath = szPath; + m_uPort = uPort > 0 ? uPort : 80; + m_uContentOffset = uContentOffset; + m_eRequestMethod = m; + m_szPostData = szPostData; + m_sock = KVI_INVALID_SOCKET; + m_bUseSSL = bUseSSL; +#ifdef COMPILE_SSL_SUPPORT + m_pSSL = 0; +#endif +} + +KviHttpRequestThread::~KviHttpRequestThread() +{ +} + +bool KviHttpRequestThread::processInternalEvents() +{ + while(KviThreadEvent *e = dequeueEvent()) + { + switch(e->id()) + { + case KVI_THREAD_EVENT_TERMINATE: + { + delete e; + return false; + } + break; + default: + debug("Unrecognized event in http thread"); + delete e; + return false; + break; + } + } + + return true; +} + +bool KviHttpRequestThread::failure(const char *error) +{ + if(error) + { + postEvent(m_pRequest,new KviThreadDataEvent<KviStr>(KVI_THREAD_EVENT_ERROR,new KviStr(error))); + } /*else { + postEvent(m_pRequest,new KviThreadDataEvent<KviStr>(KVI_THREAD_EVENT_ERROR,new KviStr(__tr2qs("Aborted")))); + }*/ + return false; +} + + +bool KviHttpRequestThread::selectForWrite(int iTimeoutInSecs) +{ + + kvi_time_t startTime = kvi_unixTime(); + + for(;;) + { + if(!processInternalEvents()) + { + return failure(0); + } + + fd_set writeSet; + + FD_ZERO(&writeSet); + + FD_SET(m_sock,&writeSet); + + struct timeval tmv; + tmv.tv_sec = 0; + tmv.tv_usec = 1000; // we wait 1000 usecs for an event + + + int nRet = kvi_socket_select(m_sock + 1,0,&writeSet,0,&tmv); + + if(nRet > 0) + { + if(FD_ISSET(m_sock,&writeSet)) + { + // connected! + return true; + } + } else { + if(nRet < 0) + { + int err = kvi_socket_error(); +#ifdef COMPILE_ON_WINDOWS + if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) +#else + if((err != EAGAIN) && (err != EINTR)) +#endif + { + return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); + } + } + } + + + if((time(0) - startTime) > iTimeoutInSecs)return failure(__tr_no_lookup("Operation timed out")); + + usleep(100000); // 1/10 sec + } + + return false; +} + +bool KviHttpRequestThread::sslFailure() +{ +#ifdef COMPILE_SSL_SUPPORT + KviStr buffer; + if(m_pSSL->getLastErrorString(buffer)) + { + failure(buffer.ptr()); + } else { + failure(__tr_no_lookup("Unexpected SSL error")); + } +#endif + return false; +} + +bool KviHttpRequestThread::connectToRemoteHost() +{ + m_sock = kvi_socket_create(KVI_SOCKET_PF_INET,KVI_SOCKET_TYPE_STREAM,0); //tcp + if(m_sock == KVI_INVALID_SOCKET) + return failure(__tr_no_lookup("Failed to create the socket")); + + if(!kvi_socket_setNonBlocking(m_sock)) + return failure(__tr_no_lookup("Failed to enter non blocking mode")); + + sockaddr_in saddr; + + if(!KviNetUtils::stringIpToBinaryIp(m_szIp,&(saddr.sin_addr))) + return failure(__tr_no_lookup("Invalid target address")); + + saddr.sin_port = htons(m_uPort); + saddr.sin_family = AF_INET; + + if(!kvi_socket_connect(m_sock,(struct sockaddr *)&saddr,sizeof(saddr))) + { + int err = kvi_socket_error(); + if(!kvi_socket_recoverableConnectError(err)) + { + return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); + } + } + + // now loop selecting for write + + //#warning "This should be a tuneable timeout" + if(!selectForWrite(60))return false; + + int sockError; + int iSize=sizeof(sockError); + if(!kvi_socket_getsockopt(m_sock,SOL_SOCKET,SO_ERROR,(void *)&sockError,&iSize))sockError = -1; + if(sockError != 0) + { + //failed + if(sockError > 0)sockError = KviError::translateSystemError(sockError); + else sockError = KviError_unknownError; + return failure(KviError::getUntranslatedDescription(sockError)); + } + +#ifdef COMPILE_SSL_SUPPORT + if(m_bUseSSL) + { + m_pSSL = new KviSSL(); + if(!m_pSSL->initContext(KviSSL::Client)) + return failure(__tr_no_lookup("Failed to initialize the SSL context")); + if(!m_pSSL->initSocket(m_sock)) + return failure(__tr_no_lookup("Failed to initialize the SSL connection")); + + for(;;) + { + switch(m_pSSL->connect()) + { + case KviSSL::Success: + // done: connected. + return true; + break; + case KviSSL::WantRead: + if(!selectForRead(60))return false; + break; + case KviSSL::WantWrite: + if(!selectForWrite(60))return false; + break; + case KviSSL::RemoteEndClosedConnection: + return failure(__tr_no_lookup("Remote end has closed the connection")); + break; + case KviSSL::SSLError: + return sslFailure(); + break; + case KviSSL::SyscallError: + { + // syscall problem + int err = kvi_socket_error(); + if(!kvi_socket_recoverableError(err)) + { + // Declare problems :) + return failure(__tr_no_lookup("Unrecoverable SSL error during handshake")); + } // else can recover ? (EAGAIN , EINTR ?) ... should select for read or for write + } + break; + default: + return sslFailure(); + break; + } + } + + // never here + return true; + } +#endif + + return true; +} + + +bool KviHttpRequestThread::sendBuffer(const char * buffer,int bufLen,int iTimeoutInSecs) +{ + const char * ptr = buffer; + int curLen = bufLen; + + time_t startTime = time(0); + + for(;;) + { + if(!processInternalEvents())return failure(); + + int wrtn; +#ifdef COMPILE_SSL_SUPPORT + if(m_pSSL) + { + wrtn = m_pSSL->write((char *)ptr,curLen); + } else { +#endif + wrtn = kvi_socket_send(m_sock,ptr,curLen); +#ifdef COMPILE_SSL_SUPPORT + } +#endif + + if(wrtn > 0) + { + curLen -= wrtn; + + if(curLen <= 0)break; + + ptr += wrtn; + } else { + if(wrtn < 0) + { +#ifdef COMPILE_SSL_SUPPORT + if(m_pSSL) + { + // ops...might be an SSL error + switch(m_pSSL->getProtocolError(wrtn)) + { + case KviSSL::WantWrite: + if(!selectForWrite(60))return false; + break; + case KviSSL::WantRead: + if(!selectForRead(60))return false; + break; + case KviSSL::SyscallError: + if(wrtn == 0) + { + return failure(__tr_no_lookup("Remote end has closed the connection")); + } else { + int iSSLErr = m_pSSL->getLastError(true); + if(iSSLErr != 0) + { + return sslFailure(); + } else { + goto handle_system_error; + } + } + break; + case KviSSL::SSLError: + return sslFailure(); + break; + default: + return sslFailure(); + break; + } + } else { +#endif //COMPILE_SSL_SUPPORT + +handle_system_error: + int err = kvi_socket_error(); +#ifdef COMPILE_ON_WINDOWS + if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) +#else + if((err != EAGAIN) && (err != EINTR)) +#endif + { + return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); + } +#ifdef COMPILE_SSL_SUPPORT + } +#endif + } + } + + int diff = time(0) - startTime; + if(diff > iTimeoutInSecs) + return failure(__tr_no_lookup("Operation timed out")); + + usleep(10000); + } + + return true; +} + + +int KviHttpRequestThread::selectForReadStep() +{ + // calls select on the main socket + // returns 1 if there is data available for reading + // returns 0 if there is no data available but there was no error + // returns -1 if there was a critical error (socket closed) + fd_set readSet; + + FD_ZERO(&readSet); + + FD_SET(m_sock,&readSet); + + struct timeval tmv; + tmv.tv_sec = 0; + tmv.tv_usec = 1000; // we wait 1000 usecs for an event + + + int nRet = kvi_socket_select(m_sock + 1,&readSet,0,0,&tmv); + + if(nRet > 0) + { + if(FD_ISSET(m_sock,&readSet)) + { + // ok + return 1; + } + } else { + if(nRet < 0) + { + int err = kvi_socket_error(); +#ifdef COMPILE_ON_WINDOWS + if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) +#else + if((err != EAGAIN) && (err != EINTR)) +#endif + { + failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); + return -1; + } + } + } + + return 0; +} + + +bool KviHttpRequestThread::selectForRead(int iTimeoutInSecs) +{ + // waits for some data to arrive on the socket + // up to iTimeoutInSecs seconds + // returns true if data is available on the socket + // or false if there was a select() error or no data + // was available in the specified amount of time + + time_t startTime = time(0); + + for(;;) + { + if(!processInternalEvents()) + { + return failure(); // ensure that the socket is closed + } + + int nRet = selectForReadStep(); + + if(nRet < 0)return false; + if(nRet > 0)return true; + + int diff = time(0) - startTime; + if(diff > iTimeoutInSecs) + return failure(__tr_no_lookup("Operation timed out (while selecting for read)")); + + usleep(100000); // 1/10 sec + } + + return false; +} + +bool KviHttpRequestThread::readDataStep() +{ + unsigned char buffer[2048]; + int readed; + + +#ifdef COMPILE_SSL_SUPPORT + if(m_pSSL) + { + readed = m_pSSL->read((char *)buffer,2048); + if(readed <= 0) + { + // ssl error....? + switch(m_pSSL->getProtocolError(readed)) + { + case KviSSL::ZeroReturn: + readed = 0; + break; + case KviSSL::WantRead: + return selectForRead(120); + break; + case KviSSL::WantWrite: + return selectForWrite(120); + break; + case KviSSL::SyscallError: + { + int iE = m_pSSL->getLastError(true); + if(iE != 0)return sslFailure(); + } + break; + case KviSSL::SSLError: + return sslFailure(); + break; + default: + return sslFailure(); + break; + } + } + } else { +#endif + readed = kvi_socket_read(m_sock,buffer,2048); +#ifdef COMPILE_SSL_SUPPORT + } +#endif + + if(readed > 0) + { + postEvent(m_pRequest,new KviThreadDataEvent<KviDataBuffer>(KVI_THREAD_EVENT_BINARYDATA,new KviDataBuffer(readed,buffer))); + } else { + if(readed < 0) + { + // Read error ? + int err = kvi_socket_error(); +#ifdef COMPILE_ON_WINDOWS + if((err != EAGAIN) && (err != EINTR) && (err != WSAEWOULDBLOCK)) +#else + if((err != EAGAIN) && (err != EINTR)) +#endif + { + // yes...read error + return failure(KviError::getUntranslatedDescription(KviError::translateSystemError(err))); + } + return selectForRead(120); // EINTR or EAGAIN...transient problem + } else { + // readed == 0 + // Connection closed by remote host + postEvent(m_pRequest,new KviThreadEvent(KVI_THREAD_EVENT_SUCCESS)); + return false; + } + } + return selectForRead(120); +} + +void KviHttpRequestThread::run() +{ + // setup: + // nothing needed + + // run: + runInternal(); + + // cleanup: +#ifdef COMPILE_SSL_SUPPORT + if(m_pSSL) + { + delete m_pSSL; + m_pSSL = 0; + } +#endif + + if(kvi_socket_isValid(m_sock)) + { + kvi_socket_close(m_sock); + m_sock = KVI_INVALID_SOCKET; + } +} + +void KviHttpRequestThread::runInternal() +{ +#ifndef COMPILE_SSL_SUPPORT + if(m_bUseSSL) + { + failure(__tr_no_lookup("This KVIrc executable has no SSL support")); + return; + } +#endif + + if(!connectToRemoteHost())return; + + postEvent(m_pRequest,new KviThreadEvent(KVI_HTTP_REQUEST_THREAD_EVENT_CONNECTED)); + + // FIXME: Other headers ? + + KviStr szMethod; + switch(m_eRequestMethod) + { + case Head: szMethod = "HEAD"; break; + case Post: szMethod = "POST"; break; + case Get: szMethod = "GET"; break; + } + + KviStr szRequest(KviStr::Format,"%s %s HTTP/1.1\r\n" \ + "Host: %s\r\n" \ + "Connection: Close\r\n" \ + "User-Agent: KVIrc-http-slave/1.0.0\r\n" \ + "Accept: */*\r\n", + szMethod.ptr(),KviQString::toUtf8(m_szPath).data(),KviQString::toUtf8(m_szHost).data()); + + if(m_uContentOffset > 0) + szRequest.append(KviStr::Format,"Range: bytes=%u-\r\n",m_uContentOffset); + + if(m_eRequestMethod == Post) + { + szRequest.append(KviStr::Format,"Content-Type: application/x-www-form-urlencoded\r\n" \ + "Content-Length: %u\r\n" \ + "Cache-control: no-cache\r\n" \ + "Pragma: no-cache\r\n",m_szPostData.length()); + } + + szRequest += "\r\n"; + + if(m_eRequestMethod == Post) + { + if(!m_szPostData.isEmpty()) + szRequest.append(m_szPostData); + szRequest += "\r\n"; + } + + //debug("SENDING REQUEST:\n%s",szRequest.ptr()); + + if(!sendBuffer(szRequest.ptr(),szRequest.len(),60))return; + + // now loop reading data + postEvent(m_pRequest,new KviThreadDataEvent<QString>(KVI_HTTP_REQUEST_THREAD_EVENT_REQUESTSENT,new QString(szRequest))); + + for(;;) + { + if(!readDataStep())return; + } +} + diff --git a/src/kvilib/net/kvi_http.h b/src/kvilib/net/kvi_http.h new file mode 100644 index 00000000..1bd6a9d9 --- /dev/null +++ b/src/kvilib/net/kvi_http.h @@ -0,0 +1,209 @@ +#ifndef _KVI_HTTP_H_ +#define _KVI_HTTP_H_ +//============================================================================= +// +// File : kvi_http.h +// Creation date : Sat Aug 17 13:43:31 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 33, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_string.h" +#include "kvi_thread.h" +#include "kvi_sockettype.h" +#include "kvi_databuffer.h" +#include "kvi_inttypes.h" +#include "kvi_url.h" + +#include <qobject.h> +#include "kvi_pointerhashtable.h" +#include "kvi_file.h" +#include <qstringlist.h> + +class KviDns; +class KviSSL; +class KviHttpRequestThread; + +// +// This class implements a HTTP protocol client. +// It's able to send GET, POST and HEAD requests, +// download stuff to a file or to a qt SLOT(). +// + +class KVILIB_API KviHttpRequest : public QObject, public KviHeapObject +{ + Q_OBJECT +public: + enum ProcessingType + { + HeadersOnly, // Download headers only (HEAD request) + WholeFile, // Emit the data as whole file (binaryData() is emitted) + Blocks, // Emit the data as blocks (binaryData() is emitted) + Lines, // Emit the data as ASCII text lines (the client must take care of decoding the data) + StoreToFile // Store the data to a file + }; + enum ExistingFileAction + { + Overwrite, // Overwrite existing file + RenameIncoming, // Automatically rename the incoming file + RenameExisting, // Automatically rename the existing file + Resume // Attempt to resume the file (get partial content) + }; +public: + KviHttpRequest(); + ~KviHttpRequest(); +protected: + // data + KviUrl m_url; + QString m_szFileName; + ProcessingType m_eProcessingType; + ExistingFileAction m_eExistingFileAction; + void * m_pPrivateData; + unsigned int m_uMaxContentLength; + unsigned int m_uContentOffset; + QString m_szPostData; + // status + QString m_szLastError; + unsigned int m_uTotalSize; + unsigned int m_uReceivedSize; + // internal status + QString m_szIp; + KviDns * m_pDns; + KviHttpRequestThread * m_pThread; + KviDataBuffer * m_pBuffer; + bool m_bHeaderProcessed; + bool m_bChunkedTransferEncoding; + bool m_bGzip; + unsigned int m_uRemainingChunkSize; + bool m_bIgnoreRemainingData; // used in chunked transfer after the last chunk has been seen + KviFile * m_pFile; +protected: + bool startDnsLookup(); + virtual bool event(QEvent *e); + void processData(KviDataBuffer * data); + bool processHeader(KviStr &szHeader); + bool openFile(); + void emitLines(KviDataBuffer * pDataBuffer); + + void resetStatus(); + void resetData(); + void resetInternalStatus(); +protected slots: + void dnsLookupDone(KviDns *d); + void haveServerIp(); +public: + const KviUrl & url(){ return m_url; }; + ProcessingType processingType(){ return m_eProcessingType; }; + ExistingFileAction existingFileAction(){ return m_eExistingFileAction; }; + const QString &fileName(){ return m_szFileName; }; + void * privateData(){ return m_pPrivateData; }; + unsigned int maxContentLength(){ return m_uMaxContentLength; }; + unsigned int contentOffset(){ return m_uContentOffset; }; + unsigned int totalSize(){ return m_uTotalSize; }; + unsigned int receivedSize(){ return m_uReceivedSize; }; + + void reset(); + + void setPostData(const QString &szPostData){ m_szPostData = szPostData; }; + void setUrl(const KviUrl &u){ m_url = u; }; + void setProcessingType(ProcessingType t){ m_eProcessingType = t; }; + void setExistingFileAction(ExistingFileAction a){ m_eExistingFileAction = a; }; + void setFileName(const QString &szFileName){ m_szFileName = szFileName; }; + void setPrivateData(void * ptr){ m_pPrivateData = ptr; }; + void setMaxContentLength(int uMaxContentLength){ m_uMaxContentLength = uMaxContentLength; }; //0 means unlimited + // this will work regardless of ExistingFileAction : even if the file doesn't exist + void setContentOffset(int uContentOffset){ m_uContentOffset = uContentOffset; }; + + bool start(); + + // this is a shortcut for reset()+setUrl()+setProcessingType()+setFileName()+start() + bool get(const KviUrl &u,ProcessingType p = WholeFile,const QString &szFileName = QString::null); + + const QString & lastError(){ return m_szLastError; }; + + void abort(); +signals: + void resolvingHost(const QString &hostname); + void contactingHost(const QString &ipandport); + void connectionEstabilished(); + void receivedResponse(const QString &response); + + void terminated(bool bSuccess); + + + void status(const QString &message); + void data(const KviStr &data); + void binaryData(const KviDataBuffer &data); + void header(KviPointerHashTable<const char *,KviStr> * hdr); + void requestSent(const QStringList &request); +}; + + +class KviHttpRequestThread : public KviSensitiveThread +{ + friend class KviHttpRequest; +public: + enum RequestMethod { Post, Get , Head }; +protected: + KviHttpRequestThread(KviHttpRequest * r, + const QString &szHost, + const QString &szIp, + unsigned short uPort, + const QString &szPath, + unsigned int uContentOffset, + RequestMethod m, + const QString &szPostData = QString::null, + bool bUseSSL = false); + +public: + ~KviHttpRequestThread(); +protected: + KviHttpRequest * m_pRequest; + + QString m_szHost; + QString m_szIp; + QString m_szPath; + unsigned int m_uContentOffset; + RequestMethod m_eRequestMethod; + QString m_szPostData; + + unsigned short m_uPort; + kvi_socket_t m_sock; + bool m_bUseSSL; +#ifdef COMPILE_SSL_SUPPORT + KviSSL * m_pSSL; +#endif +protected: + int selectForReadStep(); + bool selectForRead(int iTimeoutInSecs); + bool readDataStep(); + bool sendBuffer(const char *buffer,int bufLen,int iTimeoutInSecs); + bool failure(const char *error=0); + bool sslFailure(); + bool selectForWrite(int iTimeoutInSecs); + bool connectToRemoteHost(); + bool processInternalEvents(); + void runInternal(); + virtual void run(); +}; + + +#endif //_KVI_HTTP_H_ diff --git a/src/kvilib/net/kvi_netutils.cpp b/src/kvilib/net/kvi_netutils.cpp new file mode 100644 index 00000000..0cdb8b02 --- /dev/null +++ b/src/kvilib/net/kvi_netutils.cpp @@ -0,0 +1,1504 @@ +//============================================================================= + +// + +// File : kvi_netutlis.cpp + +// Creation date : Sun Jun 18 2000 18:37:27 by Szymon Stefanek + +// + +// This file is part of the KVirc irc client distribution + +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) + +// + +// 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 opinion) any later version. + +// + +// This program is distributed in the HOPE that it will be USEFUL, + +// but WITHOUT ANY WARRANTY; without even the implied warranty of + +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +// See the GNU General Public License for more details. + +// + +// You should have received a copy of the GNU General Public License + +// along with this program. If not, write to the Free Software Foundation, + +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +// + +//============================================================================= + +// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARGH! +// This effect is caused by the combination of broken CVS installation and +// the ugly windows "text mode" files + +#define __KVILIB__ + + + + + +#define _KVI_NETUTILS_CPP_ + + + +#include "kvi_netutils.h" + +#include "kvi_memmove.h" +#include <qstringlist.h> + + +#ifndef COMPILE_ON_WINDOWS + +#include <sys/time.h> // struct timeval + +#endif + + + +#include <sys/types.h> + + + +#include "kvi_qstring.h" + + + +#ifndef COMPILE_ON_WINDOWS + + #include <unistd.h> + + #include <netdb.h> + +#endif + + + +#ifdef COMPILE_GET_INTERFACE_ADDRESS + + #include <sys/ioctl.h> + + #include <net/if.h> + +#endif //COMPILE_GET_INTERFACE_ADDRESS + + + +#ifndef HAVE_INET_ATON + + + + + +// FIXME: #warning "Your system lacks the inet_aton function," + +// FIXME: #warning "you're trying to compile this file without" + +// FIXME: #warning "the config.h created by the configure script," + +// FIXME: #warning "Using own internal implementation of inet_aton." + + + +#include <ctype.h> + + + + + +// Need own inet_aton implementation + + + +// + +// Check whether "cp" is a valid ascii representation + +// of an Internet address and convert to a binary address. + +// Returns 1 if the address is valid, 0 if not. + +// This replaces inet_addr, the return value from which + +// cannot distinguish between failure and a local broadcast address. + +// + +// Original code comes from the ircd source. + +// + + + +bool kvi_stringIpToBinaryIp(const char *szIp,struct in_addr *address) + +{ + + register unsigned long val; + + register int base, n; + + register char c; + + unsigned int parts[4]; + + register unsigned int *pp = parts; + + if(!szIp)return false; + + c = *szIp; + + for(;;){ + + // Collect number up to ``.''. + + // Values are specified as for C: + + // 0x=hex, 0=octal, isdigit=decimal. + + if(!isdigit(c))return false; + + val = 0; + + base = 10; + + if(c == '0'){ + + c = *++szIp; + + if((c == 'x')||(c == 'X'))base = 16, c = *++szIp; + + else base = 8; + + } + + for (;;) { + + if(isascii(c) && isdigit(c)) { + + val = (val * base) + (c - '0'); + + c = *++szIp; + + } else if (base == 16 && isascii(c) && isxdigit(c)) { + + val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A')); + + c = *++szIp; + + } else break; + + } + + if(c == '.'){ + + // Internet format: + + // a.b.c.d + + // a.b.c (with c treated as 16 bits) + + // a.b (with b treated as 24 bits) + + if(pp >= (parts + 3)) return false; + + *pp++ = val; + + c = *++szIp; + + } else break; + + } + + // Check for trailing characters. + + if ((c != '\0') && (!isascii(c) || !isspace(c)))return false; + + // Concact the address according to + + // the number of parts specified. + + n = pp - parts + 1; + + switch (n) { + + case 0: return false; // initial nondigit + + case 1: break; // a -- 32 bits + + case 2: // a.b -- 8.24 bits + + if(val > 0xffffff) return false; + + val |= parts[0] << 24; + + break; + + case 3: // a.b.c -- 8.8.16 bits + + if(val > 0xffff)return false; + + val |= (parts[0] << 24) | (parts[1] << 16); + + break; + + case 4: // a.b.c.d -- 8.8.8.8 bits + + if(val > 0xff)return false; + + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + + break; + + } + + if(address)address->s_addr = htonl(val); + + return true; + +} + + + +#else //!HAVE_INET_ATON + + + +bool kvi_stringIpToBinaryIp(const char *szIp,struct in_addr *address) + +{ + + if(!szIp)return false; + + return (inet_aton(szIp,address) != 0); + +} + + + +#endif //!HAVE_INET_ATON + + + +#ifndef HAVE_INET_NTOA + + + +// FIXME: #warning "Your system lacks the inet_ntoa function," + +// FIXME: #warning "you're trying to compile this file without" + +// FIXME: #warning "the config.h created by the configure script," + +// FIXME: #warning "Using own internal implementation of inet_ntoa." + + + +// + +// Original code comes from the ircd source. + +// + + + +bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer) + +{ + + unsigned char *s = (unsigned char *)∈ + + int a,b,c,d; + + a = (int)*s++; + + b = (int)*s++; + + c = (int)*s++; + + d = (int)*s; + + szBuffer.sprintf("%d.%d.%d.%d", a,b,c,d ); + + return true; + +} + + + +#else //HAVE_INET_NTOA + + + +bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer) + +{ + +// FIXME: #warning "This is NOT thread safe!" + + char * ptr = inet_ntoa(in); + + if(!ptr)return false; + + szBuffer = ptr; + + return true; + +} + + + +#endif //HAVE_INET_NTOA + + + +bool kvi_isValidStringIp(const char *szIp) + +{ + + struct in_addr address; + + if(!szIp)return false; + + if(!isdigit(*szIp))return false; + + return kvi_stringIpToBinaryIp(szIp,&address); + +} + + + + + +#ifdef COMPILE_IPV6_SUPPORT + + + +#ifdef COMPILE_ON_WINDOWS + + + +//#include <stdlib.h> + +//#include <sys/socket.h> + +//#include <arpa/inet.h>/ + +//#include <errno.h> + +//#include "dietfeatures.h" + + + +static unsigned int scan_ip6(const char *s,char ip[16]) + +{ + + unsigned int i; + + unsigned int len=0; + + unsigned long u; + + + + char suffix[16]; + + unsigned int prefixlen=0; + + unsigned int suffixlen=0; + + + + for (i=0; i<16; i++) ip[i]=0; + + + + for (;;) { + + if (*s == ':') { + + len++; + + if (s[1] == ':') { /* Found "::", skip to part 2 */ + + s+=2; + + len++; + + break; + + } + + s++; + + } + + { + + char *tmp; + + u=strtoul(s,&tmp,16); + + i=tmp-s; + + } + + + + if (!i) return 0; + + if (prefixlen==12 && s[i]=='.') { + + /* the last 4 bytes may be written as IPv4 address */ + + if (kvi_stringIpToBinaryIp(s,(struct in_addr*)(ip+12))) + + return i+len; + + else + + return 0; + + } + + ip[prefixlen++] = (u >> 8); + + ip[prefixlen++] = (u & 255); + + s += i; len += i; + + if (prefixlen==16) + + return len; + + } + + + +/* part 2, after "::" */ + + for (;;) { + + if (*s == ':') { + + if (suffixlen==0) + + break; + + s++; + + len++; + + } else if (suffixlen!=0) + + break; + + { + + char *tmp; + + u=strtol(s,&tmp,16); + + i=tmp-s; + + } + + if (!i) { + + if (*s) len--; + + break; + + } + + if (suffixlen+prefixlen<=12 && s[i]=='.') { + + if (kvi_stringIpToBinaryIp(s,(struct in_addr*)(suffix+suffixlen))) { + + suffixlen+=4; + + len+=(unsigned int)strlen(s); + + break; + + } else + + prefixlen=12-suffixlen; /* make end-of-loop test true */ + + } + + suffix[suffixlen++] = (u >> 8); + + suffix[suffixlen++] = (u & 255); + + s += i; len += i; + + if (prefixlen+suffixlen==16) + + break; + + } + + for (i=0; i<suffixlen; i++) + + ip[16-suffixlen+i] = suffix[i]; + + return len; + +} + + + +#ifndef WIN2K + + + +int inet_pton(int AF, const char *CP, void *BUF) { + + int len; + + if (AF==AF_INET) { + + if (!kvi_stringIpToBinaryIp(CP,(struct in_addr*)BUF)) + + return 0; + + } else if (AF==AF_INET6) { + + if (CP[len=scan_ip6(CP,(char *)BUF)]) + + return 0; + + } else { + + errno=WSAEPFNOSUPPORT; + + return -1; + + } + + return 1; + +} + + + +#endif //WIN2K + + + +//#include <sys/socket.h> + +//#include <arpa/inet.h> + + + +//extern char *inet_ntoa_r(struct in_addr in,char* buf); + + + +static const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; + + + +static char tohex(char hexdigit) { + + return hexdigit>9?hexdigit+'a'-10:hexdigit+'0'; + +} + + + +static int fmt_xlong(char* s,unsigned int i) + +{ + + char* bak=s; + + *s=tohex((i>>12)&0xf); if (s!=bak || *s!='0') ++s; + + *s=tohex((i>>8)&0xf); if (s!=bak || *s!='0') ++s; + + *s=tohex((i>>4)&0xf); if (s!=bak || *s!='0') ++s; + + *s=tohex(i&0xf); + + return s-bak+1; + +} + + + +static unsigned int i2a(char* dest,unsigned int x) + +{ + + register unsigned int tmp=x; + + register unsigned int len=0; + + if (x>=100) { *dest++=tmp/100+'0'; tmp=tmp%100; ++len; } + + if (x>=10) { *dest++=tmp/10+'0'; tmp=tmp%10; ++len; } + + *dest++=tmp+'0'; + + return len+1; + +} + + + +char *inet_ntoa_r(struct in_addr in,char* buf) + +{ + + unsigned int len; + + unsigned char *ip=(unsigned char*)∈ + + len=i2a(buf,ip[0]); buf[len]='.'; ++len; + + len+=i2a(buf+ len,ip[1]); buf[len]='.'; ++len; + + len+=i2a(buf+ len,ip[2]); buf[len]='.'; ++len; + + len+=i2a(buf+ len,ip[3]); buf[len]=0; + + return buf; + +} + + + + + +unsigned int fmt_ip6(char *s,const char ip[16]) + +{ + + unsigned int len; + + unsigned int i; + + unsigned int temp; + + unsigned int compressing; // 0 not compressing , 1 compressing now , 2 already compressed once + + + + len = 0; + + compressing = 0; + + + + for(int j=0;j<16;j+=2) + + { + + if (j==12 && !memcmp(ip,V4mappedprefix,12)) + + { + + inet_ntoa_r(*(struct in_addr*)(ip+12),s); + + temp=(unsigned int)strlen(s); + + return len+temp; + + } + + temp = ((unsigned long) (unsigned char) ip[j] << 8) + (unsigned long) (unsigned char) ip[j+1]; + + if(temp == 0) + + { + + if(compressing == 0) + + { + + compressing=1; + + if (j==0) + + { + + *s++=':'; + + ++len; + + } + + } + + } else { + + if(compressing == 1) + + { + + compressing=2; // don't do it again + + *s++=':'; ++len; + + } + + i = fmt_xlong(s,temp); + + len += i; + + s += i; + + if (j<14) + + { + + *s++ = ':'; + + ++len; + + } + + } + + } + + if(compressing == 1) + + { + + *s++=':'; + + ++len; + + } + + *s=0; + + return len; + +} + + + +const char* inet_ntop(int AF, const void *CP, char *BUF, size_t LEN) + +{ + + char buf[100]; + + size_t len; + + if (AF==AF_INET) + + { + + inet_ntoa_r(*(struct in_addr*)CP,buf); + + len=strlen(buf); + + } else if (AF==AF_INET6) + + { + + len=fmt_ip6(buf,(char *)CP); + + } else + + return 0; + + if (len<LEN) + + { + + strcpy(BUF,buf); + + return BUF; + + } + + return 0; + +} + + + + + + + + + + + +#endif + + + + + +bool kvi_stringIpToBinaryIp_V6(const char *szIp,struct in6_addr *address) + +{ + + if(!szIp)return false; + + return (inet_pton(AF_INET6,szIp,(void *)address) == 1); + +} + + + +bool kvi_isValidStringIp_V6(const char *szIp) + +{ + + struct in6_addr address; + + if(!szIp)return false; + + return kvi_stringIpToBinaryIp_V6(szIp,&address); + +} + + + + + + + +bool kvi_binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer) + +{ + + char buf[46]; + + bool bRet = inet_ntop(AF_INET6,(void *)&in,buf,46); + + szBuffer= buf; + + return bRet; + +} + + + +#endif + + + +#include <errno.h> + + + +bool kvi_select(int fd,bool * bCanRead,bool * bCanWrite,int iUSecs) + +{ + + // FIXME: This stuff should DIE! + + fd_set rs; + + fd_set ws; + + FD_ZERO(&rs); + + FD_ZERO(&ws); + + FD_SET(fd,&rs); + + FD_SET(fd,&ws); + + struct timeval tv; + + tv.tv_sec = 0; + + tv.tv_usec = iUSecs; + + int ret = select(fd + 1,&rs,&ws,0,&tv); + + if(ret < 1)return false; // EINTR or ENOSTUFFATALL + + *bCanRead = FD_ISSET(fd,&rs); + + *bCanWrite = FD_ISSET(fd,&ws); + + return true; + +} + + + +namespace KviNetUtils + +{ + + bool stringIpToBinaryIp(const QString &szStringIp,struct in_addr * address) + { +#ifndef HAVE_INET_ATON + QString szAddr = szStringIp.simplifyWhiteSpace(); + Q_UINT32 iAddr=0; + QStringList ipv4 = QStringList::split(".", szAddr, FALSE); + if (ipv4.count() == 4) { + int i = 0; + bool ok = TRUE; + while(ok && i < 4) { + uint byteValue = ipv4[i].toUInt(&ok); + if ( (byteValue > 255) && ok ) + ok = FALSE; + if (ok) + iAddr = (iAddr << 8) + byteValue; + ++i; + } + if (ok) + { + if(address)address->s_addr = htonl(iAddr); + return true; + } + } + return FALSE; +#else //HAVE_INET_ATON + if(szStringIp.isEmpty())return false; + return (inet_aton(KviQString::toUtf8(szStringIp).data(),address) != 0); +#endif //HAVE_INET_ATON + } + + + bool isValidStringIp(const QString &szIp) + + { + + struct in_addr address; + + if(szIp.isEmpty())return false; + + if(!szIp[0].isNumber())return false; + + return stringIpToBinaryIp(szIp,&address); + + } + + + +#ifdef COMPILE_IPV6_SUPPORT + + bool stringIpToBinaryIp_V6(const QString &szStringIp,struct in6_addr * address) + + { + + return (inet_pton(AF_INET6,KviQString::toUtf8(szStringIp).data(),(void *)address) == 1); + + } + + + + bool isValidStringIp_V6(const QString &szIp) + + { + + struct in6_addr address; + + if(szIp.isEmpty())return false; + + return stringIpToBinaryIp_V6(szIp,&address); + + } + + bool binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer) + { + char buf[46]; + bool bRet = inet_ntop(AF_INET6,(void *)&in,buf,46); + szBuffer= buf; + return bRet; + } + + +#endif //COMPILE_IPV6_SUPPORT + + + + bool binaryIpToStringIp(struct in_addr in,QString &szBuffer) + + { + + char * ptr = inet_ntoa(in); + + if(!ptr)return false; + + szBuffer = ptr; + + return true; + + } + + + + bool isRoutableIpString(const QString &szIpString) + + { + + struct in_addr a; + + if(szIpString.isEmpty())return false; + + stringIpToBinaryIp(szIpString,&a); + + return isRoutableIp((const char *)&a); + + } + + + + bool isRoutableIp(const char * ipaddr) + + { + + if(!ipaddr)return false; + + const unsigned char * ip = (const unsigned char *)ipaddr; + + if(ip[0] == 0)return false; // old-style broadcast + + if(ip[0] == 10)return false; // Class A VPN + + if(ip[0] == 127)return false; // loopback + + if((ip[0] == 172) && (ip[1] >= 16) && (ip[1] <= 31))return false; // Class B VPN + + if((ip[0] == 192) && (ip[1] == 168))return false; // Class C VPN + + if((ip[0] == 169) && (ip[1] == 254))return false; // APIPA + + if((ip[0] == 192) && (ip[1] == 0) && (ip[2] == 2))return false; // Class B VPN + + if(ip[0] >= 224)return false; // class D multicast and class E reserved + + + + return true; + + } + + + + bool getInterfaceAddress(const QString &szInterfaceName,QString &szBuffer) + + { + +#ifdef COMPILE_GET_INTERFACE_ADDRESS + + struct sockaddr *sa; + + struct sockaddr_in *sin; + + struct ifreq ifr; + + int len = szInterfaceName.length(); + + if(len > (IFNAMSIZ - 1))return false; // invalid interface anyway + + + + kvi_memmove(ifr.ifr_name,KviQString::toUtf8(szInterfaceName).data(),len + 1); + + + + int fd = socket(AF_INET,SOCK_STREAM,0); + + if(fd < 0)return false; + + + + if(ioctl(fd,SIOCGIFADDR,&ifr) == -1)return false; // supports only IPV4 ? + + + + close(fd); + + + + sa = (struct sockaddr *)&(ifr.ifr_addr); + + + + if (sa->sa_family != AF_INET) return false; + + sin = (struct sockaddr_in*) sa; + + return binaryIpToStringIp(sin->sin_addr,szBuffer); + + // (this seems to work for AF_INET only anyway) + +#else //!COMPILE_GET_INTERFACE_ADDRESS + + return false; + +#endif //!COMPILE_GET_INTERFACE_ADDRESS + + } + + + + void formatNetworkBandwidthString(QString &szBuffer,unsigned int uBytesPerSec) + + { + + if(uBytesPerSec > (1024 * 1024)) + + { + + unsigned int uMB = uBytesPerSec / (1024 * 1024); + + unsigned int uRem = ((uBytesPerSec % (1024 * 1024)) * 100) / (1024 * 1024); + + KviQString::sprintf(szBuffer,"%u.%u%u MB/s",uMB,uRem / 10,uRem % 10); + + return; + + } + + if(uBytesPerSec >= 1024) + + { + + unsigned int uKB = uBytesPerSec / 1024; + + unsigned int uRem = ((uBytesPerSec % 1024) * 100) / 1024; + + KviQString::sprintf(szBuffer,"%u.%u%u KB/s",uKB,uRem / 10,uRem % 10); + + return; + + } + + KviQString::sprintf(szBuffer,"%u B/s",uBytesPerSec); + + } + + + + + +}; + + + +bool kvi_getInterfaceAddress(const char * ifname,QString &buffer) + +{ + + debug("kvi_getInterfaceAddress is deprecated: use KviNetUtils::getInterfaceAddress"); + + QString szRet; + + bool bRes = KviNetUtils::getInterfaceAddress(QString(ifname),szRet); + + buffer = szRet; + + return bRes; + +} + + + +bool kvi_isRoutableIpString(const char * ipstring) + +{ + + struct in_addr a; + + if(!ipstring)return false; + + kvi_stringIpToBinaryIp(ipstring,&a); + + return kvi_isRoutableIp((const char *)&a); + +} + + + +bool kvi_isRoutableIp(const char * ipaddr) + +{ + + if(!ipaddr)return false; + + const unsigned char * ip = (const unsigned char *)ipaddr; + + if(ip[0] == 0)return false; // old-style broadcast + + if(ip[0] == 10)return false; // Class A VPN + + if(ip[0] == 127)return false; // loopback + + if((ip[0] == 172) && (ip[1] >= 16) && (ip[1] <= 31))return false; // Class B VPN + + if((ip[0] == 192) && (ip[1] == 168))return false; // Class C VPN + + if((ip[0] == 169) && (ip[1] == 254))return false; // APIPA + + if((ip[0] == 192) && (ip[1] == 0) && (ip[2] == 2))return false; // Class B VPN + + if(ip[0] >= 224)return false; // class D multicast and class E reserved + + + + return true; + +} + + + +bool kvi_getLocalHostAddress(QString &buffer) + +{ + + // This will work only on windoze... + + char buf[1024]; + + if(gethostname(buf,1024) != 0)return false; + + struct hostent * h = gethostbyname(buf); + + if(!h)return false; + + QString tmp; + + int i=0; + + while(h->h_addr_list[i]) + + { + + if(kvi_binaryIpToStringIp(*((struct in_addr *)(h->h_addr_list[i])),tmp)) + + { + + if(kvi_isRoutableIp(h->h_addr_list[i])) + + { + + buffer = tmp; + + return true; + + } + + } + + i++; + + } + + buffer = tmp; + + return true; + +} + + + + + + + + + + + +KviSockaddr::KviSockaddr(const char * szIpAddress,kvi_u32_t uPort,bool bIpV6,bool bUdp) + +{ + struct addrinfo hints; + kvi_memset((void *)&hints,0,sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; +#ifdef COMPILE_IPV6_SUPPORT + hints.ai_family = bIpV6 ? PF_INET6 : PF_INET; +#else + hints.ai_family = PF_INET; +#endif + + hints.ai_socktype = bUdp ? SOCK_DGRAM : SOCK_STREAM; + + hints.ai_protocol = 0; + m_pData = 0; + KviStr szPort(KviStr::Format,"%u",uPort); + getaddrinfo(szIpAddress,szPort.ptr(),&hints,(struct addrinfo **)&m_pData); + +} + + +KviSockaddr::KviSockaddr(kvi_u32_t uPort,bool bIpV6,bool bUdp) // passive sockaddr + +{ + struct addrinfo hints; + kvi_memset((void *)&hints,0,sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; +#ifdef COMPILE_IPV6_SUPPORT + hints.ai_family = bIpV6 ? PF_INET6 : PF_INET; +#else + hints.ai_family = PF_INET; +#endif + hints.ai_socktype = bUdp ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = 0; + m_pData = 0; + KviStr szPort(KviStr::Format,"%u",uPort); + getaddrinfo(0,szPort.ptr(),&hints,(struct addrinfo **)&m_pData); + +} + + + +KviSockaddr::~KviSockaddr() + +{ + + if(m_pData) + + { + + freeaddrinfo((struct addrinfo *)m_pData); + + m_pData = 0; + + } + +} + + + +struct sockaddr * KviSockaddr::socketAddress() + +{ + + if(!m_pData)return 0; + + return ((struct addrinfo *)m_pData)->ai_addr; + +} + + + +size_t KviSockaddr::addressLength() + +{ + + if(!m_pData)return 0; + + return ((struct addrinfo *)m_pData)->ai_addrlen; + +} + + + +int KviSockaddr::addressFamily() + +{ + + if(!m_pData)return 0; + + return ((struct addrinfo *)m_pData)->ai_family; + +} + + + +bool KviSockaddr::isIpV6() + +{ + + if(!m_pData)return false; + +#ifdef COMPILE_IPV6_SUPPORT + + return false; + +#else + + return (addressFamily() == AF_INET6); + +#endif + +} + + + +kvi_u32_t KviSockaddr::port() + +{ + if(!m_pData)return 0; +#ifdef COMPILE_IPV6_SUPPORT + switch(((struct addrinfo *)m_pData)->ai_family) + { + case AF_INET: + return ntohs(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_port); + break; + case AF_INET6: + return ntohs(((struct sockaddr_in6 *)(((struct addrinfo *)m_pData)->ai_addr))->sin6_port); + break; + } + return 0; +#else + return ntohs(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_port); +#endif + +} + + + +bool KviSockaddr::getStringAddress(QString &szBuffer) + +{ + + if(!m_pData)return 0; + +#ifdef COMPILE_IPV6_SUPPORT + + switch(((struct addrinfo *)m_pData)->ai_family) + + { + + case AF_INET: + + return kvi_binaryIpToStringIp(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_addr,szBuffer); + + break; + + case AF_INET6: + + return kvi_binaryIpToStringIp_V6(((struct sockaddr_in6 *)(((struct addrinfo *)m_pData)->ai_addr))->sin6_addr,szBuffer); + + break; + + } + + return false; + +#else + + return kvi_binaryIpToStringIp(((struct sockaddr_in *)(((struct addrinfo *)m_pData)->ai_addr))->sin_addr,szBuffer); + +#endif + +} + diff --git a/src/kvilib/net/kvi_netutils.h b/src/kvilib/net/kvi_netutils.h new file mode 100644 index 00000000..b43326f0 --- /dev/null +++ b/src/kvilib/net/kvi_netutils.h @@ -0,0 +1,104 @@ +#ifndef _KVI_NETUTILS_H_ +#define _KVI_NETUTILS_H_ + +// +// File : kvi_netutlis.h +// Creation date : Sun Jun 18 2000 18:37:27 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_inttypes.h" + +#ifdef COMPILE_ON_WINDOWS + #include <winsock2.h> + #ifdef COMPILE_IPV6_SUPPORT + #ifdef WIN2K + #include <ws2ip6.h> + #else + #include <ws2tcpip.h> + //#include <tpipv6.h> + #define in6_addr in_addr6 + #endif + #endif +#else + #include <sys/types.h> + #include <sys/socket.h> + #include <netinet/in.h> //in_addr + #include <arpa/inet.h> //inet_ntoa inet_ntop and inet_pton depend on this one. +#endif + +#include "kvi_string.h" + + +KVILIB_API extern bool kvi_isValidStringIp(const char * szIp); +KVILIB_API extern bool kvi_stringIpToBinaryIp(const char * szIp,struct in_addr * address); +KVILIB_API extern bool kvi_binaryIpToStringIp(struct in_addr in,QString &szBuffer); + +#ifdef COMPILE_IPV6_SUPPORT + KVILIB_API extern bool kvi_isValidStringIp_V6(const char * szIp); + KVILIB_API extern bool kvi_stringIpToBinaryIp_V6(const char * szIp,struct in6_addr * address); + KVILIB_API extern bool kvi_binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer); +#endif + +class KVILIB_API KviSockaddr +{ +public: + KviSockaddr(const char * szIpAddress,kvi_u32_t uPort,bool bIpV6,bool bUdp = false); + KviSockaddr(kvi_u32_t uPort,bool bIpV6,bool bUdp = false); // passive + ~KviSockaddr(); +private: + void * m_pData; //addrinfo +public: + struct sockaddr * socketAddress(); + size_t addressLength(); + int addressFamily(); + bool isIpV6(); + bool getStringAddress(QString &szBuffer); + kvi_u32_t port(); + +}; + + +KVILIB_API extern bool kvi_select(int fd,bool * bCanRead,bool * bCanWrite,int iUSecs = 0); +KVILIB_API extern bool kvi_getInterfaceAddress(const char * ifname,QString &buffer); + +// Warning : NOT THREAD SAFE! +KVILIB_API extern bool kvi_getLocalHostAddress(QString &buffer); +KVILIB_API extern bool kvi_isRoutableIp(const char * ipaddr); +KVILIB_API extern bool kvi_isRoutableIpString(const char * ipstring); + +namespace KviNetUtils +{ + KVILIB_API bool stringIpToBinaryIp(const QString &szStringIp,struct in_addr * address); + KVILIB_API bool isValidStringIp(const QString &szStringIp); + KVILIB_API bool binaryIpToStringIp(struct in_addr in,QString &szBuffer); + KVILIB_API bool getInterfaceAddress(const QString &szInterfaceName,QString &szBuffer); +#ifdef COMPILE_IPV6_SUPPORT + KVILIB_API bool isValidStringIp_V6(const QString &szStringIp); + KVILIB_API bool stringIpToBinaryIp_V6(const QString &szStringIp,struct in6_addr * address); + KVILIB_API bool binaryIpToStringIp_V6(struct in6_addr in,QString &szBuffer); +#endif + KVILIB_API bool isRoutableIp(const char * ipaddr); + KVILIB_API bool isRoutableIpString(const QString &szIpString); + KVILIB_API void formatNetworkBandwidthString(QString &szBuffer,unsigned int uBytesPerSec); +}; + + +#endif //!_KVI_NETUTILS_H_ diff --git a/src/kvilib/net/kvi_socket.cpp b/src/kvilib/net/kvi_socket.cpp new file mode 100644 index 00000000..9bd3de9e --- /dev/null +++ b/src/kvilib/net/kvi_socket.cpp @@ -0,0 +1,31 @@ +// +// File : kvi_socket.cpp +// Creation date : Thu Sep 20 03:50:24 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define _KVI_SOCKET_CPP_ + +#define __KVILIB__ + +#include "kvi_socket.h" +#include "kvi_inttypes.h" + +KVILIB_API kvi_u64_t g_uOutgoingTraffic; +KVILIB_API kvi_u64_t g_uIncomingTraffic; diff --git a/src/kvilib/net/kvi_socket.h b/src/kvilib/net/kvi_socket.h new file mode 100644 index 00000000..47d51510 --- /dev/null +++ b/src/kvilib/net/kvi_socket.h @@ -0,0 +1,356 @@ +#ifndef _KVI_SOCKET_H_ +#define _KVI_SOCKET_H_ +//============================================================================= +// +// File : kvi_socket.h +// Creation date : Thu Sep 20 03:50:22 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// Socket stuff abstraction layer +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_sockettype.h" // <--- this includes <winsock2.h> if needed + +#include <errno.h> + +#include "kvi_inttypes.h" + +//#ifndef _KVI_SOCKET_CPP_ + extern KVILIB_API kvi_u64_t g_uOutgoingTraffic; + extern KVILIB_API kvi_u64_t g_uIncomingTraffic; +//#endif //!_KVI_SOCKET_CPP_ + + + +#ifdef COMPILE_ON_WINDOWS + + #define KVI_INVALID_SOCKET INVALID_SOCKET + +#else + + #include <sys/time.h> + #include <sys/types.h> + #include <sys/socket.h> + #include <netinet/tcp.h> + #include <netinet/in.h> + #include <fcntl.h> + #include <unistd.h> + + #define KVI_INVALID_SOCKET (-1) + +#endif + +#ifndef MSG_NOSIGNAL + // At least solaris seems to not have it + #define MSG_NOSIGNAL 0 +#endif + +//#include "kvi_socketcalls.h" + + +//================================================================================================ +// Constants for kvi_socket_create +// + +#define KVI_SOCKET_PF_INET PF_INET +#define KVI_SOCKET_PF_INET6 PF_INET6 +#define KVI_SOCKET_PF_UNIX PF_UNIX + +#define KVI_SOCKET_TYPE_STREAM SOCK_STREAM +#define KVI_SOCKET_TYPE_DGRAM SOCK_DGRAM + +#define KVI_SOCKET_PROTO_TCP 0 + +//================================================================================================ +// kvi_socket_create +// kvi_socket_open +// +// Open a socket of the specified protocol family , type and protocol +// You should always use the KVI_SOCKET_* constants as parameters +// Returns KVI_INVALID_SOCKET if the socket creation has failed. +// The returned socket is in blocking mode! +// + +#define kvi_socket_open kvi_socket_create + +inline kvi_socket_t kvi_socket_create(int pf,int type,int proto) +{ + return (kvi_socket_t)socket(pf,type,proto); +}; + +//================================================================================================ +// kvi_socket_isValid +// +// Check if a socket is valid or not +// + +inline void kvi_socket_flushTrafficCounters() +{ + g_uOutgoingTraffic = 0; + g_uIncomingTraffic = 0; +} + +inline bool kvi_socket_isValid(kvi_socket_t sock) +{ + return (sock != ((kvi_socket_t)(KVI_INVALID_SOCKET))); +} + +//================================================================================================ +// kvi_socket_destroy +// kvi_socket_close +// +// Close a socket...that's all :) +// + +#define kvi_socket_close kvi_socket_destroy + +inline void kvi_socket_destroy(kvi_socket_t sock) +{ +#ifdef COMPILE_ON_WINDOWS + closesocket(sock); +#else + close(sock); +#endif +}; + +//================================================================================================ +// kvi_socket_setNonBlocking +// +// Sets the socket in nonBlocking mode. Obviously returns false in case of failure +// + +inline bool kvi_socket_setNonBlocking(kvi_socket_t sock) +{ +#ifdef COMPILE_ON_WINDOWS + unsigned long arg = 1; + return (ioctlsocket(sock,FIONBIO,(unsigned long FAR *)&arg) == 0); +#else + return (fcntl(sock,F_SETFL,O_NONBLOCK) == 0); +#endif +}; + +//================================================================================================ +// kvi_socket_bind +// +// Standard bind() call on the socket. Returns false in case of failure +// + +inline bool kvi_socket_bind(kvi_socket_t sock,const struct sockaddr * sa,int salen) +{ + return (::bind(sock,sa,salen) == 0); +}; + +//================================================================================================ +// kvi_socket_connect +// +// Starts a connection to the specified remote address +// returns false if the connection can not be started. +// You might take a look at kvi_socket_errno() then. +// + +inline bool kvi_socket_connect(kvi_socket_t sock,const struct sockaddr *sa,int salen) +{ +#ifdef COMPILE_ON_WINDOWS + return (WSAConnect(sock,sa,salen,0,0,0,0) == 0); +#else + return (::connect(sock,sa,salen) == 0); +#endif +}; + +inline bool kvi_socket_recoverableConnectError(int err) +{ +#ifdef COMPILE_ON_WINDOWS + return ((err == WSAEINPROGRESS) || (err == WSAEWOULDBLOCK)); +#else + return (err == EINPROGRESS); +#endif +}; + +inline bool kvi_socket_recoverableError(int err) +{ +#ifdef COMPILE_ON_WINDOWS + return ((err == WSAEWOULDBLOCK) || (err == EINTR) || (err == EAGAIN)); +#else + return ((err == EINTR) || (err = EAGAIN)); +#endif +} + +//================================================================================================ +// kvi_socket_accept +// +// Standard accept() call. Returns KVI_INVALID_SOCKET in case of failure +// You should check kvi_socket_errno() then. +// + +inline kvi_socket_t kvi_socket_accept(kvi_socket_t sock,struct sockaddr *sa,int * salen) +{ +#ifdef COMPILE_ON_WINDOWS + return (kvi_socket_t)::accept(sock,sa,salen); +#else + return (kvi_socket_t)::accept(sock,sa,(socklen_t *)salen); +#endif +}; + +//================================================================================================ +// kvi_socket_listen +// +// Standard listen() call. Returns false in case of failure +// You should check kvi_socket_errno() then. +// + +inline bool kvi_socket_listen(kvi_socket_t sock,int backlog) +{ + return (::listen(sock,backlog) == 0); +}; + +//================================================================================================ +// kvi_socket_select +// +// Standard select() call. This is complex so here is a mini-reminder: +// nhpo is the number of the highest file descriptor in the sets plus one! +// Returns the number of sockets with data available (or space available) +// or something that is less than 0 in case of error. You should check kvi_socket_errno() then. +// + +inline int kvi_socket_select(int nhpo,fd_set *r,fd_set *w,fd_set *e,struct timeval * t) +{ + return ::select(nhpo,r,w,e,t); +}; + +//================================================================================================ +// kvi_socket_send +// kvi_socket_write +// +// Standard send() call. On UNIX ignores SIGPIPE. Returns the number of bytes sent or +// -1 in case of failure. You should check kvi_socket_errno() then. +// + +#define kvi_socket_write kvi_socket_send + +inline int kvi_socket_send(kvi_socket_t sock,const void * buf,int size) +{ + g_uOutgoingTraffic+=size; +#ifdef COMPILE_ON_WINDOWS + return ::send(sock,(const char *)buf,size,0); +#else + return ::send(sock,buf,size,MSG_NOSIGNAL | MSG_DONTWAIT); +#endif +}; + +//================================================================================================ +// kvi_socket_recv +// kvi_socket_read +// +// Standard read() call. On UNIX ignores SIGPIPE. Returns the number of bytes readed or +// -1 in case of failure. You should check kvi_socket_errno() then. +// + +#define kvi_socket_read kvi_socket_recv + +inline int kvi_socket_recv(kvi_socket_t sock,void * buf,int maxlen) +{ + int iReceived; +#ifdef COMPILE_ON_WINDOWS + iReceived = ::recv(sock,(char *)buf,maxlen,0); +#else + iReceived = ::recv(sock,buf,maxlen,MSG_NOSIGNAL); +#endif + g_uIncomingTraffic+=iReceived; + return iReceived; +}; + +//================================================================================================ +// kvi_socket_getsockopt +// +// Standard getsockopt() call. Returns false in case of failure. +// You should check kvi_socket_errno() then. +// + +inline bool kvi_socket_getsockopt(kvi_socket_t sock,int level,int optname,void *optval,int *optlen) +{ +#ifdef COMPILE_ON_WINDOWS + return (::getsockopt(sock,level,optname,(char FAR *)optval,optlen) == 0); +#else + return (::getsockopt(sock,level,optname,optval,(socklen_t *)optlen) == 0); +#endif +} + +//================================================================================================ +// kvi_socket_setsockopt +// +// Standard setsockopt() call. Returns false in case of failure. +// You should check kvi_socket_errno() then. +// + +inline bool kvi_socket_setsockopt(kvi_socket_t sock,int level,int optname,const void *optval,int optlen) +{ +#ifdef COMPILE_ON_WINDOWS + return (::setsockopt(sock,level,optname,(char FAR *)optval,optlen) == 0); +#else + return (::setsockopt(sock,level,optname,optval,optlen) == 0); +#endif +} + + +//================================================================================================ +// kvi_socket_disableNagle +// +// Disables the nagle algorithm (sets TCP_NODELAY) +// + +/* + unused for now +inline bool kvi_socket_disableNagle(kvi_socket_t sock) +{ + int opt = 1; + return kvi_socket_setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,&opt,sizeof(opt)); +}; +*/ + +//================================================================================================ +// kvi_socket_getsockname +// +// Standard getsockname() call. Returns false in case of failure. +// You should check kvi_socket_errno() then. +// + +inline bool kvi_socket_getsockname(kvi_socket_t sock,struct sockaddr * addr,int * addrlen) +{ +#ifdef COMPILE_ON_WINDOWS + return (::getsockname(sock,addr,addrlen) == 0); +#else + return (::getsockname(sock,addr,(socklen_t *)addrlen) == 0); +#endif +} + +inline int kvi_socket_error() +{ +#ifdef COMPILE_ON_WINDOWS + return WSAGetLastError(); +#else + return errno; +#endif +} + + +#endif //_KVI_SOCKET_H_ diff --git a/src/kvilib/net/kvi_sockettype.h b/src/kvilib/net/kvi_sockettype.h new file mode 100644 index 00000000..c8a45743 --- /dev/null +++ b/src/kvilib/net/kvi_sockettype.h @@ -0,0 +1,45 @@ +#ifndef _KVI_SOCKETTYPE_H_ +#define _KVI_SOCKETTYPE_H_ +//============================================================================= +// +// File : kvi_sockettype.h +// Creation date : Thu Sep 20 05:41:46 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// Socket stuff abstraction layer +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_ON_WINDOWS + + #include <winsock2.h> + + typedef SOCKET kvi_socket_t; + +#else + + typedef int kvi_socket_t; + +#endif + +#endif //_KVI_SOCKETTYPE_H_ diff --git a/src/kvilib/net/kvi_ssl.cpp b/src/kvilib/net/kvi_ssl.cpp new file mode 100644 index 00000000..6748e062 --- /dev/null +++ b/src/kvilib/net/kvi_ssl.cpp @@ -0,0 +1,687 @@ +//============================================================================= +// +// File : kvi_ssl.cpp +// Creation date : Mon May 27 2002 21:36:12 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_ssl.h" +#include "kvi_locale.h" + +#ifdef COMPILE_SSL_SUPPORT + +#include "kvi_thread.h" +#include "kvi_memmove.h" +#include "kvi_malloc.h" + +#include <openssl/asn1.h> +#include <openssl/err.h> +#include <openssl/dh.h> + +#include <stdio.h> + +static bool g_bSSLInitialized = false; +static KviMutex * g_pSSLMutex = 0; + + +static inline void my_ssl_lock() +{ + g_pSSLMutex->lock(); +} + +static inline void my_ssl_unlock() +{ + g_pSSLMutex->unlock(); +} + + +// THIS PART OF OpenSSL SUCKS + +static DH * dh_512 = 0; +static DH * dh_1024 = 0; +static DH * dh_2048 = 0; +static DH * dh_4096 = 0; + +static unsigned char dh512_p[]={ + 0x90,0x86,0xDD,0x06,0xE8,0x0F,0x10,0x86,0xF0,0x91,0xC5,0x55, + 0x4D,0x6B,0xAF,0x69,0x4F,0x01,0xED,0xF9,0x57,0x8F,0x3B,0xB8, + 0x9C,0x87,0xAE,0x85,0xC1,0xBF,0x57,0xA5,0xD5,0xBA,0x81,0x24, + 0xE7,0x99,0xE3,0xF6,0xCD,0xB4,0x41,0xB7,0x7F,0x6E,0x7B,0xB1, + 0xD2,0xF3,0xE9,0x0F,0xB9,0x0E,0x4D,0xEB,0x9D,0xD4,0xA9,0xE5, + 0x03,0x67,0xA7,0x27 +}; +static unsigned char dh512_g[]={ 0x05 }; + +static unsigned char dh1024_p[]={ + 0xA5,0x4C,0xB9,0xB9,0xC4,0x35,0x88,0x68,0x9B,0x79,0x48,0x6C, + 0x21,0xA7,0x8E,0xE2,0x9C,0xAF,0x2F,0x04,0xBF,0x45,0xBC,0xF5, + 0xAB,0x35,0x86,0xC8,0xBB,0x9B,0x75,0x18,0x7C,0x9B,0xAB,0xE8, + 0x52,0x7F,0x57,0x3E,0xD8,0x65,0x7D,0x2B,0xE1,0x6D,0x3D,0xA5, + 0x32,0xE8,0xA0,0x2B,0x7A,0x58,0x6B,0x47,0x16,0x4E,0xB1,0xFC, + 0x09,0xB7,0x7C,0xC6,0xE9,0x6E,0xC7,0xC7,0xA1,0x42,0x0F,0x4B, + 0x43,0xFB,0x58,0xBA,0xC7,0x66,0xD6,0xCA,0x6B,0xC7,0x45,0x7C, + 0x99,0xE4,0x46,0x02,0x93,0x3F,0x28,0xD2,0xCE,0x0C,0x8A,0xDD, + 0x6A,0x22,0x2E,0xA9,0x9A,0xCA,0x16,0x48,0x4E,0x67,0x4C,0xE9, + 0xC8,0x54,0xCD,0x18,0xC9,0xF3,0x30,0x3A,0x74,0xAB,0xF9,0xAF, + 0xE4,0xA4,0x0D,0x56,0x62,0x28,0x07,0xBF +}; +static unsigned char dh1024_g[]={ 0x05 }; + +static unsigned char dh2048_p[]={ + 0xBF,0x67,0x7B,0x79,0xA5,0x22,0xD3,0xB5,0x0C,0x13,0xE6,0x92, + 0x54,0xFD,0x64,0xBF,0x57,0x25,0xBD,0x02,0x7C,0xFD,0x72,0x97, + 0x82,0xA4,0xA6,0x0A,0xB9,0xE6,0x4B,0xFA,0xBD,0xFA,0x71,0x8A, + 0x2E,0x36,0xF9,0x03,0x58,0x1B,0xB6,0x3A,0xFD,0x15,0xCC,0x87, + 0x5D,0x04,0xF7,0x45,0xE0,0xE2,0x34,0x7F,0x54,0x5F,0x5D,0x14, + 0xD3,0xCA,0x3E,0xFD,0x2A,0x92,0x10,0x89,0xA0,0xB0,0xB4,0xE5, + 0x80,0x05,0x13,0xBE,0xA3,0xD0,0x42,0x4B,0x98,0x44,0x54,0xB3, + 0xE0,0x23,0x26,0xF5,0x6B,0x0E,0x4D,0x2A,0x81,0xB2,0x8A,0x06, + 0xC8,0x00,0x9E,0xAB,0x1B,0x77,0xDC,0x87,0x9C,0x6C,0xD5,0xEE, + 0xB4,0xB4,0xDD,0xDA,0x3F,0x40,0xA3,0xFA,0xC1,0x1E,0xC0,0xA2, + 0x9E,0xB8,0xAC,0x31,0xE8,0x12,0x93,0x9C,0x71,0xF6,0xE7,0xF0, + 0x65,0x7F,0xA5,0x20,0xF7,0x49,0x3D,0xD6,0xF9,0xD3,0xF0,0x3F, + 0xB3,0xF0,0xD0,0x23,0x22,0x82,0xA5,0xDD,0xFB,0xD9,0x9C,0x7D, + 0xE7,0xA0,0x78,0xE8,0xF9,0x02,0x0C,0x2F,0x1D,0x52,0xC7,0x61, + 0xED,0xA0,0xC9,0x06,0x14,0xDF,0xE7,0xB1,0x1E,0x50,0x98,0x4F, + 0x10,0xB9,0x87,0x4C,0x1C,0x9C,0xB3,0xD2,0x98,0x23,0x7C,0x47, + 0xD2,0x3C,0xC5,0x29,0x65,0xC5,0x67,0x4E,0xC0,0x76,0x0F,0x43, + 0x27,0x28,0x89,0x69,0x30,0x7D,0x04,0xFD,0xF7,0x89,0xE5,0xD6, + 0xE6,0x97,0x7D,0xBB,0x54,0x5F,0xB7,0x94,0x1D,0xBC,0x82,0xAB, + 0x9A,0xF5,0x0A,0x0C,0x89,0x68,0xE7,0x0A,0x8C,0x2D,0x0D,0x82, + 0x44,0xA7,0xB8,0xF9,0x0B,0x8E,0xCB,0xA4,0x6A,0xA7,0xEC,0x5F, + 0x0A,0xF8,0x5F,0xE7 +}; +static unsigned char dh2048_g[]={ 0x05 }; + +static unsigned char dh4096_p[]={ + 0xFA,0x14,0x72,0x52,0xC1,0x4D,0xE1,0x5A,0x49,0xD4,0xEF,0x09, + 0x2D,0xC0,0xA8,0xFD,0x55,0xAB,0xD7,0xD9,0x37,0x04,0x28,0x09, + 0xE2,0xE9,0x3E,0x77,0xE2,0xA1,0x7A,0x18,0xDD,0x46,0xA3,0x43, + 0x37,0x23,0x90,0x97,0xF3,0x0E,0xC9,0x03,0x50,0x7D,0x65,0xCF, + 0x78,0x62,0xA6,0x3A,0x62,0x22,0x83,0xA1,0x2F,0xFE,0x79,0xBA, + 0x35,0xFF,0x59,0xD8,0x1D,0x61,0xDD,0x1E,0x21,0x13,0x17,0xFE, + 0xCD,0x38,0x87,0x9E,0xF5,0x4F,0x79,0x10,0x61,0x8D,0xD4,0x22, + 0xF3,0x5A,0xED,0x5D,0xEA,0x21,0xE9,0x33,0x6B,0x48,0x12,0x0A, + 0x20,0x77,0xD4,0x25,0x60,0x61,0xDE,0xF6,0xB4,0x4F,0x1C,0x63, + 0x40,0x8B,0x3A,0x21,0x93,0x8B,0x79,0x53,0x51,0x2C,0xCA,0xB3, + 0x7B,0x29,0x56,0xA8,0xC7,0xF8,0xF4,0x7B,0x08,0x5E,0xA6,0xDC, + 0xA2,0x45,0x12,0x56,0xDD,0x41,0x92,0xF2,0xDD,0x5B,0x8F,0x23, + 0xF0,0xF3,0xEF,0xE4,0x3B,0x0A,0x44,0xDD,0xED,0x96,0x84,0xF1, + 0xA8,0x32,0x46,0xA3,0xDB,0x4A,0xBE,0x3D,0x45,0xBA,0x4E,0xF8, + 0x03,0xE5,0xDD,0x6B,0x59,0x0D,0x84,0x1E,0xCA,0x16,0x5A,0x8C, + 0xC8,0xDF,0x7C,0x54,0x44,0xC4,0x27,0xA7,0x3B,0x2A,0x97,0xCE, + 0xA3,0x7D,0x26,0x9C,0xAD,0xF4,0xC2,0xAC,0x37,0x4B,0xC3,0xAD, + 0x68,0x84,0x7F,0x99,0xA6,0x17,0xEF,0x6B,0x46,0x3A,0x7A,0x36, + 0x7A,0x11,0x43,0x92,0xAD,0xE9,0x9C,0xFB,0x44,0x6C,0x3D,0x82, + 0x49,0xCC,0x5C,0x6A,0x52,0x42,0xF8,0x42,0xFB,0x44,0xF9,0x39, + 0x73,0xFB,0x60,0x79,0x3B,0xC2,0x9E,0x0B,0xDC,0xD4,0xA6,0x67, + 0xF7,0x66,0x3F,0xFC,0x42,0x3B,0x1B,0xDB,0x4F,0x66,0xDC,0xA5, + 0x8F,0x66,0xF9,0xEA,0xC1,0xED,0x31,0xFB,0x48,0xA1,0x82,0x7D, + 0xF8,0xE0,0xCC,0xB1,0xC7,0x03,0xE4,0xF8,0xB3,0xFE,0xB7,0xA3, + 0x13,0x73,0xA6,0x7B,0xC1,0x0E,0x39,0xC7,0x94,0x48,0x26,0x00, + 0x85,0x79,0xFC,0x6F,0x7A,0xAF,0xC5,0x52,0x35,0x75,0xD7,0x75, + 0xA4,0x40,0xFA,0x14,0x74,0x61,0x16,0xF2,0xEB,0x67,0x11,0x6F, + 0x04,0x43,0x3D,0x11,0x14,0x4C,0xA7,0x94,0x2A,0x39,0xA1,0xC9, + 0x90,0xCF,0x83,0xC6,0xFF,0x02,0x8F,0xA3,0x2A,0xAC,0x26,0xDF, + 0x0B,0x8B,0xBE,0x64,0x4A,0xF1,0xA1,0xDC,0xEE,0xBA,0xC8,0x03, + 0x82,0xF6,0x62,0x2C,0x5D,0xB6,0xBB,0x13,0x19,0x6E,0x86,0xC5, + 0x5B,0x2B,0x5E,0x3A,0xF3,0xB3,0x28,0x6B,0x70,0x71,0x3A,0x8E, + 0xFF,0x5C,0x15,0xE6,0x02,0xA4,0xCE,0xED,0x59,0x56,0xCC,0x15, + 0x51,0x07,0x79,0x1A,0x0F,0x25,0x26,0x27,0x30,0xA9,0x15,0xB2, + 0xC8,0xD4,0x5C,0xCC,0x30,0xE8,0x1B,0xD8,0xD5,0x0F,0x19,0xA8, + 0x80,0xA4,0xC7,0x01,0xAA,0x8B,0xBA,0x53,0xBB,0x47,0xC2,0x1F, + 0x6B,0x54,0xB0,0x17,0x60,0xED,0x79,0x21,0x95,0xB6,0x05,0x84, + 0x37,0xC8,0x03,0xA4,0xDD,0xD1,0x06,0x69,0x8F,0x4C,0x39,0xE0, + 0xC8,0x5D,0x83,0x1D,0xBE,0x6A,0x9A,0x99,0xF3,0x9F,0x0B,0x45, + 0x29,0xD4,0xCB,0x29,0x66,0xEE,0x1E,0x7E,0x3D,0xD7,0x13,0x4E, + 0xDB,0x90,0x90,0x58,0xCB,0x5E,0x9B,0xCD,0x2E,0x2B,0x0F,0xA9, + 0x4E,0x78,0xAC,0x05,0x11,0x7F,0xE3,0x9E,0x27,0xD4,0x99,0xE1, + 0xB9,0xBD,0x78,0xE1,0x84,0x41,0xA0,0xDF +}; +static unsigned char dh4096_g[]={ 0x02 }; + +static DH * my_get_dh(int keylength) +{ + DH * dh = 0; + unsigned char * p = 0; + unsigned char * g = 0; + int sp = 0; + int sg = 0; + switch(keylength) + { + case 512: + dh = dh_512; + p = dh512_p; + g = dh512_g; + sp = sizeof(dh512_p); + sg = sizeof(dh512_g); + break; + case 1024: + dh = dh_1024; + p = dh1024_p; + g = dh1024_g; + sp = sizeof(dh1024_p); + sg = sizeof(dh1024_g); + break; + case 2048: + dh = dh_2048; + p = dh2048_p; + g = dh2048_g; + sp = sizeof(dh2048_p); + sg = sizeof(dh2048_g); + break; + case 4096: + dh = dh_4096; + p = dh4096_p; + g = dh4096_g; + sp = sizeof(dh4096_p); + sg = sizeof(dh4096_g); + break; + default: + // What the hell do you want from me ? + debug("OpenSSL is asking for a DH param with keylen %d: no way :D",keylength); + break; + + } + + if(dh)return dh; + dh = DH_new(); + if(!dh)return 0; + dh->p=BN_bin2bn(p,sp,0); + dh->g=BN_bin2bn(g,sg,0); + if((dh->p == 0) || (dh->g == 0)) + { + DH_free(dh); + return 0; + } + return dh; +} + +DH * my_ugly_dh_callback(SSL *s, int is_export, int keylength) +{ + my_ssl_lock(); + DH *dh = my_get_dh(keylength); + my_ssl_unlock(); + return dh; +} + +void KviSSL::globalInit() +{ + if(g_pSSLMutex)return; + g_pSSLMutex = new KviMutex(); +} + +void KviSSL::globalDestroy() +{ + if(!g_pSSLMutex)return; + if(dh_512)DH_free(dh_512); + if(dh_1024)DH_free(dh_1024); + if(dh_2048)DH_free(dh_2048); + if(dh_4096)DH_free(dh_4096); + delete g_pSSLMutex; + g_pSSLMutex = 0; +} + +KviSSL::KviSSL() +{ + my_ssl_lock(); + if(!g_bSSLInitialized) + { + // FIXME: this should be done only if SSL is really needed + SSL_library_init(); + SSL_load_error_strings(); + g_bSSLInitialized = true; + } + my_ssl_unlock(); + m_pSSL = 0; + m_pSSLCtx = 0; +} + +KviSSL::~KviSSL() +{ + shutdown(); +} + +#ifdef COMPILE_ON_WINDOWS + + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + + void * KviSSL::operator new(size_t tSize) + { + return kvi_malloc(tSize); + } + + void KviSSL::operator delete(void * p) + { + kvi_free(p); + } + +#endif + +void KviSSL::shutdown() +{ + if(m_pSSL) + { + // At least attempt to shutdown the connection gracefully + SSL_shutdown(m_pSSL); + SSL_free(m_pSSL); + m_pSSL = 0; + } + if(m_pSSLCtx) + { + SSL_CTX_free(m_pSSLCtx); + m_pSSLCtx = 0; + } +} + + +bool KviSSL::initContext(Method m) +{ + if(m_pSSL)return false; + m_pSSLCtx = SSL_CTX_new(m == Client ? SSLv23_client_method() : SSLv23_server_method()); + if(!m_pSSLCtx)return false; + // FIXME: this should be configurable ? + SSL_CTX_set_cipher_list(m_pSSLCtx,"ALL:eNULL"); + SSL_CTX_set_tmp_dh_callback(m_pSSLCtx,my_ugly_dh_callback); + return true; +} + +bool KviSSL::initSocket(kvi_socket_t fd) +{ + if(!m_pSSLCtx)return false; + m_pSSL = SSL_new(m_pSSLCtx); + if(!m_pSSL)return false; + if(!SSL_set_fd(m_pSSL,fd))return false; + return true; + +} + +static int cb(char *buf, int size, int rwflag, void *u) +{ + KviStr * p = (KviStr *)u; + int len = p->len(); + if(len >= size)return 0; + kvi_memmove(buf,p->ptr(),len + 1); +// debug("PASS REQYESTED: %s",p->ptr()); + return len; +} + +KviSSL::Result KviSSL::useCertificateFile(const char * cert,const char * pass) +{ + if(!m_pSSLCtx)return NotInitialized; + m_szPass = pass; + if(m_szPass.len() < 4)m_szPass.append("xxxx"); + X509 * x509 = 0; + + FILE * f = fopen(cert,"r"); + if(!f)return FileIoError; + +// debug("READING CERTIFICATE %s",cert); + if(PEM_read_X509(f,&x509,cb,&m_szPass)) + { + if(!SSL_CTX_use_certificate(m_pSSLCtx,x509)) + { + X509_free(x509); + return SSLError; + } + } + + fclose(f); + return Success; +} + + +KviSSL::Result KviSSL::usePrivateKeyFile(const char * key,const char * pass) +{ + if(!m_pSSLCtx)return NotInitialized; + m_szPass = pass; + if(m_szPass.len() < 4)m_szPass.append("xxxx"); + + EVP_PKEY * k = 0; + + FILE * f = fopen(key,"r"); + if(!f)return FileIoError; + +// debug("READING KEY %s",key); + if(PEM_read_PrivateKey(f,&k,cb,&m_szPass)) + { + if(!SSL_CTX_use_PrivateKey(m_pSSLCtx,k)) + { + EVP_PKEY_free(k); + return SSLError; + } + } + + fclose(f); + return Success; +} + +unsigned long KviSSL::getLastError(bool bPeek) +{ + return bPeek ? ERR_peek_error() : ERR_get_error(); +} + +bool KviSSL::getLastErrorString(KviStr &buffer,bool bPeek) +{ + unsigned long uErr = getLastError(bPeek); + if(uErr != 0) + { + const char * err = ERR_reason_error_string(uErr); + buffer = err ? err : "Unknown error"; + return true; + } + return false; +} + +KviSSL::Result KviSSL::connect() +{ + if(!m_pSSL)return NotInitialized; + int ret = SSL_connect(m_pSSL); + return connectOrAcceptError(ret); +} + +KviSSL::Result KviSSL::accept() +{ + if(!m_pSSL)return NotInitialized; + int ret = SSL_accept(m_pSSL); + return connectOrAcceptError(ret); +} + +KviSSL::Result KviSSL::connectOrAcceptError(int ret) +{ + switch(SSL_get_error(m_pSSL,ret)) + { + case SSL_ERROR_NONE: return Success; break; + case SSL_ERROR_WANT_READ: return WantRead; break; + case SSL_ERROR_WANT_WRITE: return WantWrite; break; + case SSL_ERROR_ZERO_RETURN: return RemoteEndClosedConnection; break; + case SSL_ERROR_WANT_X509_LOOKUP: return ObscureError; break; + case SSL_ERROR_SYSCALL: + { + if(getLastError(true) != 0)return SSLError; + if(ret == 0)return RemoteEndClosedConnection; + return SyscallError; + } + break; + case SSL_ERROR_SSL: return SSLError; break; + default: return UnknownError; break; + } + return UnknownError; +} + +int KviSSL::read(char * buffer,int len) +{ +// if(!m_pSSL)return -1; + return SSL_read(m_pSSL,buffer,len); +} +int KviSSL::write(const char * buffer,int len) +{ +// if(!m_pSSL)return -1; + return SSL_write(m_pSSL,buffer,len); +} + +KviSSL::Result KviSSL::getProtocolError(int ret) +{ + if(!m_pSSL)return NotInitialized; + switch(SSL_get_error(m_pSSL,ret)) + { + case SSL_ERROR_NONE: return Success; break; + case SSL_ERROR_WANT_READ: return WantRead; break; + case SSL_ERROR_WANT_WRITE: return WantWrite; break; + case SSL_ERROR_ZERO_RETURN: return ZeroReturn; break; + case SSL_ERROR_WANT_X509_LOOKUP: return ObscureError; break; + case SSL_ERROR_SYSCALL: return SyscallError; break; + case SSL_ERROR_SSL: return SSLError; break; + default: return UnknownError; break; + } + return UnknownError; +} + +KviSSLCertificate * KviSSL::getPeerCertificate() +{ + if(!m_pSSL)return 0; + X509 * x509 = SSL_get_peer_certificate(m_pSSL); + if(!x509)return 0; + return new KviSSLCertificate(x509); +} + +KviSSLCipherInfo * KviSSL::getCurrentCipherInfo() +{ + if(!m_pSSL)return 0; + SSL_CIPHER * c = SSL_get_current_cipher(m_pSSL); + if(!c)return 0; + return new KviSSLCipherInfo(c); +} + + + +KviSSLCertificate::KviSSLCertificate(X509 * x509) +{ + m_pSubject = new KviPointerHashTable<const char *,KviStr>(17); + m_pSubject->setAutoDelete(true); + m_pIssuer = new KviPointerHashTable<const char *,KviStr>(17); + m_pIssuer->setAutoDelete(true); + m_pX509 = 0; + setX509(x509); +} + +KviSSLCertificate::~KviSSLCertificate() +{ + X509_free(m_pX509); + delete m_pSubject; + delete m_pIssuer; +} + +#ifdef COMPILE_ON_WINDOWS + + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + + void * KviSSLCertificate::operator new(size_t tSize) + { + return kvi_malloc(tSize); + } + + void KviSSLCertificate::operator delete(void * p) + { + kvi_free(p); + } + +#endif + +void KviSSLCertificate::setX509(X509 * x509) +{ + if(m_pX509)X509_free(m_pX509); + m_pX509 = x509; + m_iVersion = X509_get_version(x509); + extractSubject(); + extractIssuer(); + extractPubKeyInfo(); + extractSerialNumber(); + extractSignature(); +} + +void KviSSLCertificate::extractSubject() +{ + char buffer[1024]; + char * t = X509_NAME_oneline(X509_get_subject_name(m_pX509),buffer,1024); + if (!t)return; + m_pSubject->clear(); + splitX509String(m_pSubject,t); +} + +void KviSSLCertificate::extractIssuer() +{ + char buffer[1024]; + char * t = X509_NAME_oneline(X509_get_issuer_name(m_pX509),buffer,1024); + if (!t)return; + m_pIssuer->clear(); + splitX509String(m_pIssuer,t); +} + +void KviSSLCertificate::splitX509String(KviPointerHashTable<const char *,KviStr> * dict,const char * t) +{ + KviStr buf = t; + int cnt; + KviStr ** arr = buf.splitToArray('/',50,&cnt); + if(arr) + { + if(cnt > 0) + { + for(int i=0;i<cnt;i++) + { + int idx = arr[i]->findFirstIdx('='); + if(idx != -1) + { + KviStr szTok = arr[i]->left(idx); + arr[i]->cutLeft(idx + 1); + if(szTok.hasData() && arr[i]->hasData()) + { + dict->replace(szTok.ptr(),new KviStr(arr[i]->ptr())); + } + } + } + } + + KviStr::freeArray(arr); + } +} + + +const char * KviSSLCertificate::dictEntry(KviPointerHashTable<const char *,KviStr> * dict,const char * entry) +{ + KviStr * t = dict->find(entry); + if(!t)return __tr("Unknown"); + return t->ptr(); +} + + +/* +void KviSSLCertificate::getPKeyType(int type,KviStr &buffer) +{ + switch(type) + { +#ifndef NO_RSA + case EVP_PKEY_RSA: buffer = "RSA"; break; +#endif +#ifndef NO_DSA + case EVP_PKEY_DSA: buffer = "DSA"; break; +#endif +#ifndef NO_DH + case EVP_PKEY_DH: buffer = "DH"; break; +#endif + case EVP_PKEY_NONE: buffer = "NONE"; break; + } +} +*/ + +void KviSSLCertificate::extractPubKeyInfo() +{ + EVP_PKEY *p = X509_get_pubkey(m_pX509); + if(p) + { + m_iPubKeyBits = EVP_PKEY_bits(p); + m_szPubKeyType = (p->type == NID_undef) ? __tr("Unknown") : OBJ_nid2ln(p->type); +// getPKeyType(p->type,m_szPubKeyType); + } else { + m_iPubKeyBits = 0; + m_szPubKeyType = "None"; + } + +} + +void KviSSLCertificate::extractSerialNumber() +{ + ASN1_INTEGER * i = X509_get_serialNumber(m_pX509); + if(i)m_iSerialNumber = ASN1_INTEGER_get(i); + else m_iSerialNumber = -1; +} + +void KviSSLCertificate::extractSignature() +{ + static char hexdigits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + //getPKeyType(X509_get_signature_type(m_pX509),m_szSignatureType); + + int i = OBJ_obj2nid(m_pX509->sig_alg->algorithm); + m_szSignatureType = (i == NID_undef) ? __tr("Unknown") : OBJ_nid2ln(i); + + m_szSignatureContents = ""; + + for(i = 0;i < m_pX509->signature->length;i++) + { + if(m_szSignatureContents.hasData())m_szSignatureContents.append(":"); + m_szSignatureContents.append(hexdigits[(m_pX509->signature->data[i] & 0xf0) >> 4]); + m_szSignatureContents.append(hexdigits[(m_pX509->signature->data[i] & 0x0f)]); + } +} + +/* +const char * KviSSLCertificate::verify() +{ + +} +*/ + + +KviSSLCipherInfo::KviSSLCipherInfo(SSL_CIPHER * c) +{ + m_szVersion = SSL_CIPHER_get_version(c); + m_iNumBitsUsed = SSL_CIPHER_get_bits(c,&m_iNumBits); + m_szName = SSL_CIPHER_get_name(c); + char buf[1024]; + m_szDescription = SSL_CIPHER_description(c,buf,1024); +} + +KviSSLCipherInfo::~KviSSLCipherInfo() +{ +} + +#ifdef COMPILE_ON_WINDOWS + + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + + void * KviSSLCipherInfo::operator new(size_t tSize) + { + return kvi_malloc(tSize); + } + + void KviSSLCipherInfo::operator delete(void * p) + { + kvi_free(p); + } + +#endif + +#endif //COMPILE_SSL_SUPPORT diff --git a/src/kvilib/net/kvi_ssl.h b/src/kvilib/net/kvi_ssl.h new file mode 100644 index 00000000..5547ecbb --- /dev/null +++ b/src/kvilib/net/kvi_ssl.h @@ -0,0 +1,180 @@ +#ifndef _KVI_SSL_H_ +#define _KVI_SSL_H_ +// +// File : kvi_ssl.h +// Creation date : Mon May 27 2002 21:36:12 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" + +#ifdef COMPILE_SSL_SUPPORT + +#include "kvi_string.h" +#include "kvi_sockettype.h" + +#include "kvi_pointerhashtable.h" + +#include <openssl/ssl.h> + + +class KVILIB_API KviSSLCertificate +{ +public: + KviSSLCertificate(X509 * x509); + ~KviSSLCertificate(); +protected: + X509 * m_pX509; + KviPointerHashTable<const char *,KviStr> * m_pSubject; + KviPointerHashTable<const char *,KviStr> * m_pIssuer; + int m_iPubKeyBits; + KviStr m_szPubKeyType; + int m_iSerialNumber; + int m_iVersion; + KviStr m_szSignatureType; + KviStr m_szSignatureContents; +private: + void extractSubject(); + void extractIssuer(); + void extractPubKeyInfo(); + void extractSerialNumber(); + void extractSignature(); + const char * dictEntry(KviPointerHashTable<const char *,KviStr> * dict,const char * entry); + void splitX509String(KviPointerHashTable<const char *,KviStr> * dict,const char * t); +// void getPKeyType(int type,KviStr &buffer); +public: + void setX509(X509 * x509); + + const char * signatureType(){ return m_szSignatureType.ptr(); }; + const char * signatureContents(){ return m_szSignatureContents.ptr(); }; + + const char * subjectCountry(){ return dictEntry(m_pSubject,"C"); }; + const char * subjectStateOrProvince(){ return dictEntry(m_pSubject,"ST"); }; + const char * subjectLocality(){ return dictEntry(m_pSubject,"L"); }; + const char * subjectOrganization(){ return dictEntry(m_pSubject,"O"); }; + const char * subjectOrganizationalUnit(){ return dictEntry(m_pSubject,"OU"); }; + const char * subjectCommonName(){ return dictEntry(m_pSubject,"CN"); }; + + const char * issuerCountry(){ return dictEntry(m_pIssuer,"C"); }; + const char * issuerStateOrProvince(){ return dictEntry(m_pIssuer,"ST"); }; + const char * issuerLocality(){ return dictEntry(m_pIssuer,"L"); }; + const char * issuerOrganization(){ return dictEntry(m_pIssuer,"O"); }; + const char * issuerOrganizationalUnit(){ return dictEntry(m_pIssuer,"OU"); }; + const char * issuerCommonName(){ return dictEntry(m_pIssuer,"CN"); }; + + int publicKeyBits(){ return m_iPubKeyBits; }; + const char * publicKeyType(){ return m_szPubKeyType.ptr(); }; + + int serialNumber(){ return m_iSerialNumber; }; + + int version(){ return m_iVersion; }; +#ifdef COMPILE_ON_WINDOWS + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + void * operator new(size_t tSize); + void operator delete(void * p); +#endif +}; + +class KVILIB_API KviSSLCipherInfo +{ +public: + KviSSLCipherInfo(SSL_CIPHER * c); + ~KviSSLCipherInfo(); +protected: + KviStr m_szVersion; + int m_iNumBits; + int m_iNumBitsUsed; + KviStr m_szName; + KviStr m_szDescription; +public: + const char * name(){ return m_szName.ptr(); }; + const char * description(){ return m_szDescription.ptr(); }; + int bits(){ return m_iNumBits; }; + int bitsUsed(){ return m_iNumBitsUsed; }; + const char * version(){ return m_szVersion.ptr(); }; +#ifdef COMPILE_ON_WINDOWS + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + void * operator new(size_t tSize); + void operator delete(void * p); +#endif +}; + +#ifdef Success + #undef Success +#endif + + +class KVILIB_API KviSSL +{ +public: + enum Method { Client , Server }; + enum Result { Success , NotInitialized , WantRead , WantWrite , ZeroReturn , FileIoError , + UnknownError , ObscureError , SSLError , SyscallError , RemoteEndClosedConnection }; +public: + KviSSL(); + ~KviSSL(); +public: + SSL * m_pSSL; + SSL_CTX * m_pSSLCtx; + KviStr m_szPass; +public: + static void globalInit(); + static void globalDestroy(); +public: + bool initSocket(kvi_socket_t fd); + bool initContext(KviSSL::Method m); + void shutdown(); + KviSSL::Result connect(); + KviSSL::Result accept(); + int read(char * buffer,int len); + int write(const char * buffer,int len); + // SSL ERRORS + unsigned long getLastError(bool bPeek = false); + bool getLastErrorString(KviStr &buffer,bool bPeek = false); + // Protocol error + KviSSL::Result getProtocolError(int ret); + KviSSLCertificate * getPeerCertificate(); + KviSSLCipherInfo * getCurrentCipherInfo(); + KviSSL::Result useCertificateFile(const char * cert,const char * pass); + KviSSL::Result usePrivateKeyFile(const char * key,const char * pass); +#ifdef COMPILE_ON_WINDOWS + // On windows we need to override new and delete operators + // to ensure that always the right new/delete pair is called for an object instance + // This bug is present in all the classes exported by a module that + // can be instantiated/destroyed from external modules. + // (this is a well known bug described in Q122675 of MSDN) + void * operator new(size_t tSize); + void operator delete(void * p); +#endif +private: + KviSSL::Result connectOrAcceptError(int ret); +}; + + +#endif //COMPILE_SSL_SUPPORT + +#endif //_KVI_SSL_H_ diff --git a/src/kvilib/net/kvi_url.cpp b/src/kvilib/net/kvi_url.cpp new file mode 100644 index 00000000..f980729c --- /dev/null +++ b/src/kvilib/net/kvi_url.cpp @@ -0,0 +1,164 @@ +// +// File : kvi_url.cpp +// Creation date : Sat Aug 17 14:09:18 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + + +#define __KVILIB__ + + +#include "kvi_url.h" + +KviUrl::KviUrl() +{ +} + +KviUrl::KviUrl(const KviUrl & u) +{ + *this = u; +} + +KviUrl::KviUrl(const char * szUrl) +{ + m_szUrl = szUrl; + parse(); +} + +KviUrl::KviUrl(const QString &szUrl) +{ + m_szUrl = szUrl; + parse(); +} + +KviUrl::~KviUrl() +{ + +} + +void KviUrl::parse() +{ + m_szProtocol = ""; + m_szHost = ""; + m_szPath = ""; + m_szUser = ""; + m_szPass = ""; + + m_szUrl.stripWhiteSpace(); + + KviStr u = m_szUrl; + + // proto + + kvi_u32_t uDefaultPort = 80; + + int i = u.findFirstIdx(":/"); + if(i != -1) + { + // there is a protocol path + m_szProtocol = u.left(i); + u.cutLeft(i + 2); + u.stripLeft('/'); + u.stripWhiteSpace(); + + // fix the default ports + if(kvi_strEqualCI(m_szProtocol,"https"))uDefaultPort = 443; + else if(kvi_strEqualCI(m_szProtocol,"ftp"))uDefaultPort = 21; + } else { + // no proto... assume http + u.stripLeft('/'); + m_szProtocol = "http"; + } + + m_uPort = uDefaultPort; + + // user and pass + + i = u.findFirstIdx('@'); + + if(i != -1) + { + KviStr szUserPass = u.left(i); + szUserPass.stripWhiteSpace(); + u.cutLeft(i + 1); + + i = szUserPass.findFirstIdx(':'); + if(i != -1) + { + m_szUser = szUserPass.left(i); + szUserPass.cutLeft(i + 1); + m_szPass = szUserPass; + m_szPass.stripWhiteSpace(); + } else { + m_szUser = szUserPass; + } + } + + // host + + i = u.findFirstIdx('/'); + if(i != -1) + { + KviStr h = u.left(i); + u.cutLeft(i + 1); + i = h.findFirstIdx(':'); + if(i != -1) + { + // has a port part + m_szHost = h.left(i); + h.cutLeft(i + 1); + h.stripWhiteSpace(); + bool bOk; + m_uPort = h.toUInt(&bOk); + if(!bOk)m_uPort = uDefaultPort; + } else { + // no port : assume default + m_szHost = h; + } + m_szPath = u; + } else { + m_szHost = u; + } + + m_szHost.stripWhiteSpace(); + m_szPath.stripWhiteSpace(); + if(!m_szPath.firstCharIs('/'))m_szPath.prepend('/'); +} + + +KviUrl & KviUrl::operator=(const char * szUrl) +{ + m_szUrl = szUrl; + parse(); + return *this; +} + +KviUrl & KviUrl::operator=(const KviUrl &u) +{ + m_szUrl = u.m_szUrl; + m_szProtocol = u.m_szProtocol; + m_szHost = u.m_szHost; + m_szPath = u.m_szPath; + m_szUser = u.m_szUser; + m_szPass = u.m_szPass; + m_uPort = u.m_uPort; + return *this; +} + + diff --git a/src/kvilib/net/kvi_url.h b/src/kvilib/net/kvi_url.h new file mode 100644 index 00000000..89adeb9f --- /dev/null +++ b/src/kvilib/net/kvi_url.h @@ -0,0 +1,63 @@ +#ifndef _KVI_URL_H_ +#define _KVI_URL_H_ +// +// File : kvi_url.h +// Creation date : Sat Aug 17 14:09:16 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_string.h" +#include "kvi_heapobject.h" +#include "kvi_inttypes.h" + +class KVILIB_API KviUrl : public KviHeapObject +{ +public: + KviUrl(); + KviUrl(const char * szUrl); + KviUrl(const QString &szUrl); + KviUrl(const KviUrl &u); + ~KviUrl(); +protected: + KviStr m_szUrl; + + KviStr m_szProtocol; + KviStr m_szHost; + KviStr m_szPath; + KviStr m_szUser; + KviStr m_szPass; + kvi_u32_t m_uPort; +protected: + void parse(); +public: + const KviStr & url() const { return m_szUrl; }; + const KviStr & protocol() const { return m_szProtocol; }; + const KviStr & host() const { return m_szHost; }; + const KviStr & path() const { return m_szPath; }; + const KviStr & user() const { return m_szUser; }; + const KviStr & pass() const { return m_szPass; }; + kvi_u32_t port() const { return m_uPort; }; + + KviUrl & operator = (const char * szUrl); + KviUrl & operator = (const KviUrl &u); + +}; + + +#endif //_KVI_URL_H_ diff --git a/src/kvilib/net/moc_kvi_dns.cpp b/src/kvilib/net/moc_kvi_dns.cpp new file mode 100644 index 00000000..5b8857a9 --- /dev/null +++ b/src/kvilib/net/moc_kvi_dns.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** KviDns meta object code from reading C++ file 'kvi_dns.h' +** +** Created: Sun Mar 23 20:56:20 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_dns.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +#include <qvariant.h> +const char *KviDns::className() const +{ + return "KviDns"; +} + +QMetaObject *KviDns::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviDns( "KviDns", &KviDns::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviDns::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviDns", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviDns::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviDns", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviDns::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUParameter param_signal_0[] = { + { 0, &static_QUType_ptr, "KviDns", QUParameter::In } + }; + static const QUMethod signal_0 = {"lookupDone", 1, param_signal_0 }; + static const QMetaData signal_tbl[] = { + { "lookupDone(KviDns*)", &signal_0, QMetaData::Private } + }; +#ifndef QT_NO_PROPERTIES + static const QMetaProperty props_tbl[1] = { + { "bool","blockingDelete", 0x12000001, &KviDns::metaObj, 0, -1 } + }; +#endif // QT_NO_PROPERTIES + metaObj = QMetaObject::new_metaobject( + "KviDns", parentObject, + 0, 0, + signal_tbl, 1, +#ifndef QT_NO_PROPERTIES + props_tbl, 1, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviDns.setMetaObject( metaObj ); + return metaObj; +} + +void* KviDns::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviDns" ) ) + return this; + if ( !qstrcmp( clname, "KviHeapObject" ) ) + return (KviHeapObject*)this; + return QObject::qt_cast( clname ); +} + +#include <qobjectdefs.h> +#include <qsignalslotimp.h> + +// SIGNAL lookupDone +void KviDns::lookupDone( KviDns* t0 ) +{ + if ( signalsBlocked() ) + return; + QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 0 ); + if ( !clist ) + return; + QUObject o[2]; + static_QUType_ptr.set(o+1,t0); + activate_signal( clist, o ); +} + +bool KviDns::qt_invoke( int _id, QUObject* _o ) +{ + return QObject::qt_invoke(_id,_o); +} + +bool KviDns::qt_emit( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->signalOffset() ) { + case 0: lookupDone((KviDns*)static_QUType_ptr.get(_o+1)); break; + default: + return QObject::qt_emit(_id,_o); + } + return TRUE; +} +#ifndef QT_NO_PROPERTIES + +bool KviDns::qt_property( int id, int f, QVariant* v) +{ + switch ( id - staticMetaObject()->propertyOffset() ) { + case 0: switch( f ) { + case 1: *v = QVariant( this->isRunning(), 0 ); break; + case 3: case 4: case 5: break; + default: return FALSE; + } break; + default: + return QObject::qt_property( id, f, v ); + } + return TRUE; +} + +bool KviDns::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/net/moc_kvi_http.cpp b/src/kvilib/net/moc_kvi_http.cpp new file mode 100644 index 00000000..7ea9b591 --- /dev/null +++ b/src/kvilib/net/moc_kvi_http.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** KviHttpRequest meta object code from reading C++ file 'kvi_http.h' +** +** Created: Sun Mar 23 20:56:22 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_http.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviHttpRequest::className() const +{ + return "KviHttpRequest"; +} + +QMetaObject *KviHttpRequest::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviHttpRequest( "KviHttpRequest", &KviHttpRequest::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviHttpRequest::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviHttpRequest", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviHttpRequest::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviHttpRequest", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviHttpRequest::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUParameter param_slot_0[] = { + { "d", &static_QUType_ptr, "KviDns", QUParameter::In } + }; + static const QUMethod slot_0 = {"dnsLookupDone", 1, param_slot_0 }; + static const QUMethod slot_1 = {"haveServerIp", 0, 0 }; + static const QMetaData slot_tbl[] = { + { "dnsLookupDone(KviDns*)", &slot_0, QMetaData::Protected }, + { "haveServerIp()", &slot_1, QMetaData::Protected } + }; + static const QUParameter param_signal_0[] = { + { "hostname", &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod signal_0 = {"resolvingHost", 1, param_signal_0 }; + static const QUParameter param_signal_1[] = { + { "ipandport", &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod signal_1 = {"contactingHost", 1, param_signal_1 }; + static const QUMethod signal_2 = {"connectionEstabilished", 0, 0 }; + static const QUParameter param_signal_3[] = { + { "response", &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod signal_3 = {"receivedResponse", 1, param_signal_3 }; + static const QUParameter param_signal_4[] = { + { "bSuccess", &static_QUType_bool, 0, QUParameter::In } + }; + static const QUMethod signal_4 = {"terminated", 1, param_signal_4 }; + static const QUParameter param_signal_5[] = { + { "message", &static_QUType_QString, 0, QUParameter::In } + }; + static const QUMethod signal_5 = {"status", 1, param_signal_5 }; + static const QUParameter param_signal_6[] = { + { "data", &static_QUType_ptr, "KviStr", QUParameter::In } + }; + static const QUMethod signal_6 = {"data", 1, param_signal_6 }; + static const QUParameter param_signal_7[] = { + { "data", &static_QUType_ptr, "KviDataBuffer", QUParameter::In } + }; + static const QUMethod signal_7 = {"binaryData", 1, param_signal_7 }; + static const QUParameter param_signal_8[] = { + { "hdr", &static_QUType_ptr, "KviPointerHashTable<const char*,KviStr>", QUParameter::In } + }; + static const QUMethod signal_8 = {"header", 1, param_signal_8 }; + static const QUParameter param_signal_9[] = { + { "request", &static_QUType_varptr, "\x04", QUParameter::In } + }; + static const QUMethod signal_9 = {"requestSent", 1, param_signal_9 }; + static const QMetaData signal_tbl[] = { + { "resolvingHost(const QString&)", &signal_0, QMetaData::Public }, + { "contactingHost(const QString&)", &signal_1, QMetaData::Public }, + { "connectionEstabilished()", &signal_2, QMetaData::Public }, + { "receivedResponse(const QString&)", &signal_3, QMetaData::Public }, + { "terminated(bool)", &signal_4, QMetaData::Public }, + { "status(const QString&)", &signal_5, QMetaData::Public }, + { "data(const KviStr&)", &signal_6, QMetaData::Public }, + { "binaryData(const KviDataBuffer&)", &signal_7, QMetaData::Public }, + { "header(KviPointerHashTable<const char*,KviStr>*)", &signal_8, QMetaData::Public }, + { "requestSent(const QStringList&)", &signal_9, QMetaData::Public } + }; + metaObj = QMetaObject::new_metaobject( + "KviHttpRequest", parentObject, + slot_tbl, 2, + signal_tbl, 10, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviHttpRequest.setMetaObject( metaObj ); + return metaObj; +} + +void* KviHttpRequest::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviHttpRequest" ) ) + return this; + if ( !qstrcmp( clname, "KviHeapObject" ) ) + return (KviHeapObject*)this; + return QObject::qt_cast( clname ); +} + +// SIGNAL resolvingHost +void KviHttpRequest::resolvingHost( const QString& t0 ) +{ + activate_signal( staticMetaObject()->signalOffset() + 0, t0 ); +} + +// SIGNAL contactingHost +void KviHttpRequest::contactingHost( const QString& t0 ) +{ + activate_signal( staticMetaObject()->signalOffset() + 1, t0 ); +} + +// SIGNAL connectionEstabilished +void KviHttpRequest::connectionEstabilished() +{ + activate_signal( staticMetaObject()->signalOffset() + 2 ); +} + +// SIGNAL receivedResponse +void KviHttpRequest::receivedResponse( const QString& t0 ) +{ + activate_signal( staticMetaObject()->signalOffset() + 3, t0 ); +} + +// SIGNAL terminated +void KviHttpRequest::terminated( bool t0 ) +{ + activate_signal_bool( staticMetaObject()->signalOffset() + 4, t0 ); +} + +// SIGNAL status +void KviHttpRequest::status( const QString& t0 ) +{ + activate_signal( staticMetaObject()->signalOffset() + 5, t0 ); +} + +#include <qobjectdefs.h> +#include <qsignalslotimp.h> + +// SIGNAL data +void KviHttpRequest::data( const KviStr& t0 ) +{ + if ( signalsBlocked() ) + return; + QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 6 ); + if ( !clist ) + return; + QUObject o[2]; + static_QUType_ptr.set(o+1,&t0); + activate_signal( clist, o ); +} + +// SIGNAL binaryData +void KviHttpRequest::binaryData( const KviDataBuffer& t0 ) +{ + if ( signalsBlocked() ) + return; + QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 7 ); + if ( !clist ) + return; + QUObject o[2]; + static_QUType_ptr.set(o+1,&t0); + activate_signal( clist, o ); +} + +// SIGNAL header +void KviHttpRequest::header( KviPointerHashTable<const char*,KviStr>* t0 ) +{ + if ( signalsBlocked() ) + return; + QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 8 ); + if ( !clist ) + return; + QUObject o[2]; + static_QUType_ptr.set(o+1,t0); + activate_signal( clist, o ); +} + +// SIGNAL requestSent +void KviHttpRequest::requestSent( const QStringList& t0 ) +{ + if ( signalsBlocked() ) + return; + QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + 9 ); + if ( !clist ) + return; + QUObject o[2]; + static_QUType_varptr.set(o+1,&t0); + activate_signal( clist, o ); +} + +bool KviHttpRequest::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: dnsLookupDone((KviDns*)static_QUType_ptr.get(_o+1)); break; + case 1: haveServerIp(); break; + default: + return QObject::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool KviHttpRequest::qt_emit( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->signalOffset() ) { + case 0: resolvingHost((const QString&)static_QUType_QString.get(_o+1)); break; + case 1: contactingHost((const QString&)static_QUType_QString.get(_o+1)); break; + case 2: connectionEstabilished(); break; + case 3: receivedResponse((const QString&)static_QUType_QString.get(_o+1)); break; + case 4: terminated((bool)static_QUType_bool.get(_o+1)); break; + case 5: status((const QString&)static_QUType_QString.get(_o+1)); break; + case 6: data((const KviStr&)*((const KviStr*)static_QUType_ptr.get(_o+1))); break; + case 7: binaryData((const KviDataBuffer&)*((const KviDataBuffer*)static_QUType_ptr.get(_o+1))); break; + case 8: header((KviPointerHashTable<const char*,KviStr>*)static_QUType_ptr.get(_o+1)); break; + case 9: requestSent((const QStringList&)*((const QStringList*)static_QUType_ptr.get(_o+1))); break; + default: + return QObject::qt_emit(_id,_o); + } + return TRUE; +} +#ifndef QT_NO_PROPERTIES + +bool KviHttpRequest::qt_property( int id, int f, QVariant* v) +{ + return QObject::qt_property( id, f, v); +} + +bool KviHttpRequest::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/system/Makefile.am b/src/kvilib/system/Makefile.am new file mode 100644 index 00000000..c84487eb --- /dev/null +++ b/src/kvilib/system/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.cpp *.h diff --git a/src/kvilib/system/kvi_byteorder.h b/src/kvilib/system/kvi_byteorder.h new file mode 100644 index 00000000..dea1902d --- /dev/null +++ b/src/kvilib/system/kvi_byteorder.h @@ -0,0 +1,62 @@ +#ifndef _KVI_BYTEORDER_H_ +#define _KVI_BYTEORDER_H_ + +//============================================================================= +// +// File : kvi_byteorder.h +// Creation date : Mon Dec 25 2006 19:56:16 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2006 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_bswap.h" +#include "kvi_inttypes.h" + + +// +// Byte Orders Reminder +// Number 0xaabbccdd +// Little Endian Stores 0xdd 0xcc 0xbb 0xaa +// Big Endian Stores 0xaa 0xbb 0xcc 0xdd +// Perverse Middle Endian 0xbb 0xaa 0xdd 0xcc or another braindamaged combination (unsupported) +// Network Byte Order is Big Endian +// Intel Stuff uses Little Endian +// + +#ifdef BIG_ENDIAN_MACHINE_BYTE_ORDER + #define kvi_localCpuToLittleEndian16(u) kvi_swap16((kvi_u16_t)(u)) + #define kvi_localCpuToLittleEndian32(u) kvi_swap32((kvi_u32_t)(u)) + #define kvi_localCpuToLittleEndian64(u) kvi_swap64((kvi_u64_t)(u)) + #define kvi_littleEndianToLocalCpu16(u) kvi_swap16((kvi_u16_t)(u)) + #define kvi_littleEndianToLocalCpu32(u) kvi_swap32((kvi_u32_t)(u)) + #define kvi_littleEndianToLocalCpu64(u) kvi_swap64((kvi_u64_t)(u)) +#else + // We ASSUME that the local cpu is little endian.. if it isn't.. well :) + #define LOCAL_CPU_LITTLE_ENDIAN + #define kvi_localCpuToLittleEndian16(u) (u) + #define kvi_localCpuToLittleEndian32(u) (u) + #define kvi_localCpuToLittleEndian64(u) (u) + #define kvi_littleEndianToLocalCpu16(u) (u) + #define kvi_littleEndianToLocalCpu32(u) (u) + #define kvi_littleEndianToLocalCpu64(u) (u) +#endif + + +#endif // !_KVI_BYTEORDER_H_ diff --git a/src/kvilib/system/kvi_env.cpp b/src/kvilib/system/kvi_env.cpp new file mode 100644 index 00000000..1497632e --- /dev/null +++ b/src/kvilib/system/kvi_env.cpp @@ -0,0 +1,89 @@ +//============================================================================= +// +// File : kvi_env.cpp +// Creation date : Sat May 05 2002 02:15:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma@kvirc.net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= +#define __KVILIB__ + +#define _KVI_ENV_CPP_ + +#include "kvi_env.h" +#include "kvi_string.h" +#include "kvi_malloc.h" +#include "kvi_memmove.h" + +#ifndef COMPILE_ON_WINDOWS + +bool kvi_setenv(const char * name,const char * value) +{ +#ifdef HAVE_SETENV + return (setenv(name,value,1) == 0); +#else + #ifdef HAVE_PUTENV + int iLen1 = kvi_strLen(name); + int iLen2 = kvi_strLen(value); + char * buf = (char *)kvi_malloc(iLen1 + iLen2 + 2); + kvi_memmove(buf,name,iLen1); + *(buf + iLen1) = '='; + kvi_memmove(buf + iLen1 + 1,value,iLen2); + *(buf + iLen1 + iLen2 + 1) = '\0'; + int iRet = putenv(buf); + if(iRet != 0) + { + kvi_free(buf); + return false; + } + return true; + #else + // no setenv , no putenv.. what the hell of system is this ? + return false; + #endif +#endif +} + +void kvi_unsetenv(const char * name) +{ +#ifdef HAVE_UNSETENV + unsetenv(name); +#else + #ifdef HAVE_PUTENV + int iLen1 = kvi_strLen(name); + char * buf = (char *)kvi_malloc(iLen1 + 1); + kvi_memmove(buf,name,iLen1); + *(buf + iLen1) = '\0'; + int iRet = putenv(buf); + if(iRet != 0) + { + kvi_free(buf); + } else { + // hmmm + if(kvi_getenv(name) == 0) + { + // ok , the string is not in the environment + // we can free it + kvi_free(buf); + } // else this system sux + } + #endif +#endif +} + +#endif //!COMPILE_ON_WINDOWS diff --git a/src/kvilib/system/kvi_env.h b/src/kvilib/system/kvi_env.h new file mode 100644 index 00000000..b3b24a2f --- /dev/null +++ b/src/kvilib/system/kvi_env.h @@ -0,0 +1,60 @@ +#ifndef _KVI_ENV_H_ +#define _KVI_ENV_H_ + +//============================================================================= +// +// File : kvi_env.h +// Creation date : Sat May 05 2002 02:15:21 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma@kvirc.net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// Enviroinement function wrappers +//============================================================================= + +#include "kvi_settings.h" + + + +#include <stdlib.h> + +inline char * kvi_getenv(const char * name) +{ +#ifdef HAVE_GETENV + return getenv(name); +#else + return 0; +#endif +} + +#ifdef COMPILE_ON_WINDOWS + #define kvi_setenv(__name,__value) SetEnvironmentVariable(__name,__value) + #define kvi_unsetenv(__name) SetEnvironmentVariable(__name,NULL) +#else + #ifndef _KVI_ENV_CPP_ + KVILIB_API extern bool kvi_setenv(const char * name,const char * value); + KVILIB_API extern void kvi_unsetenv(const char * name); + #endif +#endif + + + + +#endif //_KVI_ENV_H_ diff --git a/src/kvilib/system/kvi_library.h b/src/kvilib/system/kvi_library.h new file mode 100644 index 00000000..393ed5c7 --- /dev/null +++ b/src/kvilib/system/kvi_library.h @@ -0,0 +1,115 @@ +#ifndef _KVI_LIBRARY_H_ +#define _KVI_LIBRARY_H_ + +//===================================================================================== +// +// File : kvi_library.h +// Creation date : Tue Sep 25 16:20:40 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//===================================================================================== + + +//===================================================================================== +// System dynamic linker interface abstraction +//===================================================================================== + + +#include "kvi_settings.h" + + +#ifdef COMPILE_ON_WINDOWS + + //#include <windows.h> + #include <winsock2.h> // this will pull in windows.h + + typedef HMODULE kvi_library_t; + + inline kvi_library_t kvi_library_open(const char * path) + { +#ifndef DEBUG + // this is to avoid the ugly message boxes when the dll has + // ... but do it only in release mode + UINT nOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); +#endif + kvi_library_t ret = LoadLibrary(path); +#ifndef DEBUG + SetErrorMode(nOldErrorMode); +#endif + return ret; + }; + + inline void kvi_library_close(kvi_library_t lib) + { + FreeLibrary(lib); + }; + + inline void * kvi_library_symbol(kvi_library_t lib,const char * symName) + { + return GetProcAddress(lib,symName); + }; + + inline const char * kvi_library_error() + { + return "Windoze-like error"; + }; + +#else + + #include <dlfcn.h> + + // sparc-unknown-openbsd3.0 (At least) has only RTLD_LAZY + #ifndef RTLD_NOW + #define RTLD_NOW RTLD_LAZY + #endif + #ifndef RTLD_GLOBAL + #define RTLD_GLOBAL 0 + #endif + + typedef void * kvi_library_t; + + inline kvi_library_t kvi_library_open(const char * path) + { + return dlopen(path,RTLD_GLOBAL | RTLD_NOW); + }; + + inline void kvi_library_close(kvi_library_t lib) + { + dlclose(lib); + }; + + + inline void * kvi_library_symbol(kvi_library_t lib,const char * symName) + { + return dlsym(lib,symName); + }; + + inline const char * kvi_library_error() + { + return dlerror(); + }; + + +#endif //!COMPILE_ON_WINDOWS + + +#define kvi_library_load kvi_library_open +#define kvi_library_unload kvi_library_close + +#endif //_KVI_LIBRARY_H_ diff --git a/src/kvilib/system/kvi_locale.cpp b/src/kvilib/system/kvi_locale.cpp new file mode 100644 index 00000000..f49eabe4 --- /dev/null +++ b/src/kvilib/system/kvi_locale.cpp @@ -0,0 +1,1191 @@ +//============================================================================= +// +// File : kvi_locale.cpp +// Creation date : Fri Mar 19 1999 19:08:41 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +//#define _KVI_DEBUG_CHECK_RANGE_ +#include "kvi_debug.h" +#include "kvi_malloc.h" +#include "kvi_bswap.h" + +#define _KVI_LOCALE_CPP_ +#include "kvi_locale.h" + +#include <qglobal.h> //for debug() +#include <qtextcodec.h> +#include <qdir.h> + +#ifdef COMPILE_USE_QT4 + #include <qlocale.h> +#endif + +#include "kvi_string.h" +#include "kvi_qcstring.h" +#include "kvi_env.h" +#include "kvi_fileutils.h" +#include "kvi_file.h" + + +KVILIB_API KviMessageCatalogue * g_pMainCatalogue = 0; + +static KviStr g_szLang; +static KviTranslator * g_pTranslator = 0; +static KviPointerHashTable<const char *,KviMessageCatalogue> * g_pCatalogueDict = 0; +static QTextCodec * g_pUtf8TextCodec = 0; + + +///////////////////////////////////////////////////////////////////////////////////////////////////// +// +// The following code was extracted and adapted from gutf8.c +// from the GNU GLIB2 package. +// +// gutf8.c - Operations on UTF-8 strings. +// +// Copyright (C) 1999 Tom Tromey +// Copyright (C) 2000 Red Hat, Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301, USA. +// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef char gchar; +typedef unsigned char guchar; +typedef signed int gssize; +typedef unsigned int gunichar; + + + +#define UNICODE_VALID(Char) \ + ((Char) < 0x110000 && \ + (((Char) & 0xFFFFF800) != 0xD800) && \ + ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ + ((Char) & 0xFFFE) != 0xFFFE) + +#define CONTINUATION_CHAR \ + if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ \ + goto error; \ + val <<= 6; \ + val |= (*(guchar *)p) & 0x3f; + + +static const char * +fast_validate (const char *str) + +{ + gunichar val = 0; + gunichar min = 0; + const gchar *p; + + for (p = str; *p; p++) + { + if (*(guchar *)p < 128) + /* done */; + else + { + const gchar *last; + + last = p; + if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */ + { + if ((*(guchar *)p & 0x1e) == 0) + goto error; + p++; + if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ + goto error; + } + else + { + if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */ + { + min = (1 << 11); + val = *(guchar *)p & 0x0f; + goto TWO_REMAINING; + } + else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */ + { + min = (1 << 16); + val = *(guchar *)p & 0x07; + } + else + goto error; + + p++; + CONTINUATION_CHAR; + TWO_REMAINING: + p++; + CONTINUATION_CHAR; + p++; + CONTINUATION_CHAR; + + if (val < min) + goto error; + + if (!UNICODE_VALID(val)) + goto error; + } + + continue; + + error: + return last; + } + } + + return p; +} + +static const gchar * +fast_validate_len (const char *str, + gssize max_len) + +{ + gunichar val = 0; + gunichar min = 0; + const gchar *p; + + for (p = str; (max_len < 0 || (p - str) < max_len) && *p; p++) + { + if (*(guchar *)p < 128) + /* done */; + else + { + const gchar *last; + + last = p; + if ((*(guchar *)p & 0xe0) == 0xc0) /* 110xxxxx */ + { + if (max_len >= 0 && max_len - (p - str) < 2) + goto error; + + if ((*(guchar *)p & 0x1e) == 0) + goto error; + p++; + if ((*(guchar *)p & 0xc0) != 0x80) /* 10xxxxxx */ + goto error; + } + else + { + if ((*(guchar *)p & 0xf0) == 0xe0) /* 1110xxxx */ + { + if (max_len >= 0 && max_len - (p - str) < 3) + goto error; + + min = (1 << 11); + val = *(guchar *)p & 0x0f; + goto TWO_REMAINING; + } + else if ((*(guchar *)p & 0xf8) == 0xf0) /* 11110xxx */ + { + if (max_len >= 0 && max_len - (p - str) < 4) + goto error; + + min = (1 << 16); + val = *(guchar *)p & 0x07; + } + else + goto error; + + p++; + CONTINUATION_CHAR; + TWO_REMAINING: + p++; + CONTINUATION_CHAR; + p++; + CONTINUATION_CHAR; + + if (val < min) + goto error; + if (!UNICODE_VALID(val)) + goto error; + } + + continue; + + error: + return last; + } + } + + return p; +} + +static bool g_utf8_validate (const char *str, + gssize max_len, + const gchar **end) + +{ + const gchar *p; + + if (max_len < 0) + p = fast_validate (str); + else + p = fast_validate_len (str, max_len); + + if (end) + *end = p; + + if ((max_len >= 0 && p != str + max_len) || + (max_len < 0 && *p != '\0')) + return false; + else + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// End of gutf8.c +/////////////////////////////////////////////////////////////////////////////////////////////// + + +class KviSmartTextCodec : public QTextCodec +{ +protected: + KviQCString m_szName; + QTextCodec * m_pRecvCodec; + QTextCodec * m_pSendCodec; +public: + KviSmartTextCodec(const char * szName,const char * szChildCodecName,bool bSendInUtf8) + : QTextCodec() + { + m_szName = szName; + if(!g_pUtf8TextCodec) + { + g_pUtf8TextCodec = QTextCodec::codecForName("UTF-8"); + if(!g_pUtf8TextCodec) + { + debug("Can't find the global utf8 text codec!"); + g_pUtf8TextCodec = QTextCodec::codecForLocale(); // try anything else... + } + } + m_pRecvCodec = QTextCodec::codecForName(szChildCodecName); + if(!m_pRecvCodec) + { + debug("Can't find the codec for name %s (composite codec creation)",szName); + m_pRecvCodec = g_pUtf8TextCodec; + } + if(bSendInUtf8) + m_pSendCodec = g_pUtf8TextCodec; + else + m_pSendCodec = m_pRecvCodec; + } +public: + bool ok(){ return m_pRecvCodec && g_pUtf8TextCodec; }; + + virtual int mibEnum () const { return 0; }; + +#ifdef COMPILE_USE_QT4 + virtual QByteArray name() const { return m_szName; }; +protected: + virtual QByteArray convertFromUnicode(const QChar * input,int number,ConverterState * state) const + { + return m_pSendCodec->fromUnicode(input,number,state); + } + virtual QString convertToUnicode(const char * chars,int len,ConverterState * state) const + { + if(g_utf8_validate(chars,len,NULL))return g_pUtf8TextCodec->toUnicode(chars,len,state); + return m_pRecvCodec->toUnicode(chars,len,state); + } +#else +public: + virtual const char * mimeName () const { return m_pRecvCodec->mimeName(); }; + virtual const char * name () const { return m_szName.data(); }; + virtual QTextDecoder * makeDecoder () const { return m_pRecvCodec->makeDecoder(); }; + virtual QTextEncoder * makeEncoder () const { return m_pSendCodec->makeEncoder(); }; + QCString fromUnicode (const QString & uc) const { return m_pSendCodec->fromUnicode(uc); }; + virtual QCString fromUnicode (const QString & uc,int & lenInOut) const { return m_pSendCodec->fromUnicode(uc,lenInOut); }; + QString toUnicode(const char * chars) const + { + if(g_utf8_validate(chars,-1,NULL))return g_pUtf8TextCodec->toUnicode(chars); + return m_pRecvCodec->toUnicode(chars); + }; + virtual QString toUnicode(const char * chars,int len) const + { + if(g_utf8_validate(chars,len,NULL))return g_pUtf8TextCodec->toUnicode(chars,len); + return m_pRecvCodec->toUnicode(chars,len); + }; + QString toUnicode(const QByteArray & a,int len) const + { + if(g_utf8_validate(a.data(),len,NULL))return g_pUtf8TextCodec->toUnicode(a,len); + return m_pRecvCodec->toUnicode(a,len); + }; + QString toUnicode(const QByteArray & a) const + { + if(g_utf8_validate(a.data(),a.size(),NULL))return g_pUtf8TextCodec->toUnicode(a); + return m_pRecvCodec->toUnicode(a); + }; + QString toUnicode(const QCString & a,int len) const + { + if(g_utf8_validate(a.data(),len,NULL))return g_pUtf8TextCodec->toUnicode(a,len); + return m_pRecvCodec->toUnicode(a,len); + }; + QString toUnicode(const QCString & a) const + { + if(g_utf8_validate(a.data(),-1,NULL))return g_pUtf8TextCodec->toUnicode(a); + return m_pRecvCodec->toUnicode(a); + }; + + virtual bool canEncode(QChar ch) const { return m_pSendCodec->canEncode(ch); }; + virtual bool canEncode(const QString &s) const { return m_pSendCodec->canEncode(s); }; + virtual int heuristicContentMatch(const char * chars,int len) const + { + int iii = g_pUtf8TextCodec->heuristicContentMatch(chars,len); + if(iii < 0)return m_pRecvCodec->heuristicContentMatch(chars,len); + return iii; + } + virtual int heuristicNameMatch(const char * hint) const { return 0; }; +#endif +}; + +static KviPointerHashTable<const char *,KviSmartTextCodec> * g_pSmartCodecDict = 0; + + + +///////////////////////////////////////////////////////////////////////////////////////////////////// +// +// The following code was extracted and adapted from gettext.h and gettextP.h +// from the GNU gettext package. +// +// Internal header for GNU gettext internationalization functions. +// Copyright (C) 1995, 1997 Free Software Foundation, Inc. +// +// 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, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with the GNU C Library; see the file COPYING.LIB. If not, +// write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301, USA. +// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> + +#if HAVE_LIMITS_H || _LIBC + #include <limits.h> +#endif + +// The magic number of the GNU message catalog format. +#define KVI_LOCALE_MAGIC 0x950412de +#define KVI_LOCALE_MAGIC_SWAPPED 0xde120495 + +// Revision number of the currently used .mo (binary) file format. +#define MO_REVISION_NUMBER 0 + + +// Header for binary .mo file format. +struct GnuMoFileHeader +{ + // The magic number. + kvi_u32_t magic; + // The revision number of the file format. + kvi_u32_t revision; + // The number of strings pairs. + kvi_u32_t nstrings; + // Offset of table with start offsets of original strings. + kvi_u32_t orig_tab_offset; + // Offset of table with start offsets of translation strings. + kvi_u32_t trans_tab_offset; + // Size of hashing table. + kvi_u32_t hash_tab_size; + // Offset of first hashing entry. + kvi_u32_t hash_tab_offset; +}; + +struct GnuMoStringDescriptor +{ + // Length of addressed string. + kvi_u32_t length; + // Offset of string in file. + kvi_u32_t offset; +}; + +#define KVI_SWAP_IF_NEEDED(flag,value) (flag ? kvi_swap32(value) : (value)) + +/////////////////////////////////////////////////////////////////////////////////////////////// +// End of gettext.h & gettextP.h +/////////////////////////////////////////////////////////////////////////////////////////////// + + +// HELPERS + +static int somePrimeNumbers[90]= +{ + 257 , 521 , 769 , 1031, 1087, 1091, 1103, 1117, 1123, 1151, // Incomplete *.mo files + 1163, 1171, 1181, 1193, 1201, 1213, 1217, 1223, 1229, 1231, // Complete *.mo files + 1237, 1249, 1259, 1277, 1283, 1289, 1291, 1297, 1307, 1319, + 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1433, + 1447, 1459, 1471, 1481, 1493, 1511, 1523, 1531, 1543, 1553, + 1567, 1571, 1583, 1597, 1609, 1619, 1627, 1637, 1657, 1667, // Too big for KVIrc *.mo files + 1693, 1709, 1721, 1733, 1741, 1753, 1777, 1789, 1811, 1831, + 1907, 2069, 2111, 2221, 2309, 2441, 2531, 2617, 2731, 2837, + 2903, 3121, 3329, 3331, 3767, 4127, 5051, 6089, 7039, 9973 +}; + +int kvi_getFirstBiggerPrime(int number) +{ + for(int i=0;i<90;i++){ + if(somePrimeNumbers[i] >= number)return somePrimeNumbers[i]; + } + return 9973; //error! +} + + +KviMessageCatalogue::KviMessageCatalogue() +{ + //m_uEncoding = 0; + m_pTextCodec = QTextCodec::codecForLocale(); + + //m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(1123,true,false); // dictSize, case sensitive , don't copy keys + m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(32,true,false); // dictSize, case sensitive , don't copy keys + m_pMessages->setAutoDelete(true); +} + +KviMessageCatalogue::~KviMessageCatalogue() +{ + if(m_pMessages) + delete m_pMessages; +} + +bool KviMessageCatalogue::load(const QString& name) +{ + QString szCatalogueFile(name); + + // Try to load the header + KviFile f(szCatalogueFile); + if(!f.openForReading()) + { + debug("[KviLocale]: Failed to open the messages file %s: probably doesn't exist",KviQString::toUtf8(szCatalogueFile).data()); + return false; + } + + GnuMoFileHeader hdr; + + if(f.readBlock((char *)&hdr,sizeof(GnuMoFileHeader)) < (int)sizeof(GnuMoFileHeader)) + { + debug("KviLocale: Failed to read header of %s",KviQString::toUtf8(szCatalogueFile).data()); + f.close(); + return false; + } + + bool bMustSwap = false; + + if(hdr.magic != KVI_LOCALE_MAGIC) + { + if(hdr.magic == KVI_LOCALE_MAGIC_SWAPPED) + { + debug("KviLocale: Swapped magic for file %s: swapping data too",KviQString::toUtf8(szCatalogueFile).data()); + bMustSwap = true; + } else { + debug("KviLocale: Bad locale magic for file %s: not a *.mo file ?",KviQString::toUtf8(szCatalogueFile).data()); + f.close(); + return false; + } + } + + if(KVI_SWAP_IF_NEEDED(bMustSwap,hdr.revision) != MO_REVISION_NUMBER) + { + debug("KviLocale: Invalid *.mo file revision number for file %s",KviQString::toUtf8(szCatalogueFile).data()); + f.close(); + return false; + } + + int numberOfStrings = KVI_SWAP_IF_NEEDED(bMustSwap,hdr.nstrings); + + if(numberOfStrings <= 0) + { + debug("KviLocale: No translated messages found in file %s",KviQString::toUtf8(szCatalogueFile).data()); + f.close(); + return false; + } + + if(numberOfStrings >= 9972) + { + debug("Number of strings too big...sure that it is a KVIrc catalog file ?"); + numberOfStrings = 9972; + } + + // return back + f.seek(0); + + unsigned int fSize = f.size(); + char * buffer = (char *)kvi_malloc(fSize); + + // FIXME: maybe read it in blocks eh ? + if(f.readBlock(buffer,fSize) < (int)fSize) + { + debug("KviLocale: Error while reading the translation file %s",KviQString::toUtf8(szCatalogueFile).data()); + kvi_free(buffer); + f.close(); + return false; + } + + // Check for broken *.mo files + if(fSize < (24 + (sizeof(GnuMoStringDescriptor) * numberOfStrings))) + { + debug("KviLocale: Broken translation file %s (too small for all descriptors)",KviQString::toUtf8(szCatalogueFile).data()); + kvi_free(buffer); + f.close(); + return false; + } + + GnuMoStringDescriptor * origDescriptor = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.orig_tab_offset)); + GnuMoStringDescriptor * transDescriptor = (GnuMoStringDescriptor *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.trans_tab_offset)); + + // Check again for broken *.mo files + int expectedFileSize = KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].offset) + + KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[numberOfStrings - 1].length); + + if(fSize < (unsigned int)expectedFileSize) + { + debug("KviLocale: Broken translation file %s (too small for all the message strings)",KviQString::toUtf8(szCatalogueFile).data()); + kvi_free(buffer); + f.close(); + return false; + } + + // Ok...we can run now + + int dictSize = kvi_getFirstBiggerPrime(numberOfStrings); + if(m_pMessages) + delete m_pMessages; + m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(dictSize,true,false); // dictSize, case sensitive , don't copy keys + m_pMessages->setAutoDelete(true); + + KviStr szHeader; + + for(int i=0;i < numberOfStrings;i++) + { + // FIXME: "Check for NULL inside strings here ?" + //debug("original seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset), + // KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length)); + //debug("translated seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset), + // KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length)); + + KviTranslationEntry * e = new KviTranslationEntry( + (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].offset)), + KVI_SWAP_IF_NEEDED(bMustSwap,origDescriptor[i].length), + (char *)(buffer + KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].offset)), + KVI_SWAP_IF_NEEDED(bMustSwap,transDescriptor[i].length)); + + // In some (or all?) *.mo files the first string + // is zero bytes long and the translated one contains + // informations about the translation + if(e->m_szKey.len() == 0) + { + szHeader = e->m_szEncodedTranslation; + delete e; + continue; + } + + m_pMessages->insert(e->m_szKey.ptr(),e); + } + + kvi_free(buffer); + f.close(); + + m_pTextCodec = 0; + + // find out the text encoding , if possible + if(szHeader.hasData()) + { + // find "charset=*\n" + int idx = szHeader.findFirstIdx("charset="); + if(idx != -1) + { + szHeader.cutLeft(idx + 8); + szHeader.cutFromFirst('\n'); + szHeader.stripWhiteSpace(); + m_pTextCodec = KviLocale::codecForName(szHeader.ptr()); + if(!m_pTextCodec) + { + debug("Can't find the codec for charset=%s",szHeader.ptr()); + debug("Falling back to codecForLocale()"); + m_pTextCodec = QTextCodec::codecForLocale(); + } + } + } + + if(!m_pTextCodec) + { + debug("The message catalogue does not have a \"charset\" header"); + debug("Assuming utf8"); // FIXME: or codecForLocale() ? + m_pTextCodec = QTextCodec::codecForName("UTF-8"); + } + + return true; +} + +const char * KviMessageCatalogue::translate(const char *text) +{ + KviTranslationEntry * aux = m_pMessages->find(text); + if(aux)return aux->m_szEncodedTranslation.ptr(); + return text; +} + +const QString & KviMessageCatalogue::translateToQString(const char *text) +{ + KviTranslationEntry * aux = m_pMessages->find(text); + if(aux) + { + if(aux->m_pQTranslation)return *(aux->m_pQTranslation); + aux->m_pQTranslation = new QString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr())); + return *(aux->m_pQTranslation); + } + // no translation is available: let's avoid continous string decoding + aux = new KviTranslationEntry(text); + m_pMessages->insert(aux->m_szKey.ptr(),aux); + aux->m_pQTranslation = new QString(m_pTextCodec->toUnicode(aux->m_szEncodedTranslation.ptr())); + return *(aux->m_pQTranslation); +} + + + + +namespace KviLocale +{ +#ifndef QT_NO_BIG_CODECS + #define NUM_ENCODINGS 109 +#else + #define NUM_ENCODINGS 85 +#endif + + + + static EncodingDescription supported_encodings[]= + { + { "UTF-8" , 0 , 0 , "8-bit Unicode" }, + { "ISO-8859-1" , 0 , 0 , "Western, Latin-1" }, + { "ISO-8859-2" , 0 , 0 , "Central European 1" }, + { "ISO-8859-3" , 0 , 0 , "Central European 2" }, + { "ISO-8859-4" , 0 , 0 , "Baltic, Standard" }, + { "ISO-8859-5" , 0 , 0 , "Cyrillic, ISO" }, + { "ISO-8859-6" , 0 , 0 , "Arabic, Standard" }, + { "ISO-8859-7" , 0 , 0 , "Greek" }, + { "ISO-8859-8" , 0 , 0 , "Hebrew, visually ordered" }, + { "ISO-8859-8-i" , 0 , 0 , "Hebrew, logically ordered" }, + { "ISO-8859-9" , 0 , 0 , "Turkish, Latin-5" }, + { "ISO-8859-15" , 0 , 0 , "Western, Latin-1 + Euro" }, + { "KOI8-R" , 0 , 0 , "Cyrillic, KOI" }, + { "KOI8-U" , 0 , 0 , "Ukrainian" }, + { "CP-1250" , 0 , 0 , "Central European 3" }, + { "CP-1251" , 0 , 0 , "Cyrillic, Windows" }, + { "CP-1252" , 0 , 0 , "Western, CP" }, + { "CP-1253" , 0 , 0 , "Greek, CP" }, + { "CP-1256" , 0 , 0 , "Arabic, CP" }, + { "CP-1257" , 0 , 0 , "Baltic, CP" }, + { "CP-1255" , 0 , 0 , "Hebrew, CP" }, + { "CP-1254" , 0 , 0 , "Turkish, CP" }, + { "TIS-620" , 0 , 0 , "Thai" }, +#ifndef QT_NO_BIG_CODECS + { "Big5" , 0 , 0 , "Chinese Traditional" }, + { "Big5-HKSCS" , 0 , 0 , "Chinese Traditional, Hong Kong" }, + { "GB18030" , 0 , 0 , "Chinese Simplified" }, + { "JIS7" , 0 , 0 , "Japanese (JIS7)" }, + { "Shift-JIS" , 0 , 0 , "Japanese (Shift-JIS)" }, + { "EUC-JP" , 0 , 0 , "Japanese (EUC-JP)" }, + { "EUC-KR" , 0 , 0 , "Korean" }, + { "TSCII" , 0 , 0 , "Tamil" }, +#endif + { "ISO-8859-10" , 0 , 0 , "ISO-8859-10" }, + { "ISO-8859-13" , 0 , 0 , "ISO-8859-13" }, + { "ISO-8859-14" , 0 , 0 , "ISO-8859-14" }, + { "IBM-850" , 0 , 0 , "IBM-850" }, + { "IBM-866" , 0 , 0 , "IBM-866" }, + { "CP874" , 0 , 0 , "CP874" }, + + // smart codecs that send in the local charset + { "ISO-8859-1 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western Latin-1, O: Western Latin-1" }, + { "ISO-8859-2 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 1, O: Central European 1" }, + { "ISO-8859-3 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 2, O: Central European 2" }, + { "ISO-8859-4 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Baltic, Standard, O: Baltic, Standard" }, + { "ISO-8859-5 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, ISO, O: Cyrillic, ISO" }, + { "ISO-8859-6 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Arabic, Standard, O: Arabic, Standard" }, + { "ISO-8859-7 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Greek, O: Greek" }, + { "ISO-8859-8 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, visually ordered, O: Hebrew, visually ordered" }, + { "ISO-8859-8-i [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, logically ordered, O: Hebrew, logically ordered" }, + { "ISO-8859-9 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Turkish, Latin-5, O: Turkish, Latin-5" }, + { "ISO-8859-15 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: Western, Latin-1 + Euro" }, + { "KOI8-R [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, KOI, O: Cyrillic, KOI" }, + { "KOI8-U [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Ukrainian, O: Ukrainian" }, + { "CP-1250 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Central European 3, O: Central European 3" }, + { "CP-1251 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Cyrillic, Windows, O: Cyrillic, Windows" }, + { "CP-1252 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Western, CP, O: Western, CP" }, + { "CP-1253 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Greek, CP, O: Greek, CP" }, + { "CP-1256 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Arabic, CP, O: Arabic, CP" }, + { "CP-1257 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Baltic, CP, O: Baltic, CP" }, + { "CP-1255 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Hebrew, CP, O: Hebrew, CP" }, + { "CP-1254 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Turkish, CP, O: Turkish, CP" }, + { "TIS-620 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Thai, O: Thai" }, +#ifndef QT_NO_BIG_CODECS + { "Big5 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, O: Chinese Traditional" }, + { "Big5-HKSCS [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: Chinese Traditional, Hong Kong" }, + { "GB18030 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Chinese Simplified, O: Chinese Simplified" }, + { "JIS7 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (JIS7), O: Japanese " }, + { "Shift-JIS [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" }, + { "EUC-JP [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" }, + { "EUC-KR [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Korean, O: Korean" }, + { "TSCII [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / Tamil, O: Tamil" }, +#endif + { "ISO-8859-10 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-10, O: ISO-8859-10" }, + { "ISO-8859-13 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-13, O: ISO-8859-13" }, + { "ISO-8859-14 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / ISO-8859-14, O: ISO-8859-14" }, + { "IBM-850 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / IBM-850, O: IBM-850" }, + { "IBM-866 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / IBM-866, O: IBM-866" }, + { "CP874 [UTF-8]" , 1 , 0 , "I: 8-bit Unicode / CP874, O: CP874" }, + + // smart codecs that send in utf8 + { "UTF-8 [ISO-8859-1]" , 1 , 1 , "I: 8-bit Unicode / Western Latin-1, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-2]" , 1 , 1 , "I: 8-bit Unicode / Central European 1, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-3]" , 1 , 1 , "I: 8-bit Unicode / Central European 2, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-4]" , 1 , 1 , "I: 8-bit Unicode / Baltic, Standard, O: 8-bit Unicode" }, + + { "UTF-8 [ISO-8859-5]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, ISO, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-6]" , 1 , 1 , "I: 8-bit Unicode / Arabic, Standard, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-7]" , 1 , 1 , "I: 8-bit Unicode / Greek, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-8]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, visually ordered, O: 8-bit Unicode" }, + + { "UTF-8 [ISO-8859-8-i]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, logically ordered, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-9]" , 1 , 1 , "I: 8-bit Unicode / Turkish, Latin-5, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-15]" , 1 , 1 , "I: 8-bit Unicode / Western, Latin-1 + Euro, O: 8-bit Unicode" }, + { "UTF-8 [KOI8-R]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, KOI, O: 8-bit Unicode" }, + + { "UTF-8 [KOI8-U]" , 1 , 1 , "I: 8-bit Unicode / Ukrainian, O: 8-bit Unicode" }, + { "UTF-8 [CP-1250]" , 1 , 1 , "I: 8-bit Unicode / Central European 3, O: 8-bit Unicode" }, + { "UTF-8 [CP-1251]" , 1 , 1 , "I: 8-bit Unicode / Cyrillic, Windows, O: 8-bit Unicode" }, + { "UTF-8 [CP-1252]" , 1 , 1 , "I: 8-bit Unicode / Western, CP, O: 8-bit Unicode" }, + + { "UTF-8 [CP-1253]" , 1 , 1 , "I: 8-bit Unicode / Greek, CP, O: 8-bit Unicode" }, + { "UTF-8 [CP-1256]" , 1 , 1 , "I: 8-bit Unicode / Arabic, CP, O: 8-bit Unicode" }, + { "UTF-8 [CP-1257]" , 1 , 1 , "I: 8-bit Unicode / Baltic, CP, O: 8-bit Unicode" }, + { "UTF-8 [CP-1255]" , 1 , 1 , "I: 8-bit Unicode / Hebrew, CP, O: 8-bit Unicode" }, + + { "UTF-8 [CP-1254]" , 1 , 1 , "I: 8-bit Unicode / Turkish, CP, O: 8-bit Unicode" }, + { "UTF-8 [TIS-620]" , 1 , 1 , "I: 8-bit Unicode / Thai, O: 8-bit Unicode" }, +#ifndef QT_NO_BIG_CODECS + { "UTF-8 [Big5]" , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, O: 8-bit Unicode" }, + { "UTF-8 [Big5-HKSCS]" , 1 , 1 , "I: 8-bit Unicode / Chinese Traditional, Hong Kong, O: 8-bit Unicode" }, + + { "UTF-8 [GB18030]" , 1 , 1 , "I: 8-bit Unicode / Chinese Simplified, O: 8-bit Unicode" }, + { "UTF-8 [JIS7]" , 1 , 1 , "I: 8-bit Unicode / Japanese (JIS7), O: 8-bit Unicode" }, + { "UTF-8 [Shift-JIS]" , 1 , 1 , "I: 8-bit Unicode / Japanese (Shift-JIS), O: Japanese (Shift-JIS)" }, + { "UTF-8 [EUC-JP]" , 1 , 1 , "I: 8-bit Unicode / Japanese (EUC-JP), O: Japanese (EUC-JP)" }, + + { "UTF-8 [EUC-KR]" , 1 , 1 , "I: 8-bit Unicode / Korean, O: 8-bit Unicode" }, + { "UTF-8 [TSCII]" , 1 , 1 , "I: 8-bit Unicode / Tamil, O: 8-bit Unicode" }, +#endif + { "UTF-8 [ISO-8859-10]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-10, O: 8-bit Unicode" }, + { "UTF-8 [ISO-8859-13]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-13, O: 8-bit Unicode" }, + + { "UTF-8 [ISO-8859-14]" , 1 , 1 , "I: 8-bit Unicode / ISO-8859-14, O: 8-bit Unicode" }, + { "UTF-8 [IBM-850]" , 1 , 1 , "I: 8-bit Unicode / IBM-850, O: 8-bit Unicode" }, + { "UTF-8 [IBM-866]" , 1 , 1 , "I: 8-bit Unicode / IBM-866, O: 8-bit Unicode" }, + { "UTF-8 [CP874]" , 1 , 1 , "I: 8-bit Unicode / CP874, O: 8-bit Unicode" }, + + { 0 , 0 , 0 , 0 } + }; + + EncodingDescription * encodingDescription(int iIdx) + { + if(iIdx > NUM_ENCODINGS)return &(supported_encodings[NUM_ENCODINGS]); + return &(supported_encodings[iIdx]); + } + + QTextCodec * codecForName(const char * szName) + { + KviStr szTmp = szName; + int idx = szTmp.findFirstIdx('['); + if(idx != -1) + { + // composite codec: either UTF-8 [child codec] or child codec [UTF-8] + KviSmartTextCodec * c = g_pSmartCodecDict->find(szName); + if(c)return c; + + + if(kvi_strEqualCIN("UTF-8 [",szName,7)) + { + szTmp.replaceAll("UTF-8 [",""); + szTmp.replaceAll("]",""); + // smart codec that sends UTF-8 + c = new KviSmartTextCodec(szName,szTmp.ptr(),true); + } else { + szTmp.cutFromFirst(' '); + // smart codec that sends child encoding + c = new KviSmartTextCodec(szName,szTmp.ptr(),false); + } + if(c->ok()) + { + g_pSmartCodecDict->replace(szName,c); + return c; + } else { + delete c; + } + } + return QTextCodec::codecForName(szName); + } + + const KviStr & localeName() + { + return g_szLang; + } + + bool loadCatalogue(const QString &name,const QString &szLocaleDir) + { + //debug("Looking up catalogue %s",name); + if(g_pCatalogueDict->find(KviQString::toUtf8(name).data()))return true; // already loaded + + QString szBuffer; + + if(findCatalogue(szBuffer,name,szLocaleDir)) + { + KviMessageCatalogue * c = new KviMessageCatalogue(); + if(c->load(szBuffer)) + { + //debug("KviLocale: loaded catalogue %s",name); + g_pCatalogueDict->insert(KviQString::toUtf8(name).data(),c); + return true; + } + } + return false; + } + + bool unloadCatalogue(const QString &name) + { + //debug("Unloading catalogue : %s",name); + return g_pCatalogueDict->remove(KviQString::toUtf8(name).data()); + } + + bool findCatalogue(QString &szBuffer,const QString& name,const QString& szLocaleDir) + { + KviStr szLocale = g_szLang; + + QString szLocDir = szLocaleDir; + KviQString::ensureLastCharIs(szLocDir,KVI_PATH_SEPARATOR_CHAR); + + KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr()); + + if(KviFileUtils::fileExists(szBuffer))return true; + + if(szLocale.findFirstIdx('.') != -1) + { + // things like en_GB.utf8 + // kill them + szLocale.cutFromFirst('.'); + + KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr()); + if(KviFileUtils::fileExists(szBuffer))return true; + } + + if(szLocale.findFirstIdx('@') != -1) + { + // things like @euro ? + // kill them + szLocale.cutFromFirst('@'); + KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr()); + if(KviFileUtils::fileExists(szBuffer))return true; + } + + if(szLocale.findFirstIdx('_') != -1) + { + // things like en_GB + // kill them + szLocale.cutFromFirst('_'); + KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr()); + if(KviFileUtils::fileExists(szBuffer))return true; + } + + // try the lower case version too + szLocale.toLower(); + KviQString::sprintf(szBuffer,"%Q%Q_%s.mo",&szLocDir,&name,szLocale.ptr()); + if(KviFileUtils::fileExists(szBuffer))return true; + + return false; + } + + // + // This function attempts to determine the current locale + // and then load the corresponding translation file + // from the KVIrc locale directory + // Returns true if the locale was correctly set + // i.e. the locale is C or POSIX (no translation needed) + // or the locale is correctly defined and the + // translation map was sucesfully loaded + // + + void init(QApplication * app,const QString &localeDir) + { + // first of all try to find out the current locale + g_szLang=""; +#ifdef COMPILE_USE_QT4 + QString szLangFile=QString("%1/.kvirc_force_locale").arg(QDir::homePath()); +#else + QString szLangFile=QString("%1/.kvirc_force_locale").arg(QDir::homeDirPath()); +#endif + if(KviFileUtils::fileExists(szLangFile)) + { + QString szTmp; + KviFileUtils::readFile(szLangFile,szTmp); + g_szLang=szTmp; + } + if(g_szLang.isEmpty())g_szLang = kvi_getenv("KVIRC_LANG"); +#ifdef COMPILE_USE_QT4 + if(g_szLang.isEmpty())g_szLang = QLocale::system().name(); +#else + if(g_szLang.isEmpty())g_szLang = QTextCodec::locale(); +#endif + if(g_szLang.isEmpty())g_szLang = kvi_getenv("LC_MESSAGES"); + if(g_szLang.isEmpty())g_szLang = kvi_getenv("LANG"); + if(g_szLang.isEmpty())g_szLang = "en"; + g_szLang.stripWhiteSpace(); + + // the main catalogue is supposed to be kvirc_<language>.mo + g_pMainCatalogue = new KviMessageCatalogue(); + // the catalogue dict + g_pCatalogueDict = new KviPointerHashTable<const char *,KviMessageCatalogue>; + g_pCatalogueDict->setAutoDelete(true); + + // the smart codec dict + g_pSmartCodecDict = new KviPointerHashTable<const char *,KviSmartTextCodec>; + // the Qt docs explicitly state that we shouldn't delete + // the codecs by ourselves... + g_pSmartCodecDict->setAutoDelete(false); + + if(g_szLang.hasData()) + { + QString szBuffer; + if(findCatalogue(szBuffer,"kvirc",localeDir)) + { + g_pMainCatalogue->load(szBuffer); + g_pTranslator = new KviTranslator(app,"kvirc_translator"); + app->installTranslator(g_pTranslator); + } else { + KviStr szTmp = g_szLang; + szTmp.cutFromFirst('.'); + szTmp.cutFromFirst('_'); + szTmp.cutFromFirst('@'); + szTmp.toLower(); + if(!(kvi_strEqualCI(szTmp.ptr(),"en") || + kvi_strEqualCI(szTmp.ptr(),"c") || + kvi_strEqualCI(szTmp.ptr(),"us") || + kvi_strEqualCI(szTmp.ptr(),"gb") || + kvi_strEqualCI(szTmp.ptr(),"posix"))) + { + // FIXME: THIS IS NO LONGER VALID!!! + debug("Can't find the catalogue for locale \"%s\" (%s)",g_szLang.ptr(),szTmp.ptr()); + debug("There is no such translation or the $LANG variable was incorrectly set"); + debug("You can use $KVIRC_LANG to override the catalogue name"); + debug("For example you can set KVIRC_LANG to it_IT to force usage of the it.mo catalogue"); + } + } + } + + //g_pTextCodec = QTextCodec::codecForLocale(); + //if(!g_pTextCodec)g_pTextCodec = QTextCodec::codecForLocale(); + } + + void done(QApplication * app) + { + delete g_pMainCatalogue; + delete g_pCatalogueDict; + delete g_pSmartCodecDict; + g_pMainCatalogue = 0; + g_pCatalogueDict = 0; + g_pSmartCodecDict = 0; + if(g_pTranslator) + { + app->removeTranslator(g_pTranslator); + delete g_pTranslator; + g_pTranslator = 0; + } + } + + KviMessageCatalogue * getLoadedCatalogue(const QString& name) + { + return g_pCatalogueDict->find(KviQString::toUtf8(name).data()); + } + + + const char * translate(const char * text,const char * context) + { + if(context) + { + KviMessageCatalogue * c = g_pCatalogueDict->find(context); + if(!c) + { + // FIXME: Should really try to load the catalogue here! + c = new KviMessageCatalogue(); + g_pCatalogueDict->insert(context,c); + } + return c->translate(text); + } + return g_pMainCatalogue->translate(text); + } + + const QString & translateToQString(const char * text,const char * context) + { + if(context) + { + KviMessageCatalogue * c = g_pCatalogueDict->find(context); + if(!c) + { + // FIXME: Should really try to load the catalogue here! + c = new KviMessageCatalogue(); + g_pCatalogueDict->insert(context,c); + } + return c->translateToQString(text); + } + return g_pMainCatalogue->translateToQString(text); + } +}; + +KviTranslator::KviTranslator(QObject * par,const char * nam) +#ifdef COMPILE_USE_QT4 +: QTranslator(par) +#else +: QTranslator(par,nam) +#endif +{ +} + +KviTranslator::~KviTranslator() +{ +} + +#ifdef COMPILE_USE_QT4 +QString KviTranslator::translate(const char *context,const char * message,const char * comment) const +{ + // we ignore contexts and comments for qt translations + return g_pMainCatalogue->translateToQString(message); +} +#endif + +QString KviTranslator::find(const char *context,const char * message) const +{ + // we ignore contexts for qt translations + return g_pMainCatalogue->translateToQString(message); +} + +#ifndef COMPILE_USE_QT4 +QTranslatorMessage KviTranslator::findMessage(const char * context,const char * sourceText,const char * comment) const +{ + // we ignore contexts for qt translations + return QTranslatorMessage(context,sourceText,comment,g_pMainCatalogue->translateToQString(sourceText)); +} +#endif + +#if 0 + +// a fake table that will force these translations +// to be included in the *.pot file + +static QString fake_translations_table[]= +{ + // global + __tr2qs("OK"), + __tr2qs("Cancel"), + // color dialog + __tr2qs("Select color"), + __tr2qs("&Basic colors"), + __tr2qs("&Custom colors"), + __tr2qs("&Red"), + __tr2qs("&Green"), + __tr2qs("Bl&ue"), + __tr2qs("&Define Custom Colors >>"), + __tr2qs("&Add to Custom Colors"), + // font dialog + __tr2qs("Select Font"), + __tr2qs("&Font"), + __tr2qs("Font st&yle"), + __tr2qs("&Size"), + __tr2qs("Sample"), + __tr2qs("Effects"), + __tr2qs("Stri&keout"), + __tr2qs("&Underline"), + __tr2qs("Scr&ipt"), + //File selector + __tr2qs("Parent Directory"), + __tr2qs("Back"), + __tr2qs("Forward"), + __tr2qs("Reload"), + __tr2qs("New Directory"), + __tr2qs("Bookmarks"), + __tr2qs("Add Bookmark"), + __tr2qs("&Edit Bookmarks"), + __tr2qs("New Bookmark Folder..."), + __tr2qs("Configure"), + __tr2qs("Sorting"), + __tr2qs("By Name"), + __tr2qs("By Date"), + __tr2qs("By Size"), + __tr2qs("Reverse"), + __tr2qs("Directories First"), + __tr2qs("Case Insensitive"), + __tr2qs("Short View"), + __tr2qs("Detailed View"), + __tr2qs("Show Hidden Files"), + __tr2qs("Show Quick Access Navigation Panel"), + __tr2qs("Show Preview"), + __tr2qs("Separate Directories"), + __tr2qs("Often used directories"), + __tr2qs("Desktop"), + __tr2qs("Home Directory"), + __tr2qs("Floppy"), + __tr2qs("Temporary Files"), + __tr2qs("Network"), + __tr2qs("New Directory..."), + __tr2qs("Delete"), + __tr2qs("Thumbnail Previews"), + __tr2qs("Large Icons"), + __tr2qs("Small Icons"), + __tr2qs("Properties..."), + __tr2qs("&Automatic Preview"), + __tr2qs("&Preview"), + __tr2qs("&Location:"), + __tr2qs("&Filter:"), + __tr2qs("All Files"), + __tr2qs("&OK"), + __tr2qs("&Cancel") + +} + +#endif diff --git a/src/kvilib/system/kvi_locale.h b/src/kvilib/system/kvi_locale.h new file mode 100644 index 00000000..bc3ed8eb --- /dev/null +++ b/src/kvilib/system/kvi_locale.h @@ -0,0 +1,146 @@ +#ifndef _KVI_LOCALE_H_ +#define _KVI_LOCALE_H_ + +//============================================================================= +// +// File : kvi_locale.h +// Creation date : Sat Jan 16 1999 18:15:01 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + + +#include "kvi_settings.h" +#include "kvi_qstring.h" +#include "kvi_string.h" +#include "kvi_pointerhashtable.h" + +#include <qapplication.h> + +class QTextCodec; +class KviMessageCatalogue; + +namespace KviLocale +{ + typedef struct _EncodingDescription + { + char * szName; + char bSmart; // is it a smart codec ? + char bSendUtf8; // does it send utf8 or the local charset ? + char * szDescription; + } EncodingDescription; + + // you MUST start iterating from 0 and terminate when + // you get an entry with a NULL szName + KVILIB_API EncodingDescription * encodingDescription(int iIdx); + KVILIB_API QTextCodec * codecForName(const char * szName); + KVILIB_API const KviStr & localeName(); + KVILIB_API bool findCatalogue(QString &szBuffer,const QString& name,const QString& szLocaleDir); + KVILIB_API bool loadCatalogue(const QString& name,const QString& szLocaleDir); + KVILIB_API KviMessageCatalogue * getLoadedCatalogue(const QString& name); + KVILIB_API bool unloadCatalogue(const QString& name); + KVILIB_API void init(QApplication * app,const QString& localeDir); + KVILIB_API void done(QApplication * app); + KVILIB_API const char * translate(const char * text,const char * context); + KVILIB_API const QString & translateToQString(const char * text,const char * context); +}; + +// not exported +class KviTranslationEntry +{ +public: + KviStr m_szKey; + KviStr m_szEncodedTranslation; + QString * m_pQTranslation; +public: + KviTranslationEntry(char * keyptr,int keylen,char * trptr,int trlen) + : m_szKey(keyptr,keylen) , m_szEncodedTranslation(trptr,trlen) + { + m_pQTranslation = 0; + } + + KviTranslationEntry(const char * keyandtr) + : m_szKey(keyandtr) , m_szEncodedTranslation(keyandtr) + { + m_pQTranslation = 0; + } + + ~KviTranslationEntry() + { + if(m_pQTranslation)delete m_pQTranslation; + } +}; + + +class KVILIB_API KviMessageCatalogue +{ +public: + KviMessageCatalogue(); + ~KviMessageCatalogue(); +protected: + //KviPointerHashTable<const char *,KviTranslationEntry> * m_pMessages; + KviPointerHashTable<const char *,KviTranslationEntry> * m_pMessages; + QTextCodec * m_pTextCodec; +public: + bool load(const QString& name); + const char * translate(const char * text); + const QString & translateToQString(const char * text); +}; + +#ifndef _KVI_LOCALE_CPP_ + extern KVILIB_API KviMessageCatalogue * g_pMainCatalogue; +#endif // !_KVI_LOCALE_CPP_ + +#define __tr(__text__) g_pMainCatalogue->translate(__text__) +#define __tr_no_lookup(__text__) __text__ +#define __tr_no_xgettext(__text__) g_pMainCatalogue->translate(__text__) + +#define __tr2qs(__text__) g_pMainCatalogue->translateToQString(__text__) +#define __tr2qs_no_xgettext(__text__) g_pMainCatalogue->translateToQString(__text__) + +#define __tr_ctx(__text__,__context__) KviLocale::translate(__text__,__context__) +#define __tr_no_lookup_ctx(__text__,__context__) __text__ +#define __tr_no_xgettext_ctx(__text__,__context__) KviLocale::translate(__text__,__context__) +#define __tr2qs_ctx(__text__,__context__) KviLocale::translateToQString(__text__,__context__) +#define __tr2qs_ctx_no_xgettext(__text__,__context__) KviLocale::translateToQString(__text__,__context__) +#define __tr2qs_no_lookup(__text__) __text__ + +#include <qtranslator.h> +#include <qstring.h> + +class KVILIB_API KviTranslator : public QTranslator +{ + Q_OBJECT + public: + KviTranslator(QObject * parent,const char * name); + ~KviTranslator(); + public: +#ifdef COMPILE_USE_QT4 + virtual QString translate(const char * context,const char * message,const char * comment) const; +#endif + // Deprecated in qt 4.x + virtual QString find(const char * context,const char * message) const; +#ifndef COMPILE_USE_QT4 + // Dead in qt 4.x + virtual QTranslatorMessage findMessage(const char * context,const char * sourceText,const char * comment = 0) const; +#endif +}; + + +#endif //!_KVI_LOCALE_H_ diff --git a/src/kvilib/system/kvi_process.h b/src/kvilib/system/kvi_process.h new file mode 100644 index 00000000..ea2275dc --- /dev/null +++ b/src/kvilib/system/kvi_process.h @@ -0,0 +1,37 @@ +#ifndef _KVI_PROCESS_H_ +#define _KVI_PROCESS_H_ +//============================================================================= +// +// File : kvi_process.h +// Creation date : Tue Jan 30 2007 04:05:41 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include <q3process.h> + #define KviProcess Q3Process +#else + #include <qprocess.h> + #define KviProcess QProcess +#endif + +#endif //!_KVI_PROCESS_H_ diff --git a/src/kvilib/system/kvi_stdarg.h b/src/kvilib/system/kvi_stdarg.h new file mode 100644 index 00000000..15c5e078 --- /dev/null +++ b/src/kvilib/system/kvi_stdarg.h @@ -0,0 +1,65 @@ +#ifndef _KVI_STDARG_H_ +#define _KVI_STDARG_H_ + +//============================================================================= +// +// File : kvi_stdarg.h +// Creation date : Sat Jan 03 2004 02:08:14 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include <stdarg.h> + +#define kvi_va_list va_list +#define kvi_va_start va_start +// +// kvi_va_start_by_reference should be used when the last known argument +// is a reference type and not a pointer +// +// int SomeClass::sprintf(const QString &fmt,...) +// { +// kvi_va_list list; +// kvi_va_start_by_reference(list,fmt); +// ... +// } +// +// +#ifdef COMPILE_ON_WINDOWS + #define kvi_va_start_by_reference(__list,__arg) \ + { \ + int supercalifragilisticoespiralidoso=_INTSIZEOF(__arg); \ + __asm lea eax,__arg \ + __asm add eax,supercalifragilisticoespiralidoso \ + __asm mov __list,eax \ + } +#elif defined(__GNUC__) + // gcc doesn't use the second argument + // so we just fool it to avoid the warnings + #define kvi_va_start_by_reference(__list,__arg) va_start(__list,((const char *)(&(__arg)))) +#else + #define kvi_va_start_by_reference va_start +#endif +#define kvi_va_arg va_arg +#define kvi_va_end va_end + + + +#endif //_KVI_STDARG_H_ diff --git a/src/kvilib/system/kvi_thread.cpp b/src/kvilib/system/kvi_thread.cpp new file mode 100644 index 00000000..e9ec3ac5 --- /dev/null +++ b/src/kvilib/system/kvi_thread.cpp @@ -0,0 +1,644 @@ +//============================================================================= +// +// File : kvi_thread.cpp +// Creation date : Tue Jul 6 1999 16:04:45 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2005 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#ifndef _GNU_SOURCE + #define _GNU_SOURCE +#endif + +#include "kvi_thread.h" + +#ifdef COMPILE_ON_WINDOWS + #include <io.h> // for _pipe() +#else + #include <unistd.h> //for pipe() and other tricks + #include <signal.h> // on Windows it is useless + #include <fcntl.h> +#endif + +#include <errno.h> + + +#include "kvi_string.h" +#include "kvi_settings.h" +#include "kvi_error.h" + + +#include <qapplication.h> + + +static void kvi_threadIgnoreSigalarm() +{ + // On Windows this stuff is useless anyway +#ifdef COMPILE_IGNORE_SIGALARM + #ifndef COMPILE_ON_WINDOWS + // Funky hack for some Solaris machines (maybe others ?) + // For an obscure (at least to me) reason + // when using threads ,some part of the system + // starts kidding us by sending a SIGALRM in apparently + // "random" circumstances. (Xlib ?) (XServer ?) + // The default action for SIGALRM is to exit the application. + // Could not guess more about this stuff... + // Here goes a "blind" hack for that. + + // Update: now we have an explaination too + // + // From: "Andre Stechert" (astechert at email dot com) + // To: pragma at kvirc dot net + // Subject: sigalarm on solaris ... + // Date: 26/7/2005 09:36 + + // Hi, + // I noticed in your readme that you were having problems with sigalarm + // in your solaris port and you weren't sure why. I quickly scanned your + // source code and noticed that you use usleep and threads. That's the problem, + // if you haven't already figured it out. On Solaris, usleep is implemented with + // SIGALARM. So is threading. So if you the active thread changes while + // a usleep is in progress, bang, the process is dead. + // + // There is no real feedback on this at the moment: if somebody + // experiences the problems please drop me a mail at pragma at kvirc dot net + // and we'll try to look for a better solution. + // If the explaination is correct then KVIrc could even lock up on those machines + // (never returning from an usleep() call ?)... + + struct sigaction ignr_act; + ignr_act.sa_handler = SIG_IGN; + sigemptyset(&ignr_act.sa_mask); + + #ifdef SA_NOMASK + ignr_act.sa_flags = SA_NOMASK; + #else + ignr_act.sa_flags = 0; + #endif + + #ifdef SA_RESTART + ignr_act.sa_flags |= SA_RESTART; + #endif + + if(sigaction(SIGALRM,&ignr_act,0) == -1)debug("Failed to set SIG_IGN for SIGALRM."); + #endif +#endif +} + +#ifndef COMPILE_ON_WINDOWS + +static void kvi_threadSigpipeHandler(int) +{ + debug("Thread ????: Caught SIGPIPE: ignoring."); +} + +#endif + +static void kvi_threadCatchSigpipe() +{ + // On windows this stuff is useless +#ifndef COMPILE_ON_WINDOWS + struct sigaction act; + act.sa_handler=&kvi_threadSigpipeHandler; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGPIPE); + // CC: take care of SunOS which automatically restarts interrupted system + // calls (and thus does not have SA_RESTART) +#ifdef SA_NOMASK + act.sa_flags = SA_NOMASK; +#else + act.sa_flags = 0; +#endif + +#ifdef SA_RESTART + act.sa_flags |= SA_RESTART; +#endif + + if(sigaction(SIGPIPE,&act,0L) == -1)debug("Failed to set the handler for SIGPIPE."); +#endif +} + +static void kvi_threadInitialize() +{ +#ifndef COMPILE_ON_WINDOWS + kvi_threadIgnoreSigalarm(); + kvi_threadCatchSigpipe(); +#endif +} + + + +#define KVI_THREAD_PIPE_SIDE_MASTER 0 +#define KVI_THREAD_PIPE_SIDE_SLAVE 1 + +// the maximum length of the slave->master queue +// over this length , the slave is forced to usleep() +#define KVI_THREAD_MAX_EVENT_QUEUE_LENGTH 50 + +static KviThreadManager * g_pThreadManager = 0; + +void KviThreadManager::globalInit() +{ + kvi_threadInitialize(); // we want this to apply to the main thread too + g_pThreadManager = new KviThreadManager(); +} + +void KviThreadManager::globalDestroy() +{ + delete g_pThreadManager; + g_pThreadManager = 0; +} + +KviThreadManager::KviThreadManager() +: QObject() +{ + if(g_pThreadManager)debug("Hey...what are ya doing ?"); + + + m_pMutex = new KviMutex(); + m_pThreadList = new KviPointerList<KviThread>; + m_pThreadList->setAutoDelete(false); + + m_iWaitingThreads = 0; + +#ifndef COMPILE_ON_WINDOWS + + m_iTriggerCount = 0; + + m_pEventQueue = new KviPointerList<KviThreadPendingEvent>; + m_pEventQueue->setAutoDelete(true); + + if(pipe(m_fd) != 0) + { + debug("Ops...thread manager pipe creation failed (%s)",KviQString::toUtf8(KviError::getDescription(KviError::translateSystemError(errno))).data()); + } + + if(fcntl(m_fd[KVI_THREAD_PIPE_SIDE_SLAVE],F_SETFL,O_NONBLOCK) == -1) + { + debug("Ops...thread manager slave pipe initialisation failed (%s)",KviQString::toUtf8(KviError::getDescription(KviError::translateSystemError(errno))).data()); + } + + if(fcntl(m_fd[KVI_THREAD_PIPE_SIDE_MASTER],F_SETFL,O_NONBLOCK) == -1) + { + debug("Ops...thread manager master pipe initialisation failed (%s)",KviQString::toUtf8(KviError::getDescription(KviError::translateSystemError(errno))).data()); + } + + m_pSn = new QSocketNotifier(m_fd[KVI_THREAD_PIPE_SIDE_MASTER],QSocketNotifier::Read); + connect(m_pSn,SIGNAL(activated(int)),this,SLOT(eventsPending(int))); + m_pSn->setEnabled(true); +#endif +} + + +KviThreadManager::~KviThreadManager() +{ + m_pMutex->lock(); + // Terminate all the slaves + while(KviThread *t = m_pThreadList->first()) + { + m_pMutex->unlock(); + delete t; + m_pMutex->lock(); + } + + // there are no more child threads + // thus no more slave events are sent. + // Disable the socket notifier, we no longer need it +#ifndef COMPILE_ON_WINDOWS + m_pSn->setEnabled(false); + delete m_pSn; + m_pSn = 0; +#endif + + // we're no longer in this world + g_pThreadManager = 0; + +#ifndef COMPILE_ON_WINDOWS + // close the pipes + close(m_fd[KVI_THREAD_PIPE_SIDE_SLAVE]); + close(m_fd[KVI_THREAD_PIPE_SIDE_MASTER]); + // Kill the pending events + while(KviThreadPendingEvent *ev = m_pEventQueue->first()) + { + delete ev->e; + m_pEventQueue->removeFirst(); + } + delete m_pEventQueue; + m_pEventQueue = 0; +#endif + + m_pMutex->unlock(); + + // finish the cleanup + delete m_pMutex; + m_pMutex = 0; + delete m_pThreadList; + m_pThreadList = 0; + + // byez :) +} + +void KviThreadManager::killPendingEvents(QObject * receiver) +{ +#ifndef COMPILE_ON_WINDOWS + if(!g_pThreadManager)return; + g_pThreadManager->killPendingEventsByReceiver(receiver); +#endif +} + +void KviThreadManager::killPendingEventsByReceiver(QObject * receiver) +{ +#ifndef COMPILE_ON_WINDOWS + KviPointerList<KviThreadPendingEvent> l; + l.setAutoDelete(false); + m_pMutex->lock(); + for(KviThreadPendingEvent * ev = m_pEventQueue->first();ev;ev = m_pEventQueue->next()) + { + if(ev->o == receiver)l.append(ev); + } + for(KviThreadPendingEvent * ev = l.first();ev;ev = l.next()) + { + delete ev->e; + m_pEventQueue->removeRef(ev); + } + m_pMutex->unlock(); +#endif +} + +void KviThreadManager::registerSlaveThread(KviThread *t) +{ + m_pMutex->lock(); + m_pThreadList->append(t); + m_pMutex->unlock(); +} + +void KviThreadManager::unregisterSlaveThread(KviThread *t) +{ + m_pMutex->lock(); + m_pThreadList->removeRef(t); + m_pMutex->unlock(); +} + +void KviThreadManager::postSlaveEvent(QObject *o,QEvent *e) +{ +#ifdef COMPILE_ON_WINDOWS + QApplication::postEvent(o,e); // we believe this to be thread-safe +#else + KviThreadPendingEvent * ev = new KviThreadPendingEvent; + ev->o = o; + ev->e = e; + + m_pMutex->lock(); + + // if the queue gets too long , make this (slave) thread sleep + + // there is a special case where we can't stop the slaves posting events + // it's when a thread-master-side is waiting for it's thread-slave-side + // it the thread-master-side runs in the application main thread then + // the main thread is sleeping and can't process events. + // Since we can't be really sure that the thread-master-side will be running + // on the main application thread we also can't artificially process the events. + // So the solution is to skip this algorithm when at least one + // thread is in waiting state. + while((m_pEventQueue->count() > KVI_THREAD_MAX_EVENT_QUEUE_LENGTH) && (m_iWaitingThreads < 1)) + { + // wait for the master to process the queue + + m_pMutex->unlock(); + + // WARNING : This will fail if for some reason + // the master thread gets here! It will wait indefinitely for itself + // if(pthread_self() != m_hMasterThread) ... ???? + +#ifdef COMPILE_ON_WINDOWS + ::Sleep(1); // 1ms +#else + // FIXME : use nanosleep() ? + ::usleep(1000); // 1 ms +#endif + m_pMutex->lock(); + } + + m_pEventQueue->append(ev); + // Write bulk to the pipe... but only if there is no other wakeup pending + if(m_iTriggerCount < 1) + { + // I don't know if writing to a pipe is reentrant + // thus, in doubt, the write is interlocked (it's non blocking anyway) + int written = write(m_fd[KVI_THREAD_PIPE_SIDE_SLAVE],"?",1); + if(written < 1) + { + // ops.. failed to write down the event.. + // this is quite irritating now... + debug("Ops.. failed to write down the trigger"); + // FIXME: maybe a single shot timer ? + } else { + m_iTriggerCount++; + } + } // else no need to trigger : there is a wakeup pending in there + + m_pMutex->unlock(); + +#endif +} + +void KviThreadManager::eventsPending(int fd) +{ +#ifndef COMPILE_ON_WINDOWS + char buf[10]; + // do we need to check for errors here ? + int readed = read(fd,buf,10); + + m_pMutex->lock(); + // welcome to the critical section :) + + // grab the first event in the queue + while(KviThreadPendingEvent *ev = m_pEventQueue->first()) + { + // allow the other threads to post events: + // unlock the event queue + m_pMutex->unlock(); + // let the app process the event + // DANGER ! + QApplication::postEvent(ev->o,ev->e); + + // jump out of the loop if we have been destroyed + if(!g_pThreadManager)return; + // ufff... we're still alive :))) + + // regrab the event queue + m_pMutex->lock(); + // remove the event we have just processed + m_pEventQueue->removeRef(ev); + // here we're looping locked and havn't decremended the trigger count + } + // decrement the trigger count on the line: still atomic + if(readed >= 0) + { + if(readed < m_iTriggerCount) + { + m_iTriggerCount -= readed; + } else { + m_iTriggerCount = 0; + } + } + + // ok , job done.. can relax now + m_pMutex->unlock(); + +#endif +} + +void KviThreadManager::threadEnteredWaitState() +{ + m_pMutex->lock(); + m_iWaitingThreads++; + m_pMutex->unlock(); +} + +void KviThreadManager::threadLeftWaitState() +{ + m_pMutex->lock(); + m_iWaitingThreads--; + if(m_iWaitingThreads < 0) + { + debug("Ops.. got a negative number of waiting threads ?"); + m_iWaitingThreads = 0; + } + m_pMutex->unlock(); +} + +#ifndef COMPILE_ON_WINDOWS + bool KviMutex::locked() + { + if(!kvi_threadMutexTryLock(&m_mutex))return true; + kvi_threadMutexUnlock(&m_mutex); + return false; + } +#endif + +#ifdef COMPILE_ON_WINDOWS +DWORD WINAPI internal_start_thread(LPVOID arg) +{ + // Slave thread... + ((KviThread *)arg)->internalThreadRun_doNotTouchThis(); + return 0; +} +#else +static void * internal_start_thread(void * arg) +{ + // Slave thread... + ((KviThread *)arg)->internalThreadRun_doNotTouchThis(); + return 0; +} +#endif + +KviThread::KviThread() +{ + g_pThreadManager->registerSlaveThread(this); + m_pRunningMutex = new KviMutex(); + setRunning(false); + setStartingUp(false); +} + +KviThread::~KviThread() +{ +// debug(">> KviThread::~KviThread() : (this = %d)",this); + wait(); + delete m_pRunningMutex; + g_pThreadManager->unregisterSlaveThread(this); +// debug("<< KviThread::~KviThread() : (this = %d)",this); +} + +void KviThread::setRunning(bool bRunning) +{ + m_pRunningMutex->lock(); + m_bRunning = bRunning; + m_pRunningMutex->unlock(); +} + +void KviThread::setStartingUp(bool bStartingUp) +{ + m_pRunningMutex->lock(); + m_bStartingUp = bStartingUp; + m_pRunningMutex->unlock(); +} + +bool KviThread::isRunning() +{ + bool bRunning = true; + m_pRunningMutex->lock(); + bRunning = m_bRunning; + m_pRunningMutex->unlock(); + return bRunning; +} + +bool KviThread::isStartingUp() +{ + bool bIsStartingUp = true; + m_pRunningMutex->lock(); + bIsStartingUp = m_bStartingUp; + m_pRunningMutex->unlock(); + return bIsStartingUp; +} + +bool KviThread::start() +{ + // We're on the master side thread here! + if(isStartingUp() || isRunning())return false; + setStartingUp(true); + return kvi_threadCreate(&m_thread,internal_start_thread,this); +} + +void KviThread::wait() +{ + // We're on the master side here...and we're waiting the slave to exit +// debug(">> KviThread::wait() (this=%d)",this); + while(isStartingUp())usleep(500); // sleep 500 microseconds +// debug("!! KviThread::wait() (this=%d)",this); + g_pThreadManager->threadEnteredWaitState(); + while(isRunning()) + { + usleep(500); // sleep 500 microseconds + } + g_pThreadManager->threadLeftWaitState(); +// debug("<< KviThread::wait() (this=%d)",this); +} + +void KviThread::exit() +{ + // We're on the slave side thread here! (m_bRunning is true , m_bStartingUp is false) + setRunning(false); + kvi_threadExit(); +} + +void KviThread::internalThreadRun_doNotTouchThis() +{ + // we're on the slave thread here! +// debug(">> KviThread::internalRun (this=%d)",this); + setRunning(true); + setStartingUp(false); + kvi_threadInitialize(); + run(); + setRunning(false); +// debug("<< KviThread::internalRun (this=%d",this); +} + +void KviThread::usleep(unsigned long usec) +{ +#ifdef COMPILE_ON_WINDOWS + int s = usec / 1000; + if(s < 1)s = 1; + ::Sleep(s); // Sleep one millisecond...this is the best that we can do +#else + // FIXME : use nanosleep() ? + ::usleep(usec); +#endif +} + +void KviThread::msleep(unsigned long msec) +{ +#ifdef COMPILE_ON_WINDOWS + ::Sleep(msec); +#else + // FIXME : use nanosleep() ? + ::usleep(msec * 1000); +#endif +} + +void KviThread::sleep(unsigned long sec) +{ +#ifdef COMPILE_ON_WINDOWS + ::Sleep(sec * 1000); +#else + ::sleep(sec); +#endif +} + +void KviThread::postEvent(QObject * o,QEvent *e) +{ + // slave side + g_pThreadManager->postSlaveEvent(o,e); +} + + + +KviSensitiveThread::KviSensitiveThread() +: KviThread() +{ + m_pLocalEventQueueMutex = new KviMutex(); + m_pLocalEventQueue = new KviPointerList<KviThreadEvent>; + m_pLocalEventQueue->setAutoDelete(false); +} + +KviSensitiveThread::~KviSensitiveThread() +{ +// debug("Entering KviSensitiveThread::~KviSensitiveThread (this=%d)",this); + terminate(); +// debug("KviSensitiveThread::~KviSensitiveThread : terminate called (This=%d)",this); + m_pLocalEventQueueMutex->lock(); + m_pLocalEventQueue->setAutoDelete(true); + delete m_pLocalEventQueue; + m_pLocalEventQueue = 0; + m_pLocalEventQueueMutex->unlock(); + delete m_pLocalEventQueueMutex; + m_pLocalEventQueueMutex = 0; +// debug("Exiting KviSensitiveThread::~KviSensitiveThread (this=%d)",this); +} + +void KviSensitiveThread::enqueueEvent(KviThreadEvent *e) +{ +// debug(">>> KviSensitiveThread::enqueueEvent() (this=%d)",this); + m_pLocalEventQueueMutex->lock(); + if(!m_pLocalEventQueue) + { + // ops...already terminated (???)...eat the event and return + delete e; + m_pLocalEventQueueMutex->unlock(); + return; + } + m_pLocalEventQueue->append(e); + m_pLocalEventQueueMutex->unlock(); +// debug("<<< KviSensitiveThread::enqueueEvent() (this=%d)",this); +} + +KviThreadEvent * KviSensitiveThread::dequeueEvent() +{ +// debug(">>> KviSensitiveThread::dequeueEvent() (this=%d)",this); + KviThreadEvent * ret; + m_pLocalEventQueueMutex->lock(); + ret = m_pLocalEventQueue->first(); + if(ret)m_pLocalEventQueue->removeFirst(); + m_pLocalEventQueueMutex->unlock(); +// debug("<<< KviSensitiveThread::dequeueEvent() (this=%d)",this); + return ret; +} + +void KviSensitiveThread::terminate() +{ +// debug("Entering KviSensitiveThread::terminate (this=%d)",this); + enqueueEvent(new KviThreadEvent(KVI_THREAD_EVENT_TERMINATE)); +// debug("KviSensitiveThread::terminate() : event enqueued waiting (this=%d)",this); + wait(); +// debug("Exiting KviSensitiveThread::terminate (this=%d)",this); +} + diff --git a/src/kvilib/system/kvi_thread.h b/src/kvilib/system/kvi_thread.h new file mode 100644 index 00000000..bd6dab3b --- /dev/null +++ b/src/kvilib/system/kvi_thread.h @@ -0,0 +1,378 @@ +#ifndef _KVI_THREAD_H_ +#define _KVI_THREAD_H_ +// +// File : kvi_thread.h +// Creation date : Mon May 17 1999 04:26:41 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_heapobject.h" +#include "kvi_string.h" + +#include <qnamespace.h> +#include <qobject.h> +#include <qsocketnotifier.h> +#include "kvi_pointerlist.h" +#include <qevent.h> + + +// +// Simple thread implementation +// This is enough for KVIrc needs +// HANDLE WITH CARE +// + + +// Portability stuff + +#ifdef COMPILE_ON_WINDOWS + + #include <winsock2.h> // this will pull in windows.h and will avoid windock.h inclusion + //#include <windows.h> + // Windoze thread abstraction layer + #define kvi_mutex_t HANDLE + inline void kvi_threadMutexInit(kvi_mutex_t * _pMutex_t) + { + *_pMutex_t = CreateMutex(0,0,NULL); + } + #define kvi_threadMutexLock(_pMutex_t) WaitForSingleObject(*_pMutex_t,INFINITE) + #define kvi_threadMutexUnlock(_pMutex_t) ReleaseMutex(*_pMutex_t) + #define kvi_threadMutexDestroy(_pMutex_t) CloseHandle(*_pMutex_t) + inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t) + { + return (WaitForSingleObject(*_pMutex_t,0) == WAIT_OBJECT_0); + } + + #define kvi_thread_t HANDLE + + inline bool kvi_threadCreate(kvi_thread_t *t,LPTHREAD_START_ROUTINE start_routine,void * arg) + { + DWORD dwThreadId; + *t = CreateThread(NULL,0,start_routine,arg,0,&dwThreadId); + return (*t != NULL); + } + + #define kvi_threadExit() ExitThread(0) + +#else + #ifdef COMPILE_THREADS_USE_POSIX + // Glibc pthread implementation + + #include <pthread.h> + #include <errno.h> // for EBUSY + + // Mutex stuff + #define kvi_mutex_t pthread_mutex_t + #define kvi_threadMutexInit(_pMutex_t) pthread_mutex_init(_pMutex_t,0) + #define kvi_threadMutexLock(_pMutex_t) pthread_mutex_lock(_pMutex_t) + #define kvi_threadMutexUnlock(_pMutex_t) pthread_mutex_unlock(_pMutex_t) + #define kvi_threadMutexDestroy(_pMutex_t) pthread_mutex_destroy(_pMutex_t) + inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t) + { + return (pthread_mutex_trylock(_pMutex_t) != EBUSY); + } + // Actually unused + // #define kvi_threadMutexTryLock(_pMutex_t) pthread_mutex_trylock(_pMutex_t) + + // Thread stuff + #define kvi_thread_t pthread_t + + inline bool kvi_threadCreate(kvi_thread_t *t,void * (*start_routine)(void *),void * arg) + { + pthread_attr_t a; + pthread_attr_init(&a); + pthread_attr_setinheritsched(&a,PTHREAD_INHERIT_SCHED); + pthread_attr_setdetachstate(&a,PTHREAD_CREATE_DETACHED); + + int ret = pthread_create(t,&a,start_routine,arg); + + pthread_attr_destroy(&a); + return (ret == 0); + } + + // We don't care about exit codes at all + #define kvi_threadExit() pthread_exit(0) + #else + #ifdef COMPILE_THREADS_USE_SOLARIS_LIBTHREAD + // Native solaris implementation + #include <thread.h> + #include <synch.h> + #include <errno.h> + + // Mutex stuff + #define kvi_mutex_t mutex_t + #define kvi_threadMutexInit(_pMutex_t) mutex_init(_pMutex_t,0,0) + #define kvi_threadMutexLock(_pMutex_t) mutex_lock(_pMutex_t) + #define kvi_threadMutexUnlock(_pMutex_t) mutex_unlock(_pMutex_t) + #define kvi_threadMutexDestroy(_pMutex_t) mutex_destroy(_pMutex_t) + inline bool kvi_threadMutexTryLock(kvi_mutex_t *_pMutex_t) + { + return (mutex_trylock(_pMutex_t) != EBUSY); + }; + // Actually unused + // #define kvi_threadMutexTryLock(_pMutex_t) mutex_trylock(_pMutex_t) + + // Thread stuff + #define kvi_thread_t thread_t + + inline bool kvi_threadCreate(kvi_thread_t *t,void * (*start_routine)(void *),void *arg) + { + return (thr_create(0,0,start_routine,arg,THR_DETACHED,t) == 0); + } + + // We don't care about exit codes at all + #define kvi_threadExit() thr_exit(0) + #else +// FIXME: #warning "Missing a decent thread implementation: we're going to fail , sorry!" + #endif + #endif +#endif + +class KVILIB_API KviMutex : public KviHeapObject +{ +private: + kvi_mutex_t m_mutex; +#ifdef COMPILE_ON_WINDOWS + bool m_bLocked; +#endif +public: + KviMutex(){ kvi_threadMutexInit(&m_mutex); }; + virtual ~KviMutex(){ kvi_threadMutexDestroy(&m_mutex); }; +public: +#ifdef COMPILE_ON_WINDOWS + void lock(){ kvi_threadMutexLock(&m_mutex); m_bLocked = true; }; + void unlock(){ m_bLocked = false; kvi_threadMutexUnlock(&m_mutex); }; + bool locked(){ return m_bLocked; }; +#else + void lock(){ kvi_threadMutexLock(&m_mutex); }; + void unlock(){ kvi_threadMutexUnlock(&m_mutex); }; + bool locked(); +#endif +}; + + +// simple thread class implementation +// this is also called "Blind" thread class + +class KVILIB_API KviThread : public KviHeapObject +{ +public: + KviThread(); + virtual ~KviThread(); +private: + kvi_thread_t m_thread; + bool m_bRunning; + bool m_bStartingUp; + KviMutex * m_pRunningMutex; + KviPointerList<QEvent> * m_pLocalEventQueue; +public: + // public KviThread interface + // HANDLE WITH CARE + + // Runs the thread...call only from external threads!!! :) + // This function returns true if the child thread has been succesfully created + // this des not mean that run() is being already executed... + // isStartingUp() will return true from this moment until + // the child thread jumps into run() where it will be set to running state (isRunning() == true) + // and removed from startingUp state. + bool start(); + // Returns the state of the thread...safe to call from anywhere + bool isRunning(); + // Returns the state of the thread...safe to call from anywhere + bool isStartingUp(); // start() called , but not in run() yet... + // Waits for the termination of this thread: call only from external threads!!! :) + void wait(); + // DO NOT TOUCH THIS ONE! + void internalThreadRun_doNotTouchThis(); + + static void sleep(unsigned long sec); + static void msleep(unsigned long msec); + static void usleep(unsigned long usec); +protected: + // protected KviThread interface + // HANDLE WITH CARE TOO! + + // Reimplement this with your job + virtual void run(){}; + // Terminates the execution of the calling thread + void exit(); + // The tricky part: threadsafe event dispatching + // Slave thread -> main thread objects + void postEvent(QObject *o,QEvent *e); +private: + void setRunning(bool bRunning); + void setStartingUp(bool bStartingUp); +}; + +// QEvent::Type for Thread events +#define KVI_THREAD_EVENT (((int)QEvent::User) + 2000) + +// CONSTANTS FOR KviThreadEvent::eventId(); + +/////////////////////////////////////////////////////////////// +// extern -> slave thread + +// Your reimplementation of KviSensitiveThread MUST handle this +// and exit when this event is received + +// Terminate is a plain KviThreadEvent +#define KVI_THREAD_EVENT_TERMINATE 0 + +/////////////////////////////////////////////////////////////// +// slave thread -> master object + +// The following standard events are sent from the thread to the master object + +// The following are plain KviThreadEvent objects +#define KVI_THREAD_EVENT_SUCCESS 100 + +// The following are KviThreadDataEvent<int> +#define KVI_THREAD_EVENT_STATECHANGE 150 + +// The following are KviThreadDataEvent<KviStr> +#define KVI_THREAD_EVENT_MESSAGE 200 +#define KVI_THREAD_EVENT_WARNING 201 +#define KVI_THREAD_EVENT_ERROR 202 +#define KVI_THREAD_EVENT_DATA 203 + +// The following is KviThreadDataEvent<KviDataBuffer> +#define KVI_THREAD_EVENT_BINARYDATA 300 + +// The user events +#define KVI_THREAD_USER_EVENT_BASE 1000 + +// #warning "Get rid of the m_szMessage member of KviThreadEvent : eventual data should be passed with a KviThreadDataEvent" + +// Base class for all thread events +class KVILIB_API KviThreadEvent : public QEvent, public KviHeapObject +{ +protected: + int m_eventId; + KviThread * m_pSender; +public: + KviThreadEvent(int evId,KviThread * sender = 0) + : QEvent((QEvent::Type)KVI_THREAD_EVENT) , m_eventId(evId) , m_pSender(sender) {}; + virtual ~KviThreadEvent(){}; +public: + // This is the sender of the event + // WARNING : this MAY be null , threads CAN send anonymous events + KviThread * sender(){ return m_pSender; }; + int id(){ return m_eventId; }; +}; + +template<class TData> class KviThreadDataEvent : public KviThreadEvent +{ +protected: + TData * m_pData; +public: + KviThreadDataEvent(int evId,TData * pData = 0,KviThread * sender = 0) + : KviThreadEvent(evId,sender){ m_pData = pData; }; + virtual ~KviThreadDataEvent(){ if(m_pData)delete m_pData; }; +public: + void setData(TData * d){ if(m_pData)delete m_pData; m_pData = d; }; + TData * getData(){ TData * aux = m_pData; m_pData = 0; return aux; }; + TData * data(){ return m_pData; }; +}; + +// A thread that has also an internal event queue +// so events can be posted from the master side to the slave one +// Reimplementations of this class should periodically check +// dequeueEvent() and eventually process the incoming events (and then DELETE it) + +// KVI_THREAD_EVENT_TERMINATE should be always handled by the reimplementation +// and it should always exit (cleanly) when this event is received + + +class KVILIB_API KviSensitiveThread : public KviThread +{ +public: + KviSensitiveThread(); + virtual ~KviSensitiveThread(); +protected: + KviMutex * m_pLocalEventQueueMutex; + KviPointerList<KviThreadEvent> * m_pLocalEventQueue; +public: + // enqueues an event directed to THIS thread + // the event must be allocated with NEW and + // will be destroyed on the slave side + void enqueueEvent(KviThreadEvent *e); + // enqueues a terminate event and waits() for the slave thread + // the slave thread MUST handle KVI_THREAD_EVENT_TERMINATE + void terminate(); +protected: + // slave side: + // returns the first event in the local queue + // the event MUST BE DELETED after processing + KviThreadEvent * dequeueEvent(); +}; + +// =============================================================================================// +// This is private stuff...only KviThread and KviApp may use it +// and may call only specific functions...don't touch. + +typedef struct _KviThreadPendingEvent +{ + QObject *o; + QEvent *e; +} KviThreadPendingEvent; + +class KVILIB_API KviThreadManager : public QObject +{ + friend class KviApp; + friend class KviThread; + Q_OBJECT +protected: + // These should be private...but we don't want anyone to complain + // Treat as private plz. + KviThreadManager(); + ~KviThreadManager(); +public: + static void killPendingEvents(QObject * receiver); +private: +#ifndef COMPILE_ON_WINDOWS + QSocketNotifier * m_pSn; +#endif + KviMutex * m_pMutex; // This class performs only atomic operations + KviPointerList<KviThread> * m_pThreadList; + int m_iWaitingThreads; +#ifndef COMPILE_ON_WINDOWS + KviPointerList<KviThreadPendingEvent> * m_pEventQueue; + int m_fd[2]; + int m_iTriggerCount; +#endif +protected: + // Public to KviThread only + void registerSlaveThread(KviThread *t); + void unregisterSlaveThread(KviThread *t); + + void threadEnteredWaitState(); + void threadLeftWaitState(); + + void postSlaveEvent(QObject *o,QEvent *e); + void killPendingEventsByReceiver(QObject * receiver); + // Public to KviApp only + static void globalInit(); + static void globalDestroy(); +private slots: + void eventsPending(int fd); +}; + + +#endif //!_KVI_THREAD_H_ diff --git a/src/kvilib/system/kvi_time.cpp b/src/kvilib/system/kvi_time.cpp new file mode 100644 index 00000000..f500b7d4 --- /dev/null +++ b/src/kvilib/system/kvi_time.cpp @@ -0,0 +1,135 @@ +//============================================================================= +// +// File : kvi_time.cpp +// Creation date : Tue Sep 25 17:35:13 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001-2004 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_time.h" +#include "kvi_qstring.h" +#include "kvi_locale.h" + +#ifdef COMPILE_ON_WINDOWS + #include <windows.h> // GetSystemTime + + // Call SystemTimeToFileTime to copy the system time to a FILETIME structure. + // Call GetSystemTime to get the current system time to pass to SystemTimeToFileTime. + // Copy the contents of the FILETIME structure to a ULARGE_INTEGER structure. + // Initialize a SYSTEMTIME structure with the date and time of the first second of January 1, 1970. + // Call SystemTimeToFileTime, passing the SYSTEMTIME structure initialized in Step 3 to the call. + // Copy the contents of the FILETIME structure returned by SystemTimeToFileTime in Step 4 to + // a second ULARGE_INTEGER. The copied value should be greater than or equal to the value copied + // in Step 2. Subtract the 64-bit value in the ULARGE_INTEGER structure initialized in Step 2 + // from the 64-bit value of the ULARGE_INTEGER structure initialized in Step 5. + // This produces a value in 100-nanosecond intervals since January 1, 1970. + // To convert this value to seconds, divide by 10,000,000. + + // buah buah buahhhh lol ghgh :DDDDDDDDD + + void kvi_gettimeofday(struct timeval * tmv,struct timezone *) + { + SYSTEMTIME st; + GetSystemTime(&st); + + // this is simply fucked up.. + // to minimize the possibility of wrapping we use also the day field. + // we actually give something that is near the number of seconds from the beginning + // of the current month... + // We cannot use the wMonth field since the months have variable length :/ + tmv->tv_sec = (st.wDay * 86400) + (st.wHour * 3600) + (st.wMinute * 60) + (st.wSecond); + tmv->tv_usec = st.wMilliseconds * 1000; + } +#endif + +KviMSecTimeInterval::KviMSecTimeInterval() +{ + m_uReferenceSecs = 0; + m_uReferenceUSecs = 0; +} + + +unsigned long KviMSecTimeInterval::mark() +{ + struct timeval tmv; + kvi_gettimeofday(&tmv,0); + unsigned long uDiff = ((((unsigned long)(tmv.tv_sec)) - m_uReferenceSecs) * 1000); + if(((unsigned long)(tmv.tv_usec)) > m_uReferenceUSecs)uDiff += (((unsigned long)(tmv.tv_usec) - m_uReferenceUSecs) / 1000); + else uDiff -= ((m_uReferenceUSecs - (unsigned long)(tmv.tv_usec)) / 1000); + m_uReferenceSecs = (unsigned long)tmv.tv_sec; + m_uReferenceUSecs = (unsigned long)tmv.tv_usec; + return uDiff; +} + +namespace KviTimeUtils +{ + void secondsToDaysHoursMinsSecs(unsigned int uSecs, + unsigned int * uD,unsigned int * uH,unsigned int * uM,unsigned int * uS) + { + *uD = uSecs / 86400; + uSecs = uSecs % 86400; + *uH = uSecs / 3600; + uSecs = uSecs % 3600; + *uM = uSecs / 60; + *uS = uSecs % 60; + } + + QString formatTimeInterval(unsigned int uSeconds,int iFlags) + { + unsigned int d,h,m,s; + secondsToDaysHoursMinsSecs(uSeconds,&d,&h,&m,&s); + QString ret; + // the following tricks maybe will help translators a bit... + if(iFlags & FillWithHypens) + { + ret = __tr2qs("- d -- h -- m -- s"); + } else { + if((iFlags & NoLeadingEmptyIntervals) && (d == 0)) + { + if(h > 0) + { + if(iFlags & NoLeadingZeroes) + KviQString::sprintf(ret,__tr2qs("%u h %u m %u s"),h,m,s); + else + KviQString::sprintf(ret,__tr2qs("%u h %u%u m %u%u s"),h,m / 10,m % 10,s / 10,s % 10); + } else { + if(m > 0) + { + if(iFlags & NoLeadingZeroes) + KviQString::sprintf(ret,__tr2qs("%u m %u s"),m,s); + else + KviQString::sprintf(ret,__tr2qs("%u m %u%u s"),m,s / 10,s % 10); + } else { + KviQString::sprintf(ret,__tr2qs("%u s"),s); + } + } + } else { + if(iFlags & NoLeadingZeroes) + KviQString::sprintf(ret,__tr2qs("%u d %u h %u m %u s"),d,h,m,s); + else + KviQString::sprintf(ret,__tr2qs("%u d %u%u h %u%u m %u%u s"),d,h / 10,h % 10,m / 10,m % 10,s / 10,s % 10); + } + } + return ret; + } + +} diff --git a/src/kvilib/system/kvi_time.h b/src/kvilib/system/kvi_time.h new file mode 100644 index 00000000..309eec10 --- /dev/null +++ b/src/kvilib/system/kvi_time.h @@ -0,0 +1,92 @@ +#ifndef _KVI_TIME_H_ +#define _KVI_TIME_H_ + +//============================================================================= +// +// File : kvi_time.h +// Creation date : Tue Sep 25 17:28:46 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include <qstring.h> + + +#include <time.h> // for time() + +#define kvi_unixTime() time(0) +#define kvi_timeSpan(_time_now,_time_before) ((_time_now) - (_time_before)) +#define kvi_secondsSince(_that_time_t) kvi_timeSpan(kvi_unixTime(),_that_time_t) + +#define kvi_time_t time_t + +#ifdef COMPILE_ON_WINDOWS + + #include <winsock2.h> // struct timeval + + extern KVILIB_API void kvi_gettimeofday(struct timeval * tmv,struct timezone * tmz); + +#else //!COMPILE_ON_WINDOWS + + #include <sys/time.h> // gettimeofday() , struct timeval + + inline void kvi_gettimeofday(struct timeval * tmv,struct timezone * tmz) + { + gettimeofday(tmv,tmz); + }; + +#endif //!COMPILE_ON_WINDOWS + +// this works for time intervals a bit longer than 24 days +class KVILIB_API KviMSecTimeInterval +{ +public: + KviMSecTimeInterval(); +protected: + unsigned long m_uReferenceSecs; + unsigned long m_uReferenceUSecs; +public: + // returns the number of milliseconds since + // mark() was last called (and thus marks + // the beginning of a new interval). + unsigned long mark(); + // this wors ONLY in the same second that mark was called in + // and returns the tv_sec field of the gettimeofday() + // (remember that gettimeofday() is broken on windows) + unsigned long secondsCounter(){ return m_uReferenceSecs; }; +}; + +namespace KviTimeUtils +{ + + + // splits the time span uSecs in days, hours, minutes and seconds + KVILIB_API void secondsToDaysHoursMinsSecs(unsigned int uSecs, + unsigned int * uD,unsigned int * uH,unsigned int * uM,unsigned int * uS); + // returns a string formatted like x d x h xx m xx s + enum FormatTimeSpanFlags { + NoLeadingEmptyIntervals = 1, // causes the leading empty intervals to be omitted + NoLeadingZeroes = 2, // no leading zeroes are printed in hours and seconds + FillWithHypens = 4 // uses only -- %d -- %h -- etc.. discards all other flags + }; + KVILIB_API QString formatTimeInterval(unsigned int uSeconds,int iFlags = 0); +}; + +#endif //_KVI_TIME_H_ diff --git a/src/kvilib/system/moc_kvi_locale.cpp b/src/kvilib/system/moc_kvi_locale.cpp new file mode 100644 index 00000000..52e2ae22 --- /dev/null +++ b/src/kvilib/system/moc_kvi_locale.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** KviTranslator meta object code from reading C++ file 'kvi_locale.h' +** +** Created: Sun Mar 23 20:56:24 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_locale.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviTranslator::className() const +{ + return "KviTranslator"; +} + +QMetaObject *KviTranslator::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviTranslator( "KviTranslator", &KviTranslator::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviTranslator::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviTranslator", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviTranslator::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviTranslator", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviTranslator::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QTranslator::staticMetaObject(); + metaObj = QMetaObject::new_metaobject( + "KviTranslator", parentObject, + 0, 0, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviTranslator.setMetaObject( metaObj ); + return metaObj; +} + +void* KviTranslator::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviTranslator" ) ) + return this; + return QTranslator::qt_cast( clname ); +} + +bool KviTranslator::qt_invoke( int _id, QUObject* _o ) +{ + return QTranslator::qt_invoke(_id,_o); +} + +bool KviTranslator::qt_emit( int _id, QUObject* _o ) +{ + return QTranslator::qt_emit(_id,_o); +} +#ifndef QT_NO_PROPERTIES + +bool KviTranslator::qt_property( int id, int f, QVariant* v) +{ + return QTranslator::qt_property( id, f, v); +} + +bool KviTranslator::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/system/moc_kvi_thread.cpp b/src/kvilib/system/moc_kvi_thread.cpp new file mode 100644 index 00000000..556849a9 --- /dev/null +++ b/src/kvilib/system/moc_kvi_thread.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** KviThreadManager meta object code from reading C++ file 'kvi_thread.h' +** +** Created: Sun Mar 23 20:56:25 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_thread.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviThreadManager::className() const +{ + return "KviThreadManager"; +} + +QMetaObject *KviThreadManager::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviThreadManager( "KviThreadManager", &KviThreadManager::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviThreadManager::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviThreadManager", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviThreadManager::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviThreadManager", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviThreadManager::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QObject::staticMetaObject(); + static const QUParameter param_slot_0[] = { + { "fd", &static_QUType_int, 0, QUParameter::In } + }; + static const QUMethod slot_0 = {"eventsPending", 1, param_slot_0 }; + static const QMetaData slot_tbl[] = { + { "eventsPending(int)", &slot_0, QMetaData::Private } + }; + metaObj = QMetaObject::new_metaobject( + "KviThreadManager", parentObject, + slot_tbl, 1, + 0, 0, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviThreadManager.setMetaObject( metaObj ); + return metaObj; +} + +void* KviThreadManager::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviThreadManager" ) ) + return this; + return QObject::qt_cast( clname ); +} + +bool KviThreadManager::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: eventsPending((int)static_QUType_int.get(_o+1)); break; + default: + return QObject::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool KviThreadManager::qt_emit( int _id, QUObject* _o ) +{ + return QObject::qt_emit(_id,_o); +} +#ifndef QT_NO_PROPERTIES + +bool KviThreadManager::qt_property( int id, int f, QVariant* v) +{ + return QObject::qt_property( id, f, v); +} + +bool KviThreadManager::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES diff --git a/src/kvilib/tal/Makefile.am b/src/kvilib/tal/Makefile.am new file mode 100644 index 00000000..c84487eb --- /dev/null +++ b/src/kvilib/tal/Makefile.am @@ -0,0 +1,5 @@ +############################################################################### +# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it> +############################################################################### + +EXTRA_DIST = *.cpp *.h diff --git a/src/kvilib/tal/kvi_tal_application.cpp b/src/kvilib/tal/kvi_tal_application.cpp new file mode 100644 index 00000000..4d8bd0d5 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_application.cpp @@ -0,0 +1,69 @@ +// +// File : kvi_tal_application.coo +// Creation date : Sun Aug 12 2001 04:34:21 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#include "kvi_tal_application.h" + +#ifdef COMPILE_KDE_SUPPORT + + // The constructor below triggers a warning + // ../tal/kvi_tal_application.cpp: In constructor + // `KviTalApplication::KviTalApplication(int, char**)': + // ../tal/kvi_tal_application.cpp:31: warning: `__base_ctor' is deprecated + // (declared at /opt/kde/include/kapplication.h:198) + // + // The KApplication constructor has been declared as deprecated + // in favor of a complexier initialization that uses KCmdLineArgs + // and can't be abstracted easily. + // The other constructors are not "old" and "stable" enough + // to be safely used at this time. We'll rethink this when KDE 4 is out. + + KviTalApplication::KviTalApplication(int &argc,char ** argv) + : KApplication(argc,argv,"kvirc") + { + + + + } + + KviTalApplication::~KviTalApplication() + { + } + + #include "kvi_tal_application_kde.moc" + +#else + + KviTalApplication::KviTalApplication(int &argc,char ** argv) + : QApplication(argc,argv) + { + } + + KviTalApplication::~KviTalApplication() + { + } + + #include "kvi_tal_application_qt.moc" + +#endif diff --git a/src/kvilib/tal/kvi_tal_application.h b/src/kvilib/tal/kvi_tal_application.h new file mode 100644 index 00000000..4f9e96df --- /dev/null +++ b/src/kvilib/tal/kvi_tal_application.h @@ -0,0 +1,34 @@ +#ifndef _KVI_TAL_APPLICATION_H_ +#define _KVI_TAL_APPLICATION_H_ + +// +// File : kvi_appbase_kde.h +// Creation date : Sun Jun 18 2000 12:53:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" + +#ifdef COMPILE_KDE_SUPPORT + #include "kvi_tal_application_kde.h" +#else + #include "kvi_tal_application_qt.h" +#endif + +#endif // _KVI_TAL_APPLICATION_H_ diff --git a/src/kvilib/tal/kvi_tal_application_kde.h b/src/kvilib/tal/kvi_tal_application_kde.h new file mode 100644 index 00000000..05d6e87f --- /dev/null +++ b/src/kvilib/tal/kvi_tal_application_kde.h @@ -0,0 +1,37 @@ +#ifndef _KVI_TAL_APPLICATION_KDE_H_ +#define _KVI_TAL_APPLICATION_KDE_H_ + +// +// File : kvi_tal_application_kde.h +// Creation date : Sun Aug 12 2001 04:32:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <kapp.h> + + +class KVILIB_API KviTalApplication : public KApplication +{ + Q_OBJECT +public: + KviTalApplication(int &argc,char ** argv); + ~KviTalApplication(); +}; + +#endif // _KVI_TAL_APPLICATION_KDE_H_ diff --git a/src/kvilib/tal/kvi_tal_application_qt.h b/src/kvilib/tal/kvi_tal_application_qt.h new file mode 100644 index 00000000..953608fe --- /dev/null +++ b/src/kvilib/tal/kvi_tal_application_qt.h @@ -0,0 +1,37 @@ +#ifndef _KVI_TAL_APPLICATION_QT_H_ +#define _KVI_TAL_APPLICATION_QT_H_ + +// +// File : kvi_tal_application_qt.h +// Creation date : Sun Aug 12 2001 04:33:21 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qapplication.h> + + +class KVILIB_API KviTalApplication : public QApplication +{ + Q_OBJECT +public: + KviTalApplication(int &argc,char ** argv); + ~KviTalApplication(); +}; + +#endif // _KVI_TAL_APPLICATION_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_filedialog.cpp b/src/kvilib/tal/kvi_tal_filedialog.cpp new file mode 100644 index 00000000..b345fd0b --- /dev/null +++ b/src/kvilib/tal/kvi_tal_filedialog.cpp @@ -0,0 +1,176 @@ +//============================================================================= +// +// File : kvi_tal_filedialog.coo +// Creation date : Thu Sep 11 2003 04:09:24 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2003-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ + + +#include "kvi_tal_filedialog.h" + +#ifdef COMPILE_USE_QT4 + + #include <qdir.h> + + KviTalFileDialog::KviTalFileDialog(const QString &dirName,const QString &filter,QWidget *parent,const char *name,bool modal) + : QFileDialog(parent,"",dirName,filter) + { + setModal(modal); + } + + KviTalFileDialog::~KviTalFileDialog() + { + } + + void KviTalFileDialog::setFileMode(FileMode m) + { + switch(m) + { + case AnyFile: + QFileDialog::setFileMode(QFileDialog::AnyFile); + break; + case ExistingFile: + QFileDialog::setFileMode(QFileDialog::ExistingFile); + break; + case ExistingFiles: + QFileDialog::setFileMode(QFileDialog::ExistingFiles); + break; + case Directory: + QFileDialog::setFileMode(QFileDialog::Directory); + break; + case DirectoryOnly: + QFileDialog::setFileMode(QFileDialog::DirectoryOnly); + break; + default: + QFileDialog::setFileMode(QFileDialog::AnyFile); + break; + } + } + + void KviTalFileDialog::setDirectory(const QString &szDirectory) + { + QFileDialog::setDirectory(szDirectory); + } + + + #include "kvi_tal_filedialog_qt4.moc" + +#else + + #ifdef COMPILE_KDE_SUPPORT + + KviTalFileDialog::KviTalFileDialog(const QString &dirName,const QString &filter,QWidget *parent,const char *name,bool modal) + : KFileDialog(dirName,filter,parent,name,modal) + { + clearWFlags(WDestructiveClose); + } + + KviTalFileDialog::~KviTalFileDialog() + { + } + + void KviTalFileDialog::setFileMode(FileMode m) + { + switch(m) + { + case AnyFile: + setMode(KFile::File | KFile::LocalOnly); + setOperationMode(Saving); + break; + case ExistingFile: + setMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly); + setOperationMode(Opening); + break; + case ExistingFiles: + setMode(KFile::Files | KFile::ExistingOnly | KFile::LocalOnly); + setOperationMode(Opening); + break; + case Directory: + setMode(KFile::Directory); + break; + case DirectoryOnly: + setMode(KFile::Directory); + break; + default: + setMode(KFile::File | KFile::LocalOnly); + setOperationMode(Saving); + break; + } + } + + void KviTalFileDialog::setDirectory(const QString &szDirectory) + { + setURL(szDirectory); + } + + + #include "kvi_tal_filedialog_kde.moc" + + #else + + #include <qdir.h> + + KviTalFileDialog::KviTalFileDialog(const QString &dirName,const QString &filter,QWidget *parent,const char *name,bool modal) + : QFileDialog(dirName,filter,parent,name,modal) + { + clearWFlags(WDestructiveClose); + } + + KviTalFileDialog::~KviTalFileDialog() + { + } + + void KviTalFileDialog::setFileMode(FileMode m) + { + switch(m) + { + case AnyFile: + setMode(QFileDialog::AnyFile); + break; + case ExistingFile: + setMode(QFileDialog::ExistingFile); + break; + case ExistingFiles: + setMode(QFileDialog::ExistingFiles); + break; + case Directory: + setMode(QFileDialog::Directory); + break; + case DirectoryOnly: + setMode(QFileDialog::DirectoryOnly); + break; + default: + setMode(QFileDialog::AnyFile); + break; + } + } + + void KviTalFileDialog::setDirectory(const QString &szDirectory) + { + setDir(QDir(szDirectory)); + } + + + #include "kvi_tal_filedialog_qt.moc" + + #endif +#endif diff --git a/src/kvilib/tal/kvi_tal_filedialog.h b/src/kvilib/tal/kvi_tal_filedialog.h new file mode 100644 index 00000000..eac2e645 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_filedialog.h @@ -0,0 +1,40 @@ +#ifndef _KVI_TAL_FILEDIALOG_H_ +#define _KVI_TAL_FILEDIALOG_H_ + +//============================================================================= +// +// File : kvi_tal_filedialog.h +// Creation date : Thu Sep 11 2003 04:41:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2003-2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_filedialog_qt4.h" +#else + #ifdef COMPILE_KDE_SUPPORT + #include "kvi_tal_filedialog_kde.h" + #else + #include "kvi_tal_filedialog_qt.h" + #endif +#endif + +#endif // _KVI_TAL_FILEDIALOG_H_ diff --git a/src/kvilib/tal/kvi_tal_filedialog_kde.h b/src/kvilib/tal/kvi_tal_filedialog_kde.h new file mode 100644 index 00000000..0f04a80c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_filedialog_kde.h @@ -0,0 +1,50 @@ +#ifndef _KVI_TAL_FILEDIALOG_KDE_H_ +#define _KVI_TAL_FILEDIALOG_KDE_H_ + +// +// File : kvi_tal_filedialog_kde.h +// Creation date : Thu Aug 11 2003 04:43:58 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2003 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <kfiledialog.h> +#include <qfiledialog.h> + +class KVILIB_API KviTalFileDialog : public KFileDialog +{ + Q_OBJECT +public: + KviTalFileDialog(const QString &dirName,const QString &filter = QString::null,QWidget *parent = 0,const char *name = 0,bool modal = FALSE); + ~KviTalFileDialog(); +public: + enum FileMode { AnyFile, ExistingFile, ExistingFiles, Directory, DirectoryOnly }; + + void setFileMode(FileMode m); + void setDirectory(const QString &szDirectory); + + + static QString getExistingDirectoryPath(const QString &dir = QString::null,const QString &caption = QString::null,QWidget *parent = 0) + { + // QFileDialog allows making new directories...kfiledialog not :/ + return QFileDialog::getExistingDirectory(dir,parent,0,caption); + //return getExistingDirectory(dir,parent,caption); + }; +}; + +#endif // _KVI_TAL_FILEDIALOG_KDE_H_ diff --git a/src/kvilib/tal/kvi_tal_filedialog_qt.h b/src/kvilib/tal/kvi_tal_filedialog_qt.h new file mode 100644 index 00000000..14a24854 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_filedialog_qt.h @@ -0,0 +1,44 @@ +#ifndef _KVI_TAL_FILEDIALOG_QT_H_ +#define _KVI_TAL_FILEDIALOG_QT_H_ + +// +// File : kvi_tal_filedialog_qt.h +// Creation date : Thu Aug 11 2003 04:43:58 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2003 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qfiledialog.h> + +class KVILIB_API KviTalFileDialog : public QFileDialog +{ + Q_OBJECT +public: + KviTalFileDialog(const QString &dirName,const QString &filter = QString::null,QWidget *parent = 0,const char *name = 0,bool modal = FALSE); + ~KviTalFileDialog(); +public: + enum FileMode { AnyFile, ExistingFile, ExistingFiles, Directory, DirectoryOnly }; + + void setFileMode(FileMode m); + void setDirectory(const QString &szDirectory); + + static QString getExistingDirectoryPath(const QString &dir = QString::null,const QString &caption = QString::null,QWidget *parent = 0) + { return getExistingDirectory(dir,parent,0 /* name */,caption); }; +}; + +#endif // _KVI_TAL_FILEDIALOG_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_filedialog_qt4.h b/src/kvilib/tal/kvi_tal_filedialog_qt4.h new file mode 100644 index 00000000..eb5f7ab6 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_filedialog_qt4.h @@ -0,0 +1,46 @@ +#ifndef _KVI_TAL_FILEDIALOG_QT4_H_ +#define _KVI_TAL_FILEDIALOG_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_filedialog_qt4.h +// Creation date : Fri 19 Jan 2007 02:17:12 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <qfiledialog.h> + +class KVILIB_API KviTalFileDialog : public QFileDialog +{ + Q_OBJECT +public: + KviTalFileDialog(const QString &dirName,const QString &filter = QString::null,QWidget *parent = 0,const char *name = 0,bool modal = FALSE); + ~KviTalFileDialog(); +public: + enum FileMode { AnyFile, ExistingFile, ExistingFiles, Directory, DirectoryOnly }; + + void setFileMode(FileMode m); + void setDirectory(const QString &szDirectory); + + static QString getExistingDirectoryPath(const QString &dir = QString::null,const QString &caption = QString::null,QWidget *parent = 0) + { return getExistingDirectory(parent,caption,dir); }; +}; + +#endif // _KVI_TAL_FILEDIALOG_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_grid.cpp b/src/kvilib/tal/kvi_tal_grid.cpp new file mode 100644 index 00000000..472af5a0 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_grid.cpp @@ -0,0 +1,34 @@ +//============================================================================= +// +// File : kvi_tal_grid.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_grid.h" + + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_grid_qt4.moc" +#else + #include "kvi_tal_grid_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_grid.h b/src/kvilib/tal/kvi_tal_grid.h new file mode 100644 index 00000000..18c4af98 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_grid.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_GRID_H_ +#define _KVI_TAL_GRID_H_ + +//============================================================================= +// +// File : kvi_tal_grid.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_grid_qt4.h" +#else + #include "kvi_tal_grid_qt3.h" +#endif + +#endif // _KVI_TAL_GRID_H_ diff --git a/src/kvilib/tal/kvi_tal_grid_qt3.h b/src/kvilib/tal/kvi_tal_grid_qt3.h new file mode 100644 index 00000000..fd77d15c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_grid_qt3.h @@ -0,0 +1,39 @@ +#ifndef _KVI_TAL_GRID_QT3_H_ +#define _KVI_TAL_GRID_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_grid_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <qgrid.h> + +class KVILIB_API KviTalGrid : public QGrid +{ + Q_OBJECT +public: + KviTalGrid(int n,Qt::Orientation orient,QWidget * pParent = 0) + : QGrid(n,orient,pParent) {}; + ~KviTalGrid() {}; +}; + +#endif // _KVI_TAL_GRID_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_grid_qt4.h b/src/kvilib/tal/kvi_tal_grid_qt4.h new file mode 100644 index 00000000..57612b3c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_grid_qt4.h @@ -0,0 +1,41 @@ +#ifndef _KVI_TAL_GRID_QT4_H_ +#define _KVI_TAL_GRID_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_grid_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <q3grid.h> + +class KVILIB_API KviTalGrid : public Q3Grid +{ + Q_OBJECT +public: + KviTalGrid(int n,Qt::Orientation orient,QWidget * pParent = 0) + : Q3Grid(n,orient,pParent) {}; + ~KviTalGrid() {}; +}; + +#endif // _KVI_TAL_GRID_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_groupbox.cpp b/src/kvilib/tal/kvi_tal_groupbox.cpp new file mode 100644 index 00000000..bf2f5689 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_groupbox.cpp @@ -0,0 +1,34 @@ +//============================================================================= +// +// File : kvi_tal_groupbox.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_groupbox.h" + + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_groupbox_qt4.moc" +#else + #include "kvi_tal_groupbox_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_groupbox.h b/src/kvilib/tal/kvi_tal_groupbox.h new file mode 100644 index 00000000..ae82519b --- /dev/null +++ b/src/kvilib/tal/kvi_tal_groupbox.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_GROUPBOX_H_ +#define _KVI_TAL_GROUPBOX_H_ + +//============================================================================= +// +// File : kvi_tal_groupbox.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_groupbox_qt4.h" +#else + #include "kvi_tal_groupbox_qt3.h" +#endif + +#endif // _KVI_TAL_GROUPBOX_H_ diff --git a/src/kvilib/tal/kvi_tal_groupbox_qt3.h b/src/kvilib/tal/kvi_tal_groupbox_qt3.h new file mode 100644 index 00000000..be3340a3 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_groupbox_qt3.h @@ -0,0 +1,47 @@ +#ifndef _KVI_TAL_GROUPBOX_QT3_H_ +#define _KVI_TAL_GROUPBOX_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_groupbox_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <qgroupbox.h> + +class KVILIB_API KviTalGroupBox : public QGroupBox +{ + Q_OBJECT +public: + KviTalGroupBox(QWidget * parent = 0) + : QGroupBox(parent) {}; + KviTalGroupBox(const QString & title,QWidget * parent = 0) + : QGroupBox(title,parent) {}; + KviTalGroupBox(int strips,Qt::Orientation orientation,QWidget * parent = 0) + : QGroupBox(strips,orientation,parent) {}; + KviTalGroupBox(int strips,Qt::Orientation orientation,const QString & title,QWidget * parent = 0) + : QGroupBox(strips,orientation,title,parent) {}; + ~KviTalGroupBox() {}; +}; + + + +#endif // _KVI_TAL_GROUPBOX_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_groupbox_qt4.h b/src/kvilib/tal/kvi_tal_groupbox_qt4.h new file mode 100644 index 00000000..c8917385 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_groupbox_qt4.h @@ -0,0 +1,47 @@ +#ifndef _KVI_TAL_GROUPBOX_QT4_H_ +#define _KVI_TAL_GROUPBOX_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_groupbox_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <q3groupbox.h> + +class KVILIB_API KviTalGroupBox : public Q3GroupBox +{ + Q_OBJECT +public: + KviTalGroupBox(QWidget * parent = 0) + : Q3GroupBox(parent) {}; + KviTalGroupBox(const QString & title,QWidget * parent = 0) + : Q3GroupBox(title,parent) {}; + KviTalGroupBox(int strips,Qt::Orientation orientation,QWidget * parent = 0) + : Q3GroupBox(strips,orientation,parent) {}; + KviTalGroupBox(int strips,Qt::Orientation orientation,const QString & title,QWidget * parent = 0) + : Q3GroupBox(strips,orientation,title,parent) {}; + ~KviTalGroupBox() {}; +}; + + + +#endif // _KVI_TAL_GROUPBOX_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_hbox.cpp b/src/kvilib/tal/kvi_tal_hbox.cpp new file mode 100644 index 00000000..6df56ee8 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_hbox.cpp @@ -0,0 +1,32 @@ +//============================================================================= +// +// File : kvi_tal_hbox.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_hbox.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_hbox_qt4.moc" +#else + #include "kvi_tal_hbox_qt3.moc" +#endif diff --git a/src/kvilib/tal/kvi_tal_hbox.h b/src/kvilib/tal/kvi_tal_hbox.h new file mode 100644 index 00000000..6f955ed6 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_hbox.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_HBOX_H_ +#define _KVI_TAL_HBOX_H_ + +//============================================================================= +// +// File : kvi_tal_hbox.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_hbox_qt4.h" +#else + #include "kvi_tal_hbox_qt3.h" +#endif + +#endif // _KVI_TAL_HBOX_H_ diff --git a/src/kvilib/tal/kvi_tal_hbox_qt3.h b/src/kvilib/tal/kvi_tal_hbox_qt3.h new file mode 100644 index 00000000..992ca03a --- /dev/null +++ b/src/kvilib/tal/kvi_tal_hbox_qt3.h @@ -0,0 +1,41 @@ +#ifndef _KVI_TAL_HBOX_QT3_H_ +#define _KVI_TAL_HBOX_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_hbox_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <qhbox.h> + +class KVILIB_API KviTalHBox : public QHBox +{ + Q_OBJECT +public: + KviTalHBox(QWidget * pParent) + : QHBox(pParent) {}; + virtual ~KviTalHBox() {}; +}; + +#endif // _KVI_TAL_HBOX_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_hbox_qt4.h b/src/kvilib/tal/kvi_tal_hbox_qt4.h new file mode 100644 index 00000000..384910c2 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_hbox_qt4.h @@ -0,0 +1,41 @@ +#ifndef _KVI_TAL_HBOX_QT4_H_ +#define _KVI_TAL_HBOX_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_hbox_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <q3hbox.h> + +class KVILIB_API KviTalHBox : public Q3HBox +{ + Q_OBJECT +public: + KviTalHBox(QWidget * pParent,char* name=0) + : Q3HBox(pParent,name) {}; + virtual ~KviTalHBox() {}; +}; + +#endif // _KVI_TAL_HBOX_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_iconview.cpp b/src/kvilib/tal/kvi_tal_iconview.cpp new file mode 100644 index 00000000..2f63388c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_iconview.cpp @@ -0,0 +1,215 @@ +//============================================================================= +// +// File : kvi_tal_iconview.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_iconview.h" + +#ifdef COMPILE_USE_QT4 + + KviTalIconView::KviTalIconView(QWidget * pParent,Qt::WFlags f) + : Q3IconView(pParent,0,f) + { + connect(this,SIGNAL(selectionChanged(Q3IconViewItem *)),this,SLOT(redirect_selectionChanged(Q3IconViewItem *))); + connect(this,SIGNAL(currentChanged(Q3IconViewItem *)),this,SLOT(redirect_currentChanged(Q3IconViewItem *))); + connect(this,SIGNAL(clicked(Q3IconViewItem *)),this,SLOT(redirect_clicked(Q3IconViewItem *))); + connect(this,SIGNAL(clicked(Q3IconViewItem *,const QPoint &)),this,SLOT(redirect_clicked(Q3IconViewItem *,const QPoint &))); + connect(this,SIGNAL(pressed(Q3IconViewItem *)),this,SLOT(redirect_pressed(Q3IconViewItem *))); + connect(this,SIGNAL(pressed(Q3IconViewItem *,const QPoint &)),this,SLOT(redirect_pressed(Q3IconViewItem *,const QPoint &))); + connect(this,SIGNAL(doubleClicked(Q3IconViewItem *)),this,SLOT(redirect_doubleClicked(Q3IconViewItem *))); + connect(this,SIGNAL(returnPressed(Q3IconViewItem *)),this,SLOT(redirect_returnPressed(Q3IconViewItem *))); + connect(this,SIGNAL(rightButtonClicked(Q3IconViewItem *,const QPoint &)),this,SLOT(redirect_rightButtonClicked(Q3IconViewItem *,const QPoint &))); + connect(this,SIGNAL(rightButtonPressed(Q3IconViewItem *,const QPoint &)),this,SLOT(redirect_rightButtonPressed(Q3IconViewItem *,const QPoint &))); + connect(this,SIGNAL(mouseButtonClicked(int,Q3IconViewItem *,const QPoint &)),this,SLOT(redirect_mouseButtonClicked(int,Q3IconViewItem *,const QPoint &))); + connect(this,SIGNAL(mouseButtonPressed(int,Q3IconViewItem *,const QPoint &)),this,SLOT(redirect_mouseButtonPressed(int,Q3IconViewItem *,const QPoint &))); + connect(this,SIGNAL(contextMenuRequested(Q3IconViewItem *,const QPoint &)),this,SLOT(redirect_contextMenuRequested(Q3IconViewItem *,const QPoint &))); + connect(this,SIGNAL(onItem(Q3IconViewItem *)),this,SLOT(redirect_onItem(Q3IconViewItem *))); + } + + void KviTalIconView::redirect_selectionChanged(Q3IconViewItem * pItem) + { + emit selectionChanged((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_currentChanged(Q3IconViewItem * pItem) + { + emit currentChanged((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_clicked(Q3IconViewItem * pItem) + { + emit clicked((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_clicked(Q3IconViewItem * pItem,const QPoint &pnt) + { + emit clicked((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_pressed(Q3IconViewItem * pItem) + { + emit pressed((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_pressed(Q3IconViewItem * pItem,const QPoint &pnt) + { + emit pressed((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_doubleClicked(Q3IconViewItem * pItem) + { + emit doubleClicked((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_returnPressed(Q3IconViewItem * pItem) + { + emit returnPressed((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_rightButtonClicked(Q3IconViewItem * pItem,const QPoint &pnt) + { + emit rightButtonClicked((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_rightButtonPressed(Q3IconViewItem * pItem,const QPoint &pnt) + { + emit rightButtonPressed((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_mouseButtonClicked(int iButton,Q3IconViewItem * pItem,const QPoint &pnt) + { + emit mouseButtonClicked(iButton,(KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_mouseButtonPressed(int iButton,Q3IconViewItem * pItem,const QPoint &pnt) + { + emit mouseButtonPressed(iButton,(KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_contextMenuRequested(Q3IconViewItem * pItem,const QPoint &pnt) + { + emit contextMenuRequested((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_onItem(Q3IconViewItem * pItem) + { + emit onItem((KviTalIconViewItem *)pItem); + } + + + #include "kvi_tal_iconview_qt4.moc" +#else + + KviTalIconView::KviTalIconView(QWidget * pParent,Qt::WFlags f) + : QIconView(pParent,0,f) + { + connect(this,SIGNAL(selectionChanged(QIconViewItem *)),this,SLOT(redirect_selectionChanged(QIconViewItem *))); + connect(this,SIGNAL(currentChanged(QIconViewItem *)),this,SLOT(redirect_currentChanged(QIconViewItem *))); + connect(this,SIGNAL(clicked(QIconViewItem *)),this,SLOT(redirect_clicked(QIconViewItem *))); + connect(this,SIGNAL(clicked(QIconViewItem *,const QPoint &)),this,SLOT(redirect_clicked(QIconViewItem *,const QPoint &))); + connect(this,SIGNAL(pressed(QIconViewItem *)),this,SLOT(redirect_pressed(QIconViewItem *))); + connect(this,SIGNAL(pressed(QIconViewItem *,const QPoint &)),this,SLOT(redirect_pressed(QIconViewItem *,const QPoint &))); + connect(this,SIGNAL(doubleClicked(QIconViewItem *)),this,SLOT(redirect_doubleClicked(QIconViewItem *))); + connect(this,SIGNAL(returnPressed(QIconViewItem *)),this,SLOT(redirect_returnPressed(QIconViewItem *))); + connect(this,SIGNAL(rightButtonClicked(QIconViewItem *,const QPoint &)),this,SLOT(redirect_rightButtonClicked(QIconViewItem *,const QPoint &))); + connect(this,SIGNAL(rightButtonPressed(QIconViewItem *,const QPoint &)),this,SLOT(redirect_rightButtonPressed(QIconViewItem *,const QPoint &))); + connect(this,SIGNAL(mouseButtonClicked(int,QIconViewItem *,const QPoint &)),this,SLOT(redirect_mouseButtonClicked(int,QIconViewItem *,const QPoint &))); + connect(this,SIGNAL(mouseButtonPressed(int,QIconViewItem *,const QPoint &)),this,SLOT(redirect_mouseButtonPressed(int,QIconViewItem *,const QPoint &))); + connect(this,SIGNAL(contextMenuRequested(QIconViewItem *,const QPoint &)),this,SLOT(redirect_contextMenuRequested(QIconViewItem *,const QPoint &))); + connect(this,SIGNAL(onItem(QIconViewItem *)),this,SLOT(redirect_onItem(QIconViewItem *))); + } + + void KviTalIconView::redirect_selectionChanged(QIconViewItem * pItem) + { + emit selectionChanged((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_currentChanged(QIconViewItem * pItem) + { + emit currentChanged((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_clicked(QIconViewItem * pItem) + { + emit clicked((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_clicked(QIconViewItem * pItem,const QPoint &pnt) + { + emit clicked((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_pressed(QIconViewItem * pItem) + { + emit pressed((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_pressed(QIconViewItem * pItem,const QPoint &pnt) + { + emit pressed((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_doubleClicked(QIconViewItem * pItem) + { + emit doubleClicked((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_returnPressed(QIconViewItem * pItem) + { + emit returnPressed((KviTalIconViewItem *)pItem); + } + + void KviTalIconView::redirect_rightButtonClicked(QIconViewItem * pItem,const QPoint &pnt) + { + emit rightButtonClicked((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_rightButtonPressed(QIconViewItem * pItem,const QPoint &pnt) + { + emit rightButtonPressed((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_mouseButtonClicked(int iButton,QIconViewItem * pItem,const QPoint &pnt) + { + emit mouseButtonClicked(iButton,(KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_mouseButtonPressed(int iButton,QIconViewItem * pItem,const QPoint &pnt) + { + emit mouseButtonPressed(iButton,(KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_contextMenuRequested(QIconViewItem * pItem,const QPoint &pnt) + { + emit contextMenuRequested((KviTalIconViewItem *)pItem,pnt); + } + + void KviTalIconView::redirect_onItem(QIconViewItem * pItem) + { + emit onItem((KviTalIconViewItem *)pItem); + } + + + #include "kvi_tal_iconview_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_iconview.h b/src/kvilib/tal/kvi_tal_iconview.h new file mode 100644 index 00000000..53b1137b --- /dev/null +++ b/src/kvilib/tal/kvi_tal_iconview.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_ICONVIEW_H_ +#define _KVI_TAL_ICONVIEW_H_ + +//============================================================================= +// +// File : kvi_tal_iconview.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_iconview_qt4.h" +#else + #include "kvi_tal_iconview_qt3.h" +#endif + +#endif // _KVI_TAL_ICONVIEW_H_ diff --git a/src/kvilib/tal/kvi_tal_iconview_qt3.h b/src/kvilib/tal/kvi_tal_iconview_qt3.h new file mode 100644 index 00000000..7cfec586 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_iconview_qt3.h @@ -0,0 +1,100 @@ +#ifndef _KVI_TAL_ICONVIEW_QT3_H_ +#define _KVI_TAL_ICONVIEW_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_iconview_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" + +#include <qiconview.h> + +class KviTalIconViewItem; + + +class KVILIB_API KviTalIconView : public QIconView +{ + Q_OBJECT +public: + KviTalIconView(QWidget * pParent,Qt::WFlags f = 0); + virtual ~KviTalIconView() {}; +signals: + void selectionChanged(KviTalIconViewItem * pItem); + void currentChanged(KviTalIconViewItem * pItem); + void clicked(KviTalIconViewItem * pItem); + void clicked(KviTalIconViewItem * pItem,const QPoint &pnt); + void pressed(KviTalIconViewItem * pItem); + void pressed(KviTalIconViewItem * pItem,const QPoint &pnt); + void doubleClicked(KviTalIconViewItem * pItem); + void returnPressed(KviTalIconViewItem * pItem); + void rightButtonClicked(KviTalIconViewItem * pItem,const QPoint &pnt); + void rightButtonPressed(KviTalIconViewItem * pItem,const QPoint &pnt); + void mouseButtonClicked(int iButton,KviTalIconViewItem * pItem,const QPoint &pnt); + void mouseButtonPressed(int iButton,KviTalIconViewItem * pItem,const QPoint &pnt); + void contextMenuRequested(KviTalIconViewItem * pItem,const QPoint &pnt); + void onItem(KviTalIconViewItem * pItem); +protected slots: + void redirect_selectionChanged(QIconViewItem * pItem); + void redirect_currentChanged(QIconViewItem * pItem); + void redirect_clicked(QIconViewItem * pItem); + void redirect_clicked(QIconViewItem * pItem,const QPoint &pnt); + void redirect_pressed(QIconViewItem * pItem); + void redirect_pressed(QIconViewItem * pItem,const QPoint &pnt); + void redirect_doubleClicked(QIconViewItem * pItem); + void redirect_returnPressed(QIconViewItem * pItem); + void redirect_rightButtonClicked(QIconViewItem * pItem,const QPoint &pnt); + void redirect_rightButtonPressed(QIconViewItem * pItem,const QPoint &pnt); + void redirect_mouseButtonClicked(int iButton,QIconViewItem * pItem,const QPoint &pnt); + void redirect_mouseButtonPressed(int iButton,QIconViewItem * pItem,const QPoint &pnt); + void redirect_contextMenuRequested(QIconViewItem * pItem,const QPoint &pnt); + void redirect_onItem(QIconViewItem * pItem); +public: + KviTalIconViewItem * firstItem() const { return (KviTalIconViewItem *)QIconView::firstItem(); }; + KviTalIconViewItem * lastItem() const { return (KviTalIconViewItem *)QIconView::lastItem(); }; + KviTalIconViewItem * currentItem() const { return (KviTalIconViewItem *)QIconView::currentItem(); }; +}; + +class KVILIB_API KviTalIconViewItem : public QIconViewItem +{ +public: + KviTalIconViewItem(KviTalIconView * parent) + : QIconViewItem(parent) {}; + KviTalIconViewItem(KviTalIconView * parent,KviTalIconViewItem * after) + : QIconViewItem(parent,after) {}; + KviTalIconViewItem(KviTalIconView * parent, const QString & text) + : QIconViewItem(parent,text) {}; + KviTalIconViewItem(KviTalIconView * parent, KviTalIconViewItem * after, const QString & text) + : QIconViewItem(parent,after,text) {}; + KviTalIconViewItem(KviTalIconView * parent, const QString & text, const QPixmap & icon) + : QIconViewItem(parent,text,icon) {}; + KviTalIconViewItem(KviTalIconView * parent, KviTalIconViewItem * after, const QString & text, const QPixmap & icon) + : QIconViewItem(parent,after,text,icon) {}; +public: + KviTalIconView * iconView() const { return (KviTalIconView *)QIconViewItem::iconView(); }; + KviTalIconViewItem * prevItem() const { return (KviTalIconViewItem *)QIconViewItem::prevItem(); }; + KviTalIconViewItem * nextItem() const { return (KviTalIconViewItem *)QIconViewItem::nextItem(); }; +}; + + +#endif // _KVI_TAL_ICONVIEW_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_iconview_qt4.h b/src/kvilib/tal/kvi_tal_iconview_qt4.h new file mode 100644 index 00000000..899acaac --- /dev/null +++ b/src/kvilib/tal/kvi_tal_iconview_qt4.h @@ -0,0 +1,99 @@ +#ifndef _KVI_TAL_ICONVIEW_QT4_H_ +#define _KVI_TAL_ICONVIEW_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_iconview_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,59 Temple Place - Suite 440, Boston, MA 02111-1407, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" + +#include <q3iconview.h> + +class KviTalIconViewItem; + +class KVILIB_API KviTalIconView : public Q3IconView +{ + Q_OBJECT +public: + KviTalIconView(QWidget * pParent,Qt::WFlags f = 0); + virtual ~KviTalIconView() {}; +signals: + void selectionChanged(KviTalIconViewItem * pItem); + void currentChanged(KviTalIconViewItem * pItem); + void clicked(KviTalIconViewItem * pItem); + void clicked(KviTalIconViewItem * pItem,const QPoint &pnt); + void pressed(KviTalIconViewItem * pItem); + void pressed(KviTalIconViewItem * pItem,const QPoint &pnt); + void doubleClicked(KviTalIconViewItem * pItem); + void returnPressed(KviTalIconViewItem * pItem); + void rightButtonClicked(KviTalIconViewItem * pItem,const QPoint &pnt); + void rightButtonPressed(KviTalIconViewItem * pItem,const QPoint &pnt); + void mouseButtonClicked(int iButton,KviTalIconViewItem * pItem,const QPoint &pnt); + void mouseButtonPressed(int iButton,KviTalIconViewItem * pItem,const QPoint &pnt); + void contextMenuRequested(KviTalIconViewItem * pItem,const QPoint &pnt); + void onItem(KviTalIconViewItem * pItem); +protected slots: + void redirect_selectionChanged(Q3IconViewItem * pItem); + void redirect_currentChanged(Q3IconViewItem * pItem); + void redirect_clicked(Q3IconViewItem * pItem); + void redirect_clicked(Q3IconViewItem * pItem,const QPoint &pnt); + void redirect_pressed(Q3IconViewItem * pItem); + void redirect_pressed(Q3IconViewItem * pItem,const QPoint &pnt); + void redirect_doubleClicked(Q3IconViewItem * pItem); + void redirect_returnPressed(Q3IconViewItem * pItem); + void redirect_rightButtonClicked(Q3IconViewItem * pItem,const QPoint &pnt); + void redirect_rightButtonPressed(Q3IconViewItem * pItem,const QPoint &pnt); + void redirect_mouseButtonClicked(int iButton,Q3IconViewItem * pItem,const QPoint &pnt); + void redirect_mouseButtonPressed(int iButton,Q3IconViewItem * pItem,const QPoint &pnt); + void redirect_contextMenuRequested(Q3IconViewItem * pItem,const QPoint &pnt); + void redirect_onItem(Q3IconViewItem * pItem); +public: + KviTalIconViewItem * firstItem() const { return (KviTalIconViewItem *)Q3IconView::firstItem(); }; + KviTalIconViewItem * lastItem() const { return (KviTalIconViewItem *)Q3IconView::lastItem(); }; + KviTalIconViewItem * currentItem() const { return (KviTalIconViewItem *)Q3IconView::currentItem(); }; +}; + +class KVILIB_API KviTalIconViewItem : public Q3IconViewItem +{ +public: + KviTalIconViewItem(KviTalIconView * parent) + : Q3IconViewItem(parent) {}; + KviTalIconViewItem(KviTalIconView * parent,KviTalIconViewItem * after) + : Q3IconViewItem(parent,after) {}; + KviTalIconViewItem(KviTalIconView * parent, const QString & text) + : Q3IconViewItem(parent,text) {}; + KviTalIconViewItem(KviTalIconView * parent, KviTalIconViewItem * after, const QString & text) + : Q3IconViewItem(parent,after,text) {}; + KviTalIconViewItem(KviTalIconView * parent, const QString & text, const QPixmap & icon) + : Q3IconViewItem(parent,text,icon) {}; + KviTalIconViewItem(KviTalIconView * parent, KviTalIconViewItem * after, const QString & text, const QPixmap & icon) + : Q3IconViewItem(parent,after,text,icon) {}; +public: + KviTalIconView * iconView() const { return (KviTalIconView *)Q3IconViewItem::iconView(); }; + KviTalIconViewItem * prevItem() const { return (KviTalIconViewItem *)Q3IconViewItem::prevItem(); }; + KviTalIconViewItem * nextItem() const { return (KviTalIconViewItem *)Q3IconViewItem::nextItem(); }; +}; + + +#endif // _KVI_TAL_ICONVIEW_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_listbox.cpp b/src/kvilib/tal/kvi_tal_listbox.cpp new file mode 100644 index 00000000..f5fcc087 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listbox.cpp @@ -0,0 +1,513 @@ +//============================================================================= +// +// File : kvi_tal_listbox.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_listbox.h" + +#ifdef COMPILE_USE_QT4 + #include <qpainter.h> + #include <qstyle.h> + #include <qapplication.h> + + KviTalListBox::KviTalListBox(QWidget * pParent,Qt::WFlags f) + : Q3ListBox(pParent,0,f) + { + connect(this,SIGNAL(highlighted(Q3ListBoxItem *)),this,SLOT(redirect_highlighted(Q3ListBoxItem *))); + connect(this,SIGNAL(selected(Q3ListBoxItem *)),this,SLOT(redirect_selected(Q3ListBoxItem *))); + connect(this,SIGNAL(selectionChanged(Q3ListBoxItem *)),this,SLOT(redirect_selectionChanged(Q3ListBoxItem *))); + connect(this,SIGNAL(currentChanged(Q3ListBoxItem *)),this,SLOT(redirect_currentChanged(Q3ListBoxItem *))); + connect(this,SIGNAL(clicked(Q3ListBoxItem *)),this,SLOT(redirect_clicked(Q3ListBoxItem *))); + connect(this,SIGNAL(clicked(Q3ListBoxItem *,const QPoint &)),this,SLOT(redirect_clicked(Q3ListBoxItem *,const QPoint &))); + connect(this,SIGNAL(pressed(Q3ListBoxItem *)),this,SLOT(redirect_pressed(Q3ListBoxItem *))); + connect(this,SIGNAL(pressed(Q3ListBoxItem *,const QPoint &)),this,SLOT(redirect_pressed(Q3ListBoxItem *,const QPoint &))); + connect(this,SIGNAL(doubleClicked(Q3ListBoxItem *)),this,SLOT(redirect_doubleClicked(Q3ListBoxItem *))); + connect(this,SIGNAL(returnPressed(Q3ListBoxItem *)),this,SLOT(redirect_returnPressed(Q3ListBoxItem *))); + connect(this,SIGNAL(rightButtonClicked(Q3ListBoxItem *, const QPoint &)),this,SLOT(redirect_rightButtonClicked(Q3ListBoxItem *, const QPoint &))); + connect(this,SIGNAL(rightButtonPressed(Q3ListBoxItem *, const QPoint &)),this,SLOT(redirect_rightButtonPressed(Q3ListBoxItem *, const QPoint &))); + connect(this,SIGNAL(mouseButtonPressed(int,Q3ListBoxItem *,const QPoint &)),this,SLOT(redirect_mouseButtonPressed(int,Q3ListBoxItem *,const QPoint &))); + connect(this,SIGNAL(mouseButtonClicked(int,Q3ListBoxItem *,const QPoint &)),this,SLOT(redirect_mouseButtonClicked(int,Q3ListBoxItem *,const QPoint &))); + connect(this,SIGNAL(contextMenuRequested(Q3ListBoxItem *,const QPoint &)),this,SLOT(redirect_contextMenuRequested(Q3ListBoxItem *,const QPoint &))); + connect(this,SIGNAL(onItem(Q3ListBoxItem *)),this,SLOT(redirect_onItem(Q3ListBoxItem *))); + } + + void KviTalListBox::redirect_highlighted(Q3ListBoxItem *item) + { + emit highlighted((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_selected(Q3ListBoxItem *item) + { + emit selected((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_selectionChanged(Q3ListBoxItem * item) + { + emit selectionChanged((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_currentChanged(Q3ListBoxItem * item) + { + emit currentChanged((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_clicked(Q3ListBoxItem * item) + { + emit clicked((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_clicked(Q3ListBoxItem * item,const QPoint & pnt) + { + emit clicked((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_pressed(Q3ListBoxItem * item) + { + emit pressed((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_pressed(Q3ListBoxItem * item,const QPoint & pnt) + { + emit pressed((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_doubleClicked(Q3ListBoxItem * item) + { + emit doubleClicked((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_returnPressed(Q3ListBoxItem * item) + { + emit returnPressed((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_rightButtonClicked(Q3ListBoxItem * item, const QPoint &pnt) + { + emit rightButtonClicked((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_rightButtonPressed(Q3ListBoxItem * item, const QPoint &pnt) + { + emit rightButtonPressed((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_mouseButtonPressed(int button,Q3ListBoxItem * item,const QPoint & pos) + { + emit mouseButtonPressed(button,(KviTalListBoxItem *)item,pos); + } + + void KviTalListBox::redirect_mouseButtonClicked(int button,Q3ListBoxItem * item,const QPoint & pos) + { + emit mouseButtonClicked(button,(KviTalListBoxItem *)item,pos); + } + + void KviTalListBox::redirect_contextMenuRequested(Q3ListBoxItem * item,const QPoint & pos) + { + emit contextMenuRequested((KviTalListBoxItem *)item,pos); + } + + void KviTalListBox::redirect_onItem(Q3ListBoxItem * i) + { + emit onItem((KviTalListBoxItem *)i); + } + + KviTalListBoxText::KviTalListBoxText(KviTalListBox *listbox, const QString &text) + :KviTalListBoxItem(listbox) + { + setText(text); + } + + KviTalListBoxText::KviTalListBoxText(const QString &text) + :KviTalListBoxItem() + { + setText(text); + } + + KviTalListBoxText::KviTalListBoxText(KviTalListBox* listbox, const QString &text, KviTalListBoxItem *after) + : KviTalListBoxItem(listbox, after) + { + setText(text); + } + + KviTalListBoxText::~KviTalListBoxText() + { + } + + void KviTalListBoxText::paint(QPainter *painter) + { + int itemHeight = height(listBox()); + QFontMetrics fm = painter->fontMetrics(); + int yPos = ((itemHeight - fm.height()) / 2) + fm.ascent(); + painter->drawText(3, yPos, text()); + } + + int KviTalListBoxText::height(const KviTalListBox* lb) const + { + int h = lb ? lb->fontMetrics().lineSpacing() + 2 : 0; + return qMax(h, QApplication::globalStrut().height()); + } + + int KviTalListBoxText::width(const KviTalListBox* lb) const + { + int w = lb ? lb->fontMetrics().width(text()) + 6 : 0; + return qMax(w, QApplication::globalStrut().width()); + } + + int KviTalListBoxText::rtti() const + { + return RTTI; + } + + KviTalListBoxPixmap::KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap &pixmap) + : KviTalListBoxItem(listbox) + { + pm = pixmap; + } + + KviTalListBoxPixmap::KviTalListBoxPixmap(const QPixmap &pixmap) + : KviTalListBoxItem() + { + pm = pixmap; + } + + KviTalListBoxPixmap::KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap &pixmap, KviTalListBoxItem *after) + : KviTalListBoxItem(listbox, after) + { + pm = pixmap; + } + + KviTalListBoxPixmap::~KviTalListBoxPixmap() + { + } + + KviTalListBoxPixmap::KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap &pix, const QString& text) + : KviTalListBoxItem(listbox) + { + pm = pix; + setText(text); + } + + KviTalListBoxPixmap::KviTalListBoxPixmap(const QPixmap & pix, const QString& text) + : KviTalListBoxItem() + { + pm = pix; + setText(text); + } + + KviTalListBoxPixmap::KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap & pix, const QString& text, + KviTalListBoxItem *after) + : KviTalListBoxItem(listbox, after) + { + pm = pix; + setText(text); + } + + void KviTalListBoxPixmap::paint(QPainter *painter) + { + int itemHeight = height(listBox()); + int yPos; + + const QPixmap *pm = pixmap(); + if (pm && ! pm->isNull()) { + yPos = (itemHeight - pm->height()) / 2; + painter->drawPixmap(3, yPos, *pm); + } + + if (!text().isEmpty()) { + QFontMetrics fm = painter->fontMetrics(); + yPos = ((itemHeight - fm.height()) / 2) + fm.ascent(); + painter->drawText(pm->width() + 5, yPos, text()); + } + } + + int KviTalListBoxPixmap::height(const KviTalListBox* lb) const + { + int h; + if (text().isEmpty()) + h = pm.height(); + else + h = qMax(pm.height(), lb->fontMetrics().lineSpacing() + 2); + return qMax(h, QApplication::globalStrut().height()); + } + + int KviTalListBoxPixmap::width(const KviTalListBox* lb) const + { + if (text().isEmpty()) + return qMax(pm.width() + 6, QApplication::globalStrut().width()); + return qMax(pm.width() + lb->fontMetrics().width(text()) + 6, + QApplication::globalStrut().width()); + } + + int KviTalListBoxPixmap::rtti() const + { + return RTTI; + } + + + #include "kvi_tal_listbox_qt4.moc" +#else + #include <qpainter.h> + #include <qstyle.h> + #include <qapplication.h> + + + KviTalListBox::KviTalListBox(QWidget * pParent,Qt::WFlags f) + : QListBox(pParent,0,f) + { + connect(this,SIGNAL(highlighted(QListBoxItem *)),this,SLOT(redirect_highlighted(QListBoxItem *))); + connect(this,SIGNAL(selected(QListBoxItem *)),this,SLOT(redirect_selected(QListBoxItem *))); + connect(this,SIGNAL(selectionChanged(QListBoxItem *)),this,SLOT(redirect_selectionChanged(QListBoxItem *))); + connect(this,SIGNAL(currentChanged(QListBoxItem *)),this,SLOT(redirect_currentChanged(QListBoxItem *))); + connect(this,SIGNAL(clicked(QListBoxItem *)),this,SLOT(redirect_clicked(QListBoxItem *))); + connect(this,SIGNAL(clicked(QListBoxItem *,const QPoint &)),this,SLOT(redirect_clicked(QListBoxItem *,const QPoint &))); + connect(this,SIGNAL(pressed(QListBoxItem *)),this,SLOT(redirect_pressed(QListBoxItem *))); + connect(this,SIGNAL(pressed(QListBoxItem *,const QPoint &)),this,SLOT(redirect_pressed(QListBoxItem *,const QPoint &))); + connect(this,SIGNAL(doubleClicked(QListBoxItem *)),this,SLOT(redirect_doubleClicked(QListBoxItem *))); + connect(this,SIGNAL(returnPressed(QListBoxItem *)),this,SLOT(redirect_returnPressed(QListBoxItem *))); + connect(this,SIGNAL(rightButtonClicked(QListBoxItem *, const QPoint &)),this,SLOT(redirect_rightButtonClicked(QListBoxItem *, const QPoint &))); + connect(this,SIGNAL(rightButtonPressed(QListBoxItem *, const QPoint &)),this,SLOT(redirect_rightButtonPressed(QListBoxItem *, const QPoint &))); + connect(this,SIGNAL(mouseButtonPressed(int,QListBoxItem *,const QPoint &)),this,SLOT(redirect_mouseButtonPressed(int,QListBoxItem *,const QPoint &))); + connect(this,SIGNAL(mouseButtonClicked(int,QListBoxItem *,const QPoint &)),this,SLOT(redirect_mouseButtonClicked(int,QListBoxItem *,const QPoint &))); + connect(this,SIGNAL(contextMenuRequested(QListBoxItem *,const QPoint &)),this,SLOT(redirect_contextMenuRequested(QListBoxItem *,const QPoint &))); + connect(this,SIGNAL(onItem(QListBoxItem *)),this,SLOT(redirect_onItem(QListBoxItem *))); + } + + void KviTalListBox::redirect_highlighted(QListBoxItem *item) + { + emit highlighted((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_selected(QListBoxItem *item) + { + emit selected((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_selectionChanged(QListBoxItem * item) + { + emit selectionChanged((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_currentChanged(QListBoxItem * item) + { + emit currentChanged((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_clicked(QListBoxItem * item) + { + emit clicked((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_clicked(QListBoxItem * item,const QPoint & pnt) + { + emit clicked((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_pressed(QListBoxItem * item) + { + emit pressed((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_pressed(QListBoxItem * item,const QPoint & pnt) + { + emit pressed((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_doubleClicked(QListBoxItem * item) + { + emit doubleClicked((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_returnPressed(QListBoxItem * item) + { + emit returnPressed((KviTalListBoxItem *)item); + } + + void KviTalListBox::redirect_rightButtonClicked(QListBoxItem * item, const QPoint &pnt) + { + emit rightButtonClicked((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_rightButtonPressed(QListBoxItem * item, const QPoint &pnt) + { + emit rightButtonPressed((KviTalListBoxItem *)item,pnt); + } + + void KviTalListBox::redirect_mouseButtonPressed(int button,QListBoxItem * item,const QPoint & pos) + { + emit mouseButtonPressed(button,(KviTalListBoxItem *)item,pos); + } + + void KviTalListBox::redirect_mouseButtonClicked(int button,QListBoxItem * item,const QPoint & pos) + { + emit mouseButtonClicked(button,(KviTalListBoxItem *)item,pos); + } + + void KviTalListBox::redirect_contextMenuRequested(QListBoxItem * item,const QPoint & pos) + { + emit contextMenuRequested((KviTalListBoxItem *)item,pos); + } + + void KviTalListBox::redirect_onItem(QListBoxItem * i) + { + emit onItem((KviTalListBoxItem *)i); + } + + KviTalListBoxText::KviTalListBoxText( KviTalListBox *listbox, const QString &text ) + :KviTalListBoxItem( listbox ) + { + setText( text ); + } + + KviTalListBoxText::KviTalListBoxText( const QString &text ) + :KviTalListBoxItem() + { + setText( text ); + } + + KviTalListBoxText::KviTalListBoxText( KviTalListBox* listbox, const QString &text, KviTalListBoxItem *after ) + : KviTalListBoxItem( listbox, after ) + { + setText( text ); + } + + KviTalListBoxText::~KviTalListBoxText() + { + } + + void KviTalListBoxText::paint( QPainter *painter ) + { + int itemHeight = height( listBox() ); + QFontMetrics fm = painter->fontMetrics(); + int yPos = ( ( itemHeight - fm.height() ) / 2 ) + fm.ascent(); + painter->drawText( 3, yPos, text() ); + } + + int KviTalListBoxText::height( const KviTalListBox* lb ) const + { + int h = lb ? lb->fontMetrics().lineSpacing() + 2 : 0; + return QMAX( h, QApplication::globalStrut().height() ); + } + + int KviTalListBoxText::width( const KviTalListBox* lb ) const + { + int w = lb ? lb->fontMetrics().width( text() ) + 6 : 0; + return QMAX( w, QApplication::globalStrut().width() ); + } + + int KviTalListBoxText::RTTI = 1; + + int KviTalListBoxText::rtti() const + { + return RTTI; + } + + KviTalListBoxPixmap::KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap &pixmap ) + : KviTalListBoxItem( listbox ) + { + pm = pixmap; + } + + KviTalListBoxPixmap::KviTalListBoxPixmap( const QPixmap &pixmap ) + : KviTalListBoxItem() + { + pm = pixmap; + } + + KviTalListBoxPixmap::KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap &pixmap, KviTalListBoxItem *after ) + : KviTalListBoxItem( listbox, after ) + { + pm = pixmap; + } + + KviTalListBoxPixmap::~KviTalListBoxPixmap() + { + } + + KviTalListBoxPixmap::KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap &pix, const QString& text) + : KviTalListBoxItem( listbox ) + { + pm = pix; + setText( text ); + } + + KviTalListBoxPixmap::KviTalListBoxPixmap( const QPixmap & pix, const QString& text) + : KviTalListBoxItem() + { + pm = pix; + setText( text ); + } + + KviTalListBoxPixmap::KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap & pix, const QString& text, + KviTalListBoxItem *after ) + : KviTalListBoxItem( listbox, after ) + { + pm = pix; + setText( text ); + } + + void KviTalListBoxPixmap::paint( QPainter *painter ) + { + int itemHeight = height( listBox() ); + int yPos; + + const QPixmap *pm = pixmap(); + if ( pm && ! pm->isNull() ) { + yPos = ( itemHeight - pm->height() ) / 2; + painter->drawPixmap( 3, yPos, *pm); + } + + if ( !text().isEmpty() ) { + QFontMetrics fm = painter->fontMetrics(); + yPos = ( ( itemHeight - fm.height() ) / 2 ) + fm.ascent(); + painter->drawText( pm->width() + 5, yPos, text() ); + } + } + + int KviTalListBoxPixmap::height( const KviTalListBox* lb ) const + { + int h; + if ( text().isEmpty() ) + h = pm.height(); + else + h = QMAX( pm.height(), lb->fontMetrics().lineSpacing() + 2 ); + return QMAX( h, QApplication::globalStrut().height() ); + } + + int KviTalListBoxPixmap::width( const KviTalListBox* lb ) const + { + if ( text().isEmpty() ) + return QMAX( pm.width() + 6, QApplication::globalStrut().width() ); + return QMAX( pm.width() + lb->fontMetrics().width( text() ) + 6, + QApplication::globalStrut().width() ); + } + + int KviTalListBoxPixmap::RTTI = 2; + + int KviTalListBoxPixmap::rtti() const + { + return RTTI; + } + + #include "kvi_tal_listbox_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_listbox.h b/src/kvilib/tal/kvi_tal_listbox.h new file mode 100644 index 00000000..18594539 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listbox.h @@ -0,0 +1,50 @@ +#ifndef _KVI_TAL_LISTBOX_H_ +#define _KVI_TAL_LISTBOX_H_ + +//============================================================================= +// +// File : kvi_tal_listbox.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +// +// This is the only reasonable CROSS-QT3-QT4-COMPATIBLE implementation +// of QListBox I've been able to find. +// Note that using macros for the items will NOT work since moc +// doesn't expand them. Note also that KviTalListBoxText must +// be fully reimplemented and not be inherited from QListBoxText +// to build up a consistent item object hierarchy. To complete +// the obscenity, we need TWO COMPLETE implementations: one for Qt3 +// and one for Qt4... bleah :D +// +// The code for KviTalListBoxText is adapted from qlistbox.h/cpp +// present in qt 3.3.6 AND in qt 4.1.2. +// + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_listbox_qt4.h" +#else + #include "kvi_tal_listbox_qt3.h" +#endif + +#endif // _KVI_TAL_LISTBOX_H_ diff --git a/src/kvilib/tal/kvi_tal_listbox_qt3.h b/src/kvilib/tal/kvi_tal_listbox_qt3.h new file mode 100644 index 00000000..d65b7929 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listbox_qt3.h @@ -0,0 +1,157 @@ +#ifndef _KVI_TAL_LISTBOX_QT3_H_ +#define _KVI_TAL_LISTBOX_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_listbox_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" +#include <qlistbox.h> + +class KviTalListBoxItem; + +class KVILIB_API KviTalListBox : public QListBox +{ + Q_OBJECT +public: + KviTalListBox(QWidget * pParent,Qt::WFlags f = 0); + virtual ~KviTalListBox() {}; +public: + KviTalListBoxItem * firstItem() const { return (KviTalListBoxItem *)QListBox::firstItem(); }; + KviTalListBoxItem * selectedItem() const { return (KviTalListBoxItem *)QListBox::selectedItem(); }; + KviTalListBoxItem * item(int iIndex) const { return (KviTalListBoxItem *)QListBox::item(iIndex); }; +signals: + void highlighted(KviTalListBoxItem *); + void selected(KviTalListBoxItem *); + void selectionChanged(KviTalListBoxItem * item); + void currentChanged(KviTalListBoxItem * item); + void clicked(KviTalListBoxItem * item); + void clicked(KviTalListBoxItem * item,const QPoint & pnt); + void pressed(KviTalListBoxItem * item); + void pressed(KviTalListBoxItem * item,const QPoint & pnt); + void doubleClicked(KviTalListBoxItem * item); + void returnPressed(KviTalListBoxItem * item); + void rightButtonClicked(KviTalListBoxItem *, const QPoint &); + void rightButtonPressed(KviTalListBoxItem *, const QPoint &); + void mouseButtonPressed(int button,KviTalListBoxItem * item,const QPoint & pos); + void mouseButtonClicked(int button,KviTalListBoxItem * item,const QPoint & pos); + void contextMenuRequested(KviTalListBoxItem * item,const QPoint & pos); + void onItem(KviTalListBoxItem * i); +protected slots: + void redirect_highlighted(QListBoxItem *item); + void redirect_selected(QListBoxItem *item); + void redirect_selectionChanged(QListBoxItem * item); + void redirect_currentChanged(QListBoxItem * item); + void redirect_clicked(QListBoxItem * item); + void redirect_clicked(QListBoxItem * item,const QPoint & pnt); + void redirect_pressed(QListBoxItem * item); + void redirect_pressed(QListBoxItem * item,const QPoint & pnt); + void redirect_doubleClicked(QListBoxItem * item); + void redirect_returnPressed(QListBoxItem * item); + void redirect_rightButtonClicked(QListBoxItem * item, const QPoint &pnt); + void redirect_rightButtonPressed(QListBoxItem * item, const QPoint &pnt); + void redirect_mouseButtonPressed(int button,QListBoxItem * item,const QPoint & pos); + void redirect_mouseButtonClicked(int button,QListBoxItem * item,const QPoint & pos); + void redirect_contextMenuRequested(QListBoxItem * item,const QPoint & pos); + void redirect_onItem(QListBoxItem * i); +}; + +class KVILIB_API KviTalListBoxItem : public QListBoxItem +{ +public: + KviTalListBoxItem() + : QListBoxItem() {}; + KviTalListBoxItem(KviTalListBox * pParent) + : QListBoxItem(pParent) {}; + KviTalListBoxItem(KviTalListBox * pParent,KviTalListBoxItem * pAfter) + : QListBoxItem(pParent,pAfter) {}; + virtual ~KviTalListBoxItem() {}; +public: + KviTalListBoxItem * next() const { return (KviTalListBoxItem *)QListBoxItem::next(); }; + KviTalListBoxItem * prev() const { return (KviTalListBoxItem *)QListBoxItem::prev(); }; + KviTalListBox * listBox() const { return (KviTalListBox *)QListBoxItem::listBox(); }; + virtual int height(const KviTalListBox *) const { return 0; }; + int height(const QListBox *lb) const { return height((KviTalListBox *)lb); }; + virtual int width(const KviTalListBox *) const { return 0; }; + int width(const QListBox *lb) const { return width((KviTalListBox *)lb); }; +}; + +class KVILIB_API KviTalListBoxText : public KviTalListBoxItem +{ +public: + KviTalListBoxText( KviTalListBox* listbox, const QString & text=QString::null ); + KviTalListBoxText( const QString & text=QString::null ); + KviTalListBoxText( KviTalListBox* listbox, const QString & text, KviTalListBoxItem *after ); + ~KviTalListBoxText(); + + int height( const KviTalListBox * ) const; + int width( const KviTalListBox * ) const; + + int rtti() const; + static int RTTI; + +protected: + virtual void paint( QPainter * ); + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + KviTalListBoxText( const KviTalListBoxText & ); + KviTalListBoxText &operator=( const KviTalListBoxText & ); +#endif +}; + + +class KVILIB_API KviTalListBoxPixmap : public KviTalListBoxItem +{ +public: + KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap & ); + KviTalListBoxPixmap( const QPixmap & ); + KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap & pix, KviTalListBoxItem *after ); + KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap &, const QString& ); + KviTalListBoxPixmap( const QPixmap &, const QString& ); + KviTalListBoxPixmap( KviTalListBox* listbox, const QPixmap & pix, const QString&, KviTalListBoxItem *after ); + ~KviTalListBoxPixmap(); + + const QPixmap *pixmap() const { return ± } + + int height( const KviTalListBox * ) const; + int width( const KviTalListBox * ) const; + + int rtti() const; + static int RTTI; + +protected: + virtual void paint( QPainter * ); + +private: + QPixmap pm; +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + KviTalListBoxPixmap( const KviTalListBoxPixmap & ); + KviTalListBoxPixmap &operator=( const KviTalListBoxPixmap & ); +#endif +}; + + +#endif // _KVI_TAL_LISTBOX_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_listbox_qt4.h b/src/kvilib/tal/kvi_tal_listbox_qt4.h new file mode 100644 index 00000000..dcb92f4d --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listbox_qt4.h @@ -0,0 +1,152 @@ +#ifndef _KVI_TAL_LISTBOX_QT4_H_ +#define _KVI_TAL_LISTBOX_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_listbox_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <q3listbox.h> + +class KviTalListBoxItem; + + +class KVILIB_API KviTalListBox : public Q3ListBox +{ + Q_OBJECT +public: + KviTalListBox(QWidget * pParent,Qt::WFlags f = 0); + virtual ~KviTalListBox() {}; +public: + KviTalListBoxItem * firstItem() const { return (KviTalListBoxItem *)Q3ListBox::firstItem(); }; + KviTalListBoxItem * selectedItem() const { return (KviTalListBoxItem *)Q3ListBox::selectedItem(); }; + KviTalListBoxItem * item(int iIndex) const { return (KviTalListBoxItem *)Q3ListBox::item(iIndex); }; +signals: + void highlighted(KviTalListBoxItem *); + void selected(KviTalListBoxItem *); + void selectionChanged(KviTalListBoxItem * item); + void currentChanged(KviTalListBoxItem * item); + void clicked(KviTalListBoxItem * item); + void clicked(KviTalListBoxItem * item,const QPoint & pnt); + void pressed(KviTalListBoxItem * item); + void pressed(KviTalListBoxItem * item,const QPoint & pnt); + void doubleClicked(KviTalListBoxItem * item); + void returnPressed(KviTalListBoxItem * item); + void rightButtonClicked(KviTalListBoxItem *, const QPoint &); + void rightButtonPressed(KviTalListBoxItem *, const QPoint &); + void mouseButtonPressed(int button,KviTalListBoxItem * item,const QPoint & pos); + void mouseButtonClicked(int button,KviTalListBoxItem * item,const QPoint & pos); + void contextMenuRequested(KviTalListBoxItem * item,const QPoint & pos); + void onItem(KviTalListBoxItem * i); +protected slots: + void redirect_highlighted(Q3ListBoxItem *); + void redirect_selected(Q3ListBoxItem *); + void redirect_selectionChanged(Q3ListBoxItem * item); + void redirect_currentChanged(Q3ListBoxItem * item); + void redirect_clicked(Q3ListBoxItem * item); + void redirect_clicked(Q3ListBoxItem * item,const QPoint & pnt); + void redirect_pressed(Q3ListBoxItem * item); + void redirect_pressed(Q3ListBoxItem * item,const QPoint & pnt); + void redirect_doubleClicked(Q3ListBoxItem * item); + void redirect_returnPressed(Q3ListBoxItem *); + void redirect_rightButtonClicked(Q3ListBoxItem *, const QPoint &); + void redirect_rightButtonPressed(Q3ListBoxItem *, const QPoint &); + void redirect_mouseButtonPressed(int button,Q3ListBoxItem * item,const QPoint & pos); + void redirect_mouseButtonClicked(int button,Q3ListBoxItem * item,const QPoint & pos); + void redirect_contextMenuRequested(Q3ListBoxItem * item,const QPoint & pos); + void redirect_onItem(Q3ListBoxItem * i); +}; + +class KVILIB_API KviTalListBoxItem : public Q3ListBoxItem +{ +public: + KviTalListBoxItem() + : Q3ListBoxItem() {}; + KviTalListBoxItem(KviTalListBox * pParent) + : Q3ListBoxItem(pParent) {}; + KviTalListBoxItem(KviTalListBox * pParent,KviTalListBoxItem * pAfter) + : Q3ListBoxItem(pParent,pAfter) {}; + virtual ~KviTalListBoxItem() {}; +public: + KviTalListBoxItem * next() const { return (KviTalListBoxItem *)Q3ListBoxItem::next(); }; + KviTalListBoxItem * prev() const { return (KviTalListBoxItem *)Q3ListBoxItem::prev(); }; + KviTalListBox * listBox() const { return (KviTalListBox *)Q3ListBoxItem::listBox(); }; + virtual int height(const KviTalListBox *) const { return 0; }; + int height(const Q3ListBox *lb) const { return height((KviTalListBox *)lb); }; + virtual int width(const KviTalListBox *) const { return 0; }; + int width(const Q3ListBox *lb) const { return width((KviTalListBox *)lb); }; +}; + + +class KVILIB_API KviTalListBoxText : public KviTalListBoxItem +{ +public: + KviTalListBoxText(KviTalListBox* listbox, const QString & text=QString()); + KviTalListBoxText(const QString & text=QString()); + KviTalListBoxText(KviTalListBox* listbox, const QString & text, KviTalListBoxItem *after); + ~KviTalListBoxText(); + + int height(const KviTalListBox *) const; + int width(const KviTalListBox *) const; + + int rtti() const; + enum { RTTI = 1 }; + +protected: + virtual void paint(QPainter *); + +private: + Q_DISABLE_COPY(KviTalListBoxText) +}; + + +class KVILIB_API KviTalListBoxPixmap : public KviTalListBoxItem +{ +public: + KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap &); + KviTalListBoxPixmap(const QPixmap &); + KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap & pix, KviTalListBoxItem *after); + KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap &, const QString&); + KviTalListBoxPixmap(const QPixmap &, const QString&); + KviTalListBoxPixmap(KviTalListBox* listbox, const QPixmap & pix, const QString&, KviTalListBoxItem *after); + ~KviTalListBoxPixmap(); + + const QPixmap *pixmap() const { return ± } + + int height(const KviTalListBox *) const; + int width(const KviTalListBox *) const; + + int rtti() const; + enum { RTTI = 2 }; + +protected: + virtual void paint(QPainter *); + +private: + Q_DISABLE_COPY(KviTalListBoxPixmap) + + QPixmap pm; +}; + +#endif // _KVI_TAL_LISTBOX_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_listview.cpp b/src/kvilib/tal/kvi_tal_listview.cpp new file mode 100644 index 00000000..01b253b3 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listview.cpp @@ -0,0 +1,1542 @@ +//============================================================================= +// +// File : kvi_tal_listview.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_listview.h" + +#include "kvi_pointerhashtable.h" + + +#ifdef COMPILE_USE_QT4 + #include <qpainter.h> + #include <qstyle.h> + #include <q3header.h> + #include <qapplication.h> + #include <qhash.h> + #include <qstyleoption.h> + #include <qaccessible.h> + + static QStyleOptionQ3ListView getStyleOption(const Q3ListView *lv, const Q3ListViewItem *item) + { + QStyleOptionQ3ListView opt; + opt.init(lv); + opt.subControls = QStyle::SC_None; + opt.activeSubControls = QStyle::SC_None; + QWidget *vp = lv->viewport(); + opt.viewportPalette = vp->palette(); + opt.viewportBGRole = vp->backgroundRole(); + opt.itemMargin = lv->itemMargin(); + opt.sortColumn = 0; + opt.treeStepSize = lv->treeStepSize(); + opt.rootIsDecorated = lv->rootIsDecorated(); + bool firstItem = true; + while (item) { + QStyleOptionQ3ListViewItem lvi; + lvi.height = item->height(); + lvi.totalHeight = item->totalHeight(); + lvi.itemY = item->itemPos(); + lvi.childCount = item->childCount(); + lvi.features = QStyleOptionQ3ListViewItem::None; + lvi.state = QStyle::State_None; + if (item->isEnabled()) + lvi.state |= QStyle::State_Enabled; + if (item->isOpen()) + lvi.state |= QStyle::State_Open; + if (item->isExpandable()) + lvi.features |= QStyleOptionQ3ListViewItem::Expandable; + if (item->multiLinesEnabled()) + lvi.features |= QStyleOptionQ3ListViewItem::MultiLine; + if (item->isVisible()) + lvi.features |= QStyleOptionQ3ListViewItem::Visible; + if (item->parent() && item->parent()->rtti() == 1 + && static_cast<Q3CheckListItem *>(item->parent())->type() == Q3CheckListItem::Controller) + lvi.features |= QStyleOptionQ3ListViewItem::ParentControl; + opt.items.append(lvi); + if (!firstItem) { + item = item->nextSibling(); + } else { + firstItem = false; + item = item->firstChild(); + } + } + return opt; + } + + KviTalListView::KviTalListView(QWidget * pParent) + : Q3ListView(pParent) + { + connect(this,SIGNAL(selectionChanged(Q3ListViewItem *)),this,SLOT(redirect_selectionChanged(Q3ListViewItem *))); + connect(this,SIGNAL(currentChanged(Q3ListViewItem *)),this,SLOT(redirect_currentChanged(Q3ListViewItem *))); + connect(this,SIGNAL(clicked(Q3ListViewItem *)),this,SLOT(redirect_clicked(Q3ListViewItem *))); + connect(this,SIGNAL(clicked(Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_clicked(Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(pressed(Q3ListViewItem *)),this,SLOT(redirect_pressed(Q3ListViewItem *))); + connect(this,SIGNAL(pressed(Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_pressed(Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(doubleClicked(Q3ListViewItem *)),this,SLOT(redirect_doubleClicked(Q3ListViewItem *))); + connect(this,SIGNAL(doubleClicked(Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_doubleClicked(Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(returnPressed(Q3ListViewItem *)),this,SLOT(redirect_returnPressed(Q3ListViewItem *))); + connect(this,SIGNAL(spacePressed(Q3ListViewItem *)),this,SLOT(redirect_spacePressed(Q3ListViewItem *))); + connect(this,SIGNAL(rightButtonClicked(Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_rightButtonClicked(Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(rightButtonPressed(Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_rightButtonPressed(Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(mouseButtonClicked(int,Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_mouseButtonClicked(int,Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(mouseButtonPressed(int,Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_mouseButtonPressed(int,Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(contextMenuRequested(Q3ListViewItem *,const QPoint &,int)),this,SLOT(redirect_contextMenuRequested(Q3ListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(onItem(Q3ListViewItem *)),this,SLOT(redirect_onItem(Q3ListViewItem *))); + connect(this,SIGNAL(expanded(Q3ListViewItem *)),this,SLOT(redirect_expanded(Q3ListViewItem *))); + connect(this,SIGNAL(collapsed(Q3ListViewItem *)),this,SLOT(redirect_collapsed(Q3ListViewItem *))); + } + + void KviTalListView::redirect_selectionChanged(Q3ListViewItem * pItem) + { + emit selectionChanged((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_currentChanged(Q3ListViewItem * pItem) + { + emit currentChanged((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_clicked(Q3ListViewItem * pItem) + { + emit clicked((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_clicked(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit clicked((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_pressed(Q3ListViewItem * pItem) + { + emit pressed((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_pressed(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit pressed((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_doubleClicked(Q3ListViewItem * pItem) + { + emit doubleClicked((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_doubleClicked(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit doubleClicked((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_returnPressed(Q3ListViewItem * pItem) + { + emit returnPressed((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_spacePressed(Q3ListViewItem * pItem) + { + emit spacePressed((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_rightButtonClicked(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit rightButtonClicked((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_rightButtonPressed(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit rightButtonPressed((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_mouseButtonClicked(int iButton,Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit mouseButtonClicked(iButton,(KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_mouseButtonPressed(int iButton,Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit mouseButtonPressed(iButton,(KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_contextMenuRequested(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit contextMenuRequested((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_onItem(Q3ListViewItem * pItem) + { + emit onItem((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_expanded(Q3ListViewItem * pItem) + { + emit expanded((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_collapsed(Q3ListViewItem * pItem) + { + emit collapsed((KviTalListViewItem *)pItem); + } + + + struct KviTalCheckListItemPrivate + { + KviTalCheckListItemPrivate(): + exclusive(0), + currentState(KviTalCheckListItem::Off), + tristate(false) {} + + KviTalCheckListItem *exclusive; + KviTalCheckListItem::ToggleState currentState; + QHash<KviTalCheckListItem *, KviTalCheckListItem::ToggleState> statesDict; + bool tristate; + }; + + KviTalCheckListItem::KviTalCheckListItem(KviTalCheckListItem *parent, const QString &text, + Type tt) + : KviTalListViewItem(parent, text, QString()) + { + myType = tt; + init(); + if (myType == RadioButton) { + if (parent->type() != RadioButtonController) + qWarning("KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a controller"); + else + d->exclusive = parent; + } + } + + KviTalCheckListItem::KviTalCheckListItem(KviTalCheckListItem *parent, KviTalListViewItem *after, + const QString &text, Type tt) + : KviTalListViewItem(parent, after, text) + { + myType = tt; + init(); + if (myType == RadioButton) { + if (parent->type() != RadioButtonController) + qWarning("KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a controller"); + else + d->exclusive = parent; + } + } + + KviTalCheckListItem::KviTalCheckListItem(KviTalListViewItem *parent, const QString &text, + Type tt) + : KviTalListViewItem(parent, text, QString()) + { + myType = tt; + if (myType == RadioButton) { + qWarning("KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem"); + } + init(); + } + + KviTalCheckListItem::KviTalCheckListItem(KviTalListViewItem *parent, KviTalListViewItem *after, + const QString &text, Type tt) + : KviTalListViewItem(parent, after, text) + { + myType = tt; + if (myType == RadioButton) { + qWarning("KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem"); + } + init(); + } + + KviTalCheckListItem::KviTalCheckListItem(KviTalListView *parent, const QString &text, + Type tt) + : KviTalListViewItem(parent, text) + { + myType = tt; + if (tt == RadioButton) + qWarning("KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem"); + init(); + } + + KviTalCheckListItem::KviTalCheckListItem(KviTalListView *parent, KviTalListViewItem *after, + const QString &text, Type tt) + : KviTalListViewItem(parent, after, text) + { + myType = tt; + if (tt == RadioButton) + qWarning("KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem"); + init(); + } + + int KviTalCheckListItem::rtti() const + { + return RTTI; + } + + KviTalCheckListItem::KviTalCheckListItem(KviTalListView *parent, const QString &text, + const QPixmap & p) + : KviTalListViewItem(parent, text) + { + myType = RadioButtonController; + setPixmap(0, p); + init(); + } + + KviTalCheckListItem::KviTalCheckListItem(KviTalListViewItem *parent, const QString &text, + const QPixmap & p) + : KviTalListViewItem(parent, text) + { + myType = RadioButtonController; + setPixmap(0, p); + init(); + } + + void KviTalCheckListItem::init() + { + d = new KviTalCheckListItemPrivate(); + on = false; // ### remove on ver 4 + // CheckBoxControllers by default have tristate set to true + if (myType == CheckBoxController) + setTristate(true); + } + + KviTalCheckListItem::~KviTalCheckListItem() + { + if (myType == RadioButton + && d->exclusive && d->exclusive->d + && d->exclusive->d->exclusive == this) + d->exclusive->turnOffChild(); + d->exclusive = 0; // so the children won't try to access us. + delete d; + d = 0; + } + + void KviTalCheckListItem::setTristate(bool b) + { + if ((myType != CheckBoxController) && (myType != CheckBox)) { + qWarning("KviTalCheckListItem::setTristate(), has no effect on RadioButton " + "or RadioButtonController."); + return; + } + d->tristate = b; + } + + bool KviTalCheckListItem::isTristate() const + { + return d->tristate; + } + + KviTalCheckListItem::ToggleState KviTalCheckListItem::state() const + { + if (!isTristate() && internalState() == NoChange) + return Off; + else + return d->currentState; + } + + KviTalCheckListItem::ToggleState KviTalCheckListItem::internalState() const + { + return d->currentState; + } + + void KviTalCheckListItem::setState(ToggleState s) + { + if (myType == CheckBoxController && state() == NoChange) + updateStoredState(this); + setState(s, true, true); + } + + void KviTalCheckListItem::setState(ToggleState s, bool update, bool store) + { + + if (s == internalState()) + return; + + if (myType == CheckBox) { + setCurrentState(s); + stateChange(state()); + if (update && parent() && parent()->rtti() == 1 + && ((KviTalCheckListItem*)parent())->type() == CheckBoxController) + ((KviTalCheckListItem*)parent())->updateController(update, store); + } else if (myType == CheckBoxController) { + if (s == NoChange && childCount()) { + restoreState(this); + } else { + KviTalListViewItem *item = firstChild(); + int childCount = 0; + while(item) { + if (item->rtti() == 1 && + (((KviTalCheckListItem*)item)->type() == CheckBox || + ((KviTalCheckListItem*)item)->type() == CheckBoxController)) { + KviTalCheckListItem *checkItem = (KviTalCheckListItem*)item; + checkItem->setState(s, false, false); + childCount++; + } + item = item->nextSibling(); + } + if (update) { + if (childCount > 0) { + ToggleState oldState = internalState(); + updateController(false, false); + if (oldState != internalState() && + parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*)parent())->type() == CheckBoxController) + ((KviTalCheckListItem*)parent())->updateController(update, store); + + updateController(update, store); + } else { + // if there are no children we simply set the CheckBoxController and update its parent + setCurrentState(s); + stateChange(state()); + if (parent() && parent()->rtti() == 1 + && ((KviTalCheckListItem*)parent())->type() == CheckBoxController) + ((KviTalCheckListItem*)parent())->updateController(update, store); + } + } else { + setCurrentState(s); + stateChange(state()); + } + + } + } else if (myType == RadioButton) { + if (s == On) { + if (d->exclusive && d->exclusive->d->exclusive != this) + d->exclusive->turnOffChild(); + setCurrentState(s); + if (d->exclusive) + d->exclusive->d->exclusive = this; + } else { + if (d->exclusive && d->exclusive->d->exclusive == this) + d->exclusive->d->exclusive = 0; + setCurrentState(Off); + } + stateChange(state()); + } + repaint(); + } + + void KviTalCheckListItem::setCurrentState(ToggleState s) + { + ToggleState old = d->currentState; + d->currentState = s; + if (d->currentState == On) + on = true; + else + on = false; + + //#ifndef QT_NO_ACCESSIBILITY + // if (old != d->currentState && listView()) + // QAccessible::updateAccessibility(listView()->viewport(), indexOfItem(this), QAccessible::StateChanged); + //#else + // Q_UNUSED(old); + //#endif + } + + void KviTalCheckListItem::setStoredState(ToggleState newState, KviTalCheckListItem *key) + { + if (myType == CheckBox || myType == CheckBoxController) + d->statesDict[key] = newState; + } + + KviTalCheckListItem::ToggleState KviTalCheckListItem::storedState(KviTalCheckListItem *key) const + { + QHash<KviTalCheckListItem *, KviTalCheckListItem::ToggleState>::Iterator it = d->statesDict.find(key); + if (it != d->statesDict.end()) + return it.value(); + else + return Off; + } + + void KviTalCheckListItem::turnOffChild() + { + if (myType == RadioButtonController && d->exclusive) + d->exclusive->setOn(false); + } + + void KviTalCheckListItem::activate() + { + KviTalListView * lv = listView(); + + if (lv && !lv->isEnabled() || !isEnabled()) + return; + + QPoint pos; + int boxsize = lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv); + if (activatedPos(pos)) { + bool parentControl = false; + if (parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*) parent())->type() == RadioButtonController) + parentControl = true; + + int x = parentControl ? 0 : 3; + int align = lv->columnAlignment(0); + int marg = lv->itemMargin(); + int y = 0; + + if (align & Qt::AlignVCenter) + y = ((height() - boxsize) / 2) + marg; + else + y = (lv->fontMetrics().height() + 2 + marg - boxsize) / 2; + + QRect r(x, y, boxsize-3, boxsize-3); + // columns might have been swapped + r.moveBy(lv->header()->sectionPos(0), 0); + if (!r.contains(pos)) + return; + } + if ((myType == CheckBox) || (myType == CheckBoxController)) { + //lv->d->startEdit = FALSE; + switch (internalState()) { + case On: + setState(Off); + break; + case Off: + if (!isTristate() && myType == CheckBox) { + setState(On); + } else { + setState(NoChange); + if (myType == CheckBoxController && internalState() != NoChange) + setState(On); + } + break; + case NoChange: + setState(On); + break; + } + ignoreDoubleClick(); + } else if (myType == RadioButton) { + setOn(true); + ignoreDoubleClick(); + } + } + + void KviTalCheckListItem::setOn(bool b ) + { + if (b) + setState(On , true, true); + else + setState(Off , true, true); + } + + void KviTalCheckListItem::stateChange(bool) + { + } + + void KviTalCheckListItem::stateChange(ToggleState s) + { + stateChange(s == On); + } + + void KviTalCheckListItem::restoreState(KviTalCheckListItem *key, int depth) + { + switch (type()) { + case CheckBox: + setCurrentState(storedState(key)); + stateChange(state()); + repaint(); + break; + case CheckBoxController: { + KviTalListViewItem *item = firstChild(); + int childCount = 0; + while (item) { + // recursively calling restoreState for children of type CheckBox and CheckBoxController + if (item->rtti() == 1 && + (((KviTalCheckListItem*)item)->type() == CheckBox || + ((KviTalCheckListItem*)item)->type() == CheckBoxController)) { + ((KviTalCheckListItem*)item)->restoreState(key , depth+1); + childCount++; + } + item = item->nextSibling(); + } + if (childCount > 0) { + if (depth == 0) + updateController(true); + else + updateController(false); + } else { + // if there are no children we retrieve the CheckBoxController state directly. + setState(storedState(key), true, false); + } + } + break; + default: + break; + } + } + + void KviTalCheckListItem::updateController(bool update , bool store) + { + if (myType != CheckBoxController) + return; + + KviTalCheckListItem *controller = 0; + // checks if this CheckBoxController has another CheckBoxController as parent + if (parent() && parent()->rtti() == 1 + && ((KviTalCheckListItem*)parent())->type() == CheckBoxController) + controller = (KviTalCheckListItem*)parent(); + + ToggleState theState = Off; + bool first = true; + KviTalListViewItem *item = firstChild(); + while(item && theState != NoChange) { + if (item->rtti() == 1 && + (((KviTalCheckListItem*)item)->type() == CheckBox || + ((KviTalCheckListItem*)item)->type() == CheckBoxController)) { + KviTalCheckListItem *checkItem = (KviTalCheckListItem*)item; + if (first) { + theState = checkItem->internalState(); + first = false; + } else { + if (checkItem->internalState() == NoChange || + theState != checkItem->internalState()) + theState = NoChange; + else + theState = checkItem->internalState(); + } + } + item = item->nextSibling(); + } + if (internalState() != theState) { + setCurrentState(theState); + if (store && (internalState() == On || internalState() == Off)) + updateStoredState(this); + stateChange(state()); + if (update && controller) { + controller->updateController(update, store); + } + repaint(); + } + } + + void KviTalCheckListItem::updateStoredState(KviTalCheckListItem *key) + { + if (myType != CheckBoxController) + return; + + KviTalListViewItem *item = firstChild(); + while(item) { + if (item->rtti() == 1) { + KviTalCheckListItem *checkItem = (KviTalCheckListItem*)item; + if (checkItem->type() == CheckBox) + checkItem->setStoredState(checkItem->internalState(), key); + else if (checkItem->type() == CheckBoxController) + checkItem->updateStoredState(key); + } + item = item->nextSibling(); + } + // this state is only needed if the CheckBoxController has no CheckBox / CheckBoxController children. + setStoredState(internalState() , key); + } + + void KviTalCheckListItem::setup() + { + KviTalListViewItem::setup(); + int h = height(); + KviTalListView *lv = listView(); + if (lv) + h = qMax(lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv), + h); + h = qMax(h, QApplication::globalStrut().height()); + setHeight(h); + } + + int KviTalCheckListItem::width(const QFontMetrics& fm, const KviTalListView* lv, int column) const + { + int r = KviTalListViewItem::width(fm, lv, column); + if (column == 0) { + r += lv->itemMargin(); + if (myType == RadioButtonController && pixmap(0)) { + // r += 0; + } else { + r += lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv) + 4; + } + } + return qMax(r, QApplication::globalStrut().width()); + } + + void KviTalCheckListItem::paintCell(QPainter * p, const QColorGroup & cg, + int column, int width, int align) + { + if (!p) + return; + + KviTalListView *lv = listView(); + if (!lv) + return; + + const QPalette::ColorRole crole = lv->foregroundRole(); + if (cg.brush(crole) != lv->palette().brush(crole)) + p->fillRect(0, 0, width, height(), cg.brush(crole)); + else + lv->paintEmptyArea(p, QRect(0, 0, width, height())); + + if (column != 0) { + // The rest is text, or for subclasses to change. + KviTalListViewItem::paintCell(p, cg, column, width, align); + return; + } + + bool parentControl = false; + if (parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*) parent())->type() == RadioButtonController) + parentControl = true; + + QFontMetrics fm(lv->fontMetrics()); + int boxsize = lv->style()->pixelMetric(myType == RadioButtonController ? QStyle::PM_CheckListControllerSize : + QStyle::PM_CheckListButtonSize, 0, lv); + int marg = lv->itemMargin(); + int r = marg; + + // Draw controller / checkbox / radiobutton --------------------- + QStyle::State styleflags = QStyle::State_None; + if (internalState() == On) { + styleflags |= QStyle::State_On; + } else if (internalState() == NoChange) { + if (myType == CheckBoxController && !isTristate()) + styleflags |= QStyle::State_Off; + else + styleflags |= QStyle::State_NoChange; + } else { + styleflags |= QStyle::State_Off; + } + if (isSelected()) + styleflags |= QStyle::State_Selected; + if (isEnabled() && lv->isEnabled()) + styleflags |= QStyle::State_Enabled; + if (lv->window()->isActiveWindow()) + styleflags |= QStyle::State_Active; + + if (myType == RadioButtonController) { + int x = 0; + if(!parentControl) + x += 3; + if (!pixmap(0)) { + QStyleOptionQ3ListView opt = getStyleOption(lv, this); + opt.rect.setRect(x, 0, boxsize, fm.height() + 2 + marg); + opt.palette = cg; + opt.state = styleflags; + lv->style()->drawPrimitive(QStyle::PE_Q3CheckListController, &opt, p, lv); + r += boxsize + 4; + } + } else { + Q_ASSERT(lv); //### + int x = 0; + int y = 0; + if (!parentControl) + x += 3; + if (align & Qt::AlignVCenter) + y = ((height() - boxsize) / 2) + marg; + else + y = (fm.height() + 2 + marg - boxsize) / 2; + + QStyleOptionQ3ListView opt = getStyleOption(lv, this); + opt.rect.setRect(x, y, boxsize, fm.height() + 2 + marg); + opt.palette = cg; + opt.state = styleflags; + lv->style()->drawPrimitive((myType == CheckBox || myType == CheckBoxController) + ? QStyle::PE_Q3CheckListIndicator + : QStyle::PE_Q3CheckListExclusiveIndicator, &opt, p, lv); + r += boxsize + 4; + } + + // Draw text ---------------------------------------------------- + p->translate(r, 0); + p->setPen(QPen(cg.text())); + KviTalListViewItem::paintCell(p, cg, column, width - r, align); + } + + void KviTalCheckListItem::paintFocus(QPainter *p, const QColorGroup & cg, + const QRect & r) + { + bool intersect = true; + KviTalListView *lv = listView(); + if (lv && lv->header()->mapToActual(0) != 0) { + int xdepth = lv->treeStepSize() * (depth() + (lv->rootIsDecorated() ? 1 : 0)) + lv->itemMargin(); + int p = lv->header()->cellPos(lv->header()->mapToActual(0)); + xdepth += p; + intersect = r.intersects(QRect(p, r.y(), xdepth - p + 1, r.height())); + } + bool parentControl = false; + if (parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*) parent())->type() == RadioButtonController) + parentControl = true; + if (myType != RadioButtonController && intersect && + (lv->rootIsDecorated() || myType == RadioButton || + (myType == CheckBox && parentControl))) { + QRect rect; + int boxsize = lv->style()->pixelMetric(QStyle::PM_CheckListButtonSize, 0, lv); + if (lv->columnAlignment(0) == Qt::AlignCenter) { + QFontMetrics fm(lv->font()); + int bx = (lv->columnWidth(0) - (boxsize + fm.width(text())))/2 + boxsize; + if (bx < 0) bx = 0; + rect.setRect(r.x() + bx + 5, r.y(), r.width() - bx - 5, + r.height()); + } else + rect.setRect(r.x() + boxsize + 5, r.y(), r.width() - boxsize - 5, + r.height()); + KviTalListViewItem::paintFocus(p, cg, rect); + } else { + KviTalListViewItem::paintFocus(p, cg, r); + } + } + + + #include "kvi_tal_listview_qt4.moc" +#else + #include <qpainter.h> + #include <qstyle.h> + #include <qheader.h> + #include <qapplication.h> + + KviTalListView::KviTalListView(QWidget * pParent) + : QListView(pParent) + { + connect(this,SIGNAL(selectionChanged(QListViewItem *)),this,SLOT(redirect_selectionChanged(QListViewItem *))); + connect(this,SIGNAL(currentChanged(QListViewItem *)),this,SLOT(redirect_currentChanged(QListViewItem *))); + connect(this,SIGNAL(clicked(QListViewItem *)),this,SLOT(redirect_clicked(QListViewItem *))); + connect(this,SIGNAL(clicked(QListViewItem *,const QPoint &,int)),this,SLOT(redirect_clicked(QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(pressed(QListViewItem *)),this,SLOT(redirect_pressed(QListViewItem *))); + connect(this,SIGNAL(pressed(QListViewItem *,const QPoint &,int)),this,SLOT(redirect_pressed(QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(doubleClicked(QListViewItem *)),this,SLOT(redirect_doubleClicked(QListViewItem *))); + connect(this,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)),this,SLOT(redirect_doubleClicked(QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(returnPressed(QListViewItem *)),this,SLOT(redirect_returnPressed(QListViewItem *))); + connect(this,SIGNAL(spacePressed(QListViewItem *)),this,SLOT(redirect_spacePressed(QListViewItem *))); + connect(this,SIGNAL(rightButtonClicked(QListViewItem *,const QPoint &,int)),this,SLOT(redirect_rightButtonClicked(QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(rightButtonPressed(QListViewItem *,const QPoint &,int)),this,SLOT(redirect_rightButtonPressed(QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(mouseButtonClicked(int,QListViewItem *,const QPoint &,int)),this,SLOT(redirect_mouseButtonClicked(int,QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(mouseButtonPressed(int,QListViewItem *,const QPoint &,int)),this,SLOT(redirect_mouseButtonPressed(int,QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(contextMenuRequested(QListViewItem *,const QPoint &,int)),this,SLOT(redirect_contextMenuRequested(QListViewItem *,const QPoint &,int))); + connect(this,SIGNAL(onItem(QListViewItem *)),this,SLOT(redirect_onItem(QListViewItem *))); + connect(this,SIGNAL(expanded(QListViewItem *)),this,SLOT(redirect_expanded(QListViewItem *))); + connect(this,SIGNAL(collapsed(QListViewItem *)),this,SLOT(redirect_collapsed(QListViewItem *))); + } + + void KviTalListView::redirect_selectionChanged(QListViewItem * pItem) + { + emit selectionChanged((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_currentChanged(QListViewItem * pItem) + { + emit currentChanged((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_clicked(QListViewItem * pItem) + { + emit clicked((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_clicked(QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit clicked((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_pressed(QListViewItem * pItem) + { + emit pressed((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_pressed(QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit pressed((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_doubleClicked(QListViewItem * pItem) + { + emit doubleClicked((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_doubleClicked(QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit doubleClicked((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_returnPressed(QListViewItem * pItem) + { + emit returnPressed((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_spacePressed(QListViewItem * pItem) + { + emit spacePressed((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_rightButtonClicked(QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit rightButtonClicked((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_rightButtonPressed(QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit rightButtonPressed((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_mouseButtonClicked(int iButton,QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit mouseButtonClicked(iButton,(KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_mouseButtonPressed(int iButton,QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit mouseButtonPressed(iButton,(KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_contextMenuRequested(QListViewItem * pItem,const QPoint &pnt,int uColumn) + { + emit contextMenuRequested((KviTalListViewItem *)pItem,pnt,uColumn); + } + + void KviTalListView::redirect_onItem(QListViewItem * pItem) + { + emit onItem((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_expanded(QListViewItem * pItem) + { + emit expanded((KviTalListViewItem *)pItem); + } + + void KviTalListView::redirect_collapsed(QListViewItem * pItem) + { + emit collapsed((KviTalListViewItem *)pItem); + } + + struct KviTalCheckListItemPrivate + { + KviTalCheckListItemPrivate(): + exclusive( 0 ), + currentState( KviTalCheckListItem::Off ), + statesDict( 0 ), + tristate( FALSE ) {} + + KviTalCheckListItem *exclusive; + KviTalCheckListItem::ToggleState currentState; + KviPointerHashTable<void *,KviTalCheckListItem::ToggleState> *statesDict; + bool tristate; + }; + + // ### obscenity is warranted. + + KviTalCheckListItem::KviTalCheckListItem( KviTalCheckListItem *parent, const QString &text, + Type tt ) + : KviTalListViewItem( parent, text, QString::null ) + { + myType = tt; + init(); + if ( myType == RadioButton ) { + if ( parent->type() != RadioButtonController ) + qWarning( "KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a controller" ); + else + d->exclusive = parent; + } + } + + KviTalCheckListItem::KviTalCheckListItem( KviTalCheckListItem *parent, KviTalListViewItem *after, + const QString &text, Type tt ) + : KviTalListViewItem( parent, after, text ) + { + myType = tt; + init(); + if ( myType == RadioButton ) { + if ( parent->type() != RadioButtonController ) + qWarning( "KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a controller" ); + else + d->exclusive = parent; + } + } + + KviTalCheckListItem::KviTalCheckListItem( KviTalListViewItem *parent, const QString &text, + Type tt ) + : KviTalListViewItem( parent, text, QString::null ) + { + myType = tt; + if ( myType == RadioButton ) { + qWarning( "KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem" ); + } + init(); + } + + KviTalCheckListItem::KviTalCheckListItem( KviTalListViewItem *parent, KviTalListViewItem *after, + const QString &text, Type tt ) + : KviTalListViewItem( parent, after, text ) + { + myType = tt; + if ( myType == RadioButton ) { + qWarning( "KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem" ); + } + init(); + } + + KviTalCheckListItem::KviTalCheckListItem( KviTalListView *parent, const QString &text, + Type tt ) + : KviTalListViewItem( parent, text ) + { + myType = tt; + if ( tt == RadioButton ) + qWarning( "KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem" ); + init(); + } + + KviTalCheckListItem::KviTalCheckListItem( KviTalListView *parent, KviTalListViewItem *after, + const QString &text, Type tt ) + : KviTalListViewItem( parent, after, text ) + { + myType = tt; + if ( tt == RadioButton ) + qWarning( "KviTalCheckListItem::KviTalCheckListItem(), radio button must be " + "child of a KviTalCheckListItem" ); + init(); + } + + + int KviTalCheckListItem::RTTI = 1; + + int KviTalCheckListItem::rtti() const + { + return RTTI; + } + + KviTalCheckListItem::KviTalCheckListItem( KviTalListView *parent, const QString &text, + const QPixmap & p ) + : KviTalListViewItem( parent, text ) + { + myType = RadioButtonController; + setPixmap( 0, p ); + init(); + } + + KviTalCheckListItem::KviTalCheckListItem( KviTalListViewItem *parent, const QString &text, + const QPixmap & p ) + : KviTalListViewItem( parent, text ) + { + myType = RadioButtonController; + setPixmap( 0, p ); + init(); + } + + void KviTalCheckListItem::init() + { + d = new KviTalCheckListItemPrivate(); + on = FALSE; // ### remove on ver 4 + if ( myType == CheckBoxController || myType == CheckBox ) { + d->statesDict = new KviPointerHashTable<void *,ToggleState>(101); + d->statesDict->setAutoDelete( TRUE ); + } + // CheckBoxControllers by default have tristate set to TRUE + if ( myType == CheckBoxController ) + setTristate( TRUE ); + } + + KviTalCheckListItem::~KviTalCheckListItem() + { + if ( myType == RadioButton + && d->exclusive && d->exclusive->d + && d->exclusive->d->exclusive == this ) + d->exclusive->turnOffChild(); + d->exclusive = 0; // so the children won't try to access us. + if ( d->statesDict ) + delete d->statesDict; + delete d; + d = 0; + } + + void KviTalCheckListItem::setTristate( bool b ) + { + if ( ( myType != CheckBoxController ) && ( myType != CheckBox ) ) { + qWarning( "KviTalCheckListItem::setTristate(), has no effect on RadioButton " + "or RadioButtonController." ); + return; + } + d->tristate = b; + } + + bool KviTalCheckListItem::isTristate() const + { + return d->tristate; + } + + KviTalCheckListItem::ToggleState KviTalCheckListItem::state() const + { + if ( !isTristate() && internalState() == NoChange ) + return Off; + else + return d->currentState; + } + + KviTalCheckListItem::ToggleState KviTalCheckListItem::internalState() const + { + return d->currentState; + } + + void KviTalCheckListItem::setState( ToggleState s ) + { + if ( myType == CheckBoxController && state() == NoChange ) + updateStoredState( (void*) this ); + setState( s, TRUE, TRUE ); + } + + void KviTalCheckListItem::setState( ToggleState s, bool update, bool store) + { + + if ( s == internalState() ) + return; + + if ( myType == CheckBox ) { + setCurrentState( s ); + stateChange( state() ); + if ( update && parent() && parent()->rtti() == 1 + && ((KviTalCheckListItem*)parent())->type() == CheckBoxController ) + ((KviTalCheckListItem*)parent())->updateController( update, store ); + } else if ( myType == CheckBoxController ) { + if ( s == NoChange && childCount()) { + restoreState( (void*) this ); + } else { + KviTalListViewItem *item = firstChild(); + int childCount = 0; + while( item ) { + if ( item->rtti() == 1 && + ( ((KviTalCheckListItem*)item)->type() == CheckBox || + ((KviTalCheckListItem*)item)->type() == CheckBoxController ) ) { + KviTalCheckListItem *checkItem = (KviTalCheckListItem*)item; + checkItem->setState( s, FALSE, FALSE ); + childCount++; + } + item = item->nextSibling(); + } + if ( update ) { + if ( childCount > 0 ) { + ToggleState oldState = internalState(); + updateController( FALSE, FALSE ); + if ( oldState != internalState() && + parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*)parent())->type() == CheckBoxController ) + ((KviTalCheckListItem*)parent())->updateController( update, store ); + + updateController( update, store ); + } else { + // if there are no children we simply set the CheckBoxController and update its parent + setCurrentState( s ); + stateChange( state() ); + if ( parent() && parent()->rtti() == 1 + && ((KviTalCheckListItem*)parent())->type() == CheckBoxController ) + ((KviTalCheckListItem*)parent())->updateController( update, store ); + } + } else { + setCurrentState( s ); + stateChange( state() ); + } + + } + } else if ( myType == RadioButton ) { + if ( s == On ) { + if ( d->exclusive && d->exclusive->d->exclusive != this ) + d->exclusive->turnOffChild(); + setCurrentState( s ); + if ( d->exclusive ) + d->exclusive->d->exclusive = this; + } else { + if ( d->exclusive && d->exclusive->d->exclusive == this ) + d->exclusive->d->exclusive = 0; + setCurrentState( Off ); + } + stateChange( state() ); + } + repaint(); + } + + void KviTalCheckListItem::setCurrentState( ToggleState s ) + { + ToggleState old = d->currentState; + d->currentState = s; + if (d->currentState == On) + on = TRUE; + else + on = FALSE; + + #if defined(QT_ACCESSIBILITY_SUPPORT) + if ( old != d->currentState && listView() ) + QAccessible::updateAccessibility( listView()->viewport(), indexOfItem( this ), QAccessible::StateChanged ); + #else + Q_UNUSED( old ); + #endif + } + + void KviTalCheckListItem::setStoredState( ToggleState newState, void *key ) + { + if ( myType == CheckBox || myType == CheckBoxController ) + d->statesDict->replace( key, new ToggleState(newState) ); + } + + KviTalCheckListItem::ToggleState KviTalCheckListItem::storedState( void *key ) const + { + if ( !d->statesDict ) + return Off; + + ToggleState *foundState = d->statesDict->find( key ); + if ( foundState ) + return ToggleState( *foundState ); + else + return Off; + } + + void KviTalCheckListItem::turnOffChild() + { + if ( myType == RadioButtonController && d->exclusive ) + d->exclusive->setOn( FALSE ); + } + + void KviTalCheckListItem::activate() + { + KviTalListView * lv = listView(); + + if ( lv && !lv->isEnabled() || !isEnabled() ) + return; + + QPoint pos; + int boxsize = lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv); + if ( activatedPos( pos ) ) { + bool parentControl = FALSE; + if ( parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*) parent())->type() == RadioButtonController ) + parentControl = TRUE; + + int x = parentControl ? 0 : 3; + int align = lv->columnAlignment( 0 ); + int marg = lv->itemMargin(); + int y = 0; + + if ( align & AlignVCenter ) + y = ( ( height() - boxsize ) / 2 ) + marg; + else + y = (lv->fontMetrics().height() + 2 + marg - boxsize) / 2; + + QRect r( x, y, boxsize-3, boxsize-3 ); + // columns might have been swapped + r.moveBy( lv->header()->sectionPos( 0 ), 0 ); + if ( !r.contains( pos ) ) + return; + } + if ( ( myType == CheckBox ) || ( myType == CheckBoxController) ) { + switch ( internalState() ) { + case On: + setState( Off ); + break; + case Off: + if ( !isTristate() && myType == CheckBox ) { + setState( On ); + } else { + setState( NoChange ); + if ( myType == CheckBoxController && internalState() != NoChange ) + setState( On ); + } + break; + case NoChange: + setState( On ); + break; + } + ignoreDoubleClick(); + } else if ( myType == RadioButton ) { + setOn( TRUE ); + ignoreDoubleClick(); + } + } + + void KviTalCheckListItem::setOn( bool b ) + { + if ( b ) + setState( On , TRUE, TRUE ); + else + setState( Off , TRUE, TRUE ); + } + + void KviTalCheckListItem::stateChange( bool ) + { + } + + void KviTalCheckListItem::stateChange( ToggleState s ) + { + stateChange( s == On ); + } + + void KviTalCheckListItem::restoreState( void *key, int depth ) + { + switch ( type() ) { + case CheckBox: + setCurrentState( storedState( key ) ); + stateChange( state() ); + repaint(); + break; + case CheckBoxController: { + KviTalListViewItem *item = firstChild(); + int childCount = 0; + while ( item ) { + // recursively calling restoreState for children of type CheckBox and CheckBoxController + if ( item->rtti() == 1 && + ( ((KviTalCheckListItem*)item)->type() == CheckBox || + ((KviTalCheckListItem*)item)->type() == CheckBoxController ) ) { + ((KviTalCheckListItem*)item)->restoreState( key , depth+1 ); + childCount++; + } + item = item->nextSibling(); + } + if ( childCount > 0 ) { + if ( depth == 0 ) + updateController( TRUE ); + else + updateController( FALSE ); + } else { + // if there are no children we retrieve the CheckBoxController state directly. + setState( storedState( key ), TRUE, FALSE ); + } + } + break; + default: + break; + } + } + + void KviTalCheckListItem::updateController( bool update , bool store ) + { + if ( myType != CheckBoxController ) + return; + + KviTalCheckListItem *controller = 0; + // checks if this CheckBoxController has another CheckBoxController as parent + if ( parent() && parent()->rtti() == 1 + && ((KviTalCheckListItem*)parent())->type() == CheckBoxController ) + controller = (KviTalCheckListItem*)parent(); + + ToggleState theState = Off; + bool first = TRUE; + KviTalListViewItem *item = firstChild(); + while( item && theState != NoChange ) { + if ( item->rtti() == 1 && + ( ((KviTalCheckListItem*)item)->type() == CheckBox || + ((KviTalCheckListItem*)item)->type() == CheckBoxController ) ) { + KviTalCheckListItem *checkItem = (KviTalCheckListItem*)item; + if ( first ) { + theState = checkItem->internalState(); + first = FALSE; + } else { + if ( checkItem->internalState() == NoChange || + theState != checkItem->internalState() ) + theState = NoChange; + else + theState = checkItem->internalState(); + } + } + item = item->nextSibling(); + } + if ( internalState() != theState ) { + setCurrentState( theState ); + if ( store && ( internalState() == On || internalState() == Off ) ) + updateStoredState( (void*) this ); + stateChange( state() ); + if ( update && controller ) { + controller->updateController( update, store ); + } + repaint(); + } + } + + void KviTalCheckListItem::updateStoredState( void *key ) + { + if ( myType != CheckBoxController ) + return; + + KviTalListViewItem *item = firstChild(); + while( item ) { + if ( item->rtti() == 1 ) { + KviTalCheckListItem *checkItem = (KviTalCheckListItem*)item; + if ( checkItem->type() == CheckBox ) + checkItem->setStoredState( checkItem->internalState(), key ); + else if (checkItem->type() == CheckBoxController ) + checkItem->updateStoredState( key ); + } + item = item->nextSibling(); + } + // this state is only needed if the CheckBoxController has no CheckBox / CheckBoxController children. + setStoredState( internalState() , key ); + } + + void KviTalCheckListItem::setup() + { + KviTalListViewItem::setup(); + int h = height(); + KviTalListView *lv = listView(); + if ( lv ) + h = QMAX( lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv), + h ); + h = QMAX( h, QApplication::globalStrut().height() ); + setHeight( h ); + } + + int KviTalCheckListItem::width( const QFontMetrics& fm, const KviTalListView* lv, int column) const + { + int r = KviTalListViewItem::width( fm, lv, column ); + if ( column == 0 ) { + r += lv->itemMargin(); + if ( myType == RadioButtonController && pixmap( 0 ) ) { + // r += 0; + } else { + r += lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv) + 4; + } + } + return QMAX( r, QApplication::globalStrut().width() ); + } + + void KviTalCheckListItem::paintCell( QPainter * p, const QColorGroup & cg, + int column, int width, int align ) + { + if ( !p ) + return; + + KviTalListView *lv = listView(); + if ( !lv ) + return; + + const BackgroundMode bgmode = lv->viewport()->backgroundMode(); + const QColorGroup::ColorRole crole = QPalette::backgroundRoleFromMode( bgmode ); + if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) ) + p->fillRect( 0, 0, width, height(), cg.brush( crole ) ); + else + lv->paintEmptyArea( p, QRect( 0, 0, width, height() ) ); + + if ( column != 0 ) { + // The rest is text, or for subclasses to change. + KviTalListViewItem::paintCell( p, cg, column, width, align ); + return; + } + + bool parentControl = FALSE; + if ( parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*) parent())->type() == RadioButtonController ) + parentControl = TRUE; + + QFontMetrics fm( lv->fontMetrics() ); + int boxsize = lv->style().pixelMetric( myType == RadioButtonController ? QStyle::PM_CheckListControllerSize : + QStyle::PM_CheckListButtonSize, lv); + int marg = lv->itemMargin(); + int r = marg; + + // Draw controller / checkbox / radiobutton --------------------- + int styleflags = QStyle::Style_Default; + if ( internalState() == On ) { + styleflags |= QStyle::Style_On; + } else if ( internalState() == NoChange ) { + if ( myType == CheckBoxController && !isTristate() ) + styleflags |= QStyle::Style_Off; + else + styleflags |= QStyle::Style_NoChange; + } else { + styleflags |= QStyle::Style_Off; + } + if ( isSelected() ) + styleflags |= QStyle::Style_Selected; + if ( isEnabled() && lv->isEnabled() ) + styleflags |= QStyle::Style_Enabled; + + if ( myType == RadioButtonController ) { + int x = 0; + if(!parentControl) + x += 3; + if ( !pixmap( 0 ) ) { + lv->style().drawPrimitive(QStyle::PE_CheckListController, p, + QRect(x, 0, boxsize, + fm.height() + 2 + marg), + cg, styleflags, QStyleOption(this)); + r += boxsize + 4; + } + } else { + Q_ASSERT( lv ); //### + int x = 0; + int y = 0; + if ( !parentControl ) + x += 3; + if ( align & AlignVCenter ) + y = ( ( height() - boxsize ) / 2 ) + marg; + else + y = (fm.height() + 2 + marg - boxsize) / 2; + + if ( ( myType == CheckBox ) || ( myType == CheckBoxController ) ) { + lv->style().drawPrimitive(QStyle::PE_CheckListIndicator, p, + QRect(x, y, boxsize, + fm.height() + 2 + marg), + cg, styleflags, QStyleOption(this)); + } else { //radio button look + lv->style().drawPrimitive(QStyle::PE_CheckListExclusiveIndicator, + p, QRect(x, y, boxsize, + fm.height() + 2 + marg), + cg, styleflags, QStyleOption(this)); + } + r += boxsize + 4; + } + + // Draw text ---------------------------------------------------- + p->translate( r, 0 ); + p->setPen( QPen( cg.text() ) ); + KviTalListViewItem::paintCell( p, cg, column, width - r, align ); + } + + void KviTalCheckListItem::paintFocus( QPainter *p, const QColorGroup & cg,const QRect & r ) + { + bool intersect = TRUE; + KviTalListView *lv = listView(); + if ( lv && lv->header()->mapToActual( 0 ) != 0 ) { + int xdepth = lv->treeStepSize() * ( depth() + ( lv->rootIsDecorated() ? 1 : 0) ) + lv->itemMargin(); + int p = lv->header()->cellPos( lv->header()->mapToActual( 0 ) ); + xdepth += p; + intersect = r.intersects( QRect( p, r.y(), xdepth - p + 1, r.height() ) ); + } + bool parentControl = FALSE; + if ( parent() && parent()->rtti() == 1 && + ((KviTalCheckListItem*) parent())->type() == RadioButtonController ) + parentControl = TRUE; + if ( myType != RadioButtonController && intersect && + (lv->rootIsDecorated() || myType == RadioButton || + (myType == CheckBox && parentControl) ) ) { + QRect rect; + int boxsize = lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv); + if ( lv->columnAlignment(0) == AlignCenter ) { + QFontMetrics fm( lv->font() ); + int bx = (lv->columnWidth(0) - (boxsize + fm.width(text())))/2 + boxsize; + if ( bx < 0 ) bx = 0; + rect.setRect( r.x() + bx + 5, r.y(), r.width() - bx - 5, + r.height() ); + } else + rect.setRect( r.x() + boxsize + 5, r.y(), r.width() - boxsize - 5, + r.height() ); + KviTalListViewItem::paintFocus(p, cg, rect); + } else { + KviTalListViewItem::paintFocus(p, cg, r); + } + } + + #include "kvi_tal_listview_qt3.moc" +#endif + + + diff --git a/src/kvilib/tal/kvi_tal_listview.h b/src/kvilib/tal/kvi_tal_listview.h new file mode 100644 index 00000000..9b95e2f8 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listview.h @@ -0,0 +1,51 @@ +#ifndef _KVI_TAL_LISTVIEW_H_ +#define _KVI_TAL_LISTVIEW_H_ + +//============================================================================= +// +// File : kvi_tal_listview.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + + +// +// This is the only reasonable CROSS-QT3-QT4-COMPATIBLE implementation +// of QListView I've been able to find. +// Note that using macros for the items will NOT work since moc +// doesn't expand them. Note also that KviTalCheckListItem must +// be fully reimplemented and not be inherited from QCheckListItem +// to build up a consistent item object hierarchy. To complete +// the obscenity, we need TWO COMPLETE implementations: one for Qt3 +// and one for Qt4... bleah :D +// +// The code for KviTalCheckListItem is adapted from qlistview.h/cpp +// present in qt 3.3.6 AND in qt 4.1.2. +// + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_listview_qt4.h" +#else + #include "kvi_tal_listview_qt3.h" +#endif + +#endif // _KVI_TAL_LISTVIEW_H_ diff --git a/src/kvilib/tal/kvi_tal_listview_qt3.h b/src/kvilib/tal/kvi_tal_listview_qt3.h new file mode 100644 index 00000000..4fe4a766 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listview_qt3.h @@ -0,0 +1,190 @@ +#ifndef _KVI_TAL_LISTVIEW_QT3_H_ +#define _KVI_TAL_LISTVIEW_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_listview_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include "kvi_qstring.h" + +#include <qlistview.h> + +class KviTalListViewItem; + +class KVILIB_API KviTalListView : public QListView +{ + friend class KviTalCheckListItem; + Q_OBJECT +public: + KviTalListView(QWidget * pParent); + virtual ~KviTalListView() {}; +public: + // Shadow the internal Qt methods + KviTalListViewItem * firstChild() const { return (KviTalListViewItem *)QListView::firstChild(); }; + KviTalListViewItem * lastItem() const { return (KviTalListViewItem *)QListView::lastItem(); }; + KviTalListViewItem * selectedItem() const { return (KviTalListViewItem *)QListView::selectedItem(); }; + KviTalListViewItem * currentItem() const { return (KviTalListViewItem *)QListView::currentItem(); }; + KviTalListViewItem * itemAt(const QPoint &pnt) const { return (KviTalListViewItem *)QListView::itemAt(pnt); }; +signals: + void selectionChanged(KviTalListViewItem * pItem); + void currentChanged(KviTalListViewItem * pItem); + void clicked(KviTalListViewItem * pItem); + void clicked(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void pressed(KviTalListViewItem * pItem); + void pressed(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void doubleClicked(KviTalListViewItem * pItem); + void doubleClicked(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void returnPressed(KviTalListViewItem * pItem); + void spacePressed(KviTalListViewItem * pItem); + void rightButtonClicked(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void rightButtonPressed(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void mouseButtonClicked(int iButton,KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void mouseButtonPressed(int iButton,KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void contextMenuRequested(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void onItem(KviTalListViewItem * pItem); + void expanded(KviTalListViewItem * pItem); + void collapsed(KviTalListViewItem * pItem); +protected slots: + void redirect_selectionChanged(QListViewItem * pItem); + void redirect_currentChanged(QListViewItem * pItem); + void redirect_clicked(QListViewItem * pItem); + void redirect_clicked(QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_pressed(QListViewItem * pItem); + void redirect_pressed(QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_doubleClicked(QListViewItem * pItem); + void redirect_doubleClicked(QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_returnPressed(QListViewItem * pItem); + void redirect_spacePressed(QListViewItem * pItem); + void redirect_rightButtonClicked(QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_rightButtonPressed(QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_mouseButtonClicked(int iButton,QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_mouseButtonPressed(int iButton,QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_contextMenuRequested(QListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_onItem(QListViewItem * pItem); + void redirect_expanded(QListViewItem * pItem); + void redirect_collapsed(QListViewItem * pItem); +}; + + +class KVILIB_API KviTalListViewItem : public QListViewItem +{ +public: + KviTalListViewItem(KviTalListView * pParent) + : QListViewItem(pParent) {}; + KviTalListViewItem(KviTalListViewItem * pParent) + : QListViewItem(pParent) {}; + KviTalListViewItem(KviTalListView * pParent,KviTalListViewItem * pAfter) + : QListViewItem(pParent,pAfter) {}; + KviTalListViewItem(KviTalListViewItem * pParent,KviTalListViewItem * pAfter) + : QListViewItem(pParent,pAfter) {}; + KviTalListViewItem(KviTalListView * pParent,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty,const QString &szLabel5 = KviQString::empty) + : QListViewItem(pParent,szLabel1,szLabel2,szLabel3,szLabel4,szLabel5) {}; + KviTalListViewItem(KviTalListView * pParent,KviTalListViewItem * pAfter,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty,const QString &szLabel5 = KviQString::empty) + : QListViewItem(pParent,pAfter,szLabel1,szLabel2,szLabel3,szLabel4,szLabel5) {}; + KviTalListViewItem(KviTalListViewItem * pParent,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty) + : QListViewItem(pParent,szLabel1,szLabel2,szLabel3,szLabel4) {}; + KviTalListViewItem(KviTalListViewItem * pParent,KviTalListViewItem * pAfter,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty) + : QListViewItem(pParent,pAfter,szLabel1,szLabel2,szLabel3,szLabel4) {}; + virtual ~KviTalListViewItem() {}; +public: + // Shadow the internal Qt methods + KviTalListViewItem * firstChild() const { return (KviTalListViewItem *)QListViewItem::firstChild(); }; + KviTalListViewItem * nextSibling() const { return (KviTalListViewItem *)QListViewItem::nextSibling(); }; + KviTalListViewItem * parent() const { return (KviTalListViewItem *)QListViewItem::parent(); }; + KviTalListView * listView() const { return (KviTalListView *)QListViewItem::listView(); }; + KviTalListViewItem * itemAbove() { return (KviTalListViewItem *)QListViewItem::itemAbove(); }; + KviTalListViewItem * itemBelow() { return (KviTalListViewItem *)QListViewItem::itemBelow(); }; +}; + +struct KviTalCheckListItemPrivate; + +class KVILIB_API KviTalCheckListItem : public KviTalListViewItem +{ +public: + enum Type { + RadioButton, + CheckBox, + Controller, + RadioButtonController=Controller, + CheckBoxController + }; + enum ToggleState { Off, NoChange, On }; + + KviTalCheckListItem(KviTalCheckListItem *parent, const QString &text,Type = RadioButtonController); + KviTalCheckListItem(KviTalCheckListItem *parent, KviTalListViewItem *after,const QString &text, Type = RadioButtonController); + KviTalCheckListItem( KviTalListViewItem *parent, const QString &text,Type = RadioButtonController ); + KviTalCheckListItem( KviTalListViewItem *parent, KviTalListViewItem *after,const QString &text, Type = RadioButtonController ); + KviTalCheckListItem( KviTalListView *parent, const QString &text,Type = RadioButtonController ); + KviTalCheckListItem( KviTalListView *parent, KviTalListViewItem *after,const QString &text, Type = RadioButtonController ); + KviTalCheckListItem( KviTalListViewItem *parent, const QString &text,const QPixmap & ); + KviTalCheckListItem( KviTalListView *parent, const QString &text,const QPixmap & ); + ~KviTalCheckListItem(); + + void paintCell( QPainter *,const QColorGroup & cg,int column, int width, int alignment ); + virtual void paintFocus( QPainter *, const QColorGroup & cg, + const QRect & r ); + int width( const QFontMetrics&, const KviTalListView*, int column) const; + void setup(); + + virtual void setOn( bool ); // ### should be replaced by setChecked in ver4 + bool isOn() const { return on; } + Type type() const { return myType; } + QString text() const { return KviTalListViewItem::text( 0 ); } + QString text( int n ) const { return KviTalListViewItem::text( n ); } + + void setTristate( bool ); + bool isTristate() const; + ToggleState state() const; + void setState( ToggleState s); + + int rtti() const; + static int RTTI; + +protected: + void activate(); + void turnOffChild(); + virtual void stateChange( bool ); + +private: + void init(); + ToggleState internalState() const; + void setStoredState( ToggleState newState, void *key ); + ToggleState storedState( void *key ) const; + void stateChange( ToggleState s ); + void restoreState( void *key, int depth = 0 ); + void updateController( bool update = TRUE , bool store = FALSE ); + void updateStoredState( void *key ); + void setState( ToggleState s, bool update, bool store ); + void setCurrentState( ToggleState s ); + + Type myType; + bool on; // ### remove in ver4 + KviTalCheckListItemPrivate *d; +}; + + +#define KviTalListViewItemIterator QListViewItemIterator + +#endif // _KVI_TAL_LISTVIEW_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_listview_qt4.h b/src/kvilib/tal/kvi_tal_listview_qt4.h new file mode 100644 index 00000000..e6ccc829 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_listview_qt4.h @@ -0,0 +1,199 @@ +#ifndef _KVI_TAL_LISTVIEW_QT4_H_ +#define _KVI_TAL_LISTVIEW_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_listview_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include "kvi_qstring.h" + +#include <q3listview.h> + +class KviTalListViewItem; + + +class KVILIB_API KviTalListView : public Q3ListView +{ + friend class KviTalCheckListItem; + Q_OBJECT +public: + KviTalListView(QWidget * pParent); + virtual ~KviTalListView() {}; +public: + // Shadow the internal Qt methods + KviTalListViewItem * firstChild() const { return (KviTalListViewItem *)Q3ListView::firstChild(); }; + KviTalListViewItem * lastItem() const { return (KviTalListViewItem *)Q3ListView::lastItem(); }; + KviTalListViewItem * selectedItem() const { return (KviTalListViewItem *)Q3ListView::selectedItem(); }; + KviTalListViewItem * currentItem() const { return (KviTalListViewItem *)Q3ListView::currentItem(); }; + KviTalListViewItem * itemAt(const QPoint &pnt) const { return (KviTalListViewItem *)Q3ListView::itemAt(pnt); }; +signals: + void selectionChanged(KviTalListViewItem * pItem); + void currentChanged(KviTalListViewItem * pItem); + void clicked(KviTalListViewItem * pItem); + void clicked(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void pressed(KviTalListViewItem * pItem); + void pressed(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void doubleClicked(KviTalListViewItem * pItem); + void doubleClicked(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void returnPressed(KviTalListViewItem * pItem); + void spacePressed(KviTalListViewItem * pItem); + void rightButtonClicked(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void rightButtonPressed(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void mouseButtonClicked(int iButton,KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void mouseButtonPressed(int iButton,KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void contextMenuRequested(KviTalListViewItem * pItem,const QPoint &pnt,int uColumn); + void onItem(KviTalListViewItem * pItem); + void expanded(KviTalListViewItem * pItem); + void collapsed(KviTalListViewItem * pItem); +protected slots: + void redirect_selectionChanged(Q3ListViewItem * pItem); + void redirect_currentChanged(Q3ListViewItem * pItem); + void redirect_clicked(Q3ListViewItem * pItem); + void redirect_clicked(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_pressed(Q3ListViewItem * pItem); + void redirect_pressed(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_doubleClicked(Q3ListViewItem * pItem); + void redirect_doubleClicked(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_returnPressed(Q3ListViewItem * pItem); + void redirect_spacePressed(Q3ListViewItem * pItem); + void redirect_rightButtonClicked(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_rightButtonPressed(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_mouseButtonClicked(int iButton,Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_mouseButtonPressed(int iButton,Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_contextMenuRequested(Q3ListViewItem * pItem,const QPoint &pnt,int uColumn); + void redirect_onItem(Q3ListViewItem * pItem); + void redirect_expanded(Q3ListViewItem * pItem); + void redirect_collapsed(Q3ListViewItem * pItem); + +}; + + +class KVILIB_API KviTalListViewItem : public Q3ListViewItem +{ +public: + KviTalListViewItem(KviTalListView * pParent) + : Q3ListViewItem(pParent) {}; + KviTalListViewItem(KviTalListViewItem * pParent) + : Q3ListViewItem(pParent) {}; + KviTalListViewItem(KviTalListView * pParent,KviTalListViewItem * pAfter) + : Q3ListViewItem(pParent,pAfter) {}; + KviTalListViewItem(KviTalListViewItem * pParent,KviTalListViewItem * pAfter) + : Q3ListViewItem(pParent,pAfter) {}; + KviTalListViewItem(KviTalListView * pParent,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty,const QString &szLabel5 = KviQString::empty) + : Q3ListViewItem(pParent,szLabel1,szLabel2,szLabel3,szLabel4,szLabel5) {}; + KviTalListViewItem(KviTalListView * pParent,KviTalListViewItem * pAfter,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty,const QString &szLabel5 = KviQString::empty) + : Q3ListViewItem(pParent,pAfter,szLabel1,szLabel2,szLabel3,szLabel4,szLabel5) {}; + KviTalListViewItem(KviTalListViewItem * pParent,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty) + : Q3ListViewItem(pParent,szLabel1,szLabel2,szLabel3,szLabel4) {}; + KviTalListViewItem(KviTalListViewItem * pParent,KviTalListViewItem * pAfter,const QString &szLabel1,const QString &szLabel2 = KviQString::empty,const QString &szLabel3 = KviQString::empty,const QString &szLabel4 = KviQString::empty) + : Q3ListViewItem(pParent,pAfter,szLabel1,szLabel2,szLabel3,szLabel4) {}; +public: + // Shadow the internal Qt methods + KviTalListViewItem * firstChild() const { return (KviTalListViewItem *)Q3ListViewItem::firstChild(); }; + KviTalListViewItem * nextSibling() const { return (KviTalListViewItem *)Q3ListViewItem::nextSibling(); }; + KviTalListViewItem * parent() const { return (KviTalListViewItem *)Q3ListViewItem::parent(); }; + KviTalListView * listView() const { return (KviTalListView *)Q3ListViewItem::listView(); }; + KviTalListViewItem * itemAbove() { return (KviTalListViewItem *)Q3ListViewItem::itemAbove(); }; + KviTalListViewItem * itemBelow() { return (KviTalListViewItem *)Q3ListViewItem::itemBelow(); }; +}; + +struct KviTalCheckListItemPrivate; + +class KVILIB_API KviTalCheckListItem : public KviTalListViewItem +{ +public: + enum Type { RadioButton, + CheckBox, + Controller, + RadioButtonController=Controller, + CheckBoxController }; + + enum ToggleState { Off, NoChange, On }; + + KviTalCheckListItem(KviTalCheckListItem *parent, const QString &text, + Type = RadioButtonController); + KviTalCheckListItem(KviTalCheckListItem *parent, KviTalListViewItem *after, + const QString &text, Type = RadioButtonController); + KviTalCheckListItem(KviTalListViewItem *parent, const QString &text, + Type = RadioButtonController); + KviTalCheckListItem(KviTalListViewItem *parent, KviTalListViewItem *after, + const QString &text, Type = RadioButtonController); + KviTalCheckListItem(KviTalListView *parent, const QString &text, + Type = RadioButtonController); + KviTalCheckListItem(KviTalListView *parent, KviTalListViewItem *after, + const QString &text, Type = RadioButtonController); + KviTalCheckListItem(KviTalListViewItem *parent, const QString &text, + const QPixmap &); + KviTalCheckListItem(KviTalListView *parent, const QString &text, + const QPixmap &); + ~KviTalCheckListItem(); + + void paintCell(QPainter *, const QColorGroup & cg, + int column, int width, int alignment); + virtual void paintFocus(QPainter *, const QColorGroup &cg, + const QRect & r); + int width(const QFontMetrics&, const KviTalListView*, int column) const; + void setup(); + + virtual void setOn(bool); + bool isOn() const { return on; } + Type type() const { return myType; } + QString text() const { return KviTalListViewItem::text(0); } + QString text(int n) const { return KviTalListViewItem::text(n); } + + void setTristate(bool); + bool isTristate() const; + ToggleState state() const; + void setState(ToggleState s); + + int rtti() const; + enum { RTTI = 1 }; + +protected: + void activate(); + void turnOffChild(); + virtual void stateChange(bool); + +private: + void init(); + ToggleState internalState() const; + void setStoredState(ToggleState newState, KviTalCheckListItem *key); + ToggleState storedState(KviTalCheckListItem *key) const; + void stateChange(ToggleState s); + void restoreState(KviTalCheckListItem *key, int depth = 0); + void updateController(bool update = true , bool store = false); + void updateStoredState(KviTalCheckListItem *key); + void setState(ToggleState s, bool update, bool store); + void setCurrentState(ToggleState s); + + Type myType; + bool on; + KviTalCheckListItemPrivate *d; +}; + +#define KviTalListViewItemIterator Q3ListViewItemIterator + + +#endif // _KVI_TAL_LISTVIEW_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_mainwindow.cpp b/src/kvilib/tal/kvi_tal_mainwindow.cpp new file mode 100644 index 00000000..c2e52b2d --- /dev/null +++ b/src/kvilib/tal/kvi_tal_mainwindow.cpp @@ -0,0 +1,69 @@ +// +// File : kvi_tal_mainwindow.coo +// Creation date : Sun Aug 12 2001 04:40:24 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#include "kvi_tal_mainwindow.h" + +#ifdef COMPILE_KDE_SUPPORT + + KviTalMainWindow::KviTalMainWindow(QWidget * par,const char * nam) + : KMainWindow(par,nam) + { + } + + #include "kvi_tal_mainwindow_kde.moc" + +#else + + #ifdef COMPILE_USE_QT4 + KviTalMainWindow::KviTalMainWindow(QWidget * par,const char * nam) + : QMainWindow(par,nam) + { + } + + bool KviTalMainWindow::usesBigPixmaps() + { + return (iconSize().width() > 40); + } + + void KviTalMainWindow::setUsesBigPixmaps(bool b) + { + if(b)setIconSize(QSize(48,48)); + else setIconSize(QSize(24,24)); + } + #include "kvi_tal_mainwindow_qt4.moc" + #else + KviTalMainWindow::KviTalMainWindow(QWidget * par,const char * nam) + : QMainWindow(par,nam) + { + } + #include "kvi_tal_mainwindow_qt3.moc" + #endif + +#endif + +KviTalMainWindow::~KviTalMainWindow() +{ +} + diff --git a/src/kvilib/tal/kvi_tal_mainwindow.h b/src/kvilib/tal/kvi_tal_mainwindow.h new file mode 100644 index 00000000..76a1a79c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_mainwindow.h @@ -0,0 +1,38 @@ +#ifndef _KVI_TAL_MAINWINDOW_H_ +#define _KVI_TAL_MAINWINDOW_H_ + +// +// File : kvi_tal_mainwindow.h +// Creation date : Sun Aug 12 2001 04:41:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" + +#ifdef COMPILE_KDE_SUPPORT + #include "kvi_tal_mainwindow_kde.h" +#else + #ifdef COMPILE_USE_QT4 + #include "kvi_tal_mainwindow_qt4.h" + #else + #include "kvi_tal_mainwindow_qt3.h" + #endif +#endif + +#endif // _KVI_TAL_MAINWINDOW_H_ diff --git a/src/kvilib/tal/kvi_tal_mainwindow_kde.h b/src/kvilib/tal/kvi_tal_mainwindow_kde.h new file mode 100644 index 00000000..9f38aede --- /dev/null +++ b/src/kvilib/tal/kvi_tal_mainwindow_kde.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_MAINWINDOW_KDE_H_ +#define _KVI_TAL_MAINWINDOW_KDE_H_ + +// +// File : kvi_tal_mainwindow_kde.h +// Creation date : Sun Aug 12 2001 04:41:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <kmainwindow.h> + +class KVILIB_API KviTalMainWindow : public KMainWindow +{ + Q_OBJECT +public: + KviTalMainWindow(QWidget * par,const char * nam); + ~KviTalMainWindow(); +}; + +#endif // _KVI_TAL_MAINWINDOW_KDE_H_ diff --git a/src/kvilib/tal/kvi_tal_mainwindow_qt3.h b/src/kvilib/tal/kvi_tal_mainwindow_qt3.h new file mode 100644 index 00000000..d328774f --- /dev/null +++ b/src/kvilib/tal/kvi_tal_mainwindow_qt3.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_MAINWINDOW_QT_H_ +#define _KVI_TAL_MAINWINDOW_QT_H_ + +// +// File : kvi_tal_mainwindow_qt.h +// Creation date : Sun Aug 12 2001 04:43:58 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qmainwindow.h> + +class KVILIB_API KviTalMainWindow : public QMainWindow +{ + Q_OBJECT +public: + KviTalMainWindow(QWidget * par,const char * nam); + ~KviTalMainWindow(); +}; + +#endif // _KVI_TAL_MAINWINDOW_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_mainwindow_qt4.h b/src/kvilib/tal/kvi_tal_mainwindow_qt4.h new file mode 100644 index 00000000..b6c2c1be --- /dev/null +++ b/src/kvilib/tal/kvi_tal_mainwindow_qt4.h @@ -0,0 +1,39 @@ +#ifndef _KVI_TAL_MAINWINDOW_QT_H_ +#define _KVI_TAL_MAINWINDOW_QT_H_ + +// +// File : kvi_tal_mainwindow_qt.h +// Creation date : Sun Aug 12 2001 04:43:58 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qmainwindow.h> + +class KVILIB_API KviTalMainWindow : public QMainWindow +{ + Q_OBJECT +public: + KviTalMainWindow(QWidget * par,const char * nam); + ~KviTalMainWindow(); +public: + bool usesBigPixmaps(); + void setUsesBigPixmaps(bool b); +}; + +#endif // _KVI_TAL_MAINWINDOW_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_menubar.cpp b/src/kvilib/tal/kvi_tal_menubar.cpp new file mode 100644 index 00000000..0fbb28be --- /dev/null +++ b/src/kvilib/tal/kvi_tal_menubar.cpp @@ -0,0 +1,58 @@ +// +// File : kvi_tal_menubar.cpp +// Creation date : Sun Aug 12 06:35:18 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#include "kvi_tal_menubar.h" + +#ifdef COMPILE_KDE_SUPPORT + + KviTalMenuBar::KviTalMenuBar(QWidget * par,const char * nam) + : KMenuBar(par,nam) + { + } + + KviTalMenuBar::~KviTalMenuBar() + { + } + + #include "kvi_tal_menubar_kde.moc" + +#else + + KviTalMenuBar::KviTalMenuBar(QWidget * par,const char * nam) +#ifdef COMPILE_USE_QT4 + : QMenuBar(par) +#else + : QMenuBar(par,nam) +#endif + { + } + + KviTalMenuBar::~KviTalMenuBar() + { + } + + #include "kvi_tal_menubar_qt.moc" + +#endif diff --git a/src/kvilib/tal/kvi_tal_menubar.h b/src/kvilib/tal/kvi_tal_menubar.h new file mode 100644 index 00000000..08016bb7 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_menubar.h @@ -0,0 +1,33 @@ +#ifndef _KVI_TAL_MENUBAR_H_ +#define _KVI_TAL_MENUBAR_H_ +// +// File : kvi_tal_menubar.h +// Creation date : Sun Aug 12 06:35:15 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" + +#ifdef COMPILE_KDE_SUPPORT + #include "kvi_tal_menubar_kde.h" +#else + #include "kvi_tal_menubar_qt.h" +#endif + +#endif //_KVI_TAL_MENUBAR_H_ diff --git a/src/kvilib/tal/kvi_tal_menubar_kde.h b/src/kvilib/tal/kvi_tal_menubar_kde.h new file mode 100644 index 00000000..e345d221 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_menubar_kde.h @@ -0,0 +1,35 @@ +#ifndef _KVI_TAL_MENUBAR_KDE_H_ +#define _KVI_TAL_MENUBAR_KDE_H_ +// +// File : kvi_tal_menubar_kde.h +// Creation date : Sun Aug 12 06:35:22 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <kmenubar.h> + +class KVILIB_API KviTalMenuBar : public KMenuBar +{ + Q_OBJECT +public: + KviTalMenuBar(QWidget * par,const char * nam); + ~KviTalMenuBar(); +}; + +#endif //_KVI_TAL_MENUBAR_KDE_H_ diff --git a/src/kvilib/tal/kvi_tal_menubar_qt.h b/src/kvilib/tal/kvi_tal_menubar_qt.h new file mode 100644 index 00000000..c42dab7f --- /dev/null +++ b/src/kvilib/tal/kvi_tal_menubar_qt.h @@ -0,0 +1,35 @@ +#ifndef _KVI_TAL_MENUBAR_QT_H_ +#define _KVI_TAL_MENUBAR_QT_H_ +// +// File : kvi_tal_menubar_qt.h +// Creation date : Sun Aug 12 06:35:24 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qmenubar.h> + +class KVILIB_API KviTalMenuBar : public QMenuBar +{ + Q_OBJECT +public: + KviTalMenuBar(QWidget * par,const char * nam); + ~KviTalMenuBar(); +}; + +#endif //_KVI_TAL_MENUBAR_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_popupmenu.cpp b/src/kvilib/tal/kvi_tal_popupmenu.cpp new file mode 100644 index 00000000..ad3c8463 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_popupmenu.cpp @@ -0,0 +1,33 @@ +//============================================================================= +// +// File : kvi_tal_popupmenu.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_popupmenu.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_popupmenu_qt4.moc" +#else + #include "kvi_tal_popupmenu_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_popupmenu.h b/src/kvilib/tal/kvi_tal_popupmenu.h new file mode 100644 index 00000000..5035f031 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_popupmenu.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_POPUPMENU_H_ +#define _KVI_TAL_POPUPMENU_H_ + +//============================================================================= +// +// File : kvi_tal_popupmenu.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_popupmenu_qt4.h" +#else + #include "kvi_tal_popupmenu_qt3.h" +#endif + +#endif // _KVI_TAL_POPUPMENU_H_ diff --git a/src/kvilib/tal/kvi_tal_popupmenu_qt3.h b/src/kvilib/tal/kvi_tal_popupmenu_qt3.h new file mode 100644 index 00000000..3340945b --- /dev/null +++ b/src/kvilib/tal/kvi_tal_popupmenu_qt3.h @@ -0,0 +1,42 @@ +#ifndef _KVI_TAL_POPUPMENU_QT3_H_ +#define _KVI_TAL_POPUPMENU_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_popupmenu.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" + +#include <qpopupmenu.h> + +class KVILIB_API KviTalPopupMenu : public QPopupMenu +{ + Q_OBJECT +public: + KviTalPopupMenu(QWidget * pParent=0,const QString &szName = KviQString::empty) + : QPopupMenu(pParent,KviQString::toUtf8(szName).data()) {}; + virtual ~KviTalPopupMenu() {}; +}; + +#endif // _KVI_TAL_POPUPMENU_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_popupmenu_qt4.h b/src/kvilib/tal/kvi_tal_popupmenu_qt4.h new file mode 100644 index 00000000..58da15ef --- /dev/null +++ b/src/kvilib/tal/kvi_tal_popupmenu_qt4.h @@ -0,0 +1,89 @@ +#ifndef _KVI_TAL_POPUPMENU_QT4_H_ +#define _KVI_TAL_POPUPMENU_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_popupmenu_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" +#include "kvi_qstring.h" + +#include <q3popupmenu.h> +#include <qwidgetaction.h> + +class KVILIB_API KviTalPopupMenu : public Q3PopupMenu +{ + Q_OBJECT +public: + KviTalPopupMenu(QWidget * pParent=0,const QString &szName = KviQString::empty) + : Q3PopupMenu(pParent) + { + setName(szName); + }; + virtual ~KviTalPopupMenu() {}; + + int insertItem(const QString &szText) + { + return Q3PopupMenu::insertItem(szText); + } + int insertItem(const QPixmap &pix,const QString &szText) + { + return Q3PopupMenu::insertItem(QIcon(pix),szText,-1,-1); + } + int insertItem(const QString &szText,int id) + { + return Q3PopupMenu::insertItem(szText,id); + } + int insertItem(const QPixmap &pix,const QString &szText,int id) + { + return Q3PopupMenu::insertItem(QIcon(pix),szText,id,-1); + } + int insertItem(const QString &szText,const QObject * pReceiver,const char * szSlot) + { + return Q3PopupMenu::insertItem(szText,pReceiver,szSlot); + } + int insertItem(const QPixmap &pix,const QString &szText,const QObject * pReceiver,const char * szSlot) + { + return Q3PopupMenu::insertItem(QIcon(pix),szText,pReceiver,szSlot); + } + int insertItem(const QPixmap &pix,const QString &szText,QMenu *pMenu) + { + return Q3PopupMenu::insertItem(QIcon(pix),szText,pMenu,-1,-1); + } + int insertItem(const QString &szText,QMenu *pMenu) + { + return Q3PopupMenu::insertItem(szText,pMenu,-1,-1); + } + int insertItem(QWidget * pWidget) + { + // needs Qt 4.2 + QWidgetAction * pAct = new QWidgetAction(this); + pAct->setDefaultWidget(pWidget); + addAction(pAct); + return 0; + } + + +}; + +#endif // _KVI_TAL_POPUPMENU_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_scrollview.cpp b/src/kvilib/tal/kvi_tal_scrollview.cpp new file mode 100644 index 00000000..7e3e5eba --- /dev/null +++ b/src/kvilib/tal/kvi_tal_scrollview.cpp @@ -0,0 +1,33 @@ +//============================================================================= +// +// File : kvi_tal_scrollview.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_scrollview.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_scrollview_qt4.moc" +#else + #include "kvi_tal_scrollview_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_scrollview.h b/src/kvilib/tal/kvi_tal_scrollview.h new file mode 100644 index 00000000..ff27acf4 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_scrollview.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_SCROLLVIEW_H_ +#define _KVI_TAL_SCROLLVIEW_H_ + +//============================================================================= +// +// File : kvi_tal_scrollview.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_scrollview_qt4.h" +#else + #include "kvi_tal_scrollview_qt3.h" +#endif + +#endif // _KVI_TAL_SCROLLVIEW_H_ diff --git a/src/kvilib/tal/kvi_tal_scrollview_qt3.h b/src/kvilib/tal/kvi_tal_scrollview_qt3.h new file mode 100644 index 00000000..da6141e1 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_scrollview_qt3.h @@ -0,0 +1,41 @@ +#ifndef _KVI_TAL_SCROLLVIEW_QT3_H_ +#define _KVI_TAL_SCROLLVIEW_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_scrollview_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <qscrollview.h> + +class KVILIB_API KviTalScrollView : public QScrollView +{ + Q_OBJECT +public: + KviTalScrollView(QWidget * pParent) + : QScrollView(pParent) {}; + virtual ~KviTalScrollView() {}; +}; + +#endif // _KVI_TAL_SCROLLVIEW_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_scrollview_qt4.h b/src/kvilib/tal/kvi_tal_scrollview_qt4.h new file mode 100644 index 00000000..c82f5723 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_scrollview_qt4.h @@ -0,0 +1,41 @@ +#ifndef _KVI_TAL_SCROLLVIEW_QT4_H_ +#define _KVI_TAL_SCROLLVIEW_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_scrollview_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <q3scrollview.h> + +class KVILIB_API KviTalScrollView : public Q3ScrollView +{ + Q_OBJECT +public: + KviTalScrollView(QWidget * pParent) + : Q3ScrollView(pParent) {}; + virtual ~KviTalScrollView() {}; +}; + +#endif // _KVI_TAL_SCROLLVIEW_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_tabdialog.cpp b/src/kvilib/tal/kvi_tal_tabdialog.cpp new file mode 100644 index 00000000..81bd5b39 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_tabdialog.cpp @@ -0,0 +1,34 @@ +//============================================================================= +// +// File : kvi_tal_tabdialog.cpp +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_tabdialog.h" + + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_tabdialog_qt4.moc" +#else + #include "kvi_tal_tabdialog_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_tabdialog.h b/src/kvilib/tal/kvi_tal_tabdialog.h new file mode 100644 index 00000000..46e09843 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_tabdialog.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_TABDIALOG_H_ +#define _KVI_TAL_TABDIALOG_H_ + +//============================================================================= +// +// File : kvi_tal_tabdialog.h +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_tabdialog_qt4.h" +#else + #include "kvi_tal_tabdialog_qt3.h" +#endif + +#endif // _KVI_TAL_TABDIALOG_H_ diff --git a/src/kvilib/tal/kvi_tal_tabdialog_qt3.h b/src/kvilib/tal/kvi_tal_tabdialog_qt3.h new file mode 100644 index 00000000..061053a3 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_tabdialog_qt3.h @@ -0,0 +1,39 @@ +#ifndef _KVI_TAL_TABDIALOG_QT3_H_ +#define _KVI_TAL_TABDIALOG_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_tabdialog_qt3.h +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <qtabdialog.h> + +class KVILIB_API KviTalTabDialog : public QTabDialog +{ + Q_OBJECT +public: + KviTalTabDialog(QWidget * pParent = 0,const char * name = 0,bool bModal = false) + : QTabDialog(pParent,name,bModal) {}; + ~KviTalTabDialog() {}; +}; + +#endif // _KVI_TAL_TABDIALOG_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_tabdialog_qt4.h b/src/kvilib/tal/kvi_tal_tabdialog_qt4.h new file mode 100644 index 00000000..c9e3eb0b --- /dev/null +++ b/src/kvilib/tal/kvi_tal_tabdialog_qt4.h @@ -0,0 +1,39 @@ +#ifndef _KVI_TAL_TABDIALOG_QT4_H_ +#define _KVI_TAL_TABDIALOG_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_tabdialog_qt4.h +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <q3tabdialog.h> + +class KVILIB_API KviTalTabDialog : public Q3TabDialog +{ + Q_OBJECT +public: + KviTalTabDialog(QWidget * pParent = 0,const char * name = 0,bool bModal = false) + : Q3TabDialog(pParent,name,bModal) {}; + ~KviTalTabDialog() {}; +}; + +#endif // _KVI_TAL_TABDIALOG_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_textedit.cpp b/src/kvilib/tal/kvi_tal_textedit.cpp new file mode 100644 index 00000000..686c8cba --- /dev/null +++ b/src/kvilib/tal/kvi_tal_textedit.cpp @@ -0,0 +1,34 @@ +//============================================================================= +// +// File : kvi_tal_textedit.cpp +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_textedit.h" + + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_textedit_qt4.moc" +#else + #include "kvi_tal_textedit_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_textedit.h b/src/kvilib/tal/kvi_tal_textedit.h new file mode 100644 index 00000000..fb7381ae --- /dev/null +++ b/src/kvilib/tal/kvi_tal_textedit.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_TEXTEDIT_H_ +#define _KVI_TAL_TEXTEDIT_H_ + +//============================================================================= +// +// File : kvi_tal_textedit.h +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_textedit_qt4.h" +#else + #include "kvi_tal_textedit_qt3.h" +#endif + +#endif // _KVI_TAL_TEXTEDIT_H_ diff --git a/src/kvilib/tal/kvi_tal_textedit_qt3.h b/src/kvilib/tal/kvi_tal_textedit_qt3.h new file mode 100644 index 00000000..b698f483 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_textedit_qt3.h @@ -0,0 +1,39 @@ +#ifndef _KVI_TAL_TEXTEDIT_QT3_H_ +#define _KVI_TAL_TEXTEDIT_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_textedit_qt3.h +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <qtextedit.h> + +class KVILIB_API KviTalTextEdit : public QTextEdit +{ + Q_OBJECT +public: + KviTalTextEdit(QWidget * pParent = 0,const char * name = 0) + : QTextEdit(pParent,name) {}; + ~KviTalTextEdit() {}; +}; + +#endif // _KVI_TAL_TEXTEDIT_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_textedit_qt4.h b/src/kvilib/tal/kvi_tal_textedit_qt4.h new file mode 100644 index 00000000..a3403d7c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_textedit_qt4.h @@ -0,0 +1,39 @@ +#ifndef _KVI_TAL_TEXTEDIT_QT4_H_ +#define _KVI_TAL_TEXTEDIT_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_textedit_qt4.h +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include <q3textedit.h> + +class KVILIB_API KviTalTextEdit : public Q3TextEdit +{ + Q_OBJECT +public: + KviTalTextEdit(QWidget * pParent = 0,const char * name = 0) + : Q3TextEdit(pParent,name) {}; + ~KviTalTextEdit() {}; +}; + +#endif // _KVI_TAL_TEXTEDIT_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_toolbar.cpp b/src/kvilib/tal/kvi_tal_toolbar.cpp new file mode 100644 index 00000000..f54dc973 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_toolbar.cpp @@ -0,0 +1,107 @@ +// +// File : kvi_tal_toolbar.cpp +// Creation date : Mon Aug 13 05:05:45 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#define __KVILIB__ + + +#include "kvi_tal_toolbar.h" + +#ifdef COMPILE_KDE_SUPPORT + + KviTalToolBar::KviTalToolBar(const QString &label,QMainWindow *w,QT_TOOLBARDOCK_TYPE dock,bool bNewLine,const char * nam) + : KToolBar(w,dock,bNewLine,nam) + { + setLabel(label); + } + + KviTalToolBar::~KviTalToolBar() + { + } + + #include "kvi_tal_toolbar_kde.moc" + +#else + + #ifdef COMPILE_USE_QT4 + + KviTalToolBar::KviTalToolBar(const QString &label,QMainWindow *w,QT_TOOLBARDOCK_TYPE dock,bool bNewLine,const char * nam) + //: Q3ToolBar(label,w,dock,bNewLine,nam) + : QToolBar(label,w) + { + //setFrameStyle(QFrame::NoFrame); + setObjectName(nam); + if(!layout()) + this->setLayout(new QBoxLayout(QBoxLayout::LeftToRight)); + w->addToolBar(dock,this); + } + KviTalToolBar::KviTalToolBar(QMainWindow *w,const char * name) + : QToolBar(w) + { + //setFrameStyle(QFrame::NoFrame); + setObjectName(name); + if(!layout()) + this->setLayout(new QBoxLayout(QBoxLayout::LeftToRight)); + w->addToolBar(this); + } + + QBoxLayout * KviTalToolBar::boxLayout() + { + return (QBoxLayout*)this->layout(); + } + + void KviTalToolBar::setBoxLayout(QBoxLayout * l) + { + this->setLayout(l); + } + + bool KviTalToolBar::usesBigPixmaps() + { + return (iconSize().width() > 40); + } + + void KviTalToolBar::setUsesBigPixmaps(bool b) + { + if(b)setIconSize(QSize(48,48)); + else setIconSize(QSize(22,22)); + } + + #include "kvi_tal_toolbar_qt4.moc" + + #else + KviTalToolBar::KviTalToolBar(const QString &label,QMainWindow *w,QT_TOOLBARDOCK_TYPE dock,bool bNewLine,const char * nam) + : QToolBar(label,w,dock,bNewLine,nam) + { + } + KviTalToolBar::KviTalToolBar(QMainWindow *w,const char * name) + : QToolBar(w,name) + { + } + + #include "kvi_tal_toolbar_qt3.moc" + #endif + + KviTalToolBar::~KviTalToolBar() + { + } + + +#endif diff --git a/src/kvilib/tal/kvi_tal_toolbar.h b/src/kvilib/tal/kvi_tal_toolbar.h new file mode 100644 index 00000000..c5c9d5cc --- /dev/null +++ b/src/kvilib/tal/kvi_tal_toolbar.h @@ -0,0 +1,37 @@ +#ifndef _KVI_TAL_TOOLBAR_H_ +#define _KVI_TAL_TOOLBAR_H_ +// +// File : kvi_tal_toolbar.h +// Creation date : Mon Aug 13 05:05:44 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" + +#ifdef COMPILE_KDE_SUPPORT + #include "kvi_tal_toolbar_kde.h" +#else + #ifdef COMPILE_USE_QT4 + #include "kvi_tal_toolbar_qt4.h" + #else + #include "kvi_tal_toolbar_qt3.h" + #endif +#endif + +#endif //_KVI_TAL_TOOLBAR_H_ diff --git a/src/kvilib/tal/kvi_tal_toolbar_kde.h b/src/kvilib/tal/kvi_tal_toolbar_kde.h new file mode 100644 index 00000000..f6415f26 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_toolbar_kde.h @@ -0,0 +1,37 @@ +#ifndef _KVI_TAL_TOOLBAR_KDE_H_ +#define _KVI_TAL_TOOLBAR_KDE_H_ +// +// File : kvi_tal_toolbar_kde.h +// Creation date : Mon Aug 13 05:05:52 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <ktoolbar.h> + +#include "kvi_tal_toolbardocktype.h" + +class KVILIB_API KviTalToolBar : public KToolBar +{ + Q_OBJECT +public: + KviTalToolBar(const QString &label,QMainWindow *w,QT_TOOLBARDOCK_TYPE dock = QT_DOCK_TOP,bool bNewLine = false,const char * nam = 0); + ~KviTalToolBar(); +}; + +#endif //_KVI_TAL_TOOLBAR_KDE_H_ diff --git a/src/kvilib/tal/kvi_tal_toolbar_qt3.h b/src/kvilib/tal/kvi_tal_toolbar_qt3.h new file mode 100644 index 00000000..a9b15b52 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_toolbar_qt3.h @@ -0,0 +1,39 @@ +#ifndef _KVI_TAL_TOOLBAR_QT_H_ +#define _KVI_TAL_TOOLBAR_QT_H_ +// +// File : kvi_tal_toolbar_qt.h +// Creation date : Mon Aug 13 05:05:50 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2001 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include <qtoolbar.h> +#include <qmainwindow.h> + +#include "kvi_tal_toolbardocktype.h" + +class KVILIB_API KviTalToolBar : public QToolBar +{ + Q_OBJECT +public: + KviTalToolBar(const QString &label,QMainWindow *w,QT_TOOLBARDOCK_TYPE dock = QT_DOCK_TOP,bool bNewLine = false,const char * nam = 0); + KviTalToolBar(QMainWindow *w,const char * name=0); + ~KviTalToolBar(); +}; + +#endif //_KVI_TAL_TOOLBAR_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_toolbar_qt4.h b/src/kvilib/tal/kvi_tal_toolbar_qt4.h new file mode 100644 index 00000000..753d5a5c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_toolbar_qt4.h @@ -0,0 +1,47 @@ +#ifndef _KVI_TAL_TOOLBAR_QT4_H_ +#define _KVI_TAL_TOOLBAR_QT4_H_ +// +// File : kvi_tal_toolbar_qt4.h +// Creation date : Wed Feb 1 2007 04:11:11 2001 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +#include "kvi_tal_toolbardocktype.h" + +#include <QToolBar> +#include <QMainWindow> +#include <QBoxLayout> + + +class KVILIB_API KviTalToolBar : public QToolBar +{ + Q_OBJECT +public: + KviTalToolBar(const QString &label,QMainWindow *w,QT_TOOLBARDOCK_TYPE dock = QT_DOCK_TOP,bool bNewLine = false,const char * nam = 0); + KviTalToolBar(QMainWindow *w,const char * name=0); + ~KviTalToolBar(); +public: + QBoxLayout * boxLayout(); + void setBoxLayout(QBoxLayout *l); + bool usesBigPixmaps(); + void setUsesBigPixmaps(bool b); +}; + +#endif //_KVI_TAL_TOOLBAR_QT_H_ diff --git a/src/kvilib/tal/kvi_tal_toolbardocktype.h b/src/kvilib/tal/kvi_tal_toolbardocktype.h new file mode 100644 index 00000000..a7c9697a --- /dev/null +++ b/src/kvilib/tal/kvi_tal_toolbardocktype.h @@ -0,0 +1,71 @@ +#ifndef _KVI_TAL_TOOLBARDOCKTYPE_H_ +#define _KVI_TAL_TOOLBARDOCKTYPE_H_ +// +// File : kvi_tal_toolbardocktype.h +// Creation date : Tue Sep 17 02:11:28 2002 GMT by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2002 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "kvi_settings.h" +//#define COMPILE_USE_QT4 +#ifdef COMPILE_USE_QT4 +/* + #define QT_TOOLBARDOCK_TYPE Qt::Dock + #define QT_DOCK_TOP Qt::DockTop + #define QT_DOCK_LEFT Qt::DockLeft + #define QT_DOCK_RIGHT Qt::DockRight + #define QT_DOCK_BOTTOM Qt::DockBottom + #define QT_DOCK_MINIMIZED Qt::DockMinimized + #define QT_DOCK_TORNOFF Qt::DockTornOff + #define QT_DOCK_UNMANAGED Qt::DockUnmanaged +*/ + // We will need these when we'll use the real QToolBar in Qt 4.x + #define QT_TOOLBARDOCK_TYPE Qt::ToolBarArea + #define QT_DOCK_TOP Qt::TopToolBarArea + #define QT_DOCK_LEFT Qt::LeftToolBarArea + #define QT_DOCK_RIGHT Qt::RightToolBarArea + #define QT_DOCK_BOTTOM Qt::BottomToolBarArea + // THESE ARE UNSUPPORTED UNDER QT4! + #define QT_DOCK_MINIMIZED Qt::TopToolBarArea + #define QT_DOCK_TORNOFF Qt::TopToolBarArea + #define QT_DOCK_UNMANAGED Qt::TopToolBarArea + +#else + #if QT_VERSION >= 300 + #define QT_TOOLBARDOCK_TYPE Qt::Dock + #define QT_DOCK_TOP Qt::DockTop + #define QT_DOCK_LEFT Qt::DockLeft + #define QT_DOCK_RIGHT Qt::DockRight + #define QT_DOCK_BOTTOM Qt::DockBottom + #define QT_DOCK_MINIMIZED Qt::DockMinimized + #define QT_DOCK_TORNOFF Qt::DockTornOff + #define QT_DOCK_UNMANAGED Qt::DockUnmanaged + #else + #define QT_TOOLBARDOCK_TYPE QMainWindow::ToolBarDock + #define QT_DOCK_TOP QMainWindow::Top + #define QT_DOCK_LEFT QMainWindow::Left + #define QT_DOCK_RIGHT QMainWindow::Right + #define QT_DOCK_BOTTOM QMainWindow::Bottom + #define QT_DOCK_MINIMIZED QMainWindow::Minimized + #define QT_DOCK_TORNOFF QMainWindow::TornOff + #define QT_DOCK_UNMANAGED QMainWindow::Unmanaged + #endif +#endif + +#endif //_KVI_TAL_TOOLBARDOCKTYPE_H_ diff --git a/src/kvilib/tal/kvi_tal_tooltip.cpp b/src/kvilib/tal/kvi_tal_tooltip.cpp new file mode 100644 index 00000000..3bd384d2 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_tooltip.cpp @@ -0,0 +1,125 @@ +//============================================================================= +// +// File : kvi_tal_tooltip.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_tooltip.h" + +#include <qevent.h> + +KviTalToolTipHelper::KviTalToolTipHelper(KviTalToolTip * pToolTip,QWidget * pWidget) +: QObject(pWidget) +{ +#ifdef COMPILE_USE_QT4 + m_pToolTip = pToolTip; + pWidget->installEventFilter(this); +#endif +} + +KviTalToolTipHelper::~KviTalToolTipHelper() +{ +#ifdef COMPILE_USE_QT4 + if(m_pToolTip) + { + m_pToolTip->helperDying(); + delete m_pToolTip; + } +#endif +} + +void KviTalToolTipHelper::toolTipDying() +{ +#ifdef COMPILE_USE_QT4 + m_pToolTip = 0; +#endif +} + +bool KviTalToolTipHelper::eventFilter(QObject * pObject,QEvent * pEvent) +{ +#ifdef COMPILE_USE_QT4 + if((pEvent->type() == QEvent::ToolTip) && m_pToolTip) + { + debug("TOOL TIP EVENT WITH POSITION %d,%d",((QHelpEvent *)pEvent)->pos().x(),((QHelpEvent *)pEvent)->pos().y()); + m_pToolTip->maybeTip(((QHelpEvent *)pEvent)->pos()); + return true; + } +#endif + return false; +} + + +KviTalToolTip::KviTalToolTip(QWidget * pParent) +#ifndef COMPILE_USE_QT4 +: QToolTip(pParent) +#endif +{ +#ifdef COMPILE_USE_QT4 + m_pHelper = new KviTalToolTipHelper(this,pParent); + m_pParent = pParent; +#endif +} + +KviTalToolTip::~KviTalToolTip() +{ +#ifdef COMPILE_USE_QT4 + if(m_pHelper) + { + m_pHelper->toolTipDying(); + delete m_pHelper; + } +#endif +} + +#ifdef COMPILE_USE_QT4 +void KviTalToolTip::helperDying() +{ + m_pHelper = 0; +} +#endif + +#ifdef COMPILE_USE_QT4 +void KviTalToolTip::add(QWidget * widget,const QString & text) +{ + QToolTip::add(widget,text); +} + +void KviTalToolTip::remove(QWidget * widget) +{ + QToolTip::remove(widget); +} + +void KviTalToolTip::tip(const QRect & rect,const QString & text) +{ + debug("TOOL TIP AT %d,%d",rect.topLeft().x(),rect.topLeft().y()); + QToolTip::showText(m_pParent->mapToGlobal(rect.topLeft()),text); +} +#endif + +void KviTalToolTip::maybeTip(const QPoint & p) +{ + // does nothing here.. and in Qt 4.x will even fail to work +} + +#ifndef COMPILE_ON_WINDOWS + #include "kvi_tal_tooltip.moc" +#endif diff --git a/src/kvilib/tal/kvi_tal_tooltip.h b/src/kvilib/tal/kvi_tal_tooltip.h new file mode 100644 index 00000000..91811c3c --- /dev/null +++ b/src/kvilib/tal/kvi_tal_tooltip.h @@ -0,0 +1,79 @@ +#ifndef _KVI_TAL_TOOLTIP_H_ +#define _KVI_TAL_TOOLTIP_H_ + +//============================================================================= +// +// File : kvi_tal_tooltip.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <qtooltip.h> +#include <qobject.h> + +class KviTalToolTip; + +// This is useful only with Qt4, but we put it here anyway +// to have both a consistent API and make moc happy +class KviTalToolTipHelper : public QObject +{ + friend class KviTalToolTip; + Q_OBJECT +public: + KviTalToolTipHelper(KviTalToolTip * pToolTip,QWidget * pWidget); + ~KviTalToolTipHelper(); +protected: + KviTalToolTip * m_pToolTip; +protected: + virtual bool eventFilter(QObject * pObject,QEvent * pEvent); + void toolTipDying(); +}; + + +class KVILIB_API KviTalToolTip +#ifndef COMPILE_USE_QT4 + : public QToolTip +#endif +{ + friend class KviTalToolTipHelper; +public: + KviTalToolTip(QWidget * pParent); + virtual ~KviTalToolTip(); +protected: +#ifdef COMPILE_USE_QT4 + KviTalToolTipHelper * m_pHelper; + QWidget * m_pParent; +#endif +public: +#ifdef COMPILE_USE_QT4 + static void add(QWidget * widget,const QString & text); + static void remove(QWidget * widget); + virtual void tip(const QRect & rect,const QString & text); +#endif +protected: + virtual void maybeTip(const QPoint & p); +#ifdef COMPILE_USE_QT4 + void helperDying(); +#endif +}; + +#endif // _KVI_TAL_TOOLTIP_H_ diff --git a/src/kvilib/tal/kvi_tal_vbox.cpp b/src/kvilib/tal/kvi_tal_vbox.cpp new file mode 100644 index 00000000..5ef67152 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_vbox.cpp @@ -0,0 +1,33 @@ +//============================================================================= +// +// File : kvi_tal_vbox.cpp +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_vbox.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_vbox_qt4.moc" +#else + #include "kvi_tal_vbox_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_vbox.h b/src/kvilib/tal/kvi_tal_vbox.h new file mode 100644 index 00000000..a27df527 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_vbox.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_VBOX_H_ +#define _KVI_TAL_VBOX_H_ + +//============================================================================= +// +// File : kvi_tal_vbox.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_vbox_qt4.h" +#else + #include "kvi_tal_vbox_qt3.h" +#endif + +#endif // _KVI_TAL_VBOX_H_ diff --git a/src/kvilib/tal/kvi_tal_vbox_qt3.h b/src/kvilib/tal/kvi_tal_vbox_qt3.h new file mode 100644 index 00000000..440a2436 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_vbox_qt3.h @@ -0,0 +1,42 @@ +#ifndef _KVI_TAL_VBOX_QT3_H_ +#define _KVI_TAL_VBOX_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_vbox_qt3.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <qvbox.h> + +class KVILIB_API KviTalVBox : public QVBox +{ + Q_OBJECT +public: + KviTalVBox(QWidget * pParent) + : QVBox(pParent) {}; + virtual ~KviTalVBox() {}; +}; + + +#endif // _KVI_TAL_VBOX_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_vbox_qt4.h b/src/kvilib/tal/kvi_tal_vbox_qt4.h new file mode 100644 index 00000000..86de700d --- /dev/null +++ b/src/kvilib/tal/kvi_tal_vbox_qt4.h @@ -0,0 +1,42 @@ +#ifndef _KVI_TAL_VBOX_QT4_H_ +#define _KVI_TAL_VBOX_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_vbox_qt4.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <q3vbox.h> + +class KVILIB_API KviTalVBox : public Q3VBox +{ + Q_OBJECT +public: + KviTalVBox(QWidget * pParent) + : Q3VBox(pParent) {}; + virtual ~KviTalVBox() {}; +}; + + +#endif // _KVI_TAL_VBOX_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_widgetstack.cpp b/src/kvilib/tal/kvi_tal_widgetstack.cpp new file mode 100644 index 00000000..1a99e3f9 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_widgetstack.cpp @@ -0,0 +1,33 @@ +//============================================================================= +// +// File : kvi_tal_widgetstack.cpp +// Creation date : Mon Jan 22 2007 11:17:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_widgetstack.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_widgetstack_qt4.moc" +#else + #include "kvi_tal_widgetstack_qt3.moc" +#endif + diff --git a/src/kvilib/tal/kvi_tal_widgetstack.h b/src/kvilib/tal/kvi_tal_widgetstack.h new file mode 100644 index 00000000..7c9133c8 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_widgetstack.h @@ -0,0 +1,36 @@ +#ifndef _KVI_TAL_WIDGETSTACK_H_ +#define _KVI_TAL_WIDGETSTACK_H_ + +//============================================================================= +// +// File : kvi_tal_widgetstack.h +// Creation date : Mon Jan 22 2007 11:17:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include "kvi_tal_widgetstack_qt4.h" +#else + #include "kvi_tal_widgetstack_qt3.h" +#endif + +#endif // _KVI_TAL_WIDGETSTACK_H_ diff --git a/src/kvilib/tal/kvi_tal_widgetstack_qt3.h b/src/kvilib/tal/kvi_tal_widgetstack_qt3.h new file mode 100644 index 00000000..cc0eb969 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_widgetstack_qt3.h @@ -0,0 +1,42 @@ +#ifndef _KVI_TAL_WIDGETSTACK_QT3_H_ +#define _KVI_TAL_WIDGETSTACK_QT3_H_ + +//============================================================================= +// +// File : kvi_tal_widgetstack_qt3.h +// Creation date : Mon Jan 22 2007 11:17:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#include <qwidgetstack.h> + + +class KVILIB_API KviTalWidgetStack : public QWidgetStack +{ + Q_OBJECT +public: + KviTalWidgetStack(QWidget * pParent) + : QWidgetStack(pParent) {}; + virtual ~KviTalWidgetStack() {}; +}; + +#endif // _KVI_TAL_WIDGETSTACK_QT3_H_ diff --git a/src/kvilib/tal/kvi_tal_widgetstack_qt4.h b/src/kvilib/tal/kvi_tal_widgetstack_qt4.h new file mode 100644 index 00000000..6d0cc53f --- /dev/null +++ b/src/kvilib/tal/kvi_tal_widgetstack_qt4.h @@ -0,0 +1,42 @@ +#ifndef _KVI_TAL_WIDGETSTACK_QT4_H_ +#define _KVI_TAL_WIDGETSTACK_QT4_H_ + +//============================================================================= +// +// File : kvi_tal_widgetstack_qt4.h +// Creation date : Mon Jan 22 2007 11:17:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +//#include <qstackedwidget.h> +#include <q3widgetstack.h> + +class KVILIB_API KviTalWidgetStack : public Q3WidgetStack +{ + Q_OBJECT +public: + KviTalWidgetStack(QWidget * pParent) + : Q3WidgetStack(pParent) {}; + virtual ~KviTalWidgetStack() {}; +}; + +#endif // _KVI_TAL_WIDGETSTACK_QT4_H_ diff --git a/src/kvilib/tal/kvi_tal_windowstate.h b/src/kvilib/tal/kvi_tal_windowstate.h new file mode 100644 index 00000000..9510ba4a --- /dev/null +++ b/src/kvilib/tal/kvi_tal_windowstate.h @@ -0,0 +1,42 @@ +#ifndef _KVI_TAL_WINDOWSTATE_H_ +#define _KVI_TAL_WINDOWSTATE_H_ + +//============================================================================= +// +// File : kvi_tal_windowstate.h +// Creation date : Mon Jan 22 2007 11:25:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #define QT_WINDOWSTATE_FLAGS Qt::WindowState + + #define QT_WINDOWSTATE_MAXIMIZED Qt::WindowMaximized + #define QT_WINDOWSTATE_MINIMIZED Qt::WindowMinimized +#else + #define QT_WINDOWSTATE_FLAGS Qt::WidgetState + + #define QT_WINDOWSTATE_MAXIMIZED Qt::WState_Maximized + #define QT_WINDOWSTATE_MINIMIZED Qt::WState_Minimized +#endif + +#endif // _KVI_TAL_WINDOWSTATE_H_ diff --git a/src/kvilib/tal/kvi_tal_wizard.cpp b/src/kvilib/tal/kvi_tal_wizard.cpp new file mode 100644 index 00000000..6f5f39da --- /dev/null +++ b/src/kvilib/tal/kvi_tal_wizard.cpp @@ -0,0 +1,584 @@ +//============================================================================= +// +// File : kvi_tal_wizard.cpp +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#define __KVILIB__ +#include "kvi_tal_wizard.h" +#include "kvi_tal_hbox.h" +#include "kvi_pointerlist.h" +#include "kvi_locale.h" + +#ifdef COMPILE_USE_QT4 + #include <QShowEvent> + #include <QLabel> + #include <QPushButton> + #include <QGridLayout> + #include <QFrame> + #include <QStackedWidget> + #include <QPalette> +#else + #include <qlabel.h> + #include <qpushbutton.h> + #include <qlayout.h> + #include <qevent.h> + #include <qframe.h> + #include <qwidgetstack.h> + #include <qpalette.h> +#endif + + +class KviTalWizardPageData +{ +public: + enum EnableFlags + { + EnableNext = 1, + EnableBack = 2, + EnableHelp = 4, + EnableCancel = 8, + EnableFinish = 16 + }; +public: + QWidget * pWidget; + QString szTitle; + bool bEnabled; + int iEnableFlags; + int iVisibleIndex; +}; + +class KviTalWizardPrivate +{ +public: + KviPointerList<KviTalWizardPageData> * pPageList; + int iEnabledPageCount; + KviTalWizardPageData * pCurrentPage; + QGridLayout * pLayout; + QLabel * pTitleLabel; + QLabel * pStepsLabel; + QPushButton * pBackButton; + QPushButton * pCancelButton; + QPushButton * pHelpButton; + QPushButton * pNextButton; + QWidget * pNextSpacer; + QPushButton * pFinishButton; + QWidget * pFinishSpacer; +#ifdef COMPILE_USE_QT4 + QStackedWidget * pWidgetStack; +#else + QWidgetStack * pWidgetStack; +#endif +public: + KviTalWizardPageData * findPage(QWidget * pWidget) + { + for(KviTalWizardPageData * pData = pPageList->first();pData;pData = pPageList->next()) + { + if(pData->pWidget == pWidget) + return pData; + } + return NULL; + } + + KviTalWizardPageData * findFirstEnabledPage() + { + KviTalWizardPageData * pData; + for(pData = pPageList->first();pData;pData = pPageList->next()) + { + if(pData->bEnabled) + return pData; + } + return NULL; + } + + KviTalWizardPageData * findLastEnabledPage() + { + KviTalWizardPageData * pData; + for(pData = pPageList->last();pData;pData = pPageList->prev()) + { + if(pData->bEnabled) + return pData; + } + return NULL; + } + + KviTalWizardPageData * findNextEnabledPage(QWidget * pReference) + { + if(!pReference) + return findFirstEnabledPage(); + KviTalWizardPageData * pData = findPage(pReference); + if(!pData) + return NULL; + for(pData = pPageList->next();pData;pData = pPageList->next()) + { + if(pData->bEnabled) + return pData; + } + return NULL; + } + + KviTalWizardPageData * findPrevEnabledPage(QWidget * pReference) + { + if(!pReference) + return findLastEnabledPage(); + KviTalWizardPageData * pData = findPage(pReference); + if(!pData) + return NULL; + for(pData = pPageList->prev();pData;pData = pPageList->prev()) + { + if(pData->bEnabled) + return pData; + } + return NULL; + } + + int reindexPages() + { + int iEnabledCount = 0; + for(KviTalWizardPageData * pData = pPageList->next();pData;pData = pPageList->next()) + { + if(pData->bEnabled) + { + iEnabledCount++; + pData->iVisibleIndex = iEnabledCount; + } + } + return iEnabledCount; + } +}; + + +KviTalWizard::KviTalWizard(QWidget * pParent) +: QDialog(pParent) +{ + m_p = new KviTalWizardPrivate; + m_p->pPageList = new KviPointerList<KviTalWizardPageData>; + m_p->pPageList->setAutoDelete(true); + m_p->pCurrentPage = NULL; + m_p->iEnabledPageCount = 0; + m_p->pLayout = new QGridLayout(this); + + m_p->pTitleLabel = new QLabel(this); +#ifdef COMPILE_USE_QT4 + m_p->pLayout->addWidget(m_p->pTitleLabel,0,0,1,3); +#else + m_p->pLayout->addMultiCellWidget(m_p->pTitleLabel,0,0,0,3); +#endif + m_p->pStepsLabel = new QLabel(this); + m_p->pStepsLabel->setMinimumWidth(80); + m_p->pStepsLabel->setAlignment(Qt::AlignRight); +#ifdef COMPILE_USE_QT4 + m_p->pLayout->addWidget(m_p->pStepsLabel,0,4,1,3); +#else + m_p->pLayout->addMultiCellWidget(m_p->pStepsLabel,0,0,4,6); +#endif + + QFrame * f1 = new QFrame(this); + f1->setFrameStyle(QFrame::Sunken | QFrame::HLine); +#ifdef COMPILE_USE_QT4 + m_p->pLayout->addWidget(f1,1,0,1,7); +#else + m_p->pLayout->addMultiCellWidget(f1,1,1,0,6); +#endif + +#ifdef COMPILE_USE_QT4 + m_p->pWidgetStack = new QStackedWidget(this); + m_p->pLayout->addWidget(m_p->pWidgetStack,2,0,1,7); +#else + m_p->pWidgetStack = new QWidgetStack(this); + m_p->pLayout->addMultiCellWidget(m_p->pWidgetStack,2,2,0,6); +#endif + + QFrame * f2 = new QFrame(this); + f2->setFrameStyle(QFrame::Sunken | QFrame::HLine); +#ifdef COMPILE_USE_QT4 + m_p->pLayout->addWidget(f2,3,0,1,7); +#else + m_p->pLayout->addMultiCellWidget(f2,3,3,0,6); +#endif + + KviTalHBox * pButtonBox = new KviTalHBox(this); +#ifdef COMPILE_USE_QT4 + m_p->pLayout->addWidget(pButtonBox,4,0,1,7); +#else + m_p->pLayout->addMultiCellWidget(pButtonBox,4,4,0,6); +#endif + + pButtonBox->setMargin(0); + pButtonBox->setSpacing(0); + + + m_p->pCancelButton = new QPushButton(__tr("Cancel"),pButtonBox); + m_p->pCancelButton->setMinimumWidth(80); + QObject::connect( + m_p->pCancelButton, + SIGNAL(clicked()), + this, + SLOT(cancelButtonClicked()) + ); + + QWidget * pSpacer = new QWidget(pButtonBox); + pSpacer->setFixedWidth(4); + + m_p->pHelpButton = new QPushButton(__tr("Help"),pButtonBox); + m_p->pHelpButton->setMinimumWidth(80); + QObject::connect( + m_p->pHelpButton, + SIGNAL(clicked()), + this, + SLOT(helpButtonClicked()) + ); + + QWidget * pLargeSpacer = new QWidget(pButtonBox); + pLargeSpacer->setMinimumWidth(50); + pButtonBox->setStretchFactor(pLargeSpacer,100); + + QString szText = "< "; + szText += __tr("Back"); + m_p->pBackButton = new QPushButton(szText,pButtonBox); + m_p->pBackButton->setMinimumWidth(80); + QObject::connect( + m_p->pBackButton, + SIGNAL(clicked()), + this, + SLOT(backButtonClicked()) + ); + + m_p->pNextSpacer = new QWidget(pButtonBox); + m_p->pNextSpacer->setFixedWidth(4); + + szText = __tr("Next"); + szText += " >"; + m_p->pNextButton = new QPushButton(szText,pButtonBox); + m_p->pNextButton->setMinimumWidth(80); + QObject::connect( + m_p->pNextButton, + SIGNAL(clicked()), + this, + SLOT(nextButtonClicked()) + ); + + m_p->pFinishSpacer = new QWidget(pButtonBox); + m_p->pFinishSpacer->setFixedWidth(4); + + m_p->pFinishButton = new QPushButton(__tr("Finish"),pButtonBox); + m_p->pFinishButton->setMinimumWidth(80); + QObject::connect( + m_p->pFinishButton, + SIGNAL(clicked()), + this, + SLOT(finishButtonClicked()) + ); + + m_p->pLayout->setMargin(8); + m_p->pLayout->setSpacing(4); + m_p->pLayout->setRowStretch(2,1); + m_p->pLayout->setColStretch(0,1); +} + +KviTalWizard::~KviTalWizard() +{ + delete m_p->pPageList; + delete m_p; +} + +void KviTalWizard::insertPage(QWidget * pWidget,const QString &szTitle,int iIndex) +{ + KviTalWizardPageData * pPageData = m_p->findPage(pWidget); + if(!pPageData) + { + pPageData = new KviTalWizardPageData; + pPageData->pWidget = pWidget; + pPageData->iEnableFlags = \ + KviTalWizardPageData::EnableNext | \ + KviTalWizardPageData::EnableCancel | \ + KviTalWizardPageData::EnableBack; + if(iIndex < 0) + { + m_p->pPageList->append(pPageData); + m_p->iEnabledPageCount++; + pPageData->iVisibleIndex = m_p->iEnabledPageCount; + } else { + m_p->pPageList->insert(iIndex,pPageData); + m_p->iEnabledPageCount = m_p->reindexPages(); + } + m_p->pWidgetStack->addWidget(pWidget); + } + pPageData->szTitle = szTitle; + pPageData->bEnabled = true; + +} + +void KviTalWizard::addPage(QWidget * pWidget,const QString &szTitle) +{ + insertPage(pWidget,szTitle,-1); +} + +bool KviTalWizard::setPageEnabled(QWidget * pWidget,bool bEnabled) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return false; + pData->bEnabled = bEnabled; + m_p->iEnabledPageCount = m_p->reindexPages(); + setCurrentPage(m_p->pCurrentPage); + return true; +} + +bool KviTalWizard::setPageTitle(QWidget * pWidget,const QString &szTitle) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return false; + pData->szTitle = szTitle; + return true; +} + +bool KviTalWizard::setCurrentPage(QWidget * pWidget) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return false; + setCurrentPage(pData); + return true; +} + +QWidget * KviTalWizard::currentPage() +{ + if(!m_p->pCurrentPage) + return NULL; + return m_p->pCurrentPage->pWidget; +} + +void KviTalWizard::setCurrentPage(KviTalWizardPageData * pData) +{ + m_p->pCurrentPage = pData; + + bool bCancelEnabled = true; + bool bNextEnabled = false; + bool bBackEnabled = false; + bool bHelpEnabled = false; + bool bFinishEnabled = false; + + QString szTitle; + QString szSteps; + + if(pData) + { + bNextEnabled = (pData->iEnableFlags & KviTalWizardPageData::EnableNext) && m_p->findNextEnabledPage(pData->pWidget); + bBackEnabled = (pData->iEnableFlags & KviTalWizardPageData::EnableBack) && m_p->findPrevEnabledPage(pData->pWidget); + bCancelEnabled = (pData->iEnableFlags & KviTalWizardPageData::EnableCancel); + bFinishEnabled = (pData->iEnableFlags & KviTalWizardPageData::EnableFinish); + bHelpEnabled = (pData->iEnableFlags & KviTalWizardPageData::EnableHelp); +#ifdef COMPILE_USE_QT4 + m_p->pWidgetStack->setCurrentWidget(pData->pWidget); +#else + m_p->pWidgetStack->raiseWidget(pData->pWidget); +#endif + szTitle = "<b>"; + szTitle += pData->szTitle; + szTitle += "</b>"; + QPalette pal = m_p->pStepsLabel->palette(); +#ifdef COMPILE_USE_QT4 + QColor clrWin = pal.color(QPalette::Normal,QPalette::Window); + QColor clrTxt = pal.color(QPalette::Normal,QPalette::WindowText); +#else + QColor clrWin = pal.color(QPalette::Normal,QColorGroup::Foreground); + QColor clrTxt = pal.color(QPalette::Normal,QColorGroup::Background); +#endif + QColor clrMid = qRgb( + (clrWin.red() + clrTxt.red()) / 2, + (clrWin.green() + clrTxt.green()) / 2, + (clrWin.blue() + clrTxt.blue()) / 2 + ); + + szSteps = "<nobr><font color=\""; + szSteps += clrMid.name(); + szSteps += "\"><b>["; + szSteps += QString("Step %1 of %2").arg(pData->iVisibleIndex).arg(m_p->iEnabledPageCount); + szSteps += "]</b></font></nobr>"; + } + + m_p->pTitleLabel->setText(szTitle); + m_p->pStepsLabel->setText(szSteps); + + m_p->pNextButton->setEnabled(bNextEnabled); + if(bNextEnabled) + { + m_p->pNextButton->show(); + m_p->pNextSpacer->show(); + } else { + m_p->pNextButton->hide(); + m_p->pNextSpacer->hide(); + } + m_p->pBackButton->setEnabled(bBackEnabled); + m_p->pHelpButton->setEnabled(bHelpEnabled); + if(bHelpEnabled) + m_p->pHelpButton->show(); + else + m_p->pHelpButton->hide(); + m_p->pCancelButton->setEnabled(bCancelEnabled); + m_p->pFinishButton->setEnabled(bFinishEnabled); + if(bFinishEnabled) + { + m_p->pFinishButton->show(); + m_p->pFinishSpacer->show(); + } else { + m_p->pFinishButton->hide(); + m_p->pFinishSpacer->hide(); + } +} + +void KviTalWizard::showEvent(QShowEvent * e) +{ + if(!(m_p->pCurrentPage)) + { + // display the first page + KviTalWizardPageData * pData = m_p->findFirstEnabledPage(); + if(pData) + setCurrentPage(pData->pWidget); + } + QDialog::showEvent(e); +} + +void KviTalWizard::closeEvent(QCloseEvent * e) +{ + e->ignore(); + cancelButtonClicked(); +} + +void KviTalWizard::backButtonClicked() +{ + if(!m_p->pCurrentPage) + return; + setCurrentPage(m_p->findPrevEnabledPage(m_p->pCurrentPage->pWidget)); +} + +void KviTalWizard::nextButtonClicked() +{ + setCurrentPage(m_p->findNextEnabledPage(m_p->pCurrentPage->pWidget)); +} + +void KviTalWizard::helpButtonClicked() +{ + emit helpClicked(); +} + +void KviTalWizard::cancelButtonClicked() +{ + reject(); +} + +void KviTalWizard::finishButtonClicked() +{ + accept(); +} + +void KviTalWizard::setHelpEnabled(QWidget * pWidget,bool bEnabled) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return; + if(bEnabled) + pData->iEnableFlags |= KviTalWizardPageData::EnableHelp; + else + pData->iEnableFlags &= ~KviTalWizardPageData::EnableHelp; + if(pData == m_p->pCurrentPage) + setCurrentPage(pData); +} + +void KviTalWizard::setCancelEnabled(QWidget * pWidget,bool bEnabled) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return; + if(bEnabled) + pData->iEnableFlags |= KviTalWizardPageData::EnableCancel; + else + pData->iEnableFlags &= ~KviTalWizardPageData::EnableCancel; + if(pData == m_p->pCurrentPage) + setCurrentPage(pData); +} + +void KviTalWizard::setFinishEnabled(QWidget * pWidget,bool bEnabled) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return; + if(bEnabled) + pData->iEnableFlags |= KviTalWizardPageData::EnableFinish; + else + pData->iEnableFlags &= ~KviTalWizardPageData::EnableFinish; + if(pData == m_p->pCurrentPage) + setCurrentPage(pData); +} + +void KviTalWizard::setNextEnabled(QWidget * pWidget,bool bEnabled) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return; + if(bEnabled) + pData->iEnableFlags |= KviTalWizardPageData::EnableNext; + else + pData->iEnableFlags &= ~KviTalWizardPageData::EnableNext; + if(pData == m_p->pCurrentPage) + setCurrentPage(pData); +} + +void KviTalWizard::setBackEnabled(QWidget * pWidget,bool bEnabled) +{ + KviTalWizardPageData * pData = m_p->findPage(pWidget); + if(!pData) + return; + if(bEnabled) + pData->iEnableFlags |= KviTalWizardPageData::EnableBack; + else + pData->iEnableFlags &= ~KviTalWizardPageData::EnableBack; + if(pData == m_p->pCurrentPage) + setCurrentPage(pData); +} + +QPushButton * KviTalWizard::cancelButton() +{ + return m_p->pCancelButton; +} + +QPushButton * KviTalWizard::helpButton() +{ + return m_p->pHelpButton; +} + +QPushButton * KviTalWizard::finishButton() +{ + return m_p->pFinishButton; +} + +QPushButton * KviTalWizard::nextButton() +{ + return m_p->pNextButton; +} + +QPushButton * KviTalWizard::backButton() +{ + return m_p->pBackButton; +} + diff --git a/src/kvilib/tal/kvi_tal_wizard.h b/src/kvilib/tal/kvi_tal_wizard.h new file mode 100644 index 00000000..f84e3555 --- /dev/null +++ b/src/kvilib/tal/kvi_tal_wizard.h @@ -0,0 +1,169 @@ +#ifndef _KVI_TAL_WIZARD_H_ +#define _KVI_TAL_WIZARD_H_ + +//============================================================================= +// +// File : kvi_tal_wizard.h +// Creation date : Tue Feb 06 2007 14:35:08 by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 2007 Szymon Stefanek (pragma at kvirc dot net) +// +// 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 opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +#include "kvi_settings.h" + +#ifdef COMPILE_USE_QT4 + #include <QDialog> +#else + #include <qdialog.h> +#endif + +class QShowEvent; +class QPushButton; +class KviTalWizardPrivate; +class KviTalWizardPageData; + +/// +/// \class KviTalWizard +/// +/// \brief Provides a wizard-style dialog with steps +/// +class KVILIB_API KviTalWizard : public QDialog +{ + Q_OBJECT +public: + KviTalWizard(QWidget * pParent); + ~KviTalWizard(); +protected: + KviTalWizardPrivate * m_p; +public: + /// + /// Adds a page to the wizard with the specified title. + /// The pages are displayed in order they're added. + /// Adding a page a second time is equivalent to calling + /// setPageTitle() and enabling the page. + /// + void addPage(QWidget * pWidget,const QString &szTitle); + /// + /// Adds a page to the wizard with the specified title + /// and in the specified position. + /// Adding a page a second time is equivalent to calling + /// setPageTitle() and enabling the page. + /// + void insertPage(QWidget * pWidget,const QString &szTitle,int iIndex); + /// + /// Enables or disables a page. A disabled page + /// is skipped when the user presses "Next" in the + /// previous page or "Back" in the page after. + /// Disabling the current page has no effect. + /// + /// Returns true on success or false if the pWidget + /// does not identify a page that has been added to this wizard. + /// + bool setPageEnabled(QWidget * pWidget,bool bEnabled); + /// + /// Changes a page title. + /// + /// Returns true on success or false if the pWidget + /// does not identify a page that has been added to this wizard. + /// + bool setPageTitle(QWidget * pWidget,const QString &szTitle); + /// + /// Switches the wizard to the specified page. + /// Please note that this class handles page switching + /// automatically so you usually don't need to call this function. + /// + /// Returns true on success or false if the pWidget + /// does not identify a page that has been added to this wizard. + /// + bool setCurrentPage(QWidget * pWidget); + /// + /// Returns a pointer to the current page + /// + QWidget * currentPage(); + /// + /// Enables or disables the help button for the specified page. + /// By default the help button is always disabled. + /// + void setHelpEnabled(QWidget * pWidget,bool bEnabled); + /// + /// Enables or disables the cancel button for the specified page. + /// By default the cancel button is always enabled. + /// + void setCancelEnabled(QWidget * pWidget,bool bEnabled); + /// + /// Enables or disables the finish button for the specified page. + /// By default the finish button is always disabled. + /// + void setFinishEnabled(QWidget * pWidget,bool bEnabled); + /// + /// Enables or disables the next button for the specified page. + /// By default the next button is always enabled. + /// + void setNextEnabled(QWidget * pWidget,bool bEnabled); + /// + /// Enables or disables the prev button for the specified page. + /// By default the prev button is always enabled. + /// + void setBackEnabled(QWidget * pWidget,bool bEnabled); + /// + /// Returns a pointer to the cancel button displayed in the dialog. + /// + QPushButton * cancelButton(); + /// + /// Returns a pointer to the help button displayed in the dialog. + /// + QPushButton * helpButton(); + /// + /// Returns a pointer to the finish button displayed in the dialog. + /// + QPushButton * finishButton(); + /// + /// Returns a pointer to the next button displayed in the dialog. + /// + QPushButton * nextButton(); + /// + /// Returns a pointer to the back button displayed in the dialog. + /// + QPushButton * backButton(); +signals: + /// + /// Emitted when the help button is clicked. + /// + void helpClicked(); +protected: + /// + /// Displays the first page if no other page is shown yet. + /// + virtual void showEvent(QShowEvent * e); + /// + /// Handles redirects the close button to the "cancel" operation. + /// + virtual void closeEvent(QCloseEvent * e); +protected: + void setCurrentPage(KviTalWizardPageData * pData); +protected slots: + void backButtonClicked(); + void nextButtonClicked(); + void helpButtonClicked(); + void cancelButtonClicked(); + void finishButtonClicked(); +}; + + +#endif // _KVI_TAL_WIZARD_H_ diff --git a/src/kvilib/tal/moc_kvi_tal_wizard.cpp b/src/kvilib/tal/moc_kvi_tal_wizard.cpp new file mode 100644 index 00000000..0ad29754 --- /dev/null +++ b/src/kvilib/tal/moc_kvi_tal_wizard.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** KviTalWizard meta object code from reading C++ file 'kvi_tal_wizard.h' +** +** Created: Sun Mar 23 20:56:27 2008 +** by: The Qt MOC ($Id: qt/moc_yacc.cpp 3.3.8 edited Feb 2 14:59 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#undef QT_NO_COMPAT +#include "kvi_tal_wizard.h" +#include <qmetaobject.h> +#include <qapplication.h> + +#include <private/qucomextra_p.h> +#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != 26) +#error "This file was generated using the moc from 3.3.8. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +const char *KviTalWizard::className() const +{ + return "KviTalWizard"; +} + +QMetaObject *KviTalWizard::metaObj = 0; +static QMetaObjectCleanUp cleanUp_KviTalWizard( "KviTalWizard", &KviTalWizard::staticMetaObject ); + +#ifndef QT_NO_TRANSLATION +QString KviTalWizard::tr( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviTalWizard", s, c, QApplication::DefaultCodec ); + else + return QString::fromLatin1( s ); +} +#ifndef QT_NO_TRANSLATION_UTF8 +QString KviTalWizard::trUtf8( const char *s, const char *c ) +{ + if ( qApp ) + return qApp->translate( "KviTalWizard", s, c, QApplication::UnicodeUTF8 ); + else + return QString::fromUtf8( s ); +} +#endif // QT_NO_TRANSLATION_UTF8 + +#endif // QT_NO_TRANSLATION + +QMetaObject* KviTalWizard::staticMetaObject() +{ + if ( metaObj ) + return metaObj; + QMetaObject* parentObject = QDialog::staticMetaObject(); + static const QUMethod slot_0 = {"backButtonClicked", 0, 0 }; + static const QUMethod slot_1 = {"nextButtonClicked", 0, 0 }; + static const QUMethod slot_2 = {"helpButtonClicked", 0, 0 }; + static const QUMethod slot_3 = {"cancelButtonClicked", 0, 0 }; + static const QUMethod slot_4 = {"finishButtonClicked", 0, 0 }; + static const QMetaData slot_tbl[] = { + { "backButtonClicked()", &slot_0, QMetaData::Protected }, + { "nextButtonClicked()", &slot_1, QMetaData::Protected }, + { "helpButtonClicked()", &slot_2, QMetaData::Protected }, + { "cancelButtonClicked()", &slot_3, QMetaData::Protected }, + { "finishButtonClicked()", &slot_4, QMetaData::Protected } + }; + static const QUMethod signal_0 = {"helpClicked", 0, 0 }; + static const QMetaData signal_tbl[] = { + { "helpClicked()", &signal_0, QMetaData::Public } + }; + metaObj = QMetaObject::new_metaobject( + "KviTalWizard", parentObject, + slot_tbl, 5, + signal_tbl, 1, +#ifndef QT_NO_PROPERTIES + 0, 0, + 0, 0, +#endif // QT_NO_PROPERTIES + 0, 0 ); + cleanUp_KviTalWizard.setMetaObject( metaObj ); + return metaObj; +} + +void* KviTalWizard::qt_cast( const char* clname ) +{ + if ( !qstrcmp( clname, "KviTalWizard" ) ) + return this; + return QDialog::qt_cast( clname ); +} + +// SIGNAL helpClicked +void KviTalWizard::helpClicked() +{ + activate_signal( staticMetaObject()->signalOffset() + 0 ); +} + +bool KviTalWizard::qt_invoke( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->slotOffset() ) { + case 0: backButtonClicked(); break; + case 1: nextButtonClicked(); break; + case 2: helpButtonClicked(); break; + case 3: cancelButtonClicked(); break; + case 4: finishButtonClicked(); break; + default: + return QDialog::qt_invoke( _id, _o ); + } + return TRUE; +} + +bool KviTalWizard::qt_emit( int _id, QUObject* _o ) +{ + switch ( _id - staticMetaObject()->signalOffset() ) { + case 0: helpClicked(); break; + default: + return QDialog::qt_emit(_id,_o); + } + return TRUE; +} +#ifndef QT_NO_PROPERTIES + +bool KviTalWizard::qt_property( int id, int f, QVariant* v) +{ + return QDialog::qt_property( id, f, v); +} + +bool KviTalWizard::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; } +#endif // QT_NO_PROPERTIES |