summaryrefslogtreecommitdiffstats
path: root/src/kvilib
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 02:13:59 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 02:13:59 +0000
commita6d58bb6052ac8cb01805a48c4ad2f129126116f (patch)
treedd867a099fcbb263a8009a9fb22695b87855dad6 /src/kvilib
downloadkvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.tar.gz
kvirc-a6d58bb6052ac8cb01805a48c4ad2f129126116f.zip
Added KDE3 version of kvirc
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kvirc@1095341 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/kvilib')
-rw-r--r--src/kvilib/Makefile.am5
-rw-r--r--src/kvilib/build/Makefile.am339
-rw-r--r--src/kvilib/config/Makefile.am5
-rw-r--r--src/kvilib/config/kvi_confignames.h61
-rw-r--r--src/kvilib/config/kvi_debug.h52
-rw-r--r--src/kvilib/config/kvi_defaults.h65
-rw-r--r--src/kvilib/config/kvi_fileextensions.h37
-rw-r--r--src/kvilib/config/kvi_settings.h140
-rw-r--r--src/kvilib/config/kvi_sourcesdate.h40
-rw-r--r--src/kvilib/config/kvi_version.h33
-rw-r--r--src/kvilib/config/kvi_wincfg.h210
-rw-r--r--src/kvilib/core/Makefile.am5
-rw-r--r--src/kvilib/core/kvi_bswap.h63
-rw-r--r--src/kvilib/core/kvi_error.cpp237
-rw-r--r--src/kvilib/core/kvi_error.h188
-rw-r--r--src/kvilib/core/kvi_heapobject.cpp96
-rw-r--r--src/kvilib/core/kvi_heapobject.h50
-rw-r--r--src/kvilib/core/kvi_inttypes.h95
-rw-r--r--src/kvilib/core/kvi_malloc.cpp198
-rw-r--r--src/kvilib/core/kvi_malloc.h88
-rw-r--r--src/kvilib/core/kvi_memmove.cpp253
-rw-r--r--src/kvilib/core/kvi_memmove.h105
-rw-r--r--src/kvilib/core/kvi_pointerhashtable.h999
-rw-r--r--src/kvilib/core/kvi_pointerlist.h1069
-rw-r--r--src/kvilib/core/kvi_qcstring.h39
-rw-r--r--src/kvilib/core/kvi_qstring.cpp1125
-rw-r--r--src/kvilib/core/kvi_qstring.h293
-rw-r--r--src/kvilib/core/kvi_strasm.h194
-rw-r--r--src/kvilib/core/kvi_string.cpp3063
-rw-r--r--src/kvilib/core/kvi_string.h552
-rw-r--r--src/kvilib/core/kvi_stringarray.cpp119
-rw-r--r--src/kvilib/core/kvi_stringarray.h55
-rw-r--r--src/kvilib/core/kvi_valuelist.h37
-rw-r--r--src/kvilib/ext/Makefile.am5
-rw-r--r--src/kvilib/ext/kvi_accel.h38
-rw-r--r--src/kvilib/ext/kvi_cmdformatter.cpp242
-rw-r--r--src/kvilib/ext/kvi_cmdformatter.h64
-rw-r--r--src/kvilib/ext/kvi_config.cpp1007
-rw-r--r--src/kvilib/ext/kvi_config.h162
-rw-r--r--src/kvilib/ext/kvi_crypt.cpp240
-rw-r--r--src/kvilib/ext/kvi_crypt.h160
-rw-r--r--src/kvilib/ext/kvi_databuffer.cpp135
-rw-r--r--src/kvilib/ext/kvi_databuffer.h56
-rw-r--r--src/kvilib/ext/kvi_dcophelper.cpp357
-rw-r--r--src/kvilib/ext/kvi_dcophelper.h82
-rw-r--r--src/kvilib/ext/kvi_doublebuffer.cpp90
-rw-r--r--src/kvilib/ext/kvi_doublebuffer.h62
-rw-r--r--src/kvilib/ext/kvi_draganddrop.h45
-rw-r--r--src/kvilib/ext/kvi_garbage.cpp148
-rw-r--r--src/kvilib/ext/kvi_garbage.h51
-rw-r--r--src/kvilib/ext/kvi_imagelib.cpp138
-rw-r--r--src/kvilib/ext/kvi_imagelib.h73
-rw-r--r--src/kvilib/ext/kvi_md5.cpp298
-rw-r--r--src/kvilib/ext/kvi_md5.h68
-rw-r--r--src/kvilib/ext/kvi_mediatype.cpp541
-rw-r--r--src/kvilib/ext/kvi_mediatype.h83
-rw-r--r--src/kvilib/ext/kvi_miscutils.cpp86
-rw-r--r--src/kvilib/ext/kvi_miscutils.h44
-rw-r--r--src/kvilib/ext/kvi_msgtype.cpp68
-rw-r--r--src/kvilib/ext/kvi_msgtype.h74
-rw-r--r--src/kvilib/ext/kvi_osinfo.cpp510
-rw-r--r--src/kvilib/ext/kvi_osinfo.h43
-rw-r--r--src/kvilib/ext/kvi_parameterlist.cpp254
-rw-r--r--src/kvilib/ext/kvi_parameterlist.h72
-rw-r--r--src/kvilib/ext/kvi_pixmap.cpp180
-rw-r--r--src/kvilib/ext/kvi_pixmap.h61
-rw-r--r--src/kvilib/ext/kvi_proxydb.cpp192
-rw-r--r--src/kvilib/ext/kvi_proxydb.h86
-rw-r--r--src/kvilib/ext/kvi_regchan.cpp181
-rw-r--r--src/kvilib/ext/kvi_regchan.h74
-rw-r--r--src/kvilib/ext/kvi_regusersdb.cpp743
-rw-r--r--src/kvilib/ext/kvi_regusersdb.h201
-rw-r--r--src/kvilib/ext/kvi_sharedfiles.cpp391
-rw-r--r--src/kvilib/ext/kvi_sharedfiles.h133
-rw-r--r--src/kvilib/ext/kvi_stringconversion.cpp277
-rw-r--r--src/kvilib/ext/kvi_stringconversion.h91
-rw-r--r--src/kvilib/ext/kvi_xlib.h45
-rw-r--r--src/kvilib/ext/moc_kvi_crypt.cpp94
-rw-r--r--src/kvilib/ext/moc_kvi_garbage.cpp104
-rw-r--r--src/kvilib/ext/moc_kvi_regusersdb.cpp143
-rw-r--r--src/kvilib/ext/moc_kvi_sharedfiles.cpp157
-rw-r--r--src/kvilib/file/Makefile.am5
-rw-r--r--src/kvilib/file/kvi_file.cpp256
-rw-r--r--src/kvilib/file/kvi_file.h120
-rw-r--r--src/kvilib/file/kvi_fileutils.cpp505
-rw-r--r--src/kvilib/file/kvi_fileutils.h112
-rw-r--r--src/kvilib/file/kvi_packagefile.cpp1028
-rw-r--r--src/kvilib/file/kvi_packagefile.h142
-rw-r--r--src/kvilib/include/Makefile.am4
-rw-r--r--src/kvilib/irc/Makefile.am5
-rw-r--r--src/kvilib/irc/kvi_avatar.cpp165
-rw-r--r--src/kvilib/irc/kvi_avatar.h83
-rw-r--r--src/kvilib/irc/kvi_avatarcache.cpp250
-rw-r--r--src/kvilib/irc/kvi_avatarcache.h69
-rw-r--r--src/kvilib/irc/kvi_ircmask.cpp760
-rw-r--r--src/kvilib/irc/kvi_ircmask.h164
-rw-r--r--src/kvilib/irc/kvi_ircserver.cpp373
-rw-r--r--src/kvilib/irc/kvi_ircserver.h206
-rw-r--r--src/kvilib/irc/kvi_ircserverdb.cpp646
-rw-r--r--src/kvilib/irc/kvi_ircserverdb.h116
-rw-r--r--src/kvilib/irc/kvi_ircuserdb.cpp285
-rw-r--r--src/kvilib/irc/kvi_ircuserdb.h145
-rw-r--r--src/kvilib/irc/kvi_mirccntrl.cpp307
-rw-r--r--src/kvilib/irc/kvi_mirccntrl.h163
-rw-r--r--src/kvilib/irc/kvi_nickserv.cpp312
-rw-r--r--src/kvilib/irc/kvi_nickserv.h112
-rw-r--r--src/kvilib/irc/kvi_useridentity.cpp252
-rw-r--r--src/kvilib/irc/kvi_useridentity.h145
-rw-r--r--src/kvilib/irc/moc_kvi_ircuserdb.cpp119
-rw-r--r--src/kvilib/net/Makefile.am5
-rw-r--r--src/kvilib/net/kvi_dns.cpp450
-rw-r--r--src/kvilib/net/kvi_dns.h142
-rw-r--r--src/kvilib/net/kvi_http.cpp1440
-rw-r--r--src/kvilib/net/kvi_http.h209
-rw-r--r--src/kvilib/net/kvi_netutils.cpp1504
-rw-r--r--src/kvilib/net/kvi_netutils.h104
-rw-r--r--src/kvilib/net/kvi_socket.cpp31
-rw-r--r--src/kvilib/net/kvi_socket.h356
-rw-r--r--src/kvilib/net/kvi_sockettype.h45
-rw-r--r--src/kvilib/net/kvi_ssl.cpp687
-rw-r--r--src/kvilib/net/kvi_ssl.h180
-rw-r--r--src/kvilib/net/kvi_url.cpp164
-rw-r--r--src/kvilib/net/kvi_url.h63
-rw-r--r--src/kvilib/net/moc_kvi_dns.cpp137
-rw-r--r--src/kvilib/net/moc_kvi_http.cpp263
-rw-r--r--src/kvilib/system/Makefile.am5
-rw-r--r--src/kvilib/system/kvi_byteorder.h62
-rw-r--r--src/kvilib/system/kvi_env.cpp89
-rw-r--r--src/kvilib/system/kvi_env.h60
-rw-r--r--src/kvilib/system/kvi_library.h115
-rw-r--r--src/kvilib/system/kvi_locale.cpp1191
-rw-r--r--src/kvilib/system/kvi_locale.h146
-rw-r--r--src/kvilib/system/kvi_process.h37
-rw-r--r--src/kvilib/system/kvi_stdarg.h65
-rw-r--r--src/kvilib/system/kvi_thread.cpp644
-rw-r--r--src/kvilib/system/kvi_thread.h378
-rw-r--r--src/kvilib/system/kvi_time.cpp135
-rw-r--r--src/kvilib/system/kvi_time.h92
-rw-r--r--src/kvilib/system/moc_kvi_locale.cpp92
-rw-r--r--src/kvilib/system/moc_kvi_thread.cpp104
-rw-r--r--src/kvilib/tal/Makefile.am5
-rw-r--r--src/kvilib/tal/kvi_tal_application.cpp69
-rw-r--r--src/kvilib/tal/kvi_tal_application.h34
-rw-r--r--src/kvilib/tal/kvi_tal_application_kde.h37
-rw-r--r--src/kvilib/tal/kvi_tal_application_qt.h37
-rw-r--r--src/kvilib/tal/kvi_tal_filedialog.cpp176
-rw-r--r--src/kvilib/tal/kvi_tal_filedialog.h40
-rw-r--r--src/kvilib/tal/kvi_tal_filedialog_kde.h50
-rw-r--r--src/kvilib/tal/kvi_tal_filedialog_qt.h44
-rw-r--r--src/kvilib/tal/kvi_tal_filedialog_qt4.h46
-rw-r--r--src/kvilib/tal/kvi_tal_grid.cpp34
-rw-r--r--src/kvilib/tal/kvi_tal_grid.h36
-rw-r--r--src/kvilib/tal/kvi_tal_grid_qt3.h39
-rw-r--r--src/kvilib/tal/kvi_tal_grid_qt4.h41
-rw-r--r--src/kvilib/tal/kvi_tal_groupbox.cpp34
-rw-r--r--src/kvilib/tal/kvi_tal_groupbox.h36
-rw-r--r--src/kvilib/tal/kvi_tal_groupbox_qt3.h47
-rw-r--r--src/kvilib/tal/kvi_tal_groupbox_qt4.h47
-rw-r--r--src/kvilib/tal/kvi_tal_hbox.cpp32
-rw-r--r--src/kvilib/tal/kvi_tal_hbox.h36
-rw-r--r--src/kvilib/tal/kvi_tal_hbox_qt3.h41
-rw-r--r--src/kvilib/tal/kvi_tal_hbox_qt4.h41
-rw-r--r--src/kvilib/tal/kvi_tal_iconview.cpp215
-rw-r--r--src/kvilib/tal/kvi_tal_iconview.h36
-rw-r--r--src/kvilib/tal/kvi_tal_iconview_qt3.h100
-rw-r--r--src/kvilib/tal/kvi_tal_iconview_qt4.h99
-rw-r--r--src/kvilib/tal/kvi_tal_listbox.cpp513
-rw-r--r--src/kvilib/tal/kvi_tal_listbox.h50
-rw-r--r--src/kvilib/tal/kvi_tal_listbox_qt3.h157
-rw-r--r--src/kvilib/tal/kvi_tal_listbox_qt4.h152
-rw-r--r--src/kvilib/tal/kvi_tal_listview.cpp1542
-rw-r--r--src/kvilib/tal/kvi_tal_listview.h51
-rw-r--r--src/kvilib/tal/kvi_tal_listview_qt3.h190
-rw-r--r--src/kvilib/tal/kvi_tal_listview_qt4.h199
-rw-r--r--src/kvilib/tal/kvi_tal_mainwindow.cpp69
-rw-r--r--src/kvilib/tal/kvi_tal_mainwindow.h38
-rw-r--r--src/kvilib/tal/kvi_tal_mainwindow_kde.h36
-rw-r--r--src/kvilib/tal/kvi_tal_mainwindow_qt3.h36
-rw-r--r--src/kvilib/tal/kvi_tal_mainwindow_qt4.h39
-rw-r--r--src/kvilib/tal/kvi_tal_menubar.cpp58
-rw-r--r--src/kvilib/tal/kvi_tal_menubar.h33
-rw-r--r--src/kvilib/tal/kvi_tal_menubar_kde.h35
-rw-r--r--src/kvilib/tal/kvi_tal_menubar_qt.h35
-rw-r--r--src/kvilib/tal/kvi_tal_popupmenu.cpp33
-rw-r--r--src/kvilib/tal/kvi_tal_popupmenu.h36
-rw-r--r--src/kvilib/tal/kvi_tal_popupmenu_qt3.h42
-rw-r--r--src/kvilib/tal/kvi_tal_popupmenu_qt4.h89
-rw-r--r--src/kvilib/tal/kvi_tal_scrollview.cpp33
-rw-r--r--src/kvilib/tal/kvi_tal_scrollview.h36
-rw-r--r--src/kvilib/tal/kvi_tal_scrollview_qt3.h41
-rw-r--r--src/kvilib/tal/kvi_tal_scrollview_qt4.h41
-rw-r--r--src/kvilib/tal/kvi_tal_tabdialog.cpp34
-rw-r--r--src/kvilib/tal/kvi_tal_tabdialog.h36
-rw-r--r--src/kvilib/tal/kvi_tal_tabdialog_qt3.h39
-rw-r--r--src/kvilib/tal/kvi_tal_tabdialog_qt4.h39
-rw-r--r--src/kvilib/tal/kvi_tal_textedit.cpp34
-rw-r--r--src/kvilib/tal/kvi_tal_textedit.h36
-rw-r--r--src/kvilib/tal/kvi_tal_textedit_qt3.h39
-rw-r--r--src/kvilib/tal/kvi_tal_textedit_qt4.h39
-rw-r--r--src/kvilib/tal/kvi_tal_toolbar.cpp107
-rw-r--r--src/kvilib/tal/kvi_tal_toolbar.h37
-rw-r--r--src/kvilib/tal/kvi_tal_toolbar_kde.h37
-rw-r--r--src/kvilib/tal/kvi_tal_toolbar_qt3.h39
-rw-r--r--src/kvilib/tal/kvi_tal_toolbar_qt4.h47
-rw-r--r--src/kvilib/tal/kvi_tal_toolbardocktype.h71
-rw-r--r--src/kvilib/tal/kvi_tal_tooltip.cpp125
-rw-r--r--src/kvilib/tal/kvi_tal_tooltip.h79
-rw-r--r--src/kvilib/tal/kvi_tal_vbox.cpp33
-rw-r--r--src/kvilib/tal/kvi_tal_vbox.h36
-rw-r--r--src/kvilib/tal/kvi_tal_vbox_qt3.h42
-rw-r--r--src/kvilib/tal/kvi_tal_vbox_qt4.h42
-rw-r--r--src/kvilib/tal/kvi_tal_widgetstack.cpp33
-rw-r--r--src/kvilib/tal/kvi_tal_widgetstack.h36
-rw-r--r--src/kvilib/tal/kvi_tal_widgetstack_qt3.h42
-rw-r--r--src/kvilib/tal/kvi_tal_widgetstack_qt4.h42
-rw-r--r--src/kvilib/tal/kvi_tal_windowstate.h42
-rw-r--r--src/kvilib/tal/kvi_tal_wizard.cpp584
-rw-r--r--src/kvilib/tal/kvi_tal_wizard.h169
-rw-r--r--src/kvilib/tal/moc_kvi_tal_wizard.cpp128
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 *)&in;
+
+ 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*)&in;
+
+ 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 &pm; }
+
+ 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 &pm; }
+
+ 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