summaryrefslogtreecommitdiffstats
path: root/ksirc
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbcb704366cb5e333a626c18c308c7e0448a8e69f (patch)
treef0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /ksirc
downloadtdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz
tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'ksirc')
-rw-r--r--ksirc/Artistic131
-rw-r--r--ksirc/ChangeLog270
-rw-r--r--ksirc/FAQ73
-rw-r--r--ksirc/FilterRuleEditor.cpp244
-rw-r--r--ksirc/FilterRuleEditor.dlg215
-rw-r--r--ksirc/FilterRuleEditor.h53
-rw-r--r--ksirc/FilterRuleWidget.ui239
-rw-r--r--ksirc/KSOpenkSirc/Makefile.am26
-rwxr-xr-xksirc/KSOpenkSirc/convert-mIRC19
-rw-r--r--ksirc/KSOpenkSirc/enter_combo.cpp10
-rw-r--r--ksirc/KSOpenkSirc/enter_combo.h37
-rw-r--r--ksirc/KSOpenkSirc/open_ksirc.cpp377
-rw-r--r--ksirc/KSOpenkSirc/open_ksirc.h53
-rw-r--r--ksirc/KSOpenkSirc/open_ksircData.ui337
-rw-r--r--ksirc/KSOpenkSirc/serverDataType.h56
-rw-r--r--ksirc/KSOpenkSirc/serverFileParser.cpp114
-rw-r--r--ksirc/KSOpenkSirc/serverFileParser.h13
-rw-r--r--ksirc/KSOpenkSirc/servers.ini362
-rw-r--r--ksirc/KSOpenkSirc/servers.txt654
-rw-r--r--ksirc/KSPrefs/Makefile.am50
-rw-r--r--ksirc/KSPrefs/ksprefs.cpp244
-rw-r--r--ksirc/KSPrefs/ksprefs.h65
-rw-r--r--ksirc/KSPrefs/page_autoconnect.cpp309
-rw-r--r--ksirc/KSPrefs/page_autoconnect.h36
-rw-r--r--ksirc/KSPrefs/page_autoconnectbase.ui391
-rw-r--r--ksirc/KSPrefs/page_colors.cpp295
-rw-r--r--ksirc/KSPrefs/page_colors.h53
-rw-r--r--ksirc/KSPrefs/page_colorsbase.ui1063
-rw-r--r--ksirc/KSPrefs/page_font.cpp38
-rw-r--r--ksirc/KSPrefs/page_font.h62
-rw-r--r--ksirc/KSPrefs/page_general.cpp117
-rw-r--r--ksirc/KSPrefs/page_general.h35
-rw-r--r--ksirc/KSPrefs/page_generalbase.ui540
-rw-r--r--ksirc/KSPrefs/page_irccolors.cpp181
-rw-r--r--ksirc/KSPrefs/page_irccolors.h40
-rw-r--r--ksirc/KSPrefs/page_irccolorsbase.ui1275
-rw-r--r--ksirc/KSPrefs/page_looknfeel.cpp72
-rw-r--r--ksirc/KSPrefs/page_looknfeel.h37
-rw-r--r--ksirc/KSPrefs/page_looknfeelbase.ui323
-rw-r--r--ksirc/KSPrefs/page_rmbmenu.cpp206
-rw-r--r--ksirc/KSPrefs/page_rmbmenu.h38
-rw-r--r--ksirc/KSPrefs/page_rmbmenubase.ui252
-rw-r--r--ksirc/KSPrefs/page_servchan.cpp135
-rw-r--r--ksirc/KSPrefs/page_servchan.h38
-rw-r--r--ksirc/KSPrefs/page_servchanbase.ui172
-rw-r--r--ksirc/KSPrefs/page_shortcuts.cpp57
-rw-r--r--ksirc/KSPrefs/page_shortcuts.h40
-rw-r--r--ksirc/KSPrefs/page_shortcutsbase.ui57
-rw-r--r--ksirc/KSPrefs/page_startup.cpp126
-rw-r--r--ksirc/KSPrefs/page_startup.h40
-rw-r--r--ksirc/KSPrefs/page_startupbase.ui197
-rw-r--r--ksirc/KSProgress/Makefile.am11
-rw-r--r--ksirc/KSProgress/ksprogress.cpp60
-rw-r--r--ksirc/KSProgress/ksprogress.dlg167
-rw-r--r--ksirc/KSProgress/ksprogress.h47
-rw-r--r--ksirc/KSProgress/ksprogressdata.cpp72
-rw-r--r--ksirc/KSProgress/ksprogressdata.h48
-rw-r--r--ksirc/KSTicker/Makefile.am20
-rw-r--r--ksirc/KSTicker/kspainter.cpp186
-rw-r--r--ksirc/KSTicker/kspainter.h25
-rw-r--r--ksirc/KSTicker/ksticker.cpp548
-rw-r--r--ksirc/KSTicker/ksticker.h106
-rw-r--r--ksirc/KSTicker/ksttest.cpp93
-rw-r--r--ksirc/KSTicker/ksttest.h24
-rw-r--r--ksirc/KSTicker/libksticker.c0
-rw-r--r--ksirc/KSTicker/speeddialog.cpp61
-rw-r--r--ksirc/KSTicker/speeddialog.dlg117
-rw-r--r--ksirc/KSTicker/speeddialog.h42
-rw-r--r--ksirc/KSTicker/speeddialogData.cpp107
-rw-r--r--ksirc/KSTicker/speeddialogData.h51
-rw-r--r--ksirc/Makefile.am146
-rw-r--r--ksirc/NewWindowDialog.cpp73
-rw-r--r--ksirc/NewWindowDialog.h35
-rw-r--r--ksirc/advfollow.pl125
-rw-r--r--ksirc/ahistlineedit.cpp437
-rw-r--r--ksirc/ahistlineedit.h56
-rw-r--r--ksirc/alistbox.cpp508
-rw-r--r--ksirc/alistbox.h112
-rw-r--r--ksirc/autodcc.pl71
-rw-r--r--ksirc/baserules.cpp167
-rw-r--r--ksirc/baserules.h35
-rw-r--r--ksirc/boundscheckingarray.h67
-rw-r--r--ksirc/chanButtons.cpp268
-rw-r--r--ksirc/chanButtons.h85
-rw-r--r--ksirc/chanparser.cpp1047
-rw-r--r--ksirc/chanparser.h289
-rw-r--r--ksirc/charSelector.cpp77
-rw-r--r--ksirc/charSelector.h42
-rw-r--r--ksirc/colorpicker.cpp342
-rw-r--r--ksirc/colorpicker.h91
-rw-r--r--ksirc/control_message.h15
-rw-r--r--ksirc/dccManager.cpp403
-rw-r--r--ksirc/dccManager.h138
-rw-r--r--ksirc/dccManagerbase.ui202
-rw-r--r--ksirc/dccMgrTest.cpp44
-rw-r--r--ksirc/dccNew.cpp162
-rw-r--r--ksirc/dccNew.h44
-rw-r--r--ksirc/dccNewbase.ui237
-rw-r--r--ksirc/dccToplevel.cpp49
-rw-r--r--ksirc/dccToplevel.h33
-rw-r--r--ksirc/default.pl867
-rw-r--r--ksirc/displayMgr.h28
-rw-r--r--ksirc/displayMgrMDI.cpp306
-rw-r--r--ksirc/displayMgrMDI.h48
-rw-r--r--ksirc/displayMgrSDI.cpp40
-rw-r--r--ksirc/displayMgrSDI.h25
-rw-r--r--ksirc/dockservercontroller.cpp451
-rw-r--r--ksirc/dockservercontroller.h110
-rwxr-xr-xksirc/dsirc2721
-rw-r--r--ksirc/eventsrc364
-rw-r--r--ksirc/filters.pl171
-rw-r--r--ksirc/getdate.c7
-rw-r--r--ksirc/icons/Makefile.am5
-rw-r--r--ksirc/icons/X.pngbin0 -> 840 bytes
-rw-r--r--ksirc/icons/cr22-action-info.pngbin0 -> 1195 bytes
-rw-r--r--ksirc/icons/cr22-action-ksirc_dock.pngbin0 -> 1129 bytes
-rw-r--r--ksirc/icons/ctcpping.pngbin0 -> 1040 bytes
-rw-r--r--ksirc/icons/error.pngbin0 -> 1043 bytes
-rw-r--r--ksirc/icons/hi16-app-ksirc.pngbin0 -> 903 bytes
-rw-r--r--ksirc/icons/hi22-app-ksirc.pngbin0 -> 1227 bytes
-rw-r--r--ksirc/icons/hi32-app-ksirc.pngbin0 -> 2134 bytes
-rw-r--r--ksirc/icons/hi48-app-ksirc.pngbin0 -> 3911 bytes
-rw-r--r--ksirc/icons/hi64-app-ksirc.pngbin0 -> 4237 bytes
-rw-r--r--ksirc/img/Makefile.am18
-rw-r--r--ksirc/img/X.pngbin0 -> 854 bytes
-rw-r--r--ksirc/img/action.pngbin0 -> 842 bytes
-rw-r--r--ksirc/img/arrow.pngbin0 -> 1235 bytes
-rw-r--r--ksirc/img/blueball.pngbin0 -> 584 bytes
-rw-r--r--ksirc/img/bluepin.pngbin0 -> 434 bytes
-rw-r--r--ksirc/img/bminus.pngbin0 -> 854 bytes
-rw-r--r--ksirc/img/bplus.pngbin0 -> 870 bytes
-rw-r--r--ksirc/img/channel.xpm36
-rw-r--r--ksirc/img/channels.xpm60
-rw-r--r--ksirc/img/ctcpping.pngbin0 -> 863 bytes
-rw-r--r--ksirc/img/dcc.pngbin0 -> 812 bytes
-rw-r--r--ksirc/img/dccget.pngbin0 -> 832 bytes
-rw-r--r--ksirc/img/dccsend.pngbin0 -> 809 bytes
-rw-r--r--ksirc/img/elipsis.pngbin0 -> 765 bytes
-rw-r--r--ksirc/img/emoticons/Makefile.am5
-rw-r--r--ksirc/img/emoticons/biggrin.pngbin0 -> 803 bytes
-rw-r--r--ksirc/img/emoticons/clown.pngbin0 -> 751 bytes
-rw-r--r--ksirc/img/emoticons/cry.pngbin0 -> 1092 bytes
-rw-r--r--ksirc/img/emoticons/devil.pngbin0 -> 852 bytes
-rw-r--r--ksirc/img/emoticons/frown.pngbin0 -> 709 bytes
-rw-r--r--ksirc/img/emoticons/heart.pngbin0 -> 1037 bytes
-rw-r--r--ksirc/img/emoticons/loveit.pngbin0 -> 959 bytes
-rw-r--r--ksirc/img/emoticons/puh.pngbin0 -> 1101 bytes
-rw-r--r--ksirc/img/emoticons/puh2.pngbin0 -> 1116 bytes
-rw-r--r--ksirc/img/emoticons/redface.pngbin0 -> 778 bytes
-rw-r--r--ksirc/img/emoticons/sadley.pngbin0 -> 615 bytes
-rw-r--r--ksirc/img/emoticons/slime.pngbin0 -> 1130 bytes
-rw-r--r--ksirc/img/emoticons/smile.pngbin0 -> 609 bytes
-rw-r--r--ksirc/img/emoticons/wink.pngbin0 -> 619 bytes
-rw-r--r--ksirc/img/emoticons/yummie.pngbin0 -> 1126 bytes
-rw-r--r--ksirc/img/error.pngbin0 -> 870 bytes
-rw-r--r--ksirc/img/greenpin.pngbin0 -> 743 bytes
-rw-r--r--ksirc/img/info.pngbin0 -> 757 bytes
-rw-r--r--ksirc/img/info1.pngbin0 -> 831 bytes
-rw-r--r--ksirc/img/join.pngbin0 -> 835 bytes
-rw-r--r--ksirc/img/kick.pngbin0 -> 835 bytes
-rw-r--r--ksirc/img/ksirc.pngbin0 -> 3464 bytes
-rw-r--r--ksirc/img/ksirc_a.xpm46
-rw-r--r--ksirc/img/ksirc_b.xpm48
-rw-r--r--ksirc/img/ksirc_dock.pngbin0 -> 1192 bytes
-rw-r--r--ksirc/img/ksirc_dock.xpm192
-rw-r--r--ksirc/img/madsmiley.pngbin0 -> 701 bytes
-rw-r--r--ksirc/img/mdi.pngbin0 -> 12434 bytes
-rw-r--r--ksirc/img/mini-run.pngbin0 -> 254 bytes
-rw-r--r--ksirc/img/minus.pngbin0 -> 714 bytes
-rw-r--r--ksirc/img/misc1.pngbin0 -> 901 bytes
-rw-r--r--ksirc/img/misc2.pngbin0 -> 795 bytes
-rw-r--r--ksirc/img/misc3.pngbin0 -> 848 bytes
-rw-r--r--ksirc/img/misc4.pngbin0 -> 882 bytes
-rw-r--r--ksirc/img/misc5.pngbin0 -> 817 bytes
-rw-r--r--ksirc/img/misc6.pngbin0 -> 848 bytes
-rw-r--r--ksirc/img/misc7.pngbin0 -> 848 bytes
-rw-r--r--ksirc/img/misc8.pngbin0 -> 865 bytes
-rw-r--r--ksirc/img/misc9.pngbin0 -> 856 bytes
-rw-r--r--ksirc/img/miscA.pngbin0 -> 893 bytes
-rw-r--r--ksirc/img/mode.pngbin0 -> 843 bytes
-rw-r--r--ksirc/img/notice.pngbin0 -> 826 bytes
-rw-r--r--ksirc/img/ominus.pngbin0 -> 826 bytes
-rw-r--r--ksirc/img/oplus.pngbin0 -> 849 bytes
-rw-r--r--ksirc/img/part.pngbin0 -> 842 bytes
-rw-r--r--ksirc/img/plus.pngbin0 -> 791 bytes
-rw-r--r--ksirc/img/ppl.pngbin0 -> 462 bytes
-rw-r--r--ksirc/img/quit.pngbin0 -> 859 bytes
-rw-r--r--ksirc/img/sadsmiley.pngbin0 -> 685 bytes
-rw-r--r--ksirc/img/sdi.pngbin0 -> 4910 bytes
-rw-r--r--ksirc/img/server.xpm320
-rw-r--r--ksirc/img/servinfo.pngbin0 -> 858 bytes
-rw-r--r--ksirc/img/smiley.pngbin0 -> 687 bytes
-rw-r--r--ksirc/img/star.pngbin0 -> 566 bytes
-rw-r--r--ksirc/img/start.xpm29
-rw-r--r--ksirc/img/stop.xpm120
-rw-r--r--ksirc/img/tile.xpmbin0 -> 6236 bytes
-rw-r--r--ksirc/img/topic.pngbin0 -> 765 bytes
-rw-r--r--ksirc/ioBroadcast.cpp101
-rw-r--r--ksirc/ioBroadcast.h25
-rw-r--r--ksirc/ioDCC.cpp643
-rw-r--r--ksirc/ioDCC.h65
-rw-r--r--ksirc/ioDiscard.cpp23
-rw-r--r--ksirc/ioDiscard.h20
-rw-r--r--ksirc/ioLAG.cpp61
-rw-r--r--ksirc/ioLAG.h31
-rw-r--r--ksirc/ioNotify.cpp75
-rw-r--r--ksirc/ioNotify.h31
-rw-r--r--ksirc/iocontroller.cpp426
-rw-r--r--ksirc/iocontroller.h54
-rw-r--r--ksirc/ksirc.cpp151
-rw-r--r--ksirc/ksirc.desktop87
-rw-r--r--ksirc/ksirc.pl781
-rw-r--r--ksirc/ksircchannel.h35
-rw-r--r--ksirc/ksircprocess.cpp663
-rw-r--r--ksirc/ksircprocess.h92
-rw-r--r--ksirc/ksircrc62
-rw-r--r--ksirc/ksircserver.h34
-rw-r--r--ksirc/ksopts.cpp542
-rw-r--r--ksirc/ksopts.h218
-rw-r--r--ksirc/ksparser.cpp192
-rw-r--r--ksirc/ksparser.h43
-rw-r--r--ksirc/kstextview.cpp2269
-rw-r--r--ksirc/kstextview.h577
-rw-r--r--ksirc/kstextviewtest.cpp51
-rw-r--r--ksirc/ksview.cpp344
-rw-r--r--ksirc/ksview.h74
-rw-r--r--ksirc/logfile.cpp93
-rw-r--r--ksirc/logfile.h40
-rw-r--r--ksirc/mditoplevel.cpp260
-rw-r--r--ksirc/mditoplevel.h75
-rw-r--r--ksirc/messageReceiver.cpp73
-rw-r--r--ksirc/messageReceiver.h62
-rw-r--r--ksirc/nickColourMaker.cpp86
-rw-r--r--ksirc/nickColourMaker.h44
-rw-r--r--ksirc/objFinder.cpp160
-rw-r--r--ksirc/objFinder.h41
-rw-r--r--ksirc/openksircproc.dlg76
-rw-r--r--ksirc/puke/HOWTO-PUKE.pod325
-rw-r--r--ksirc/puke/Makefile.am43
-rw-r--r--ksirc/puke/commands-handler.pl61
-rw-r--r--ksirc/puke/commands-perl.pl605
-rw-r--r--ksirc/puke/commands.h1052
-rw-r--r--ksirc/puke/controller.cpp974
-rw-r--r--ksirc/puke/controller.h211
-rwxr-xr-xksirc/puke/convert_commands.pl13
-rw-r--r--ksirc/puke/dcc_progress.pm55
-rw-r--r--ksirc/puke/dcc_status.pm525
-rw-r--r--ksirc/puke/load_all.pm14
-rw-r--r--ksirc/puke/palistbox.cpp156
-rw-r--r--ksirc/puke/palistbox.h35
-rw-r--r--ksirc/puke/palistbox.pm117
-rw-r--r--ksirc/puke/pbase.pm265
-rw-r--r--ksirc/puke/pboxlayout.pm201
-rw-r--r--ksirc/puke/pbutton.cpp157
-rw-r--r--ksirc/puke/pbutton.h40
-rw-r--r--ksirc/puke/pbutton.pm79
-rw-r--r--ksirc/puke/pframe.cpp84
-rw-r--r--ksirc/puke/pframe.h28
-rw-r--r--ksirc/puke/pframe.pm57
-rw-r--r--ksirc/puke/pkfiledialog-cmd.h56
-rw-r--r--ksirc/puke/pkfiledialog.cpp123
-rw-r--r--ksirc/puke/pkfiledialog.h31
-rw-r--r--ksirc/puke/pkfiledialog.pm76
-rw-r--r--ksirc/puke/plabel.cpp127
-rw-r--r--ksirc/puke/plabel.h34
-rw-r--r--ksirc/puke/plabel.pm105
-rw-r--r--ksirc/puke/playout.cpp157
-rw-r--r--ksirc/puke/playout.h42
-rw-r--r--ksirc/puke/plined.cpp153
-rw-r--r--ksirc/puke/plined.h33
-rw-r--r--ksirc/puke/plined.pm84
-rw-r--r--ksirc/puke/plistbox.cpp224
-rw-r--r--ksirc/puke/plistbox.h37
-rw-r--r--ksirc/puke/plistbox.pm196
-rw-r--r--ksirc/puke/pmenudta.cpp79
-rw-r--r--ksirc/puke/pmenudta.h57
-rw-r--r--ksirc/puke/pmenudta.pm60
-rw-r--r--ksirc/puke/pmessage.h38
-rw-r--r--ksirc/puke/pobject.cpp138
-rw-r--r--ksirc/puke/pobject.h134
-rw-r--r--ksirc/puke/pobjfinder-cmd.h32
-rw-r--r--ksirc/puke/pobjfinder.cpp86
-rw-r--r--ksirc/puke/pobjfinder.h33
-rw-r--r--ksirc/puke/pobjfinder.pm89
-rw-r--r--ksirc/puke/ppopmenu.cpp120
-rw-r--r--ksirc/puke/ppopmenu.h36
-rw-r--r--ksirc/puke/ppopmenu.pm65
-rw-r--r--ksirc/puke/pprogress.cpp133
-rw-r--r--ksirc/puke/pprogress.h32
-rw-r--r--ksirc/puke/pprogress.pm86
-rw-r--r--ksirc/puke/ppushbt.cpp70
-rw-r--r--ksirc/puke/ppushbt.h33
-rw-r--r--ksirc/puke/ppushbt.pm30
-rw-r--r--ksirc/puke/ptabdialog.cpp101
-rw-r--r--ksirc/puke/ptabdialog.h41
-rw-r--r--ksirc/puke/ptabdialog.pm49
-rw-r--r--ksirc/puke/ptablevw.cpp76
-rw-r--r--ksirc/puke/ptablevw.h33
-rw-r--r--ksirc/puke/ptablevw.pm57
-rw-r--r--ksirc/puke/puke.pl225
-rw-r--r--ksirc/puke/pwidget.cpp492
-rw-r--r--ksirc/puke/pwidget.h45
-rw-r--r--ksirc/puke/pwidget.pm231
-rw-r--r--ksirc/puke/small.pl65
-rw-r--r--ksirc/puke/test.pl63
-rwxr-xr-xksirc/puke/tester.pl28
-rw-r--r--ksirc/puke/user_monitor.ks440
-rw-r--r--ksirc/puke/widgethdlr.h3
-rw-r--r--ksirc/relnotes107
-rw-r--r--ksirc/servercontroller.cpp978
-rw-r--r--ksirc/servercontroller.dlg33
-rw-r--r--ksirc/servercontroller.h267
-rw-r--r--ksirc/sirc.help.gzbin0 -> 7270 bytes
-rw-r--r--ksirc/ssfeprompt.cpp54
-rw-r--r--ksirc/ssfeprompt.h37
-rw-r--r--ksirc/ssfepromptdata.cpp68
-rw-r--r--ksirc/ssfepromptdata.h47
-rw-r--r--ksirc/stringparserstate.h71
-rw-r--r--ksirc/test/nicklist.pl77
-rw-r--r--ksirc/test/tester.pl65
-rw-r--r--ksirc/topic.cpp245
-rw-r--r--ksirc/topic.h70
-rw-r--r--ksirc/toplevel.cpp1848
-rw-r--r--ksirc/toplevel.h535
-rw-r--r--ksirc/usercontrolmenu.cpp167
-rw-r--r--ksirc/usercontrolmenu.h52
-rw-r--r--ksirc/version.h6
327 files changed, 46451 insertions, 0 deletions
diff --git a/ksirc/Artistic b/ksirc/Artistic
new file mode 100644
index 00000000..11f4d82d
--- /dev/null
+++ b/ksirc/Artistic
@@ -0,0 +1,131 @@
+
+
+
+
+ The "Artistic License"
+
+ Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+ "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+
+ "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes
+ of the Copyright Holder as specified below.
+
+ "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+
+ "You" is you, if you're thinking about copying or distributing
+ this Package.
+
+ "Reasonable copying fee" is whatever you can justify on the
+ basis of media cost, duplication charges, time of people involved,
+ and so on. (You will not be required to justify it to the
+ Copyright Holder, but only to the computing community at large
+ as a market that must bear the fee.)
+
+ "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item.
+ It also means that recipients of the item may redistribute it
+ under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder. A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or
+ an equivalent medium, or placing the modifications on a major archive
+ site such as uunet.uu.net, or by allowing the Copyright Holder to include
+ your modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict
+ with standard executables, which must also be provided, and provide
+ a separate manual page for each non-standard executable that clearly
+ documents how it differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where
+ to get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of
+ the Package with your modifications.
+
+ c) give non-standard executables non-standard names, and clearly
+ document the differences in manual pages (or equivalent), together
+ with instructions on where to get the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package. You may charge any fee you choose for support of this
+Package. You may not charge a fee for this Package itself. However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own. You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whomever generated
+them, and may be sold commercially, and may be aggregated with this
+Package. If such scripts or library files are aggregated with this
+Package via the so-called "undump" or "unexec" methods of producing a
+binary executable image, then distribution of such an image shall
+neither be construed as a distribution of this Package nor shall it
+fall under the restrictions of Paragraphs 3 and 4, provided that you do
+not represent such an executable image as a Standard Version of this
+Package.
+
+7. C subroutines (or comparably compiled subroutines in other
+languages) supplied by you and linked into this Package in order to
+emulate subroutines and variables of the language defined by this
+Package shall not be considered part of this Package, but are the
+equivalent of input as in Paragraph 6, provided these subroutines do
+not change the language in any way that would cause it to fail the
+regression tests for the language.
+
+8. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution. Such use shall not be
+construed as a distribution of this Package.
+
+9. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ The End
diff --git a/ksirc/ChangeLog b/ksirc/ChangeLog
new file mode 100644
index 00000000..808b9e8c
--- /dev/null
+++ b/ksirc/ChangeLog
@@ -0,0 +1,270 @@
+1998-03-29 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Fixed problem with "/names" opening a zillion windows and
+ joining every channel in existance.
+
+ * toplevel.cpp: re-writting parse-input to do better checking and
+ error handling. Now uses an internal EString, a QString class
+ which emits exceptions on error conditions. Currently only 1
+ exception exists, the estringOutOfBounds exception to indicate
+ find returned a value out of the bounds of the string. Other
+ exception handling include failure cases like parse errors.
+
+ * Added better puke support and more widgets. Currently 8
+ diffrent widgets exist, and 1 layout manager.
+
+1998-03-13 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Nick list sorting works much better, still broken when
+ there's only a couple of entries, but it's better.
+
+ * Fixed /names problem.
+
+1998-03-07 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Majour update comes in the form of the puke sub directory. This
+ contains the starting frame work for full control of ksirc from
+ perl scripts. Right now it implements a small widget set (ha!
+ small!! a widget, a frame and a lineedit). Ground work is all set
+ to start adding more. :)
+
+ * puke/pwidget.pm (close): Wow it's been a while since this was
+ updated =)
+
+
+
+1998-02-17 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Default rules added:
+ + Filter ksirc colours
+ + Filter mirc colours
+ + Colourize nicks
+ + Colourize your nick
+
+ * KSPrefs/defaultfilters.cpp: Added default filters
+ configure/prefrences dialog.
+
+ * baserules.cpp (defaultRules): Added basic default filter rules.
+
+1998-02-16 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Numberous other changes in toplevel.cpp to support changes to
+ nick list.
+
+ * alistbox.cpp (nickListItem): New nick list item keeps all nicks
+ in special items with setable colours and op/voice status falgs.
+ (findNick): New findNick() function allows quick searchin of nick
+ list via binary search.
+ (item): Returns nickListItem now.
+
+1998-02-07 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Misc bug fixes and updates.
+
+1998-02-01 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * KSCutDialog/KSCutDialog.cpp (scrollToBot): Added copy button,
+ and made it scroll to the bottom better.
+
+ * ahistlineedit.cpp (mousePressEvent): Fixed paste problem, added
+ copy button for poor soles who have problem with highlighting and
+ copying.
+
+ * dsirc (donumeric): Fixed dcc chat messages going to the wrong window.
+
+1998-01-30 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * When talking to a nick doesn't show nick list.
+
+ * toplevel.cpp (KSircTopLevel): Fixed a few bugs with drawing and
+ reszing.
+
+ * New freeze slot for irc listitems, should speed up global
+ changes, etc.
+
+ * Misc changes and fixes.
+
+ * toplevel.cpp (parse_input): If we see a nick change that's
+ pertinent to us, ie we're talking to a nick and he changes nicks,
+ try and follow the nick change.
+
+1998-01-28 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * toplevel.cpp (parse_input): Clears screan before displaying the
+ prompt. Needed minor changes everywhere.
+ (parse_input): Added ssfe 'R' message to rejoin a channel.
+
+ * servercontroller.cpp (saveProperties): Added KDE session
+ management.
+
+1998-01-25 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Handles +v on nicks in channels.
+
+ * Big fixes throughout.
+
+ * irclistbox.cpp (updateScrollBars): General cleanup of scroll
+ bars, they work correctly now.
+
+1998-01-24 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Ran ksirc through gprof and inlined a few small functions to
+ help in performance.
+
+ * toplevel.cpp: Fixed Menubar being offset.
+
+ * irclistitem.cpp (setupPainterText): Majour update to painting
+ routine. Now pre draws the "line" in a QPixmap buffer, and simply
+ dumps the pixmap to the screen in a paintevent. Essentially
+ double buffered, much faster, very nice.
+
+1998-01-21 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * toplevel.cpp (UserParseMenu): User menus no longer support %s,
+ but rather the perl variable $$dest_nick, this means you can now
+ use any sirc variable available, and as many times as you like.
+ This is going to break a lot of things!
+
+ * servercontroller.cpp (ProcMessage): Disabled Connections->Join
+ Channel when last server connection is closed.
+ Added icon, thanks to Druppy for making it.
+
+ * toplevel.cpp (showTicker): Fixed bug in starting ticker, was -5
+ instead of -i.
+
+ * KSTicker/ksticker.cpp (timerEvent): Added colour printing
+ support and double support. Little cleaner, looks ok.
+
+1998-01-20 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * ksircprocess.cpp (KSircProcess): Added sirc.help.gz and
+ SIRCLIBDIR infor so help now works correctly!!!! ADDED /help!!
+
+ * Moved all UserMenu support into the prefrences list box, and all
+ that it entails. Not 100% clean, but it's pretty good.
+
+ * toplevel.cpp (control_message): Added support for changing the
+ font size of the line edit.
+
+ * cleaned up support for the user menu in toplevel, and remove all
+ the extra classes.
+
+1998-01-18 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * KSPrefs/ksprefs.cpp: New Preferences and settings window. The
+ basic window and idea has been set out, it simply needs more pages
+ plugged into it now.
+
+ * ksircprocess.cpp (KSircProcess): Added support for the new
+ startup settings, etc.
+
+ * ksircprocess/servercontroller/toplevel: Now starts with channel
+ name !no_channel so that deletes go through correctly. (we never
+ delete !default).
+
+ * servercontroller.h: Updated and fixed so the window resizes
+ correctly.
+
+1998-01-15 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Ticker now starts with data right away, heck, I just plug it
+ with the last 5 lines!
+
+ * FilterRuleEditor.cpp (moveRule): Fixed error with $$var being
+ nuked.
+
+ * Updated the entire messaging system between ServerController and
+ ksirc process, they can now talk freely without a zillion signals
+ and slots. Communications is fully bidirectional and should work
+ well.
+
+ * toplevel.cpp (parse_input): Now deals with ssfe#p correctly!!!
+ Finally!!!! (prompts, for say nicks and passwords, try /oper :) )
+
+1998-01-13 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * servercontroller.cpp (notify_nick_online): Added grahical notify
+ list. It uses the server controller and adds an Online brancs
+ with the nicks of people currently online on each server.
+
+1998-01-12 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Fixed filters.pl so being "away" doesn't mess up the lag'o'meter.
+
+ * Updated docs added keys.help and updates servercontroller for it.
+
+1998-01-10 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * toplevel.cpp (KSircTopLevel): Menus updated and working correctly.
+
+ * filters.pl (hook_ctcp_lag): Added feature for lag monitoring up
+ in the upper right hand corner. Menus are broken though :(
+
+1998-01-09 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * toplevel.cpp (pasteToWindow): Fixed ut & paste to work correctly.
+
+1998-01-02 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * alistbox.cpp (inSort): Fixed sorting routine. Stripped it made
+ it work, it's faster, etc. SHould work better.
+
+ * toplevel.cpp: Added new Willy power tab completion.
+
+1998-01-01 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Various bug fixes as per the BUGLIST.
+
+ * Fixed scroll to bottom, no longer scroll to bottom when you're
+ scrolled up, except when you hit enter.
+
+1997-12-31 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Fixed mem leak in KSTicker. Leaked 1 byte per message.
+
+ * Cleaned up the cut&paste code, made it a little consistend with X.
+
+1997-12-30 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Added support for multiple op/deop'ings. Seems ok, except for
+ when a non-op changes their nick they might be shown as an op.
+ Looking into it.
+
+ * Generic bug fixing and re-orginization since the 26th. Check
+ the cvs logs.
+
+ * Added full cut&paste support. Seems to work ok.
+
+1997-12-26 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * toplevel.cpp (resizeEvent): fixed resize problem.
+ (parse_input): Added `sirc clear handeling.
+ (parse_input): I think I fixed the auto create auto joining windows
+
+ * Added filter rule control mechanisim where each module is
+ queired and can suply it's own filter rules. Usefull for DCC and
+ bolding etc. Be carefull with toplevel, since there's multiple
+ instances each will suppy it's rule, and should ONLY be used if
+ each toplevel needs a filter rule.
+
+ * irclistitem.cpp (colourDrawText): Added ~~ to escape and print a
+ single ~. ~~ is always garunteed to print ~.
+
+ * ioBroadcast.cpp (defaultRules): Added a a default rule to seek
+ out stray ~[bcui]nick@someplace due to bad idents and to escape
+ the ~.
+
+1997-12-25 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Added listing of OPs at the top of list box with a seperator
+ dividing ops from non-ops. Toplevel now tracks nick change and op
+ status.
+
+1997-12-24 Andrew Stanley-Jones <asj@chowtown.cban.com>
+
+ * Added code to look fro same fg and bg and change the bg so you
+ can see the text.
+
+ * Cleaned up nick completion, etc.
+
+$Revision$
diff --git a/ksirc/FAQ b/ksirc/FAQ
new file mode 100644
index 00000000..8166b0e5
--- /dev/null
+++ b/ksirc/FAQ
@@ -0,0 +1,73 @@
+
+FAQ answers:
+
+*** Why KSirc:
+*** Do I need KDE and the QT libraries installed?!?!?
+*** Why use QT/KDE instead of GTK or other toolkits?
+*** Filters in under 25 words:
+*** How do I Query Someone? (private convertation)
+*** What are all the keystrokes?
+*** How does nick completion work?
+
+*** Why KSirc:
+
+There's already a lot of good irc clients, so why write another one?
+In my opinion X lacked a flexible and script-able irc client. While
+"xterm -e irc" works well, it doesn't take advantage of a graphical
+environment. On the other hand, most X irc clients focus on the
+graphical part and never really develop the scripting side very well.
+KSirc tries to solve these two problems. It uses sirc and as such
+provides VERY powerful perl scripting while providing the X interface.
+
+*** Do I need KDE and the QT libraries installed?!?!?
+
+No.
+
+Static binary versions are installed and work fine. If you want to
+compile the source though, you'll need QT and KDE installed.
+
+
+*** Why use QT/KDE instead of GTK or other toolkits?
+
+At the time KSirc started QT/KDE provided the best possible graphical
+interface and programming environment in my opinion. GTK while
+potentially a useful toolkit in the future doesn't provide a stable
+working environment at the moment. Plus I don't like what GTK looks
+like.
+
+I once started writing a client in Xforms, but it wasn't flexible
+enough and turned me against most GUI C programming.
+
+
+*** Filters in under 25 words:
+
+Filters allow you to modify, mangle and redirect irc messages. You
+can send messages which mean a certain format or style into different
+windows (for oper's filter out NickServ kill's etc)
+
+README.filters contains a detailed explanation and examples on how to
+use filters.
+
+*** How do I Query Someone? (private convertation)
+
+/join <nick>
+
+or
+
+/join =<nick> for a dcc chat, make sure to open the dcc chat first
+
+*** What are all the keystrokes?
+
+Ctrl-Enter - go backwards through nicks that have messaged you
+Ctrl-Shift-Enter - goes forwards
+
+Shft-PageUp/PageDown - scroll forwards and backwards
+
+*** How does nick completion work?
+
+part-nick: at the beginning of the line is expanded to nick:
+
+::part-nick anywhere in the line is expanded to nick. If part-nick is
+not found the :: is removed and part-nick remains.
+
+
diff --git a/ksirc/FilterRuleEditor.cpp b/ksirc/FilterRuleEditor.cpp
new file mode 100644
index 00000000..08ac6584
--- /dev/null
+++ b/ksirc/FilterRuleEditor.cpp
@@ -0,0 +1,244 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: FilterRuleEditor.cpp
+ Last generated: Mon Dec 15 18:14:27 1997
+
+ *********************************************************************/
+
+#include "FilterRuleEditor.h"
+
+#include <qregexp.h>
+#include <qpushbutton.h>
+#include <qlistbox.h>
+#include <qlineedit.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+FilterRuleEditor::FilterRuleEditor
+(
+ QWidget* parent,
+ const char* name
+)
+ : KDialogBase( parent, name, true, i18n( "Edit Filter Rules" ),
+ Close, Close, true )
+{
+ filter = new FilterRuleWidget( this, name );
+
+ setMainWidget( filter );
+
+ updateListBox();
+ newHighlight(0);
+
+ // ### split "OkPressed()" into 2 slots
+ connect( filter->ModifyButton, SIGNAL(clicked()), SLOT(OkPressed()) );
+ connect( filter->InsertButton, SIGNAL(clicked()), SLOT(OkPressed()) );
+
+ connect( filter->NewButton, SIGNAL(clicked()), SLOT(newRule()) );
+ connect( filter->DeleteButton, SIGNAL(clicked()), SLOT(deleteRule()) );
+
+ connect( filter->UpButton, SIGNAL(clicked()), SLOT(raiseRule()) );
+ connect( filter->DownButton, SIGNAL(clicked()), SLOT(lowerRule()) );
+
+ connect( filter->RuleList, SIGNAL(highlighted(int)), SLOT(newHighlight(int)) );
+ connect( filter->RuleList, SIGNAL(selected(int)), SLOT(newHighlight(int)) );
+
+
+ filter->RuleList->setHScrollBarMode( QListBox::AlwaysOff );
+ filter->RuleList->setMultiSelection( FALSE );
+
+ filter->DownButton->setPixmap( BarIcon( "down", KIcon::SizeSmall ) );
+ filter->UpButton->setPixmap( BarIcon( "up", KIcon::SizeSmall ) );
+}
+
+
+FilterRuleEditor::~FilterRuleEditor()
+{
+}
+
+void FilterRuleEditor::newRule()
+{
+ filter->LineTitle->setText( QString::null );
+ filter->LineSearch->setText( QString::null );
+ filter->LineFrom->setText( QString::null );
+ filter->LineTo->setText( QString::null );
+ filter->LineTitle->setFocus();
+
+ filter->InsertButton->setEnabled( true );
+ filter->ModifyButton->setEnabled( false );
+}
+
+void FilterRuleEditor::OkPressed()
+{
+ int number, after;
+ KConfig *kConfig = kapp->config();
+
+ if(filter->InsertButton->isEnabled()){
+ number = kConfig->readNumEntry("Rules", 0) + 1;
+ after = number - 1;
+ kConfig->writeEntry("Rules", number);
+ }
+ else if(filter->ModifyButton->isEnabled()){
+ number = filter->RuleList->currentItem() + 1;
+ after = number - 1;
+ }
+ else{
+ return;
+ }
+
+ QString name = filter->LineTitle->text();
+ QString search = filter->LineSearch->text();
+ QString from = filter->LineFrom->text();
+ QString to = filter->LineTo->text();
+
+ if( name.isEmpty() || search.isEmpty() || from.isEmpty() || to.isEmpty() ){
+ KMessageBox::error(this, i18n("Cannot create the rule since not\n"
+ "all the fields are filled in."), i18n("Error"));
+
+ }
+ else{
+ kConfig->setGroup("FilterRules");
+ QString key;
+ key.sprintf("name-%d", number);
+ kConfig->writeEntry(key, convertSpecial(name));
+ key.sprintf("search-%d", number);
+ kConfig->writeEntry(key, convertSpecial(search));
+ key.sprintf("from-%d", number);
+ kConfig->writeEntry(key, convertSpecial(from));
+ key.sprintf("to-%d", number);
+ kConfig->writeEntry(key, convertSpecial(to));
+ // kConfig->sync();
+ updateListBox(after);
+ }
+}
+
+void FilterRuleEditor::updateListBox(int citem )
+{
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("FilterRules");
+ int number = kConfig->readNumEntry("Rules", 0);
+ filter->RuleList->clear();
+
+ for(; number > 0; number--){
+ QString key;
+ key.sprintf("name-%d", number);
+ filter->RuleList->insertItem(kConfig->readEntry(key), 0);
+ }
+ if(filter->RuleList->count() > 0)
+ filter->RuleList->setCurrentItem(citem);
+ filter->RuleList->repaint();
+
+ filter->DeleteButton->setEnabled( filter->RuleList->currentItem() > -1 );
+ filter->ModifyButton->setEnabled( filter->RuleList->currentItem() > -1 );
+ filter->InsertButton->setEnabled( false );
+ filter->NewButton->setEnabled( true );
+}
+
+void FilterRuleEditor::moveRule(int from, int to)
+{
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("FilterRules");
+ QString src;
+ QString dest;
+ src.sprintf("name-%d", from);
+ dest.sprintf("name-%d", to);
+ kConfig->writeEntry(dest, kConfig->readEntry(src));
+ kConfig->deleteEntry(src);
+ src.sprintf("search-%d", from);
+ dest.sprintf("search-%d", to);
+ kConfig->writeEntry(dest, kConfig->readEntry(src));
+ kConfig->deleteEntry(src);
+ src.sprintf("from-%d", from);
+ dest.sprintf("from-%d", to);
+ kConfig->writeEntry(dest, kConfig->readEntry(src));
+ kConfig->deleteEntry(src);
+ src.sprintf("to-%d", from);
+ dest.sprintf("to-%d", to);
+ kConfig->writeEntry(dest, kConfig->readEntry(src));
+ kConfig->deleteEntry(src);
+}
+
+void FilterRuleEditor::deleteRule()
+{
+ int number = filter->RuleList->currentItem();
+
+ if( number >= 0){
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("FilterRules");
+ int max = kConfig->readNumEntry("Rules");
+ for(int i = number+2; i <= max; i++){
+ moveRule(i, i-1);
+ }
+ max--;
+ kConfig->writeEntry("Rules", max);
+
+ updateListBox();
+ }
+}
+
+void FilterRuleEditor::newHighlight(int i)
+{
+ i++;
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("FilterRules");
+ QString key;
+ key.sprintf("name-%d", i);
+ filter->LineTitle->setText(convertSpecialBack(kConfig->readEntry(key)));
+ key.sprintf("search-%d", i);
+ filter->LineSearch->setText(convertSpecialBack(kConfig->readEntry(key)));
+ key.sprintf("from-%d", i);
+ filter->LineFrom->setText(convertSpecialBack(kConfig->readEntry(key)));
+ key.sprintf("to-%d", i);
+ filter->LineTo->setText(convertSpecialBack(kConfig->readEntry(key)));
+}
+
+void FilterRuleEditor::raiseRule()
+{
+ int item = filter->RuleList->currentItem();
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("FilterRules");
+ int max = kConfig->readNumEntry("Rules");
+ if(item > 0){
+ moveRule(item, max+1);
+ moveRule(item+1, item);
+ moveRule(max+1, item+1);
+ updateListBox(item - 1);
+ }
+}
+
+void FilterRuleEditor::lowerRule()
+{
+ int item = filter->RuleList->currentItem();
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("FilterRules");
+ int max = kConfig->readNumEntry("Rules");
+ if(item < max-1){
+ moveRule(item+2, max+1);
+ moveRule(item+1, item+2);
+ moveRule(max+1, item+1);
+ updateListBox(item+1);
+ }
+}
+
+QString FilterRuleEditor::convertSpecial(QString str)
+{
+ str.replace(QRegExp("\\$"), "$$");
+ return str;
+}
+
+QString FilterRuleEditor::convertSpecialBack(QString str)
+{
+ str.replace(QRegExp("\\$\\$"), "$");
+ return str;
+}
+
+#include "FilterRuleEditor.moc"
+
+// vim:tabstop=2:shiftwidth=2:expandtab:cinoptions=(s,U1,m1
+
diff --git a/ksirc/FilterRuleEditor.dlg b/ksirc/FilterRuleEditor.dlg
new file mode 100644
index 00000000..5461d839
--- /dev/null
+++ b/ksirc/FilterRuleEditor.dlg
@@ -0,0 +1,215 @@
+DlgEdit:v2.0:Dialog:
+Dialog {
+ ClassHeader {FilterRuleEditor.h}
+ ClassSource {FilterRuleEditor.cpp}
+ ClassName {FilterRuleEditor}
+ DataHeader {FilterRuleEditorData.h}
+ DataSource {FilterRuleEditorData.cpp}
+ DataName {FilterRuleEditorData}
+ WindowBaseClass {QDialog}
+ IsModal {FALSE}
+ WindowCaption {Edit Filter Rules}
+ WindowFlags {118784}
+}
+WidgetLayout {
+InitialPos {-1 -1}
+Size {510 250}
+MinSize {0 0}
+MaxSize {32767 32767}
+Grid {10}
+
+Label {
+ Text {Description:}
+ AutoResize {FALSE}
+ Margin {-1}
+ Rect {140 10 80 30}
+ Name {Label_1}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+LineEdit {
+ Text {}
+ EchoMode {Normal}
+ MaxLength {80}
+ FrameShown {TRUE}
+ Rect {220 10 280 30}
+ Name {LineEdit_1}
+ Variable {LineTitle}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+Label {
+ Text {Match:}
+ AutoResize {FALSE}
+ Margin {-1}
+ Rect {140 50 70 30}
+ Name {Label_4}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+LineEdit {
+ Text {}
+ EchoMode {Normal}
+ MaxLength {80}
+ FrameShown {TRUE}
+ Rect {220 50 280 30}
+ Name {LineEdit_2}
+ Variable {LineSearch}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+Label {
+ Text {From:}
+ AutoResize {FALSE}
+ Margin {-1}
+ Rect {140 90 80 30}
+ Name {Label_7}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+Label {
+ Text {To:}
+ AutoResize {FALSE}
+ Margin {-1}
+ Rect {140 130 70 30}
+ Name {Label_9}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+LineEdit {
+ Text {}
+ EchoMode {Normal}
+ MaxLength {32767}
+ FrameShown {TRUE}
+ Rect {220 90 280 30}
+ Name {LineEdit_3}
+ Variable {LineFrom}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+LineEdit {
+ Text {}
+ EchoMode {Normal}
+ MaxLength {80}
+ FrameShown {TRUE}
+ Rect {220 130 280 30}
+ Name {LineEdit_4}
+ Variable {LineTo}
+ LayoutStatus {NoLayout}
+ MinimumSize {0 0}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {TRUE}
+ Text {&Modify}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {390 170 110 30}
+ Name {PushButton_1}
+ Variable {ApplyButton}
+ Signal {[Protected] clicked --> OkPressed ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {FALSE}
+ Text {&Close}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {390 210 110 30}
+ Name {PushButton_2}
+ Signal {[Protected] clicked --> closePressed ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {FALSE}
+ Text {&New Rule}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {270 170 110 30}
+ Name {PushButton_7}
+ Signal {[Protected] clicked --> newRule ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {FALSE}
+ Text {&Delete}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {150 170 110 30}
+ Name {PushButton_8}
+ Variable {deleteButton}
+ Signal {[Protected] clicked --> deleteRule ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {FALSE}
+ Text {Up}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {10 210 55 30}
+ Name {PushButton_9}
+ Signal {[Protected] clicked --> raiseRule ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {FALSE}
+ Text {Down}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {75 210 55 30}
+ Name {PushButton_10}
+ Signal {[Protected] clicked --> lowerRule ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+ListBox {
+ DragSelect {FALSE}
+ AutoScroll {FALSE}
+ ScrollBar {FALSE}
+ AutoScrollBar {TRUE}
+ BottomScrollBar {FALSE}
+ AutoBottomScrollBar {FALSE}
+ SmoothScrolling {FALSE}
+ MultiSelection {FALSE}
+ Style {51}
+ LineWidth {2}
+ Rect {10 10 120 190}
+ Name {ListBox_2}
+ Variable {RuleList}
+ Signal {[Protected] highlighted --> newHighlight (int)}
+ Signal {[Protected] selected --> newHighlight (int)}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+}
diff --git a/ksirc/FilterRuleEditor.h b/ksirc/FilterRuleEditor.h
new file mode 100644
index 00000000..c9cf0437
--- /dev/null
+++ b/ksirc/FilterRuleEditor.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: FilterRuleEditor.h
+ Last generated: Mon Dec 15 18:14:27 1997
+
+ *********************************************************************/
+
+#ifndef FilterRuleEditor_h
+#define FilterRuleEditor_h
+
+#include <qstring.h>
+
+#include <kdialogbase.h>
+
+#include "FilterRuleWidget.h"
+
+class FilterRuleEditor : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ FilterRuleEditor
+ (
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~FilterRuleEditor();
+
+protected slots:
+
+ virtual void newRule();
+ virtual void OkPressed();
+ virtual void deleteRule();
+ virtual void newHighlight(int);
+ virtual void raiseRule();
+ virtual void lowerRule();
+
+protected:
+ void updateListBox(int citem = 0);
+ void moveRule(int, int);
+ QString convertSpecial(QString);
+ QString convertSpecialBack(QString);
+
+ FilterRuleWidget *filter;
+};
+#endif // FilterRuleEditor_included
+
+// vim:tabstop=2:shiftwidth=2:expandtab:cinoptions=(s,U1,m1
+
diff --git a/ksirc/FilterRuleWidget.ui b/ksirc/FilterRuleWidget.ui
new file mode 100644
index 00000000..2ac7f6d4
--- /dev/null
+++ b/ksirc/FilterRuleWidget.ui
@@ -0,0 +1,239 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>FilterRuleWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>FilterRuleWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>541</width>
+ <height>229</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>Layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>InsertButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Insert</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="0">
+ <property name="name">
+ <cstring>DeleteButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Delete</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="0">
+ <property name="name">
+ <cstring>NewButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;New</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="1">
+ <property name="name">
+ <cstring>ModifyButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Modify</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>Layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>DownButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="0">
+ <property name="name">
+ <cstring>UpButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QListBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>RuleList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="0" column="1">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Details</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>LineTitle</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>D&amp;escription:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>LineTitle</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;To:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>LineTo</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>LineTo</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>LineSearch</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>LineFrom</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>M&amp;atch:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>LineSearch</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;From:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>LineFrom</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksirc/KSOpenkSirc/Makefile.am b/ksirc/KSOpenkSirc/Makefile.am
new file mode 100644
index 00000000..3af4d5f2
--- /dev/null
+++ b/ksirc/KSOpenkSirc/Makefile.am
@@ -0,0 +1,26 @@
+KDE_CXXFLAGS = $(USE_RTTI) $(USE_EXCEPTIONS) -UQT_NO_ASCII_CAST
+
+# set the include path for X, qt and KDE
+INCLUDES= $(all_includes)
+
+####### This part is very pws specific
+# you can add here more. This one gets installed
+noinst_LTLIBRARIES = libksopenksirc.la
+
+# Which sources should be compiled for dialog
+
+libksopenksirc_la_SOURCES = \
+ open_ksirc.cpp\
+ open_ksircData.ui\
+ serverFileParser.cpp\
+ enter_combo.cpp
+
+# this option you can leave out. Just, if you use "make dist", you need it
+noinst_HEADERS = open_ksirc.h open_ksircData.h serverDataType.h serverFileParser.h enter_combo.h
+
+# just to make sure, automake makes them
+METASOURCES = AUTO
+
+misc_DATA = servers.txt servers.ini
+miscdir = $(kde_datadir)/ksirc
+
diff --git a/ksirc/KSOpenkSirc/convert-mIRC b/ksirc/KSOpenkSirc/convert-mIRC
new file mode 100755
index 00000000..85550dd3
--- /dev/null
+++ b/ksirc/KSOpenkSirc/convert-mIRC
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+
+while ($line = <STDIN>) {
+ if ($line =~ /.*=(Random .*)SERVER:(.*):(.*)GROUP:.*/) {
+ $service = 'Random';
+ $servername = $1;
+ $server = $2;
+ $ports = $3;
+ print "$service\:$servername\:$server\:$ports\:\n";
+ }
+ elsif ($line =~ /.*=(.*): (.*)SERVER:(.*):(.*)GROUP:.*/) {
+ $service = $1;
+ $servername = $2;
+ $server = $3;
+ $ports = $4;
+
+ print "$service\:$servername\:$server\:$ports\:\n";
+ }
+}
diff --git a/ksirc/KSOpenkSirc/enter_combo.cpp b/ksirc/KSOpenkSirc/enter_combo.cpp
new file mode 100644
index 00000000..3394423d
--- /dev/null
+++ b/ksirc/KSOpenkSirc/enter_combo.cpp
@@ -0,0 +1,10 @@
+#include "enter_combo.h"
+
+void EnterCombo::keyPressEvent( QKeyEvent *e ){
+ if(e->key() == Key_Return || e->key() == Key_Enter)
+ emit(enterPressed());
+ else
+ QComboBox::keyPressEvent(e);
+}
+
+#include "enter_combo.moc"
diff --git a/ksirc/KSOpenkSirc/enter_combo.h b/ksirc/KSOpenkSirc/enter_combo.h
new file mode 100644
index 00000000..f0752a2d
--- /dev/null
+++ b/ksirc/KSOpenkSirc/enter_combo.h
@@ -0,0 +1,37 @@
+#ifndef ENTER_COMBO_H
+#define ENTER_COMBO_H
+
+#include <qcombobox.h>
+#include <qevent.h>
+#include <qkeycode.h>
+#include <qlineedit.h>
+
+#undef KeyPress // X headers...
+
+class EnterCombo : public QComboBox {
+ Q_OBJECT
+public:
+ EnterCombo ( QWidget * parent=0, const char * name=0 )
+ : QComboBox(TRUE, parent, name)
+ {
+ }
+ EnterCombo ( bool rw, QWidget * parent=0, const char * name=0 )
+ : QComboBox(rw, parent, name)
+ {
+ QKeyEvent ke(QEvent::KeyPress, SHIFT|Key_Home, 0, 0);
+ keyPressEvent(&ke);
+ }
+
+ virtual void show(){
+ QComboBox::show();
+ lineEdit()->selectAll();
+ }
+
+signals:
+ void enterPressed();
+
+protected:
+ virtual void keyPressEvent( QKeyEvent *e );
+};
+
+#endif
diff --git a/ksirc/KSOpenkSirc/open_ksirc.cpp b/ksirc/KSOpenkSirc/open_ksirc.cpp
new file mode 100644
index 00000000..5a4a4799
--- /dev/null
+++ b/ksirc/KSOpenkSirc/open_ksirc.cpp
@@ -0,0 +1,377 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: open_ksirc.cpp
+ Last generated: Wed Jul 29 16:41:26 1998
+
+ *********************************************************************/
+
+#include "open_ksirc.h"
+#include "serverDataType.h"
+#include "serverFileParser.h"
+#include "enter_combo.h"
+#include "../ksircserver.h"
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qdict.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kmdcodec.h>
+
+QPtrList<Server> Groups;
+
+#undef Inherited
+#define Inherited open_ksircData
+
+open_ksirc::open_ksirc
+(
+ QWidget* parent,
+ const char* name
+)
+ :
+ Inherited( parent, name, true )
+{
+ setCaption( i18n("Connect to Server") );
+
+ // check for existance of ~/.kde/share/apps/ksirc/servers.txt
+ // if it don't exist use $KDEDIR/share/apps/ksirc/servers.txt
+ // changes are written to ~/.kde/share/apps/ksirc/servers.txt
+
+ QString filename = locate("appdata", "servers.txt");
+ serverFileParser::readDatafile( filename );
+
+ Groups.setAutoDelete(TRUE);
+
+ // TODO add "Recent" to global listing servers here..
+ // Now we read in the Recent group from the config file
+ // remove all recent servers first
+
+ for(Server *s = Groups.first(); s != 0x0; s = Groups.next()){
+ if(s->group() == i18n("Recent")){
+ Groups.remove();
+ }
+ }
+
+ // Add current ones
+ KConfig *conf = kapp->config();
+ conf->setGroup("ServerList");
+ CheckB_StorePassword->setChecked( conf->readBoolEntry("StorePasswords") );
+ QStringList recent = conf->readListEntry("RecentServers");
+ for(QStringList::ConstIterator it = recent.begin(); it != recent.end(); ++it){
+ if(conf->hasGroup("RecentServer-" + *it)){
+ conf->setGroup("RecentServer-" + *it);
+ QPtrList<port> rp;
+ rp.inSort(new port(conf->readEntry("Port", "6667")));
+ QString password = decryptPassword(conf->readEntry("Password"));
+ bool ssl = conf->readBoolEntry("SSL");
+ Groups.insert(0, new Server(i18n("Recent"), *it, rp,
+ i18n("Recent Server"), "", password,
+ ssl));
+ }
+ else {
+ QStringList info = QStringList::split(":", *it);
+ if (info.isEmpty())
+ continue;
+ QString name = info[0];
+ QPtrList<port> rp;
+ if (info.count() > 1)
+ rp.inSort(new port(info[1]));
+ else
+ rp.inSort(new port("6667"));
+ QString password;
+ if (info.count() > 2)
+ password = decryptPassword(info[2]);
+
+ conf->setGroup("RecentServer-" + name);
+ conf->writeEntry("Port", rp.first()->portnum());
+ conf->writeEntry("Password", encryptPassword(password));
+ conf->writeEntry("SSL", false);
+
+ Groups.insert(0, new Server(i18n("Recent"), name, rp,
+ i18n("Recent Server"), "", password));
+ }
+ }
+
+ ComboB_ServerName->setAutoCompletion( TRUE );
+ ComboB_ServerPort->setAutoCompletion( TRUE );
+
+ insertGroupList();
+
+ QString blah = i18n("Recent");
+ setGroup(blah);
+
+ connect(ComboB_ServerGroup, SIGNAL(activated( const QString& )),
+ this, SLOT(setGroup( const QString& )));
+ connect(ComboB_ServerName, SIGNAL(activated( const QString& )),
+ this, SLOT(setServer( const QString& )));
+
+ connect(PB_Connect, SIGNAL(clicked()), this, SLOT(clickConnect()));
+ connect(PB_Edit, SIGNAL(clicked()), this, SLOT(clickEdit()));
+ connect(PB_Cancel, SIGNAL(clicked()), this, SLOT(clickCancel()));
+
+ PB_Connect->setDefault(TRUE);
+ PB_Connect->setAutoDefault(TRUE);
+ PB_Edit->setEnabled(false); // Not yet implemented.
+
+ ComboB_ServerName->setFocus();
+ connect(ComboB_ServerName, SIGNAL(enterPressed()), this, SLOT(clickConnect()));
+}
+
+// insert a sorted list of groups into ComboB_ServerGroup, note that
+// we want to get the recent servers in first so we insert "Recent"
+// in first, then we want Random.
+
+void open_ksirc::insertGroupList()
+{
+ QStrList tempgroups;
+ Server *serv;
+
+ for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
+ if (tempgroups.find(serv->group()) == -1)
+ tempgroups.inSort( serv->group() );
+ }
+
+ ComboB_ServerGroup->insertItem(i18n( "Recent") );
+ ComboB_ServerGroup->insertItem(i18n( "Random") );
+ for (const char* t = tempgroups.first(); t; t = tempgroups.next()) {
+ ComboB_ServerGroup->insertItem( t );
+ }
+}
+
+// insert a sorted list of servers from the group passed as an arg
+// into ComboB_ServerName, if a list is already there delete it.
+// note this does not check for multiple occurrances of the same server
+
+void open_ksirc::insertServerList( const char * group )
+{
+ QListBox *newListBox = new QListBox();
+ Server *serv;
+
+ for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
+ if ( !qstrcmp(serv->group(), group) ) {
+ newListBox->insertItem( serv->server(), 0 );
+ }
+ }
+
+ ComboB_ServerName->setListBox(newListBox);
+// ComboB_ServerName->setCurrentItem( 0 ); // this don't work =(
+ if (newListBox->count() > 0)
+ ComboB_ServerName->setEditText( newListBox->text( 0 ) );
+}
+
+// insert a sorted list of ports from the server passed as an arg
+// into ComboB_ServerPort, if a list is already there delete it.
+// note that this only takes the first occurrance if there is two
+// entiies with the same server.
+
+void open_ksirc::setServer( const QString &serveraddress )
+{
+ QListBox *newListBox = new QListBox();
+ Server *serv;
+ QPtrList<port> portlist;
+ port *p;
+ bool defaultport = FALSE;
+
+ for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
+ if (serv->server() == serveraddress) {
+ setServerDesc( serv->serverdesc() );
+ portlist = serv->ports();
+ for ( p=portlist.last(); p != 0; p=portlist.prev() ) {
+ newListBox->insertItem( p->portnum() );
+ if (strcmp(p->portnum(), "6667") == 0)
+ defaultport = TRUE;
+ }
+ LineE_Password->setText( serv->password() );
+ CheckB_StorePassword->setEnabled( !serv->password().isEmpty() );
+ CheckB_UseSSL->setChecked(serv->usessl());
+ break;
+ }
+ }
+ ComboB_ServerPort->setListBox(newListBox);
+// ComboB_ServerPort->setCurrentItem( 0 ); // doesn't work
+ if (defaultport) {
+ ComboB_ServerPort->setEditText("6667");
+ } else {
+ if (newListBox->count() > 0)
+ ComboB_ServerPort->setEditText( newListBox->text( 0 ) );
+ }
+}
+
+// Sets the server description if the isn't one set it to "Not Available"
+
+void open_ksirc::setServerDesc( QString description )
+{
+ if (description.isNull() || description.isEmpty()) {
+ Label_ServerDesc->setText( i18n("Not available"));
+ } else {
+ Label_ServerDesc->setText( description );
+ }
+}
+
+// This has got nothing to do with real encryption, it just scrambles
+// the password a little bit for saving it into the config file.
+// A random string of the same length as the password in UTF-8 is generated
+// and then each byte of the UTF-8 password is xored with the corresponding
+// byte of the random string. The returned value is a base64 encoding of
+// that random string followed by the scrambled password.
+QString open_ksirc::encryptPassword( const QString &password )
+{
+ QCString utf8 = password.utf8();
+ // Can contain NULL bytes after XORing
+ unsigned int utf8Length(utf8.length());
+ QByteArray result(utf8Length << 1);
+ memcpy(result.data(), kapp->randomString(utf8Length).latin1(), utf8Length);
+ for (unsigned int i = 0; i < utf8Length; ++i)
+ result[i + utf8Length] = utf8[i] ^ result[i];
+ return QString::fromLatin1(KCodecs::base64Encode(result));
+}
+
+QString open_ksirc::decryptPassword( const QString &scrambled )
+{
+ QByteArray base64, orig;
+ base64.duplicate(scrambled.latin1(), scrambled.length());
+ KCodecs::base64Decode(base64, orig);
+ QCString result;
+ for (unsigned int i = 0; i < (orig.size() >> 1); ++i)
+ result += orig[i] ^ orig[i + (orig.size() >> 1)];
+ return QString::fromUtf8(result);
+}
+
+void open_ksirc::setGroup( const QString &group )
+{
+ insertServerList( group );
+ if (ComboB_ServerName->count() > 0) {
+ QString blah = QString(ComboB_ServerName->text( 0 ));
+ setServer(blah);
+ } else {
+ setServerDesc( "" );
+ ComboB_ServerPort->setEditText("6667");
+ ComboB_ServerPort->insertItem("6667");
+ }
+ if(ComboB_ServerPort->currentText() == 0x0){
+ ComboB_ServerPort->setEditText("6667");
+ ComboB_ServerPort->insertItem("6667");
+ }
+}
+
+void open_ksirc::clickConnect()
+{
+ if ( ComboB_ServerName->currentText().isEmpty() )
+ {
+ KMessageBox::information( this, i18n( "Please enter a server name." ) );
+ return;
+ }
+
+ QString server;
+ QString port;
+ QString script;
+ Server *serv;
+ KConfig *conf = kapp->config();
+
+ hide();
+
+ server = ComboB_ServerName->currentText();
+ port = ComboB_ServerPort->currentText();
+
+ for ( serv=Groups.first(); serv != 0; serv=Groups.next() ) {
+ if (strcmp(serv->server(), server) == 0) {
+ script = serv->script();
+ }
+ break;
+ }
+
+ if(server.length() == 0)
+ reject();
+
+ if(port.isEmpty())
+ port = "6667";
+
+ QString plain, scrambled;
+ if (!LineE_Password->text().isEmpty())
+ {
+ plain = LineE_Password->text();
+ if (CheckB_StorePassword->isChecked())
+ scrambled = encryptPassword(LineE_Password->text());
+ }
+
+ conf->setGroup("ServerList");
+ conf->writeEntry("StorePasswords", CheckB_StorePassword->isChecked());
+ QStringList recent = conf->readListEntry("RecentServers");
+ if(recent.contains(server)){
+ QStringList::Iterator it = recent.find(server);
+ recent.remove(it);
+ }
+
+ /*
+ * This is legacy code only
+ */
+ //str is now "server:port"
+ //plain is now "server:port" or "server:port:pass" if a password was entered
+ //scrambled is now "server:port" or "server:port:scrambledpass" if
+ //a password was given and "store password" is checked
+
+ for (QStringList::Iterator it = recent.begin(); it != recent.end(); ) {
+ if ((*it).startsWith(server)) // ignore password
+ {
+ QStringList::Iterator del = it++;
+ recent.remove(del);
+ }
+ else
+ ++it;
+ }
+
+ recent.prepend(server);
+ conf->writeEntry("RecentServers", recent);
+
+ conf->setGroup("RecentServer-" + server);
+ conf->writeEntry("Port", port);
+ conf->writeEntry("Password", scrambled);
+ conf->writeEntry("SSL", CheckB_UseSSL->isChecked());
+
+ conf->sync();
+
+ KSircServer kss(server,
+ port,
+ script,
+ plain,
+ CheckB_UseSSL->isChecked());
+
+ // emit open_ksircprocess( server, port, script );
+ emit open_ksircprocess(kss);
+
+ accept();
+}
+
+void open_ksirc::clickCancel()
+{
+ reject();
+}
+
+void open_ksirc::clickEdit()
+{
+ // TODO open new server editor
+}
+
+void open_ksirc::passwordChanged( const QString& password )
+{
+ CheckB_StorePassword->setEnabled( !password.isEmpty() );
+}
+
+open_ksirc::~open_ksirc()
+{
+ Groups.clear();
+}
+
+#include "open_ksirc.moc"
+
+// vim: ts=2 sw=2 et
diff --git a/ksirc/KSOpenkSirc/open_ksirc.h b/ksirc/KSOpenkSirc/open_ksirc.h
new file mode 100644
index 00000000..81145fca
--- /dev/null
+++ b/ksirc/KSOpenkSirc/open_ksirc.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: open_ksirc.h
+ Last generated: Wed Jul 29 16:41:26 1998
+
+ *********************************************************************/
+
+#ifndef open_ksirc_included
+#define open_ksirc_included
+
+#include "open_ksircData.h"
+
+#include <qdict.h>
+
+class KSircServer;
+
+class open_ksirc : public open_ksircData
+{
+ Q_OBJECT
+
+public:
+
+ open_ksirc
+ (
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~open_ksirc();
+
+protected slots:
+ void setGroup( const QString& );
+ void setServer( const QString& );
+ void clickConnect();
+ void clickCancel();
+ void clickEdit();
+ void passwordChanged( const QString& );
+
+private:
+ void insertGroupList();
+ void insertServerList( const char * );
+ void setServerDesc( QString );
+ QString encryptPassword( const QString & );
+ QString decryptPassword( const QString & );
+
+signals:
+// void open_ksircprocess( const char *, int, const char * );
+ void open_ksircprocess( KSircServer & );
+
+};
+#endif // open_ksirc_included
diff --git a/ksirc/KSOpenkSirc/open_ksircData.ui b/ksirc/KSOpenkSirc/open_ksircData.ui
new file mode 100644
index 00000000..ae97f341
--- /dev/null
+++ b/ksirc/KSOpenkSirc/open_ksircData.ui
@@ -0,0 +1,337 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>open_ksircData</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>Form1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>593</width>
+ <height>196</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Server/Quick connect to:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ComboB_ServerName</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="4">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Port:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ComboB_ServerPort</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ComboB_ServerGroup</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose a server for an IRC Network</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Usually IRC Servers are connected to a net (IRCNet, Freenode, etc.). Here, you can select the closest server for your favorite network.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Group:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ComboB_ServerGroup</cstring>
+ </property>
+ </widget>
+ <widget class="EnterCombo" row="1" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ComboB_ServerName</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter/choose a server to connect to</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If you selected an IRC Network in &lt;i&gt;"Group"&lt;/i&gt;, this window shows all of its servers. If you did not choose a group, you can enter your own here or select one of the recently used ones (&lt;i&gt;"Quick Connect"&lt;/i&gt;).</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="4">
+ <property name="name">
+ <cstring>ComboB_ServerPort</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose a server port</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Using &lt;i&gt;"6667"&lt;/i&gt; or &lt;i&gt;"6666"&lt;/i&gt; here is safe in most cases. Only use other values if you have been told so.</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>GroupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Server Description</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This is the description of the server currently selected</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>Label_ServerDesc</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox" row="2" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Server Access</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Pass&amp;word:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>LineE_Password</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>LineE_Password</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>CheckB_UseSSL</cstring>
+ </property>
+ <property name="text">
+ <string>Use SS&amp;L</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This will use a secure connection to the server. This must be supported by the server.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="2">
+ <property name="name">
+ <cstring>CheckB_StorePassword</cstring>
+ </property>
+ <property name="text">
+ <string>S&amp;tore password</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This will cause your server password to be stored on your disk.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton" row="3" column="4">
+ <property name="name">
+ <cstring>PB_Cancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Cancel Connect</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Cancel Connect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="3">
+ <property name="name">
+ <cstring>PB_Connect</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>C&amp;onnect</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Connect to the selected server</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Connect to the server given in &lt;i&gt;"Server / Quick Connect to:"&lt;/i&gt; on the port given in &lt;i&gt;"Port:"&lt;/i&gt;.</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>PB_Edit</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Edit Servers</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>EnterCombo</class>
+ <header location="local">enter_combo.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>1</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="646">789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>LineE_Password</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>Form1</receiver>
+ <slot>passwordChanged(const QString&amp;)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>ComboB_ServerGroup</tabstop>
+ <tabstop>ComboB_ServerName</tabstop>
+ <tabstop>ComboB_ServerPort</tabstop>
+ <tabstop>LineE_Password</tabstop>
+ <tabstop>CheckB_StorePassword</tabstop>
+ <tabstop>PB_Edit</tabstop>
+ <tabstop>PB_Connect</tabstop>
+ <tabstop>PB_Cancel</tabstop>
+</tabstops>
+<slots>
+ <slot access="protected">passwordChanged(const QString &amp;)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksirc/KSOpenkSirc/serverDataType.h b/ksirc/KSOpenkSirc/serverDataType.h
new file mode 100644
index 00000000..80b94e27
--- /dev/null
+++ b/ksirc/KSOpenkSirc/serverDataType.h
@@ -0,0 +1,56 @@
+#ifndef SERVERDATATYPE_H
+#define SERVERDATATYPE_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+class port
+{
+
+public:
+ port( const QString &portnum ) { p=portnum; }
+ QString portnum() const { return p; }
+
+private:
+ QString p;
+
+};
+
+
+class Server
+{
+
+public:
+ Server( const QString &group,
+ const QString &server,
+ QPtrList<port> ports,
+ const QString &serverdesc,
+ const QString &script,
+ const QString &password = QString::null,
+ bool dossl = false
+ ) {
+ g=group; s=server; p=ports; sd=serverdesc; sc=script;
+ pass=password;
+ ssl = dossl;
+ p.setAutoDelete(TRUE);
+ }
+ QString group() const { return g; }
+ QString server() const { return s; }
+ QPtrList<port> ports() const { return p; }
+ QString serverdesc() const { return sd; }
+ QString script() const { return sc; }
+ QString password() const { return pass; }
+ bool usessl() const { return ssl; }
+
+private:
+ QString g;
+ QString s;
+ QPtrList<port> p;
+ QString sd;
+ QString sc;
+ QString pass;
+ bool ssl;
+
+};
+
+#endif
diff --git a/ksirc/KSOpenkSirc/serverFileParser.cpp b/ksirc/KSOpenkSirc/serverFileParser.cpp
new file mode 100644
index 00000000..8e6ba80e
--- /dev/null
+++ b/ksirc/KSOpenkSirc/serverFileParser.cpp
@@ -0,0 +1,114 @@
+#include "serverFileParser.h"
+#include "serverDataType.h"
+#include <qfile.h>
+#include <stdlib.h>
+
+#include <kstandarddirs.h>
+#include <kdebug.h>
+
+extern QPtrList<Server> Groups;
+
+// Opens, reads and parses server information from a server file,
+// sets the information in the global variable and returns 1 if
+// sucessful, takes a filename as an argument.
+
+int serverFileParser::readDatafile( const char *fileName )
+{
+ Groups.setAutoDelete( TRUE );
+ Groups.clear();
+ QFile serverFile( fileName );
+ if ( !serverFile.open( IO_ReadOnly ) )
+ return -1;
+
+ QTextStream fileStream(&serverFile);
+
+ // the file is layed out as follows:
+ // service:servername:serveraddress:ports:script:
+ // so we parse it this way
+
+ while( !fileStream.eof() ) {
+ QString str = fileStream.readLine();
+ const char *strC = str.ascii();
+ char *token;
+ char groupC[1024], servernameC[1024], serveraddressC[1024], portsC[1024];
+ int pos = 0;
+ QString group;
+ QString servername;
+ QString serveraddress;
+ QPtrList<port> ports;
+ QString script;
+
+ QString buf;
+ QString portbuff;
+
+ pos = sscanf(strC, "%1023[^:]:%1024[^:]:%1023[^:]:%1023[^:]:", groupC, servernameC, serveraddressC, portsC);
+ if(pos != 4){
+ kdWarning() << "Failed to parse servers.txt on line: " << strC << ". Invalid format" << endl;
+ return 0;
+ }
+ group = groupC;
+ servername = servernameC;
+ serveraddress = serveraddressC;
+ token = strtok(portsC, ",");
+ while(token != NULL){
+ ports.inSort(new port(token));
+ token = strtok(NULL, ",");
+ }
+
+ /*
+ for( uint loc = 0; loc <= str.length(); loc++ ) {
+ if ( str[loc] == ':' || loc == str.length()) {
+ switch(pos) {
+ case 0: // service
+ group = buf.copy();
+ break;
+ case 1: // server name
+ servername = buf.copy();
+ break;
+ case 2: // server address
+ serveraddress = buf.copy();
+ break;
+ case 3: // port listing
+ for ( uint portloc = 0; portloc <= buf.length(); portloc++ ) {
+ if (buf[portloc] == ',' || portloc == buf.length()) {
+ if (!portbuff.isEmpty())
+ ports.inSort( new port(portbuff));
+ portbuff.truncate( 0 );
+ } else {
+ portbuff += buf[portloc];
+ }
+ }
+ break;
+ default: // script
+ script = buf.copy();
+ }
+ pos++;
+ buf.truncate( 0 );
+ portbuff.truncate( 0 );
+ } else {
+ buf += str[loc];
+ }
+ } // for loop
+ */
+
+
+ Groups.inSort( new Server(group, serveraddress, ports,
+ servername, script) );
+
+ } // while loop
+
+ serverFile.close();
+ return 1;
+
+}
+
+// Writes the data stored in the global variable to the server file,
+// returns 1 if sucessful, takes a filename as an argument, uhh NOT.
+// we want to write it ~/.kde/share/apps/ksirc/servers.txt
+//
+
+int writeDataFile()
+{
+ QString filename(KGlobal::dirs()->saveLocation("appdata")+"servers.txt");
+ return 1;
+}
diff --git a/ksirc/KSOpenkSirc/serverFileParser.h b/ksirc/KSOpenkSirc/serverFileParser.h
new file mode 100644
index 00000000..f3fd67e1
--- /dev/null
+++ b/ksirc/KSOpenkSirc/serverFileParser.h
@@ -0,0 +1,13 @@
+#ifndef serverFileParser_included
+#define serverFileParser_included
+
+#include <qobject.h>
+
+class serverFileParser
+{
+ public:
+ static int readDatafile( const char *fileName );
+ static int writeDataFile();
+};
+
+#endif
diff --git a/ksirc/KSOpenkSirc/servers.ini b/ksirc/KSOpenkSirc/servers.ini
new file mode 100644
index 00000000..8f3de1ee
--- /dev/null
+++ b/ksirc/KSOpenkSirc/servers.ini
@@ -0,0 +1,362 @@
+; Please report errors and broken servers to servers@mirc.com
+; June 12th, 2001
+
+[servers]
+n0=Random US DALnet serverSERVER:irc.dal.net:6662,6663,6664GROUP:01
+n1=Random EU DALnet serverSERVER:irc.eu.dal.net:6667GROUP:02
+n2=Random US EFnet serverSERVER:us.rr.efnet.net:6667GROUP:03
+n3=Random EU EFnet serverSERVER:eu.rr.efnet.net:6667GROUP:04
+n4=Random CA EFnet serverSERVER:ca.rr.efnet.net:6667GROUP:05
+n5=Random AU EFnet serverSERVER:au.rr.efnet.net:6667GROUP:06
+n6=Random US IRCnet serverSERVER:us.ircnet.org:6665,6666,6668GROUP:07
+n7=Random EU IRCnet serverSERVER:eu.ircnet.org:6665,6666,6668GROUP:08
+n8=Random AU IRCnet serverSERVER:au.ircnet.org:6667GROUP:09
+n9=Random US Undernet serverSERVER:us.undernet.org:6667GROUP:10
+n10=Random EU Undernet serverSERVER:eu.undernet.org:6667GROUP:11
+n11=Accessirc: Random serverSERVER:irc.accessirc.net:6667GROUP:Accessirc
+n12=Acestar: Random serverSERVER:irc.acestar.org:6667GROUP:Acestar
+n13=Action-IRC: Random serverSERVER:irc.action-irc.net:6660,6662,6664GROUP:Action-IRC
+n14=Afternet: Random serverSERVER:irc.afternet.org:6667GROUP:Afternet
+n15=Alternativenet: Random serverSERVER:irc.altnet.org:6667GROUP:Alternativenet
+n16=AnotherNet: Random serverSERVER:irc.another.net:6667,7000GROUP:Anothernet
+n17=ArabChat: Random serverSERVER:irc.arabchat.org:6660,6661,6662GROUP:ArabChat
+n18=AstroLink: Random serverSERVER:irc.astrolink.org:6660,6662,6663GROUP:AstroLink
+n19=Asylumnet: Random serverSERVER:irc.asylum-net.org:6661,6664,7000GROUP:Asylumnet
+n20=Austnet: Random AU serverSERVER:au.austnet.org:6667GROUP:Austnet
+n21=Austnet: Random NZ serverSERVER:nz.austnet.org:6667GROUP:Austnet
+n22=Austnet: Random SG serverSERVER:sg.austnet.org:6667GROUP:Austnet
+n23=Austnet: Random US serverSERVER:us.austnet.org:6667GROUP:Austnet
+n24=AwesomeChat: Random serverSERVER:irc.awesomechat.net:6662,6665,6666GROUP:AwesomeChat
+n25=Axenet: Random serverSERVER:irc.axenet.org:6661,6664,6665GROUP:Axenet
+n26=BeyondIRC: Random serverSERVER:irc.beyondirc.net:6660,6662,6664GROUP:Beyondirc
+n27=Blabbernet: Random serverSERVER:irc.blabber.net:6667,7000GROUP:Blabbernet
+n28=Blitzed: Random serverSERVER:irc.blitzed.org:6667,7000GROUP:Blitzed
+n29=Brasirc: Random serverSERVER:irc.brasirc.net:6666,6667GROUP:Brasirc
+n30=Brasirc: BR, PA, BelemSERVER:irc.libnet.com.br:6666,6668,7777GROUP:Brasirc
+n31=Brasirc: BR, SC, FlorianopolisSERVER:irc.globalite.com.br:6667GROUP:Brasirc
+n32=Brasnet: Random European serverSERVER:eu.brasnet.org:6665,6666,6668GROUP:Brasnet
+n33=Brasnet: Random serverSERVER:irc.brasnet.org:6665,6666,6668GROUP:Brasnet
+n34=Brasnet: Random US serverSERVER:us.brasnet.org:6665,6666,6668GROUP:Brasnet
+n35=Bulgaria: Random serverSERVER:irc.bulgaria.org:6666,6668,6669GROUP:Bulgaria
+n36=CCnet: Random serverSERVER:irc.cchat.net:6667,7000GROUP:CCnet
+n37=CCnet: US, TX, DallasSERVER:irc2.cchat.net:6667,7000GROUP:CCnet
+n38=ChatArea: Random serverSERVER:irc.chatarea.net:6667GROUP:ChatArea
+n39=Chatcafe: Random serverSERVER:irc.chatcafe.net:6667GROUP:Chatcafe
+n40=ChatCentral2: Random serverSERVER:irc.cc2.org:6660,6661,6663GROUP:ChatCentral2
+n41=ChatCircuit: Random serverSERVER:irc.chatcircuit.com:6668GROUP:ChatCircuit
+n42=Chatlink: Random serverSERVER:irc.chatlink.org:6667GROUP:Chatlink
+n43=Chatnet: Random AU serverSERVER:au.chatnet.org:6667GROUP:Chatnet
+n44=Chatnet: Random EU serverSERVER:eu.chatnet.org:6667GROUP:Chatnet
+n45=Chatnet: Random US serverSERVER:us.chatnet.org:6667GROUP:Chatnet
+n46=Chatpinoy: Random serverSERVER:irc.chatpinoy.com:6667GROUP:Chatpinoy
+n47=ChatPR: Random serverSERVER:irc.chatpr.org:6667GROUP:ChatPR
+n48=Chatroom: Random serverSERVER:irc.chatroom.org:6667GROUP:Chatroom
+n49=Chatsolutions: Random serverSERVER:irc.chatsolutions.org:6667GROUP:Chatsolutions
+n50=Chatster: Random serverSERVER:irc.chatster.org:6667GROUP:Chatster
+n51=ChatX: Random serverSERVER:irc.chatx.net:6667GROUP:ChatX
+n52=CNN: CNN News discussionsSERVER:chat.cnn.com:6668,6669,7000GROUP:CNN
+n53=Coolchat: Random serverSERVER:irc.coolchat.net:6667GROUP:Coolchat
+n54=Criten: Random serverSERVER:irc.criten.net:6667GROUP:Criten
+n55=Cyberchat: Random serverSERVER:irc.cyberchat.org:6667,6668GROUP:Cyberchat
+n56=CyGanet: Random serverSERVER:irc.cyga.net:6667GROUP:CyGanet
+n57=DALnet: AS, MY, Kuala LumpurSERVER:coins.dal.net:6663,6664,6668GROUP:DALnet
+n58=DALnet: AU, AdelaideSERVER:ozbytes.dal.net:6667,7000GROUP:DALnet
+n59=DALnet: CA, BC, VancouverSERVER:vancouver.dal.net:6661,6662,6666GROUP:DALnet
+n60=DALnet: EU, DE, FrankfurtSERVER:nexgo.de.eu.dal.net:6664,6665,6669GROUP:DALnet
+n61=DALnet: EU, NO, OsloSERVER:powertech.no.eu.dal.net:6666,6667,7000GROUP:DALnet
+n62=DALnet: EU, NO, TromsoSERVER:viking.dal.net:6666,6668,6669GROUP:DALnet
+n63=DALnet: EU, SE, GoteborgSERVER:ced.dal.net:6667,7000GROUP:DALnet
+n64=DALnet: EU, SE, StockholmSERVER:paranoia.dal.net:6661,6662,6669GROUP:DALnet
+n65=DALnet: EU, UK, LondonSERVER:defiant.dal.net:6668,6669,7001GROUP:DALnet
+n66=DALnet: US, FL, HollywoodSERVER:sodre.dal.net:6663,6666,6668GROUP:DALnet
+n67=DALnet: US, IN, HebronSERVER:hebron.dal.net:6661,6664,6669GROUP:DALnet
+n68=DALnet: US, MA, NorwoodSERVER:twisted.dal.net:6663,6665,6669GROUP:DALnet
+n69=DALnet: US, MD, ManchesterSERVER:qis.md.us.dal.net:6660,6664,6668GROUP:DALnet
+n70=DALnet: US, NY, New York CitySERVER:liberty.dal.net:6662,6666,6669GROUP:DALnet
+n71=DALnet: US, OH, ToledoSERVER:glass.dal.net:6660,6661,6664GROUP:DALnet
+n72=DALnet: US, OK, TulsaSERVER:webzone.dal.net:6665,6666,6669GROUP:DALnet
+n73=Darkfire: Random serverSERVER:irc.darkfire.net:6667,7000,8000GROUP:Darkfire
+n74=Darkfyre: Random serverSERVER:irc.darkfyre.net:6667GROUP:Darkfyre
+n75=DarkMyst: Random serverSERVER:irc.darkmyst.org:6667GROUP:DarkMyst
+n76=DarkServ: Random serverSERVER:irc.darkserv.net:6664,6665,6666GROUP:DarkServ
+n77=Darktree: Random serverSERVER:irc.darktree.net:6667GROUP:Darktree
+n78=Deepspace: Disability networkSERVER:irc.deepspace.org:6667GROUP:Deepspace
+n79=Different: Random serverSERVER:irc.different.net:6667GROUP:Different
+n80=Digarix: Random serverSERVER:irc.digarix.net:6667GROUP:Digarix
+n81=Digatech: Random serverSERVER:irc.digatech.net:6667GROUP:Digatech
+n82=Digitalirc: Random serverSERVER:irc.digitalirc.net:6667GROUP:Digitalirc
+n83=Dobbernet: Random serverSERVER:irc.dobber.net:6667GROUP:Dobbernet
+n84=DragonLynk: Random serverSERVER:irc.dragonlynk.net:6661,6665,6666GROUP:DragonLynk
+n85=Dreamcast: Random serverSERVER:irc0.dreamcast.com:6667GROUP:Dreamcast
+n86=Dreamnet: Random serverSERVER:irc.dreamnet.org:6664,6665,6666GROUP:Dreamnet
+n87=DwarfStar: Random serverSERVER:irc.dwarfstar.net:6667GROUP:Dwarfstar
+n88=Dynastynet: Random serverSERVER:irc.dynastynet.net:6667GROUP:Dynastynet
+n89=EFnet: CA, AB, EdmontonSERVER:irc.powersurfr.com:6667GROUP:EFnet
+n90=EFnet: CA, ON, TorontoSERVER:irc2.magic.ca:6667GROUP:EFnet
+n91=EFnet: CA, QB, MontrealSERVER:irc.etsmtl.ca:6667GROUP:EFnet
+n92=EFnet: EU, FI, HelsinkiSERVER:efnet.cs.hut.fi:6667GROUP:EFnet
+n93=EFnet: EU, FR, ParisSERVER:irc.isdnet.fr:6667,6668,6669GROUP:EFnet
+n94=EFnet: EU, NL, AmsterdamSERVER:efnet.vuurwerk.nl:6667GROUP:EFnet
+n95=EFnet: EU, NO, HomelienSERVER:irc.homelien.no:6666,7000,7001GROUP:EFnet
+n96=EFnet: EU, RU, MoscowSERVER:irc.rt.ru:6662,6665,6668GROUP:EFnet
+n97=EFnet: EU, SE, DalarnaSERVER:irc.du.se:6666,6668,6669GROUP:EFnet
+n98=EFnet: EU, SE, SwedenSERVER:irc.light.se:6667GROUP:EFnet
+n99=EFnet: EU, UK, DemonSERVER:efnet.demon.co.uk:6665,6666,6668GROUP:EFnet
+n100=EFnet: EU, UK, LondonSERVER:irc.ins.net.uk:6665,6666,6668GROUP:EFnet
+n101=EFnet: ME, IL, InterSERVER:irc.inter.net.il:6665,6666,6668GROUP:EFnet
+n102=EFnet: US, CA, Los AngelesSERVER:irc.west.gblx.net:6667GROUP:EFnet
+n103=EFnet: US, CA, San Luis ObispoSERVER:irc.prison.net:6666,6667GROUP:EFnet
+n104=EFnet: US, CA, StanfordSERVER:irc.stanford.edu:6667GROUP:EFnet
+n105=EFnet: US, CO, ColoradoSERVER:irc.colorado.edu:5555,6665,6666GROUP:EFnet
+n106=EFnet: US, GA, Atlanta (Emory)SERVER:irc.emory.edu:6667GROUP:EFnet
+n107=EFnet: US, GA, Atlanta (Mindspring)SERVER:irc.mindspring.com:6660,6663,6668GROUP:EFnet
+n108=EFnet: US, IL, ChicagoSERVER:irc.mcs.net:6666,6667,6668GROUP:EFnet
+n109=EFnet: US, IL, ChicagoSERVER:irc.plur.net:6667GROUP:EFnet
+n110=EFnet: US, MI, Ann ArborSERVER:irc.umich.edu:6667GROUP:EFnet
+n111=EFnet: US, MN, Twin CitiesSERVER:irc.umn.edu:6665,6666,6668GROUP:EFnet
+n112=EFnet: US, NY, New YorkSERVER:irc.east.gblx.net:6667GROUP:EFnet
+n113=EgyptianIRC: Random serverSERVER:irc.egyptianirc.net:6667,6668,6669GROUP:EgyptianIRC
+n114=EntertheGame: Random serverSERVER:irc.enterthegame.com:6667,6668,6669GROUP:EntertheGame
+n115=Escaped: Random serverSERVER:irc.escaped.net:6661,6665,6668GROUP:Escaped
+n116=Esprit: Random serverSERVER:irc.esprit.net:6667GROUP:Esprit
+n117=euIRC: Random serverSERVER:irc.euirc.net:6665,6666,6668GROUP:euIRC
+n118=ExodusIRC: Random serverSERVER:irc.exodusirc.net:6662,6663,6664GROUP:ExodusIRC
+n119=FDFnet: Random serverSERVER:irc.fdf.net:6666,6668,9999GROUP:FDFnet
+n120=FEFnet: Random serverSERVER:irc.fef.net:6667GROUP:FEFnet
+n121=Forestnet: Random serverSERVER:irc.forestnet.org:6667,7000GROUP:Forestnet
+n122=FreedomChat: Random serverSERVER:chat.freedomchat.net:6667GROUP:FreedomChat
+n123=FunNet: Random serverSERVER:irc.funnet.org:6667GROUP:FunNet
+n124=Galaxynet: Random serverSERVER:irc.galaxynet.org:6662,6663,6666GROUP:GalaxyNet
+n125=Galaxynet: AU, NZ, AucklandSERVER:auckland.nz.galaxynet.org:6661,6666,6668GROUP:GalaxyNet
+n126=Galaxynet: EU, BE, OnlineSERVER:online.be.galaxynet.org:6664,6666,6668GROUP:GalaxyNet
+n127=Galaxynet: EU, SE, VltmediaSERVER:vltmedia.se.galaxynet.org:6662,6664,6666GROUP:GalaxyNet
+n128=Galaxynet: US, FL, FloridaSERVER:gymnet.us.galaxynet.org:6663,6666,6668GROUP:GalaxyNet
+n129=Galaxynet: US, WA, SeattleSERVER:freei.us.galaxynet.org:6661,6665,6666GROUP:GalaxyNet
+n130=Gamesnet: Random east US serverSERVER:east.gamesnet.net:6667GROUP:Gamesnet
+n131=Gamesnet: Random west US serverSERVER:west.gamesnet.net:6667GROUP:Gamesnet
+n132=GizNet: Random serverSERVER:irc.giznet.com:6666,6668,6669GROUP:GizNet
+n133=Globalchat: Random serverSERVER:irc.globalchat.org:6667GROUP:Globalchat
+n134=Grnet: Random EU serverSERVER:gr.irc.gr:6667,7000GROUP:GRnet
+n135=Grnet: Random serverSERVER:srv.irc.gr:6667,7000GROUP:GRnet
+n136=Grnet: Random US serverSERVER:us.irc.gr:6667,7000GROUP:GRnet
+n137=HabberNet: Random serverSERVER:irc.habber.net:6667GROUP:HabberNet
+n138=HanIRC: Random serverSERVER:irc.hanirc.org:6667GROUP:HanIRC
+n139=Hellenicnet: Random serverSERVER:irc.mirc.gr:6667,7000GROUP:Hellenicnet
+n140=Hybnet: Random serverSERVER:irc.hybnet.net:6667GROUP:Hybnet
+n141=ICQnet: Random serverSERVER:irc.icq.com:6667GROUP:ICQnet
+n142=Infatech: Random serverSERVER:irc.infatech.net:6661,6663,6666GROUP:Infatech
+n143=Infinity: Random serverSERVER:irc.infinity-irc.org:6667GROUP:Infinity
+n144=Infomatrix: Random serverSERVER:irc.infomatrix.net:6667GROUP:Infomatrix
+n145=IRC-Hispano: Random serverSERVER:irc.irc-hispano.org:6667GROUP:IRC-Hispano
+n146=IRChat: Random serverSERVER:irc.irchat.net:6661,6662,6666GROUP:IRChat
+n147=IRChat-br: Random serverSERVER:irc.irchat.com.br:6667GROUP:IRChat-br
+n148=IRCLink: EU, NO, AlesundSERVER:alesund.no.eu.irclink.net:6667,6668,6669GROUP:IRCLink
+n149=IRCLink: EU, NO, OsloSERVER:frogn.no.eu.irclink.net:6667,6668,6669GROUP:IRCLink
+n150=IRCLink: US, SC, Rock HillSERVER:rockhill.sc.us.irclink.net:6667,6668,6669GROUP:IRCLink
+n151=IRCnet: EU, IT, RandomSERVER:irc.ircd.it:6665,6666,6668GROUP:IRCnet
+n152=IRCnet: AS, JP, TokyoSERVER:irc.tokyo.wide.ad.jp:6667GROUP:IRCnet
+n153=IRCnet: AU, MelbourneSERVER:yoyo.cc.monash.edu.au:6668,6669,9990GROUP:IRCnet
+n154=IRCnet: AU, SydneySERVER:irc.usyd.edu.au:6667GROUP:IRCnet
+n155=IRCnet: EU, AT, LinzSERVER:linz.irc.at:6666,6667,6668GROUP:IRCnet
+n156=IRCnet: EU, AT, WienSERVER:vienna.irc.at:6666,6668,6669GROUP:IRCnet
+n157=IRCnet: EU, BE, BrusselsSERVER:irc.belnet.be:6667GROUP:IRCnet
+n158=IRCnet: EU, BE, ZaventemSERVER:ircnet.wanadoo.be:6661,6664,6665GROUP:IRCnet
+n159=IRCnet: EU, CZ, PragueSERVER:irc.felk.cvut.cz:6667GROUP:IRCnet
+n160=IRCnet: EU, DE, BerlinSERVER:irc.fu-berlin.de:6665,6666,6668GROUP:IRCnet
+n161=IRCnet: EU, DE, DusseldorfSERVER:irc.freenet.de:6665,6666,6668GROUP:IRCnet
+n162=IRCnet: EU, DE, StuttgartSERVER:irc.belwue.de:6665,6666,6668GROUP:IRCnet
+n163=IRCnet: EU, DK, CopenhagenSERVER:irc.ircnet.dk:6667GROUP:IRCnet
+n164=IRCnet: EU, EE, TallinnSERVER:irc.estpak.ee:6666,6667,6668GROUP:IRCnet
+n165=IRCnet: EU, FI, EspooSERVER:irc.funet.fi:6661,6663,6668GROUP:IRCnet
+n166=IRCnet: EU, FI, HelsinkiSERVER:irc.cs.hut.fi:6667GROUP:IRCnet
+n167=IRCnet: EU, FR, NiceSERVER:irc.eurecom.fr:6667GROUP:IRCnet
+n168=IRCnet: EU, FR, ParisSERVER:irc.fr.ircnet.net:6667GROUP:IRCnet
+n169=IRCnet: EU, GR, ThessalonikiSERVER:irc.ee.auth.gr:6666,6668,6669GROUP:IRCnet
+n170=IRCnet: EU, HU, BudapestSERVER:irc.elte.hu:6667GROUP:IRCnet
+n171=IRCnet: EU, IL, HaifaSERVER:ircnet.netvision.net.il:6661,6662,6663GROUP:IRCnet
+n172=IRCnet: EU, IS, ReykjavikSERVER:irc.ircnet.is:6663,6664,6668GROUP:IRCnet
+n173=IRCnet: EU, IS, ReykjavikSERVER:irc.ircnet.is:6661,6662,6666GROUP:IRCnet
+n174=IRCnet: EU, IT, RomeSERVER:irc.tin.it:6665,6666,6668GROUP:IRCnet
+n175=IRCnet: EU, LV, RigaSERVER:irc.telia.lv:6666,6668,6669GROUP:IRCnet
+n176=IRCnet: EU, NL, Amsterdam (nlnet)SERVER:irc.nl.uu.net:6661,6662,6663GROUP:IRCnet
+n177=IRCnet: EU, NL, Amsterdam (xs4all)SERVER:irc.xs4all.nl:6663,6664,6665GROUP:IRCnet
+n178=IRCnet: EU, NL, EnschedeSERVER:irc.snt.utwente.nl:6661,6662,6666GROUP:IRCnet
+n179=IRCnet: EU, NL, NijmegenSERVER:irc.sci.kun.nl:6663,6664,6668GROUP:IRCnet
+n180=IRCnet: EU, NO, OsloSERVER:irc.ifi.uio.no:6667GROUP:IRCnet
+n181=IRCnet: EU, NO, TrondheimSERVER:irc.pvv.ntnu.no:6667GROUP:IRCnet
+n182=IRCnet: EU, PL, WarsawSERVER:warszawa.irc.pl:6666,6667,6668GROUP:IRCnet
+n183=IRCnet: EU, RU, MoscowSERVER:irc.msu.ru:6667GROUP:IRCnet
+n184=IRCnet: EU, SE, LuleaSERVER:irc.ludd.luth.se:6665,6666,6668GROUP:IRCnet
+n185=IRCnet: EU, UK, London (Btnet)SERVER:chat.bt.net:6662,6663,6668GROUP:IRCnet
+n186=IRCnet: EU, UK, London (Demon)SERVER:ircnet.demon.co.uk:6665,6666,6668GROUP:IRCnet
+n187=IRCnet: EU, UK, London (Netcom)SERVER:irc.netcom.net.uk:6660,6661,6662GROUP:IRCnet
+n188=IRCnet: EU, UK, Warrington (u-net)SERVER:irc.u-net.com:6660,6661,6665GROUP:IRCnet
+n189=IRCnet: US, NY, New YorkSERVER:irc.stealth.net:6663,6664,6665GROUP:IRCnet
+n190=Irctoo: Random serverSERVER:irc.irctoo.net:6667GROUP:Irctoo
+n191=IRCworld: Random serverSERVER:irc.ircworld.org:6667GROUP:IRCworld
+n192=Israelnet: Random serverSERVER:irc.israel.net:6667GROUP:Israelnet
+n193=K0wNet: Random serverSERVER:irc.k0w.net:6661,6665,6668GROUP:K0wNet
+n194=Kewl.org: Random serverSERVER:irc.kewl.org:6667GROUP:KewlOrg
+n195=Kewl.org: EU, FR, NanterreSERVER:nanterre.fr.eu.kewl.org:6667GROUP:KewlOrg
+n196=Kewl.org: EU, UK, LondonSERVER:london.uk.eu.kewl.org:6667GROUP:KewlOrg
+n197=Kidsworld: US, CO, DenverSERVER:denver.co.us.kidsworld.org:6666,6668,6669GROUP:KidsWorld
+n198=Kidsworld: US, MD, BaltimoreSERVER:baltimore.md.us.kidsworld.org:6666,6668,6669GROUP:KidsWorld
+n199=KissLand: Random serverSERVER:irc.kissland.com:6667GROUP:KissLand
+n200=Knightnet: AF, ZA, DurbanSERVER:orc.dbn.za.knightnet.net:6667,5555GROUP:Knightnet
+n201=Knightnet: US, CA, GoldengateSERVER:goldengate.ca.us.knightnet.net:6667,5555GROUP:Knightnet
+n202=KreyNet: Random serverSERVER:irc.krey.net:6667GROUP:Kreynet
+n203=Krushnet: Random serverSERVER:irc.krushnet.org:6667GROUP:Krushnet
+n204=LagNet: Random serverSERVER:irc.lagnet.org.za:6667GROUP:LagNet
+n205=LagNet: AF, ZA, Cape TownSERVER:reaper.lagnet.org.za:6667GROUP:LagNet
+n206=LagNet: AF, ZA, JohannesburgSERVER:mystery.lagnet.org.za:6667GROUP:LagNet
+n207=Librenet: Random serverSERVER:irc.librenet.net:6667GROUP:Librenet
+n208=Lunarnetirc: Random serverSERVER:irc.lunarnetirc.org:6667GROUP:Lunarnetirc
+n209=Lunatics: Random serverSERVER:irc.lunatics.net:6667,6668,6669GROUP:Lunatics
+n210=MagicStar: Random serverSERVER:irc.magicstar.net:6667GROUP:MagicStar
+n211=MavraNet: Random serverSERVER:irc.mavra.net:6662,6663,6664GROUP:MavraNet
+n212=MediaDriven: Random serverSERVER:irc.mediadriven.com:6667,6668,6669GROUP:MediaDriven
+n213=Messique: Random serverSERVER:irc.messique.org:6661,6664,6666GROUP:Messique
+n214=Millenia: Random serverSERVER:irc.millenia.org:6664,6665,6666GROUP:Millenia
+n215=Mozilla: Random serverSERVER:irc.mozilla.org:6667,7000GROUP:Mozilla
+n216=Mysteria: Random serverSERVER:irc.mysteria.net:6667,7000GROUP:Mysteria
+n217=Mystical: Random serverSERVER:irc.mystical.net:6667,7000GROUP:Mystical
+n218=NdrsNet: Random serverSERVER:irc.ndrsnet.com:6666,6668,6669GROUP:NdrsNet
+n219=Net-France: Random serverSERVER:irc.net-france.com:6667GROUP:Net-France
+n220=Nevernet: Random serverSERVER:irc.nevernet.net:6667GROUP:Nevernet
+n221=Newnet: Random serverSERVER:irc.newnet.net:6665,6666,6667GROUP:Newnet
+n222=Newnet: EU, DE, TrustedSERVER:irc.trusted-network.de:6666,7000GROUP:Newnet
+n223=Newnet: EU, UK, OasisSERVER:irc.oasis-net.net:6666,7000GROUP:Newnet
+n224=Newnet: NZ, AucklandSERVER:irc.uplink.net.nz:6661,6662,6666GROUP:Newnet
+n225=Newnet: US, CA, FlagglerockSERVER:irc.fragglerock.org:6666,7000GROUP:Newnet
+n226=Newnet: US, MA, ChelmsfordSERVER:irc.chelmsford.com:6660,6665,6668GROUP:Newnet
+n227=Newnet: US, VA, RandolphSERVER:irc.rma.edu:6665,6666,6668GROUP:Newnet
+n228=Nexusirc: Random serverSERVER:irc.nexusirc.org:6667GROUP:Nexusirc
+n229=Nightstar: Random serverSERVER:irc.nightstar.net:6665,6666,6668GROUP:NightStar
+n230=NitroNet: Random serverSERVER:irc.nitro.net:6667GROUP:NitroNet
+n231=Novernet: Random serverSERVER:irc.novernet.com:6665,6666,6668GROUP:Novernet
+n232=Novernet: US, GA, AugustaSERVER:irc.c-plusnet.com:6666,6668,6669GROUP:Novernet
+n233=Novernet: US, MN, MinneapolisSERVER:chat.novernet.com:6667GROUP:Novernet
+n234=Othernet: Random serverSERVER:irc.othernet.org:6667GROUP:Othernet
+n235=Othernet: US, FL, MiamiSERVER:miami.fl.us.othernet.org:6667GROUP:Othernet
+n236=Othernet: US, MO, StLouisSERVER:stlouis.mo.us.othernet.org:6667GROUP:Othernet
+n237=Otherside: Random serverSERVER:irc.othersideirc.net:6667GROUP:OtherSide
+n238=Outsiderz: Random serverSERVER:irc.outsiderz.com:6667GROUP:Outsiderz
+n239=OzChat: Random serverSERVER:irc.ozchat.org:6667GROUP:OzChat
+n240=OzOrg: AU, AdelaideSERVER:chariot.adelaide.oz.org:6666,6668,7000GROUP:OzOrg
+n241=OzOrg: AU, PerthSERVER:iinet.perth.oz.org:6667GROUP:OzOrg
+n242=OzOrg: AU, SydneySERVER:aussie.sydney.oz.org:6668,6669,7000GROUP:OzOrg
+n243=Pinoycentral: Random serverSERVER:chat.abs-cbn.com:6667GROUP:Pinoycentral
+n244=Planetarion: Random serverSERVER:irc.planetarion.com:6667GROUP:Planetarion
+n245=PowerChat: Random serverSERVER:irc.powerchat.org:6954,6956,6999GROUP:PowerChat
+n246=Pseudonet: Random serverSERVER:irc.pseudonet.org:6667GROUP:Pseudonet
+n247=PTlink: Random serverSERVER:irc.ptlink.net:6667GROUP:PTlink
+n248=PTnet: EU, PT, FaroSERVER:ualg.ptnet.org:6667GROUP:PTnet
+n249=PTnet: EU, PT, LisboaSERVER:telepac2.ptnet.org:6667GROUP:PTnet
+n250=QChat: Random serverSERVER:irc.qchat.net:6667GROUP:QChat
+n251=QuakeNet: Random serverSERVER:irc.quakenet.eu.org:6667,6668,6669GROUP:QuakeNet
+n252=Raptanet: Random serverSERVER:irc.rapta.net:6667GROUP:Raptanet
+n253=Raptornet: Random serverSERVER:irc.raptornet.org:6667GROUP:Raptornet
+n254=Realirc: Random serverSERVER:irc.realirc.org:6667GROUP:Realirc
+n255=Rebelchat: Random serverSERVER:irc.rebelchat.org:6667GROUP:Rebelchat
+n256=Red-Latina: Random serverSERVER:irc.red-latina.org:6667GROUP:Red-Latina
+n257=Red-Latina: NA, MX, SanJoseSERVER:irc.dalsom.net:6666,6667GROUP:Red-Latina
+n258=RedeBrasil: BR, CE, CearaSERVER:irc.linline.com.br:6666,7000,7001GROUP:RedeBrasil
+n259=RedeBrasil: BR, PE, RecifeSERVER:irc.hotlink.com.br:6665,6666,7000GROUP:RedeBrasil
+n260=RedeBrasil: BR, PR, ParanaSERVER:irc.intermam.com.br:6660,6661,6662GROUP:RedeBrasil
+n261=RedeBrasil: BR, SP, Sao PauloSERVER:irc.aserver.com.br:6662,6666,7000GROUP:RedeBrasil
+n262=RedeSul: BR, PR, MaringaSERVER:irc.wnet.com.br:6667GROUP:RedeSul
+n263=RedeSul: BR, SC, BlumenauSERVER:irc.braznet.com.br:6667,9001GROUP:RedeSul
+n264=RedLatona: Random serverSERVER:irc.redlatona.net:6667,6668GROUP:RedLatona
+n265=RekorNet: Random serverSERVER:irc.rekor.net:6665,6668,6669GROUP:RekorNet
+n266=Relicnet: Random serverSERVER:irc.relic.net:6667GROUP:Relicnet
+n267=Relicnet: US, MA, CycloneSERVER:cyclone.us.relic.net:6661,6662,6663GROUP:Relicnet
+n268=Risanet: Random serverSERVER:irc.risanet.com:6667,6668,6669GROUP:Risanet
+n269=Rusnet: EU, RU, TomskSERVER:irc.tsk.ru:7771,7773,7774GROUP:Rusnet
+n270=Rusnet: EU, RU, VladivostokSERVER:irc.vladivostok.ru:6669,7771,7774GROUP:Rusnet
+n271=Rusnet: EU, UA, KievSERVER:irc.kar.net:6669,7770,7774GROUP:Rusnet
+n272=Sandnet: Random serverSERVER:irc.sandnet.net:6660,6662,6668GROUP:Sandnet
+n273=Sandnet: US, CA, MysticSERVER:mystic.tides.sandnet.net:6662,6665,6666GROUP:Sandnet
+n274=Sandnet: US, NJ, DuneBuggySERVER:dunebuggy.nj.sandnet.net:6661,6662,6666GROUP:Sandnet
+n275=Scunc: Random serverSERVER:irc.scunc.net:6667GROUP:Scunc
+n276=SexNet: Random serverSERVER:irc.sexnet.org:6667GROUP:SexNet
+n277=SgNet: Random serverSERVER:irc.sgnet.org:6661,6663,6668GROUP:SgNet
+n278=ShadowFire: Random serverSERVER:irc.shadowfire.org:6667GROUP:ShadowFire
+n279=ShadowWorld: Random serverSERVER:irc.shadowworld.net:6667GROUP:shadowWorld
+n280=SideNet: Random serverSERVER:irc.sidenet.org:6661,6663,6666GROUP:SideNet
+n281=Skyyenet: US, VA, ArlingtonSERVER:arlington.va.us.skyyenet.org:6667GROUP:Skyyenet
+n282=Slashnet: Random serverSERVER:irc.slashnet.org:6667GROUP:Slashnet
+n283=Solarchat: Random serverSERVER:irc.solarchat.net:6667,7000GROUP:Solarchat
+n284=Sorcerynet: Random serverSERVER:irc.sorcery.net:6667,7000,9000GROUP:Sorcery
+n285=Sorcerynet: EU, SE, KarlskronaSERVER:nexus.sorcery.net:6667,7000,9000GROUP:Sorcery
+n286=Sorcerynet: US, CA, Palo AltoSERVER:kechara.sorcery.net:6667,7000,9000GROUP:Sorcery
+n287=Spamnet: Random serverSERVER:irc.spamnet.org:6667,6668,6669GROUP:Spamnet
+n288=StarChat: Random serverSERVER:irc.starchat.net:6668,6669,7000GROUP:StarChat
+n289=StarChat: AU, QLD, SouthernCrossSERVER:boomer.qld.au.starchat.net:6668,6669,7000GROUP:StarChat
+n290=StarChat: EU, NO, AskerSERVER:reality.no.eu.starchat.net:6668,6669,7000GROUP:StarChat
+n291=StarChat: US, CA, San JoseSERVER:sand.ca.us.starchat.net:6668,6669,7000GROUP:StarChat
+n292=StarLink-irc: Random serverSERVER:irc.starlink-irc.org:6667GROUP:starlink-irc
+n293=StarLink-irc: US, MI, RochesterSERVER:rochester.mi.us.starlink-irc.org:6667GROUP:Starlink-irc
+n294=StarLink-irc: US, TX, HoustonSERVER:houston.tx.us.starlink-irc.org:6667GROUP:Starlink-irc
+n295=StarLink Org: US, CO, DenverSERVER:denver.co.us.starlink.org:6660,6662,6666GROUP:StarlinkOrg
+n296=StarLink Org: US, NC, DurhamSERVER:durham-r.nc.us.starlink.org:6661,6663,6668GROUP:StarlinkOrg
+n297=StarLink Org: US, TX, WichitaFallsSERVER:wichitafalls.tx.us.starlink.org:6666,6667,6668GROUP:StarlinkOrg
+n298=StarWars-IRC: Random serverSERVER:irc.starwars-irc.net:6663,6664,6665GROUP:StarWars-IRC
+n299=Stormdancing: Random serverSERVER:irc.stormdancing.net:6664,6668,7000GROUP:Stormdancing
+n300=Sub-city: Random serverSERVER:irc.sub-city.net:6668,6669,7000GROUP:Sub-city
+n301=Superchat: Random serverSERVER:irc.superchat.org:6660,6664,6665GROUP:Superchat
+n302=Superonline: Random serverSERVER:irc.superonline.com:6663,6664,6669GROUP:Superonline
+n303=Sysopnet: Random serverSERVER:irc.sysopnet.org:6666,6667,6668GROUP:Sysopnet
+n304=Techdreams: Random serverSERVER:irc.techdreams.net:6667GROUP:Techdreams
+n305=Telstra: Random serverSERVER:irc.telstra.com:6667,6668,6669GROUP:Telstra
+n306=TR-net: EU, TR, AnkaraSERVER:irc.dominet.com.tr:6667GROUP:TR-net
+n307=TR-net: EU, Tr, IstanbulSERVER:irc.teklan.com.tr:6667GROUP:TR-net
+n308=TRcom: Random serverSERVER:irc.trcom.net:6666,6668,6669GROUP:TRcom
+n309=Tri-net: Random serverSERVER:irc.tri-net.org:6667GROUP:Tri-net
+n310=UltraIRC: Random serverSERVER:irc.ultrairc.net:6667GROUP:UltraIRC
+n311=Undernet: CA, ON, TorontoSERVER:toronto.on.ca.undernet.org:6661,6662,6666GROUP:Undernet
+n312=Undernet: CA, QC, MontrealSERVER:montreal.qu.ca.undernet.org:6660,6661,6664GROUP:Undernet
+n313=Undernet: EU, AT, GrazSERVER:graz.at.eu.undernet.org:6661,6663,6668GROUP:Undernet
+n314=Undernet: EU, BE, AntwerpSERVER:flanders.be.eu.undernet.org:6660,6662,6663GROUP:Undernet
+n315=Undernet: EU, BE, BrusselsSERVER:brussels.be.eu.undernet.org:6661,6663,6668GROUP:Undernet
+n316=Undernet: EU, FR, CaenSERVER:caen.fr.eu.undernet.org:6666,6668,6669GROUP:undernet
+n317=Undernet: EU, FR, ParisSERVER:paris.fr.eu.undernet.org:6662,6663,6666GROUP:Undernet
+n318=Undernet: EU, NL, DiemenSERVER:diemen.nl.eu.undernet.org:6665,6666,6668GROUP:Undernet
+n319=Undernet: EU, NL, HaarlemSERVER:haarlem.nl.eu.undernet.org:6660,6662,6666GROUP:Undernet
+n320=Undernet: EU, NO, OsloSERVER:oslo.no.eu.undernet.org:6662,6664,6668GROUP:Undernet
+n321=Undernet: EU, SE, StockholmSERVER:stockholm.se.eu.undernet.org:6661,6662,6664GROUP:Undernet
+n322=Undernet: EU, UK, LondonSERVER:london.uk.eu.undernet.org:6666,6668,6669GROUP:Undernet
+n323=Undernet: EU, UK, SurreySERVER:surrey.uk.eu.undernet.org:6662,6665,6666GROUP:Undernet
+n324=Undernet: US, CA, San DiegoSERVER:sandiego.ca.us.undernet.org:6665,6666,6668GROUP:Undernet
+n325=Undernet: US, DC, WashingtonSERVER:washington.dc.us.undernet.org:6660,6665,6668GROUP:Undernet
+n326=Undernet: US, KS, ManhattanSERVER:manhattan.ks.us.undernet.org:6662,6664,6665GROUP:Undernet
+n327=Undernet: US, NV, Las VegasSERVER:lasvegas.nv.us.undernet.org:6662,6663,6668GROUP:Undernet
+n328=Undernet: US, TX, AustinSERVER:austin.tx.us.undernet.org:6661,6663,6664GROUP:Undernet
+n329=Undernet: US, UT, SaltlakeSERVER:saltlake.ut.us.undernet.org:6663,6665,6666GROUP:Undernet
+n330=Undernet: US, VA, ArlingtonSERVER:arlington.va.us.undernet.org:6661,6663,6665GROUP:Undernet
+n331=Undernet: US, VA, McLeanSERVER:mclean.va.us.undernet.org:6666,6668,6669GROUP:Undernet
+n332=UnderZ: Random serverSERVER:irc.underz.org:6667,6668GROUP:UnderZ
+n333=UnionLatina: Random serverSERVER:irc.unionlatina.org:6667GROUP:UnionLatina
+n334=UnitedChat Net: Random serverSERVER:irc.unitedchat.net:6667GROUP:UnitedchatNet
+n335=UnitedChat Org: Random serverSERVER:irc.unitedchat.org:6667GROUP:UnitedchatOrg
+n336=Univers: Random serverSERVER:irc.univers.org:6665,6666,6668GROUP:Univers
+n337=Vidgamechat: Random serverSERVER:irc.vidgamechat.com:6667GROUP:Vidgamechat
+n338=Virtuanet: Random serverSERVER:irc.virtuanet.org:6662,6666,6669GROUP:Virtuanet
+n339=Vitamina: Random serverSERVER:irc-rr.vitamina.ca:6667GROUP:Vitamina
+n340=Warpednet: Random serverSERVER:irc.warped.net:6667GROUP:Warpednet
+n341=Webnet: Random serverSERVER:irc.webchat.org:6668,6669,7000GROUP:Webnet
+n342=Webnet: US, AL, DothanSERVER:wiregrass.al.us.webchat.org:6668,6669,7000GROUP:Webnet
+n343=Webnet: US, CA, Santa ClaraSERVER:webmaster.ca.us.webchat.org:6662,6663,6664GROUP:Webnet
+n344=Webnet: US, MA, BostonSERVER:greennet.ma.us.webchat.org:6668,6669,7000GROUP:Webnet
+n345=WonKnet: Random serverSERVER:irc.wonk.net:6668,6669,7000GROUP:Wonknet
+n346=WorldIRC: Random serverSERVER:irc.worldirc.org:6661,6662,6665GROUP:WorldIRC
+n347=Xevion: Random serverSERVER:irc.xevion.net:6667,7000GROUP:Xevion
+n348=XNet: Random serverSERVER:irc.xnet.org:6667GROUP:XNet
+n349=XWorld: Random serverSERVER:irc.xworld.org:6667GROUP:XWorld
+n350=ZAnet Net: AF, ZA, CI (lia)SERVER:lia.zanet.net:6667GROUP:ZAnetNet
+n351=ZAnet Net: AF, ZA, MWeb (timewiz)SERVER:timewiz.zanet.net:6667GROUP:ZAnetNet
+n352=ZAnet Org: AF, ZA, Cape Town (gaspode)SERVER:gaspode.zanet.org.za:6667GROUP:ZAnetOrg
+n353=ZAnet Org: AF, ZA, Johannesburg (is)SERVER:is.zanet.org.za:6667GROUP:ZAnetOrg
+n354=ZAnet Org: AF, ZA, Midrand (ethereal)SERVER:ethereal.zanet.org.za:6660,6666GROUP:ZAnetOrg
+n355=ZiRC: Random serverSERVER:irc.zirc.org:6660,6662,6665GROUP:ZiRC
+n356=ZUHnet: Random serverSERVER:irc.zuh.net:6667GROUP:ZUHnet
+n357=Zurna: Random serverSERVER:irc.zurna.net:6667GROUP:Zurna
diff --git a/ksirc/KSOpenkSirc/servers.txt b/ksirc/KSOpenkSirc/servers.txt
new file mode 100644
index 00000000..a61b0199
--- /dev/null
+++ b/ksirc/KSOpenkSirc/servers.txt
@@ -0,0 +1,654 @@
+Random:Random AU EFnet server:au.rr.efnet.net:6667:
+Random:Random AU IRCnet server:au.ircnet.org:6667:
+Random:Random CA EFnet server:ca.rr.efnet.net:6667:
+Random:Random EFnet server:irc.chat.org:6667:
+Random:Random EU DALnet server:irc.eu.dal.net:6667:
+Random:Random EU DALnet server:irc.eu.dal.net:7000:
+Random:Random EU EFnet server:eu.rr.efnet.net:6667:
+Random:Random EU IRCnet server:eu.ircnet.org:6665,6666,6668:
+Random:Random EU Undernet server:eu.undernet.org:6667:
+Random:Random Freenode server:irc.freenode.net:6667:
+Random:Random US DALnet server:irc.dal.net:6662,6663,6664:
+Random:Random US DALnet server:irc.dal.net:7000:
+Random:Random US EFnet server:us.rr.efnet.net:6667:
+Random:Random US IRCnet server:us.ircnet.org:6665,6666,6668:
+Random:Random US Undernet server:us.undernet.org:6667:
+Accessirc:Random server:irc.accessirc.net:6667:
+Acestar:Random server:irc.acestar.org:6667:
+Action-IRC:Random server:irc.action-irc.net:6660,6662,6664:
+Afternet:Random server:irc.afternet.org:6667:
+Afternet:US, CA, San Diego:blacklodge.c2.org:6667:
+Afternet:US, LA, Ruston:scorpion.latech.edu:6667:
+Afternet:US, OH, Columbus:irc.coldfusion.net:6667:
+Afternet:US, OR, Portland:agora.rdrop.com:6667:
+Alternativenet:Random server:irc.altnet.org:6667:
+AnotherNet:Random server:irc.another.net:6667,7000:
+Anothernet:US, CA, Los Angeles:sunrise.ca.us.another.net:6667:
+Anothernet:US, CA, Morgan Hill:neato.ca.us.another.net:6667:
+Anothernet:US, VT, Burlington:together.vt.us.another.net:6667:
+ArabChat:Random server:irc.arabchat.org:6660,6661,6662:
+AstroLink:Random server:irc.astrolink.org:6660,6662,6663:
+Asylumnet:Random server:irc.asylum-net.org:6661,6664,7000:
+Austnet:AS, Singapore:ntu.sg.austnet.org:6667:
+Austnet:AU, Melbourne:aussie.au.austnet.org:6667,6668:
+Austnet:AU, Sydney:sydney.au.austnet.org:6667,6668:
+Austnet:CA, ON, Toronto:insane.ca.austnet.org:6667,6668:
+Austnet:Random AU server:au.austnet.org:6667:
+Austnet:Random NZ server:nz.austnet.org:6667:
+Austnet:Random SG server:sg.austnet.org:6667:
+Austnet:Random US server:us.austnet.org:6667:
+Austnet:US, CA, Santa Clara:webmaster.us.austnet.org:6667,6668:
+Austnet:US, FL, Wizard:wizard.us.austnet.org:6667,6668:
+Austnet:US, PA, Wallaby:wallaby.us.austnet.org:6667,6668:
+AwesomeChat:Random server:irc.awesomechat.net:6662,6665,6666:
+Axenet:Random server:irc.axenet.org:6661,6664,6665:
+BeyondIRC:Random server:irc.beyondirc.net:6660,6662,6664:
+BeyondIRC:US, AL, Snowhill:irc.snowhill.com:6667,6668,6669,6670:
+BeyondIRC:US, CA, Los Angeles:babylon.beyondirc.net:6667,6668,6669:
+BeyondIRC:US, MO, Jefferson City:irc.telcentral.com:6667:
+Blabbernet:Random server:irc.blabber.net:6667,7000:
+Blitzed:Random server:irc.blitzed.org:6667,7000:
+BrasIRC:Brazil, PI, Teresina:irc.ranet.com.br:6667:
+BrasIRC:Brazil, PR, Curitiba:irc2.kanopus.com.br:6667:
+BrasIRC:Brazil, RJ, Rio de Janeiro:irc.ism.com.br:6667:
+BrasIRC:Brazil, SP, Santos:irc.iron.com.br:6667:
+BrasIRC:Brazil, Starcom:irc.stc.com.br:6667:
+BrasIRC:US, FL, Miami:irc2.sodre.net:6667:
+Brasilnet:Brazil, BA, Bahia:irc.magiclink.com.br:6667,6668,6669,7000,7001,7002:
+Brasilnet:Brazil, BA, Salvador:irc.nway.com.br:6667,6668,6669,7000,7001,7002:
+Brasilnet:Brazil, GO, Brasilia (ab):irc.abordo.com.br:6667,6668,6669,7000,7001,7002:
+Brasilnet:Brazil, GO, Brasilia (pc):irc.persocom.com.br:6667,6668,6669,7000,7001,7002:
+Brasilnet:Brazil, PE, Caruaru:irc.netstage.com.br:6667,6668,6669,7000,7001,7002:
+Brasilnet:Brazil, PE, Recife:irc.elogica.com.br:6667,6668,6669,7000,7001,7002:
+Brasirc:BR, PA, Belem:irc.libnet.com.br:6666,6668,7777:
+Brasirc:BR, SC, Florianopolis:irc.globalite.com.br:6667:
+Brasirc:Random server:irc.brasirc.net:6666,6667:
+Brasnet:Brazil, DF, Brasilia:irc.americasnet.com.br:6667:
+Brasnet:Brazil, RJ, Rio de Janeiro:irc.pontocom.com.br:6667:
+Brasnet:Brazil, SP, Campinas:irc.correionet.com.br:6667:
+Brasnet:Brazil, SP, Sao Paulo:irc.cpunet.com.br:6667:
+Brasnet:Random European server:eu.brasnet.org:6665,6666,6668:
+Brasnet:Random US server:us.brasnet.org:6665,6666,6668:
+Brasnet:Random server:irc.brasnet.org:6665,6666,6668:
+Brasnet:US, Americasnet:americasnet.usa.brasnet.org:6667:
+Bulgaria:Random server:irc.bulgaria.org:6666,6668,6669:
+CCnet:Random server:irc.cchat.net:6667,7000:
+CCnet:US, TX, Dallas:irc2.cchat.net:6667,7000:
+CNN:CNN News discussions:chat.cnn.com:6668,6669,7000:
+ChatArea:Random server:irc.chatarea.net:6667:
+ChatCentral2:Random server:irc.cc2.org:6660,6661,6663:
+ChatCircuit:Random server:irc.chatcircuit.com:6668:
+ChatPR:Random server:irc.chatpr.org:6667:
+ChatX:Random server:irc.chatx.net:6667:
+Chatcafe:Random server:irc.chatcafe.net:6667:
+Chatlink:Random server:irc.chatlink.org:6667:
+Chatnet:EU, Norway:Frogn.NO.ChatNet.Org:6667:
+Chatnet:Random AU server:au.chatnet.org:6667:
+Chatnet:Random EU server:eu.chatnet.org:6667:
+Chatnet:Random US server:us.chatnet.org:6667:
+Chatnet:US, CA, Los Angeles:LosAngeles.CA.US.ChatNet.Org:6667:
+Chatnet:US, CA, San Francisco:SF.CA.US.Chatnet.Org:6667:
+Chatnet:US, CA, Walnut Creek:WalnutCreek.CA.US.ChatNet.Org:6667:
+Chatnet:US, FL, Pensacola:Pensacola.FL.US.ChatNet.Org:6666,6667,6668,6669:
+Chatnet:US, ID, Pocatello:Pocatello.IS.US.ChatNet.Org:6667:
+Chatnet:US, KY, Louisville:Louisville.KY.US.ChatNet.Org:6667:
+Chatnet:US, MS, Tupelo:Tupelo.MS.US.Chatnet.Org:6666,6667,6668,6669:
+Chatnet:US, OK, Stillwater:Stillwater.OK.US.ChatNet.Org:6667:
+Chatnet:US, OR, Portland:Portland.OR.US.Chatnet.Org:6666,6667,6668,6669:
+Chatnet:US, SC, Rock Hill:RockHill.SC.US.ChatNet.Org:6666,6667,6668,6669:
+Chatnet:US, UT, Salt Lake City:SLC.UT.US.Chatnet.Org:6666,6667,6668,6669:
+Chatpinoy:Random server:irc.chatpinoy.com:6667:
+Chatroom:Random server:irc.chatroom.org:6667:
+Chatsolutions:Random server:irc.chatsolutions.org:6667:
+Chatster:Random server:irc.chatster.org:6667:
+Cobranet:CA, AK, Specific:Specific.AK.US.Cobra.Net:6667:
+Cobranet:CA, ON, StrathRoy:StrathRoy.ON.CA.Cobra.Net:6667:
+Cobranet:EU, UK, London:London.UK.EU.Cobra.Net:6667:
+Cobranet:US, RI, Providence:Providence.RI.US.Cobra.Net:6667:
+Coolchat:Random server:irc.coolchat.net:6667:
+Criten:Random server:irc.criten.net:6667:
+CyGanet:Random server:irc.cyga.net:6667:
+Cyberchat:Random server:irc.cyberchat.org:6667,6668:
+DALnet:AS, MY, Kuala Lumpur:coins.dal.net:6663,6664,6668:
+DALnet:AU, Adelaide:ozbytes.dal.net:6667,7000:
+DALnet:AU, New South Wales:bunyip.DAL.net:7000,6665,6666,6668,6669:
+DALnet:CA, BC, Vancouver:vancouver.dal.net:6661,6662,6666:
+DALnet:Canada, Edmonton Alb.:raptor.DAL.net:6661,6662,6663,7000:
+DALnet:Canada, Toronto:toronto.DAL.net:7000,7001,7002:
+DALnet:EU, DE, Frankfurt:nexgo.de.eu.dal.net:6664,6665,6669:
+DALnet:EU, FI, Espoo:xgw.DAL.net:6668,7000:
+DALnet:EU, NO, Oslo:powertech.no.eu.dal.net:6666,6667,7000:
+DALnet:EU, NO, Tromso:viking.dal.net:6666,6668,6669:
+DALnet:EU, SE, Goteborg:ced.dal.net:6667,7000:
+DALnet:EU, SE, Stockholm:paranoia.dal.net:6661,6662,6669:
+DALnet:EU, UK, Bristol:liberator.DAL.net:6668,6669,7000:
+DALnet:EU, UK, London:defiant.dal.net:6668,6669,7001:
+DALnet:EU, UK, London:defiant.dal.net:7000,7001,7002,7003:
+DALnet:US, CA, Davis:davis.DAL.net:6668,6669,7000:
+DALnet:US, CA, El Segundo:cyberverse.DAL.net:6667,7000:
+DALnet:US, CA, San Diego:voyager.DAL.net:6666,6667,6668,6669,7000:
+DALnet:US, CA, Santa Clara:spider.DAL.net:6668,6669,7000,7777:
+DALnet:US, CA, Sunnyvale:mindijari.DAL.net:6667,6668,6669,7000:
+DALnet:US, FL, Hollywood:sodre.dal.net:6663,6666,6668:
+DALnet:US, FL, Jacksonville:centurion.dal.net:6668,7000,7500:
+DALnet:US, IN, Hebron:hebron.dal.net:6661,6662,6663,7000:
+DALnet:US, IN, Hebron:hebron.dal.net:6661,6664,6669:
+DALnet:US, MA, Norwood:twisted.dal.net:6663,6665,6669:
+DALnet:US, MD, Manchester:qis.md.us.dal.net:6660,6664,6668:
+DALnet:US, MO, St.Louis:stlouis.DAL.net:6665,6666,6667,7000:
+DALnet:US, NC, Charlotte:uncc.DAL.net:6667,6668,6669,7000:
+DALnet:US, NY, New York City:liberty.dal.net:6662,6666,6669:
+DALnet:US, OH, Cleveland:barovia.dal.net:6661,6662,6663,7000:
+DALnet:US, OH, Toledo:glass.DAL.net:6667,7000:
+DALnet:US, OH, Toledo:glass.dal.net:6660,6661,6664:
+DALnet:US, OK, Tulsa:webzone.dal.net:6664,6665,6668,7000:
+DALnet:US, OK, Tulsa:webzone.dal.net:6665,6666,6669:
+DarkMyst:Random server:irc.darkmyst.org:6667:
+DarkServ:Random server:irc.darkserv.net:6664,6665,6666:
+Darkfire:Random server:irc.darkfire.net:6667,7000,8000:
+Darkfyre:Random server:irc.darkfyre.net:6667:
+Darktree:Random server:irc.darktree.net:6667:
+Deepspace:Disability network:irc.deepspace.org:6667:
+Different:Random server:irc.different.net:6667:
+Digarix:Random server:irc.digarix.net:6667:
+Digatech:Random server:irc.digatech.net:6667:
+Digitalirc:Random server:irc.digitalirc.net:6667:
+Dobbernet:Random server:irc.dobber.net:6667:
+DragonLynk:Random server:irc.dragonlynk.net:6661,6665,6666:
+Dreamcast:Random server:irc0.dreamcast.com:6667:
+Dreamnet:Random server:irc.dreamnet.org:6664,6665,6666:
+DwarfStar:Random server:irc.dwarfstar.net:6667:
+Dynastynet:Random server:irc.dynastynet.net:6667:
+EFnet:Australia, Telstra:efnet.telstra.net.au:6667:
+EFnet:CA, AB, Edmonton:irc.powersurfr.com:6667:
+EFnet:CA, ON, Toronto:irc2.magic.ca:6667:
+EFnet:CA, QB, Montreal:irc.etsmtl.ca:6667:
+EFnet:Canada, Cadvision:irc.cadvision.ab.ca:6667:
+EFnet:Canada, Internex:irc.io.org:6667:
+EFnet:Canada, Magic:irc.magic.mb.ca:6667:
+EFnet:Canada, McGill:irc.mcgill.ca:6667:
+EFnet:Canada, Mun:irc.cs.mun.ca:6667:
+EFnet:Canada, Polymtl:irc.polymtl.ca:6667:
+EFnet:Canada, Portal:portal.mbnet.mb.ca:6667:
+EFnet:Canada, Vianet:irc.vianet.on.ca:6667:
+EFnet:Canada, Yorku:irc.yorku.ca:6667:
+EFnet:EU, FI, Helsinki:efnet.cs.hut.fi:6667:
+EFnet:EU, FR, Paris:irc.isdnet.fr:6667,6668,6669:
+EFnet:EU, France:irc.ec-lille.fr:6667:
+EFnet:EU, Israel (ibm):irc.ibm.net.il:6667:
+EFnet:EU, Israel (tau):irc.tau.ac.il:6667:
+EFnet:EU, Israel (tech):irc.technion.ac.il:6667:
+EFnet:EU, NL, Amsterdam:efnet.vuurwerk.nl:6667:
+EFnet:EU, NO, Homelien:irc.homelien.no:6666,7000,7001:
+EFnet:EU, Netherlands:irc.nijenrode.nl:6667:
+EFnet:EU, Norway:irc.homelien.no:6667:
+EFnet:EU, RU, Moscow:irc.rt.ru:6662,6665,6668:
+EFnet:EU, SE, Dalarna:irc.du.se:6666,6668,6669:
+EFnet:EU, SE, Sweden:irc.light.se:6667:
+EFnet:EU, Sweden (gu):irc.gd.gu.se:6667:
+EFnet:EU, Sweden (lth):irc.df.lth.se:6667:
+EFnet:EU, UK, Bofh:irc.bofh.co.uk:6667:
+EFnet:EU, UK, Demon:efnet.demon.co.uk:6665,6666,6668,6669:
+EFnet:EU, UK, Demon:efnet.demon.co.uk:6665,6666,6668:
+EFnet:EU, UK, London:irc.ins.net.uk:6665,6666,6668:
+EFnet:ME, IL, Inter:irc.inter.net.il:6665,6666,6668:
+EFnet:US, AZ, Phoenix:irc.primenet.com:6667:
+EFnet:US, AZ, Tucson:irc.blackened.com:6667:
+EFnet:US, America OnLine:irc02.irc.aol.com:6667:
+EFnet:US, CA, Los Angeles:irc.west.gblx.net:6667:
+EFnet:US, CA, San Diego:irc.cerf.net:6667:
+EFnet:US, CA, San Luis Obispo:irc.prison.net:6666,6667:
+EFnet:US, CA, Stanford:irc.stanford.edu:6667:
+EFnet:US, CO, Colorado:irc.colorado.edu:5555,6665,6666:
+EFnet:US, CO, Colorado:irc.colorado.edu:6667:
+EFnet:US, FL, Miami:opus.bridge.net:6667:
+EFnet:US, GA, Atlanta (Emory):irc.emory.edu:6667:
+EFnet:US, GA, Atlanta (Mindspring):irc.mindspring.com:6660,6663,6668:
+EFnet:US, GA, Atlanta:irc.emory.edu:6667:
+EFnet:US, IL, Chicago (ais):irc.ais.net:6667:
+EFnet:US, IL, Chicago (mcs):irc.mcs.net:6667:
+EFnet:US, IL, Chicago:irc.mcs.net:6666,6667,6668:
+EFnet:US, IL, Chicago:irc.plur.net:6667:
+EFnet:US, MI, Ann Arbor:irc.umich.edu:6667:
+EFnet:US, MN, Twin Cities:irc.umn.edu:6665,6666,6668:
+EFnet:US, MO, Missouri:irc.mo.net:6667:
+EFnet:US, NY, New York:irc.east.gblx.net:6667:
+EFnet:US, Netcom0:ircd.netcom.com:6667:
+EFnet:US, Netcom1:irc.netcom.com:6667:
+EFnet:US, Netcom2:irc2.netcom.com:6667:
+EFnet:US, OK, Oklahoma:irc.ionet.net:6667:
+EFnet:US, PA, Ivyland:irc.voicenet.com:6667:
+EFnet:US, TX, Houston (Phoenix):irc.phoenix.net:6667:
+EFnet:US, TX, Houston (University):irc.tech.uh.edu:6667:
+EFnet:US, VA, Herndon:irc.psinet.com:6667:
+EFnet:US, WA, Seattle:irc.sprynet.com:6667:
+EICN:AU, Perth:Perth.WA.AU.EarthInt.Net:6667:
+EICN:EU, FI, Espoo:FOO.FI.EarthInt.Net:6667:
+EICN:US, FL, Tampa:Shadow.FL.US.EarthInt.Net:6667:
+EgyptianIRC:Random server:irc.egyptianirc.net:6667,6668,6669:
+EntertheGame:Random server:irc.enterthegame.com:6667,6668,6669:
+Escaped:Random server:irc.escaped.net:6661,6665,6668:
+Esprit:Random server:irc.esprit.net:6667:
+ExodusIRC:Random server:irc.exodusirc.net:6662,6663,6664:
+FDFnet:Random server:irc.fdf.net:6666,6668,9999:
+FEFnet:Random server:irc.fef.net:6667:
+FEFnet:UK, Quantum:quantum.uk.fef.net:6667:
+FEFnet:US, AZ, Phoenix:stf.fef.net:6667:
+FEFnet:US, CA, San Jose:vendetta.fef.net:6667:
+FEFnet:US, DC, Auburn:blizzard.fef.net:6667:
+FEFnet:US, NY, Long Island:liii.fef.net:6667:
+Forestnet:Random server:irc.forestnet.org:6667,7000:
+FreedomChat:Random server:chat.freedomchat.net:6667:
+Freenode:Random server:irc.freenode.net:6667:
+FunNet:Random server:irc.funnet.org:6667:
+GalaxyNet:AS, Singapore:pacific.sg.galaxynet.org:6667:
+GalaxyNet:AU, NZ, Auckland:auckland.nz.galaxynet.org:6666,6667,6668:
+GalaxyNet:Canada, Vancouver:vancouver.bc.ca.galaxynet.org:6667:
+GalaxyNet:EU, NO, Oslo:oslo.no.galaxynet.org:6666,6667,6668:
+GalaxyNet:US, Atlanta:atlanta.ga.us.galaxynet.org:6667:
+Galaxynet:AU, NZ, Auckland:auckland.nz.galaxynet.org:6661,6666,6668:
+Galaxynet:EU, BE, Online:online.be.galaxynet.org:6664,6666,6668:
+Galaxynet:EU, SE, Vltmedia:vltmedia.se.galaxynet.org:6662,6664,6666:
+Galaxynet:Random server:irc.galaxynet.org:6662,6663,6666:
+Galaxynet:US, FL, Florida:gymnet.us.galaxynet.org:6663,6666,6668:
+Galaxynet:US, WA, Seattle:freei.us.galaxynet.org:6661,6665,6666:
+Gamesnet:Random east US server:east.gamesnet.net:6667:
+Gamesnet:Random west US server:west.gamesnet.net:6667:
+GammaNet:US, Alfheim:Alfheim.NJ.US.gamma.net:6667:
+GammaNet:US, Chromium:Chromium.VA.US.gamma.net:6667:
+GammaNet:US, Galaxy:Galaxy.CT.US.gamma.net:6667:
+GammaNet:US, Wildstar:Wildstar.OK.US.gamma.net:6667:
+GizNet:Random server:irc.giznet.com:6666,6668,6669:
+Globalchat:Random server:irc.globalchat.org:6667:
+Grnet:Random EU server:gr.irc.gr:6667,7000:
+Grnet:Random US server:us.irc.gr:6667,7000:
+Grnet:Random server:srv.irc.gr:6667,7000:
+HabberNet:Random server:irc.habber.net:6667:
+HanIRC:Random server:irc.hanirc.org:6667:
+Hellenicnet:Random server:irc.mirc.gr:6667,7000:
+Hybnet:Random server:irc.hybnet.net:6667:
+ICQnet:Random server:irc.icq.com:6667:
+IRC-Hispano:Random server:irc.irc-hispano.org:6667:
+IRCLink:EU, NO, Alesund:alesund.no.eu.irclink.net:6667,6668,6669:
+IRCLink:EU, NO, Oslo:frogn.no.eu.irclink.net:6667,6668,6669:
+IRCLink:US, SC, Rock Hill:rockhill.sc.us.irclink.net:6667,6668,6669:
+IRCNet:AF, ZA, Sprint:irc-2.sprintlink.co.za:6667:
+IRCNet:AU, Dfat:irc.dfat.gov.au:6667:
+IRCNet:AU, Monash:yoyo.cc.monash.edu.au:6667:
+IRCNet:AU, Telstra:flute.telstra.net.au:6667:
+IRCNet:AU, Usyd:irc.usyd.edu.au:6667:
+IRCNet:CA, Quebec, Montreal:irc.openface.ca:6667:
+IRCNet:EU, Austria, Vienna:irc.wu-wien.ac.at:6667:
+IRCNet:EU, BE, Belnet:irc.belnet.be:6667:
+IRCNet:EU, DE, Berlin:irc.fu-berlin.de:6667:
+IRCNet:EU, DE, Muenchen:irc.informatik.tu-muenchen.de:6667:
+IRCNet:EU, DE, Stuttgart:irc.rus.uni-stuttgart.de:6667:
+IRCNet:EU, ES, Gondwana:gondwana.upc.es:6667:
+IRCNet:EU, FI, Espoo:irc.funet.fi:6667:
+IRCNet:EU, FI, Kuopio:irc.pspt.fi:6667:
+IRCNet:EU, FR, Eurecom:irc.eurecom.fr:6667:
+IRCNet:EU, FR, Lille:irc.ec-lille.fr:6667:
+IRCNet:EU, FR, Lyon:irc.univ-lyon1.fr:6667:
+IRCNet:EU, FR, Nice:irc.eurecom.fr:6667:
+IRCNet:EU, FR, Paris (Enst):irc.enst.fr:6667:
+IRCNet:EU, FR, Paris (Poly):sil.polytechnique.fr:6667:
+IRCNet:EU, FR, Poly:sil.polytechnique.fr:6667:
+IRCNet:EU, IS, Reykjavik:irc.isnet.is:6667:
+IRCNet:EU, IT, Pisa:irc.ccii.unipi.it:6667:
+IRCNet:EU, NL, Amsterdam:irc.xs4all.nl:6667:
+IRCNet:EU, NL, Nijmegen:irc2.sci.kun.nl:6667:
+IRCNet:EU, SE, Lulea:irc.ludd.luth.se:6667:
+IRCNet:EU, UK, London (BT):chat.btinternet.com:6667:
+IRCNet:EU, UK, London (Demon):ircnet.demon.co.uk:6665,6666,6668,6669:
+IRCNet:EU, UK, London (Imperial):stork.doc.ic.ac.uk:6667:
+IRCNet:EU, UK, London (Netcom):irc.netcom.net.uk:6667:
+IRCNet:US, AOL:irc02.irc.aol.com:6666:
+IRCNet:US, CA, Santa Clara:irc.aimnet.com:6667:
+IRCNet:US, IL, Chicago:irc.anet-chi.com:6667:
+IRCNet:US, MI, Taylor:irc.webbernet.net:6667:
+IRCNet:US, NY, New York:irc.stealth.net:6667:
+IRCNet:US, WA, Seattle:ircnet.sprynet.com:6667:
+IRChat-br:Random server:irc.irchat.com.br:6667:
+IRChat:Random server:irc.irchat.net:6661,6662,6666:
+IRCnet:AS, JP, Tokyo:irc.tokyo.wide.ad.jp:6667:
+IRCnet:AU, Melbourne:yoyo.cc.monash.edu.au:6668,6669,9990:
+IRCnet:AU, Sydney:irc.usyd.edu.au:6667:
+IRCnet:EU, AT, Linz:linz.irc.at:6666,6667,6668:
+IRCnet:EU, AT, Wien:vienna.irc.at:6666,6668,6669:
+IRCnet:EU, BE, Brussels:irc.belnet.be:6667:
+IRCnet:EU, BE, Zaventem:ircnet.wanadoo.be:6661,6664,6665:
+IRCnet:EU, CZ, Prague:irc.felk.cvut.cz:6667:
+IRCnet:EU, DE, Berlin:irc.fu-berlin.de:6665,6666,6668:
+IRCnet:EU, DE, Dusseldorf:irc.freenet.de:6665,6666,6668:
+IRCnet:EU, DE, Stuttgart:irc.belwue.de:6665,6666,6668:
+IRCnet:EU, DK, Copenhagen:irc.ircnet.dk:6667:
+IRCnet:EU, EE, Tallinn:irc.estpak.ee:6666,6667,6668:
+IRCnet:EU, FI, Espoo:irc.funet.fi:6661,6663,6668:
+IRCnet:EU, FI, Helsinki:irc.cs.hut.fi:6667:
+IRCnet:EU, FR, Nice:irc.eurecom.fr:6667:
+IRCnet:EU, FR, Paris:irc.fr.ircnet.net:6667:
+IRCnet:EU, GR, Thessaloniki:irc.ee.auth.gr:6666,6668,6669:
+IRCnet:EU, HU, Budapest:irc.elte.hu:6667:
+IRCnet:EU, IL, Haifa:ircnet.netvision.net.il:6661,6662,6663:
+IRCnet:EU, IS, Reykjavik:irc.ircnet.is:6661,6662,6666:
+IRCnet:EU, IS, Reykjavik:irc.ircnet.is:6663,6664,6668:
+IRCnet:EU, IT, Random:irc.ircd.it:6665,6666,6668:
+IRCnet:EU, IT, Rome:irc.tin.it:6665,6666,6668:
+IRCnet:EU, LV, Riga:irc.telia.lv:6666,6668,6669:
+IRCnet:EU, NL, Amsterdam (nlnet):irc.nl.uu.net:6661,6662,6663:
+IRCnet:EU, NL, Amsterdam (xs4all):irc.xs4all.nl:6663,6664,6665:
+IRCnet:EU, NL, Enschede:irc.snt.utwente.nl:6661,6662,6666:
+IRCnet:EU, NL, Nijmegen:irc.sci.kun.nl:6663,6664,6668:
+IRCnet:EU, NO, Oslo:irc.ifi.uio.no:6667:
+IRCnet:EU, NO, Trondheim:irc.pvv.ntnu.no:6667:
+IRCnet:EU, PL, Warsaw:warszawa.irc.pl:6666,6667,6668:
+IRCnet:EU, RU, Moscow:irc.msu.ru:6667:
+IRCnet:EU, SE, Lulea:irc.ludd.luth.se:6665,6666,6668:
+IRCnet:EU, UK, London (Btnet):chat.bt.net:6662,6663,6668:
+IRCnet:EU, UK, London (Demon):ircnet.demon.co.uk:6665,6666,6668:
+IRCnet:EU, UK, London (Netcom):irc.netcom.net.uk:6660,6661,6662:
+IRCnet:EU, UK, Warrington (u-net):irc.u-net.com:6660,6661,6665:
+IRCnet:US, NY, New York:irc.stealth.net:6663,6664,6665:
+IRCworld:Random server:irc.ircworld.org:6667:
+Icenet:AU, Perth:ois.perth.au.icenet.org:6667:
+Icenet:AU, Sydney:zip.syd.au.icenet.org:6667:
+Icenet:SA, Johannesburg:Snowflake.Jhb.Za.IceNet.Org:6667:
+Icenet:US, CA, San Diego:slurpee.ca.us.icenet.org:6667:
+Icenet:US, MO, Kansas City:frozen.mo.us.icenet.org:6667:
+Icenet:US, NC, Charlotte:WebServe.Nc.Us.IceNet.Org:6667:
+Icenet:US, NY, Warwick:Warwick.Ny.Us.IceNet.Org:6667:
+Icenet:US, WI, Ashland:Dockernet.Wi.Us.IceNet.Org:6667:
+Idealnet:US, Boston:irc.aasp.net:6667:
+Idealnet:US, New Jersey:irc.cps.k12.ny.us:6667:
+Idealnet:US, Tennesse:irc.pov.net:6667:
+Infatech:Random server:irc.infatech.net:6661,6663,6666:
+Infinity:Random server:irc.infinity-irc.org:6667:
+Infomatrix:Random server:irc.infomatrix.net:6667:
+IniQuity:EU, SE, Stockholm:StockHolm.SE.EU.iNiQuiTY.NeT:6667:
+IniQuity:US, KY, Louisville:Louisville.ky.us.Iniquity.net:6667:
+IniQuity:US, PA, Belle-Vernon:Belle-Vernon.PA.US.iNiQuiTY.Net:6667:
+IniQuity:US, WI, Milwaukee:Milwaukee.WI.US.iNiQuiTY.Net:6667:
+Irctoo:Random server:irc.irctoo.net:6667:
+Israelnet:Random server:irc.israel.net:6667:
+K0wNet:Random server:irc.k0w.net:6661,6665,6668:
+Kewl.org:EU, FR, Nanterre:nanterre.fr.eu.kewl.org:6667:
+Kewl.org:EU, UK, London:london.uk.eu.kewl.org:6667:
+Kewl.org:Random server:irc.kewl.org:6667:
+Kidsworld:EU, UK, Notts:notts.uk.eu.Kidsworld.org:6664,6666,6668:
+Kidsworld:US, CA, Los Angeles:Losangeles.ca.us.Kidsworld.org:6664,6666,6668:
+Kidsworld:US, CO, Denver:denver.co.us.kidsworld.org:6666,6668,6669:
+Kidsworld:US, IN, Jeffersonville:Jeffersonville.In.us.Kidsworld.org:6664,6666,6668:
+Kidsworld:US, MD, Baltimore:Baltimore.MD.US.Kidsworld.org:6664,6666,6668:
+Kidsworld:US, MD, Baltimore:baltimore.md.us.kidsworld.org:6666,6668,6669:
+Kidsworld:US, NY, New York:CCSD.NY.us.Kidsworld.org:6664,6666,6668:
+KissLand:Random server:irc.kissland.com:6667:
+Knightnet:AF, ZA, Durban:orc.dbn.za.knightnet.net:6667,5555:
+Knightnet:US, CA, Goldengate:goldengate.ca.us.knightnet.net:6667,5555:
+KreyNet:Random server:irc.krey.net:6667:
+Krushnet:Random server:irc.krushnet.org:6667:
+LagNet:AF, South Africa, Cape Town:babylon5.lagnet.org.za:6667:
+LagNet:AF, South Africa, Johannesburg:halcyon.lagnet.org.za:6667:
+LagNet:AF, South Africa, Pretoria:splash.lagnet.org.za:6667:
+LagNet:AF, ZA, Cape Town:reaper.lagnet.org.za:6667:
+LagNet:AF, ZA, Johannesburg:mystery.lagnet.org.za:6667:
+LagNet:Random server:irc.lagnet.org.za:6667:
+Librenet:Random server:irc.librenet.net:6667:
+Lunarnetirc:Random server:irc.lunarnetirc.org:6667:
+Lunatics:Random server:irc.lunatics.net:6667,6668,6669:
+MagicStar:Random server:irc.magicstar.net:6667:
+MavraNet:Random server:irc.mavra.net:6662,6663,6664:
+MediaDriven:Random server:irc.mediadriven.com:6667,6668,6669:
+Messique:Random server:irc.messique.org:6661,6664,6666:
+Millenia:Random server:irc.millenia.org:6664,6665,6666:
+Mozilla:Random server:irc.mozilla.org:6667,7000:
+Mysteria:Random server:irc.mysteria.net:6667,7000:
+Mystical:Random server:irc.mystical.net:6667,7000:
+NdrsNet:Random server:irc.ndrsnet.com:6666,6668,6669:
+Net-France:Random server:irc.net-france.com:6667:
+Nevernet:Random server:irc.nevernet.net:6667:
+NewNet:AF, South Africa:irc.sprintlink.co.za:6667:
+NewNet:EU, NL, Amsterdam:irc.desk.nl:6660,6663,6666,6669:
+NewNet:US, AZ, Phoenix:irc2.inficad.com:6667:
+NewNet:US, FL, Gainsville:irc.aohell.org:6667:
+NewNet:US, MD, Ocean City:irc.beachin.net:6667:
+NewNet:US, MI, Detroit:irc.tyme.net:6667:
+NewNet:US, NY, Buffalo:irc.localnet.com:6667:
+NewNet:US, NY, Freedom:vader.institute.wnyric.org:6667:
+NewNet:US, NY, Ysp:irc.ysp.com:6667:
+NewNet:US, TX, Houston:irc.localhost.net:6667:
+NewNet:US, WA, Seattle:irc.eskimo.com:6667:
+NewNet:US, WA, Silverdale:irc.tscnet.com:6667:
+Newnet:EU, DE, Trusted:irc.trusted-network.de:6666,7000:
+Newnet:EU, UK, Oasis:irc.oasis-net.net:6666,7000:
+Newnet:NZ, Auckland:irc.uplink.net.nz:6661,6662,6666:
+Newnet:Random server:irc.newnet.net:6665,6666,6667:
+Newnet:US, CA, Flagglerock:irc.fragglerock.org:6666,7000:
+Newnet:US, MA, Chelmsford:irc.chelmsford.com:6660,6665,6668:
+Newnet:US, VA, Randolph:irc.rma.edu:6665,6666,6668:
+Nexusirc:Random server:irc.nexusirc.org:6667:
+Nightstar:Random server:irc.nightstar.net:6665,6666,6668:
+NitroNet:Random server:irc.nitro.net:6667:
+Novernet:Random server:irc.novernet.com:6665,6666,6668:
+Novernet:US, GA, Augusta:irc.c-plusnet.com:6666,6668,6669:
+Novernet:US, MN, Minneapolis:chat.novernet.com:6667:
+Othernet:Random server:irc.othernet.org:6667:
+Othernet:US, FL, Miami:miami.fl.us.othernet.org:6667:
+Othernet:US, MO, StLouis:stlouis.mo.us.othernet.org:6667:
+Otherside:Random server:irc.othersideirc.net:6667:
+Outsiderz:Random server:irc.outsiderz.com:6667:
+OzChat:Random server:irc.ozchat.org:6667:
+OzOrg:AU, Adelaide:chariot.adelaide.oz.org:6666,6668,7000:
+OzOrg:AU, Goldcoast:onthenet.goldcoast.oz.org:6667:
+OzOrg:AU, Perth:iinet.perth.oz.org:6667:
+OzOrg:AU, Sydney (aussie):aussie.sydney.oz.org:6667:
+OzOrg:AU, Sydney (mpx):mpx.sydney.oz.org:6667:
+OzOrg:AU, Sydney:aussie.sydney.oz.org:6668,6669,7000:
+OzOrg:AU, Wollongong:wollongong.oz.org:6667:
+OzOrg:US, CA, Davis:davis.oz.org:6667:
+PTlink:Random server:irc.ptlink.net:6667:
+PTnet:EU, PT, Faro:ualg.ptnet.org:6667:
+PTnet:EU, PT, Lisboa:telepac2.ptnet.org:6667:
+ParaBolax:US, MA, Westminster:irc.parabolax.com:6667:
+ParaBolax:US, MI, Farmington Hills:irc.redhot.parabolax.com:6667:
+ParaBolax:US, NY, Madison:irc.bluewonder.parabolax.com:6667:
+Pinoycentral:Random server:chat.abs-cbn.com:6667:
+Planetarion:Random server:irc.planetarion.com:6667:
+PowerChat:Random server:irc.powerchat.org:6954,6956,6999:
+Pseudonet:Random server:irc.pseudonet.org:6667:
+QChat:Random server:irc.qchat.net:6667:
+QuakeNet:Random server:irc.quakenet.eu.org:6667,6668,6669:
+Raptanet:Random server:irc.rapta.net:6667:
+Raptornet:Random server:irc.raptornet.org:6667:
+Realirc:Random server:irc.realirc.org:6667:
+Rebelchat:Random server:irc.rebelchat.org:6667:
+Red-Latina:NA, MX, SanJose:irc.dalsom.net:6666,6667:
+Red-Latina:Random server:irc.red-latina.org:6667:
+RedLatina:NA, Mexico, Guadalajara:irc.udg.mx:6667:
+RedLatina:NA, Mexico, Mexico, D.F:yuju.anahuac.mx:6667:
+RedLatina:NA, Mexico, Morelos:academ02.mor.itesm.mx:6667:
+RedLatina:NA, México, Aguascalientes:sundi.basico.uaa.mx:6667:
+RedLatona:Random server:irc.redlatona.net:6667,6668:
+RedeBrasil:BR, CE, Ceara:irc.linline.com.br:6666,7000,7001:
+RedeBrasil:BR, PE, Recife:irc.hotlink.com.br:6665,6666,7000:
+RedeBrasil:BR, PR, Parana:irc.intermam.com.br:6660,6661,6662:
+RedeBrasil:BR, SP, Sao Paulo:irc.aserver.com.br:6662,6666,7000:
+RedeSul:BR, PR, Maringa:irc.wnet.com.br:6667:
+RedeSul:BR, SC, Blumenau:irc.braznet.com.br:6667,9001:
+RekorNet:Random server:irc.rekor.net:6665,6668,6669:
+Relicnet:Random server:irc.relic.net:6667:
+Relicnet:US, MA, Cyclone:cyclone.us.relic.net:6661,6662,6663:
+Risanet:Random server:irc.risanet.com:6667,6668,6669:
+Rusnet:EU, RU, Tomsk:irc.tsk.ru:7771,7773,7774:
+Rusnet:EU, RU, Vladivostok:irc.vladivostok.ru:6669,7771,7774:
+Rusnet:EU, UA, Kiev:irc.kar.net:6669,7770,7774:
+SandNet:FL, Ocala:ocala.fl.us.sandnet.org:7000:
+SandNet:GA, Atlanta:atlanta.ga.us.sandnet.org:6667:
+SandNet:MO, Stlouis:stlouis.mo.us.sandnet.org:6667,7000:
+SandNet:TX, Laredo:laredo.tx.us.sandnet.org:6667:
+Sandnet:Random server:irc.sandnet.net:6660,6662,6668:
+Sandnet:US, CA, Mystic:mystic.tides.sandnet.net:6662,6665,6666:
+Sandnet:US, NJ, DuneBuggy:dunebuggy.nj.sandnet.net:6661,6662,6666:
+Scunc:Random server:irc.scunc.net:6667:
+SexNet:Random server:irc.sexnet.org:6667:
+SgNet:Random server:irc.sgnet.org:6661,6663,6668:
+ShadowFire:Random server:irc.shadowfire.org:6667:
+ShadowWorld:Random server:irc.shadowworld.net:6667:
+SideNet:Random server:irc.sidenet.org:6661,6663,6666:
+Skyyenet:US, VA, Arlington:arlington.va.us.skyyenet.org:6667:
+Slashnet:Random server:irc.slashnet.org:6667:
+Solarchat:Random server:irc.solarchat.net:6667,7000:
+SorceryNet:CA, ON, Jordan:blackmagic.sorcery.net:9000:
+SorceryNet:EU, DE, Hamburg:atlantis.sorcery.net:9000:
+SorceryNet:EU, NL, Amsterdam:tardis.sorcery.net:9000:
+SorceryNet:US, MA, Cambridge:kechara.sorcery.net:9000:
+SorceryNet:US, MD, Clinton:quasar.sorcery.net:9000:
+Sorcerynet:EU, SE, Karlskrona:nexus.sorcery.net:6667,7000,9000:
+Sorcerynet:Random server:irc.sorcery.net:6667,7000,9000:
+Sorcerynet:US, CA, Palo Alto:kechara.sorcery.net:6667,7000,9000:
+Spamnet:Random server:irc.spamnet.org:6667,6668,6669:
+StarChat:AU, QLD, SouthernCross:boomer.qld.au.starchat.net:6668,6669,7000:
+StarChat:EU, NO, Asker:reality.no.eu.starchat.net:6668,6669,7000:
+StarChat:Random server:irc.starchat.net:6668,6669,7000:
+StarChat:US, CA, San Jose:sand.ca.us.starchat.net:6668,6669,7000:
+StarLink Org:US, CO, Denver:denver.co.us.starlink.org:6660,6662,6666:
+StarLink Org:US, NC, Durham:durham-r.nc.us.starlink.org:6661,6663,6668:
+StarLink Org:US, TX, WichitaFalls:wichitafalls.tx.us.starlink.org:6666,6667,6668:
+StarLink-irc:Random server:irc.starlink-irc.org:6667:
+StarLink-irc:US, MI, Rochester:rochester.mi.us.starlink-irc.org:6667:
+StarLink-irc:US, TX, Houston:houston.tx.us.starlink-irc.org:6667:
+StarLink:EU, NL, Utrecht:Utrecht.NL.EU.StarLink.Org:6667:
+StarLink:US, CO, Aspen:Aspen.CO.US.StarLink.Org:6667:
+StarLink:US, CO, Denver:Denver.CO.US.StarLink.Org:6667:
+StarLink:US, FL, Miami:Miami.FL.US.StarLink.Org:6667:
+StarLink:US, SC, Rockhill:RockHill.SC.US.StarLink.Org:6667:
+StarLinkIRC:US, GA, Atlanta:Atlanta.GA.US.Starlink-IRC.Org:6667:
+StarLinkIRC:US, MI, Rochester:Rochester.MI.US.Starlink-IRC.Org:6667:
+StarLinkIRC:US, OH, Cleveland:Cleveland.OH.US.Starlink-IRC.Org:6667:
+StarNet:US, FL, Jacksonville:irc.starnet.org:6667:
+StarNet:US, NY, New york:ny.us.starnet.org:6660,6662,6664,6666,6668:
+StarNet:US, OH, Cincinatti:oh.us.starnet.org:6662,6664,6666,6667:
+StarNet:US, TX, San Antonio:irc.xtatix.com:6667:
+StarWars-IRC:Random server:irc.starwars-irc.net:6663,6664,6665:
+StormNet:NZ, Auckland:auckland.nz.stormnet.org:6667:
+StormNet:US, CA, Valencia:valencia.ca.us.stormnet.org:6667:
+StormNet:US, FL, Brandon:brandon.fl.us.stormnet.org:6667:
+StormNet:US, IN, Indianapolis:indianapolis.in.us.stormnet.org:6667:
+StormNet:US, NC, Durham:durham.nc.us.stormnet.org:6667:
+Stormdancing:Random server:irc.stormdancing.net:6664,6668,7000:
+Sub-city:Random server:irc.sub-city.net:6668,6669,7000:
+Superchat:Random server:irc.superchat.org:6660,6664,6665:
+Superchat:US, GA, Cartersville:superchat.innerx.net:6660,6662,6664,6666,6668:
+Superchat:US, LA, Houma:chat.cajun.net:6660,6662,6664,6666,6668:
+Superchat:US, NJ, New Brunswick:irc.superlink.net:6660,6662,6664,6666,6668:
+Superchat:US, PA, Pittsburgh:irc.pitnet.net:6660,6662,6664,6666,6668:
+Superchat:US, TX, Dallas:irc.airmail.net:6660,6662,6664,6666,6668:
+Superonline:Random server:irc.superonline.com:6663,6664,6669:
+Sysopnet:Random server:irc.sysopnet.org:6666,6667,6668:
+TR-net:EU, TR, Ankara:irc.dominet.com.tr:6667:
+TR-net:EU, Tr, Istanbul:irc.teklan.com.tr:6667:
+TRcom:Random server:irc.trcom.net:6666,6668,6669:
+Techdreams:Random server:irc.techdreams.net:6667:
+Telstra:Random server:irc.telstra.com:6667,6668,6669:
+Tri-net:Random server:irc.tri-net.org:6667:
+UltraIRC:Random server:irc.ultrairc.net:6667:
+UltraNet:EU, FR, Neuilly:Neuilly.FR.EU.UltraNET.Org:6668:
+UltraNet:EU, UK, London:London.UK.EU.UltraNET.Org:6667:
+UltraNet:US, MS, Vicksburg:Vicksburg.MS.US.UltraNET.Org:6667:
+UltraNet:US, PA, Philadelphia:Philadelphia.PA.US.Ultranet.Org:6667:
+UnderZ:Random server:irc.underz.org:6667,6668:
+Undergrid:US, AS, Little Rock:tomes.undergrid.com:6665,6667,6669,7000,10000:
+Undergrid:US, CA, Chatsworth:ribbit.undergrid.com:10000:
+Undergrid:US, IA, Hawarden:starwars.undergrid.com:667,7000,10000:
+Undergrid:US, OK, Oklahoma City:thor.undergrid.com:6667,7000,10000:
+Undernet:CA, ON, Toronto:toronto.on.ca.undernet.org:6661,6662,6666:
+Undernet:CA, QC, Montreal:montreal.qu.ca.undernet.org:6660,6661,6664:
+Undernet:Canada, Montreal:montreal.qu.ca.undernet.org:6667,6668,6669,7777:
+Undernet:Canada, Toronto:toronto.on.ca.undernet.org:6667,6668,6669,7777:
+Undernet:Canada, Vancouver:vancouver.bc.ca.undernet.org:6666,6667,6668,6669:
+Undernet:EU, AT, Graz:graz.at.eu.undernet.org:6661,6663,6668:
+Undernet:EU, BE, Antwerp:flanders.be.eu.undernet.org:6660,6662,6663:
+Undernet:EU, BE, Brussels:brussels.be.eu.undernet.org:6661,6663,6668:
+Undernet:EU, DE, Regensburg:regensburg.de.eu.undernet.org:6667,6668:
+Undernet:EU, FI, Espoo:espoo.fi.eu.undernet.org:6667,6668:
+Undernet:EU, FR, Caen:caen.fr.eu.undernet.org:6666,6668,6669:
+Undernet:EU, FR, Caen:caen.fr.eu.undernet.org:6667,6668:
+Undernet:EU, FR, Paris:paris.fr.eu.undernet.org:6662,6663,6666:
+Undernet:EU, NL, Amsterdam:amsterdam.nl.eu.undernet.org:6667,6668,6669,7000:
+Undernet:EU, NL, Diemen:diemen.nl.eu.undernet.org:6665,6666,6668:
+Undernet:EU, NL, Diemen:diemen.nl.eu.undernet.org:6667,6668,6669,7000:
+Undernet:EU, NL, Haarlem:haarlem.nl.eu.undernet.org:6660,6662,6666:
+Undernet:EU, NO, Oslo:oslo.no.eu.undernet.org:6662,6664,6668:
+Undernet:EU, NO, Oslo:oslo.no.eu.undernet.org:6667,6668:
+Undernet:EU, SE, Lulea:lulea.se.eu.undernet.org:6667,7000,7777:
+Undernet:EU, SE, Stockholm:stockholm.se.eu.undernet.org:6661,6662,6664:
+Undernet:EU, UK, London:london.uk.eu.undernet.org:6666,6667:
+Undernet:EU, UK, London:london.uk.eu.undernet.org:6666,6668,6669:
+Undernet:EU, UK, Surrey:surrey.uk.eu.undernet.org:6662,6665,6666:
+Undernet:NZ, Auckland:auckland.nz.undernet.org:6667:
+Undernet:US, AZ, Phoenix:phoenix.az.us.undernet.org:6667,6668,6669:
+Undernet:US, America OnLine:irc01.irc.aol.com:6667:
+Undernet:US, CA, San Diego:sandiego.ca.us.undernet.org:6665,6666,6668:
+Undernet:US, CA, SanDiego:sandiego.ca.us.undernet.org:6667,6668,7000,7777:
+Undernet:US, DC, Washington:washington.dc.us.undernet.org:6660,6665,6668:
+Undernet:US, DC, Washington:washington.dc.us.undernet.org:6661,6663,6665,6667:
+Undernet:US, IL, Chicago:chicago.il.us.Undernet.org:6667,6668,6669,7777:
+Undernet:US, KS, Manhattan:manhattan.ks.us.undernet.org:6662,6664,6665:
+Undernet:US, KS, Manhattan:manhattan.ks.us.undernet.org:6667,6668,7000,7777:
+Undernet:US, MA, Lowell:lowell.ma.us.undernet.org:6667,6668,6669,7777:
+Undernet:US, MO, Springfield:springfield.mo.us.undernet.org:6667,6668,6669,7000:
+Undernet:US, MO, St.Louis:stlouis.mo.us.undernet.org:6666,6667,6668,6669:
+Undernet:US, NV, Las Vegas:lasvegas.nv.us.undernet.org:6662,6663,6668:
+Undernet:US, PA , Pittsburg:pittsburgh.pa.us.undernet.org:6667,6668,6669:
+Undernet:US, TX, Austin:austin.tx.us.undernet.org:6661,6663,6664:
+Undernet:US, TX, Dallas:dallas.tx.us.undernet.org:6667,6668,6669:
+Undernet:US, UT, Saltlake:saltlake.ut.us.undernet.org:6663,6665,6666:
+Undernet:US, VA, Arlington:arlington.va.us.undernet.org:6661,6663,6665:
+Undernet:US, VA, Blacksburg:blacksburg.va.us.undernet.org:6667,6668,7000,7777:
+Undernet:US, VA, McLean:mclean.va.us.undernet.org:6666,6668,6669:
+UnionLatina:Random server:irc.unionlatina.org:6667:
+UnitedChat Net:Random server:irc.unitedchat.net:6667:
+UnitedChat Org:Random server:irc.unitedchat.org:6667:
+Univers:Random server:irc.univers.org:6665,6666,6668:
+Vidgamechat:Random server:irc.vidgamechat.com:6667:
+Virtuanet:Random server:irc.virtuanet.org:6662,6666,6669:
+Vitamina:Random server:irc-rr.vitamina.ca:6667:
+Warpednet:Random server:irc.warped.net:6667:
+WebNet:US, CA, Santa Clara:webmaster.ca.us.webchat.org:7000:
+WebNet:US, IL, Geneva:inil.il.us.webchat.org:7000:
+WebNet:US, MN, St.Paul:mwweb.oh.us.webchat.org:7000:
+WebNet:US, OK, Tulsa:webzone.ok.us.webchat.org:7000:
+WebNet:US, WA, Seattle:prostar.wa.us.webchat.org:7000:
+Webnet:Random server:irc.webchat.org:6668,6669,7000:
+Webnet:US, AL, Dothan:wiregrass.al.us.webchat.org:6668,6669,7000:
+Webnet:US, CA, Santa Clara:webmaster.ca.us.webchat.org:6662,6663,6664:
+Webnet:US, MA, Boston:greennet.ma.us.webchat.org:6668,6669,7000:
+WonKnet:Random server:irc.wonk.net:6668,6669,7000:
+WorldIRC:Random server:irc.worldirc.org:6661,6662,6665:
+WorldIRC:US, IL, Chicago:Chicago.Il.Us.WorldIRC.Org:6667:
+WorldIRC:US, MD, Baltimore:Baltimore.Md.US.WorldIRC.Org:6667:
+WorldIRC:US, MI, GrandRapids:GrandRapids.Mi.Us.WorldIRC.Org:6667:
+WorldIRC:US, OK, Norman:Norman.Ok.US.WorldIRC.Org:6667:
+Wwfin:US, FL, Gainesville:irc.afn.org:6667:
+Wwfin:US, IL, Champaign:prairienet.org:6667:
+Wwfin:US, MI, Grand Rapids:irc.grfn.org:6667:
+Wwfin:US, MI, Holland:irc.macatawa.org:6667:
+XNet:Random server:irc.xnet.org:6667:
+XWorld:EU, DE, Wesel:startrek.xworld.org:6667:
+XWorld:Random server:irc.xworld.org:6667:
+XWorld:US, FL, Pensacola:llama.xworld.org:6667:
+XWorld:US, KS ,Kansas City:irc.xworld.org:6667:
+XWorld:US, SC, Rockhill:chat.xworld.org:6667:
+Xevion:Random server:irc.xevion.net:6667,7000:
+ZAnet Net:AF, ZA, CI (lia):lia.zanet.net:6667:
+ZAnet Net:AF, ZA, MWeb (timewiz):timewiz.zanet.net:6667:
+ZAnet Org:AF, ZA, Cape Town (gaspode):gaspode.zanet.org.za:6667:
+ZAnet Org:AF, ZA, Johannesburg (is):is.zanet.org.za:6667:
+ZAnet Org:AF, ZA, Midrand (ethereal):ethereal.zanet.org.za:6660,6666:
+ZAnet:AF, ZA, Cape Town:gaspode.zanet.org.za:6667:
+ZAnet:AF, ZA, Cape Town:guru.zanet.org.za:6667:
+ZAnet:AF, ZA, Johannesburg:is.zanet.org.za:6667:
+ZAnet:AF, ZA, Midrand:ibi.zanet.org.za:6667:
+ZUHnet:Random server:irc.zuh.net:6667:
+ZiRC:Random server:irc.zirc.org:6660,6662,6665:
+Zurna:Random server:irc.zurna.net:6667:
+euIRC:Random server:irc.euirc.net:6665,6666,6668:
diff --git a/ksirc/KSPrefs/Makefile.am b/ksirc/KSPrefs/Makefile.am
new file mode 100644
index 00000000..64d38261
--- /dev/null
+++ b/ksirc/KSPrefs/Makefile.am
@@ -0,0 +1,50 @@
+
+INCLUDES= -I$(srcdir)/.. $(all_includes)
+
+noinst_LTLIBRARIES = libksprefs.la
+
+libksprefs_la_SOURCES = \
+ ksprefs.cpp \
+ page_colorsbase.ui\
+ page_generalbase.ui\
+ page_rmbmenubase.ui \
+ page_servchanbase.ui \
+ page_startupbase.ui \
+ page_colors.cpp \
+ page_general.cpp \
+ page_rmbmenu.cpp \
+ page_servchan.cpp \
+ page_startup.cpp \
+ page_font.cpp \
+ page_autoconnectbase.ui \
+ page_autoconnect.cpp \
+ page_irccolorsbase.ui\
+ page_irccolors.cpp \
+ page_looknfeelbase.ui \
+ page_looknfeel.cpp \
+ page_shortcutsbase.ui \
+ page_shortcuts.cpp
+
+METASOURCES = AUTO
+
+noinst_HEADERS = ksprefs.h \
+ page_colorsbase.h \
+ page_generalbase.h \
+ page_rmbmenubase.h \
+ page_servchanbase.h \
+ page_startupbase.h \
+ page_colors.h \
+ page_general.h \
+ page_rmbmenu.h \
+ page_servchan.h \
+ page_startup.h \
+ page_font.h \
+ page_autoconnectbase.h \
+ page_autoconnect.h \
+ page_irccolors.h \
+ page_irccolorsbase.h \
+ page_looknfeel.h \
+ page_looknfeelbase.h \
+ page_shortcutsbase.h \
+ page_shortcuts.h
+
diff --git a/ksirc/KSPrefs/ksprefs.cpp b/ksirc/KSPrefs/ksprefs.cpp
new file mode 100644
index 00000000..2bf97e84
--- /dev/null
+++ b/ksirc/KSPrefs/ksprefs.cpp
@@ -0,0 +1,244 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+
+#include <kdebug.h>
+
+#include "ksprefs.moc"
+#include "page_general.h"
+#include "page_colors.h"
+#include "page_startup.h"
+#include "page_rmbmenu.h"
+#include "page_servchan.h"
+#include "page_font.h"
+#include "page_autoconnect.h"
+#include "page_irccolors.h"
+#include "page_looknfeel.h"
+#include "page_shortcuts.h"
+
+KSPrefs::KSPrefs(QWidget * parent, const char * name):
+ KDialogBase(KDialogBase::IconList, i18n("Configure KSirc"),
+ KDialogBase::Help | KDialogBase::Ok | KDialogBase::Apply | KDialogBase::Cancel | KDialogBase::Default,
+ KDialogBase::Ok, parent, name)
+{
+ setWFlags( getWFlags() | WDestructiveClose );
+ QFrame *itemLooknFeel= addPage( i18n( "Look and Feel" ), i18n( "Controls how kSirc looks" ), BarIcon( "ksirc", KIcon::SizeMedium ) );
+ QFrame *itemGeneral = addPage( i18n( "General" ), i18n( "General KSirc Settings" ), BarIcon( "ksirc", KIcon::SizeMedium ) );
+ QFrame *itemStartup = addPage( i18n( "Startup" ), i18n( "KSirc Startup Settings" ), BarIcon( "gear", KIcon::SizeMedium ) );
+ QFrame *itemColors = addPage( i18n( "Colors" ), i18n( "KSirc Color Settings" ), BarIcon( "colors", KIcon::SizeMedium ) );
+ QFrame *itemIRCColors = addPage( i18n( "IRC Colors" ), i18n( "KSirc IRC Color Settings" ), BarIcon( "colors", KIcon::SizeMedium ) );
+
+ QFrame *itemRMBMenu = addPage( i18n( "User Menu" ), i18n( "User Menu Configuration" ), BarIcon( "", KIcon::SizeMedium ) );
+ QFrame *itemServChan = addPage( i18n( "Server/Channel" ), i18n( "Server/Channel Configuration" ), BarIcon( "", KIcon::SizeMedium ) );
+ QFrame *itemAutoConnect = addPage( i18n( "Auto Connect" ), i18n( "Auto Connect Configuration" ), BarIcon( "", KIcon::SizeMedium ) );
+ QFrame *itemFont = addPage( i18n( "Fonts" ), i18n( "Font Settings" ), BarIcon( "fonts", KIcon::SizeMedium ) );
+ QFrame *itemShortcuts = addPage( i18n( "Shortcuts" ), i18n( "Shortcut Configuration" ), BarIcon( "", KIcon::SizeMedium ) );
+
+ QVBoxLayout *fontTopLayout = new QVBoxLayout( itemFont, 0, 6 );
+
+
+ QVBoxLayout *looknfeelTopLayout= new QVBoxLayout( itemLooknFeel, 0, 6 );
+ QVBoxLayout *generalTopLayout = new QVBoxLayout( itemGeneral, 0, 6 );
+ QVBoxLayout *startupTopLayout = new QVBoxLayout( itemStartup, 0, 6 );
+ QVBoxLayout *colorsTopLayout = new QVBoxLayout( itemColors, 0, 6 );
+ QVBoxLayout *ircColorsTopLayout = new QVBoxLayout( itemIRCColors, 0, 6 );
+
+ QVBoxLayout *rmbMenuTopLayout = new QVBoxLayout( itemRMBMenu, 0, 6 );
+ QVBoxLayout *servChanTopLayout = new QVBoxLayout( itemServChan, 0, 6 );
+ QVBoxLayout *autoConnectTopLayout = new QVBoxLayout( itemAutoConnect, 0, 6 );
+ QVBoxLayout *autoShortcutsTopLayout = new QVBoxLayout( itemShortcuts, 0, 6 );
+
+ pageLooknFeel= new PageLooknFeel( itemLooknFeel );
+ pageGeneral = new PageGeneral( itemGeneral );
+ pageStartup = new PageStartup( itemStartup );
+ pageColors = new PageColors( itemColors );
+ pageIRCColors = new PageIRCColors( itemIRCColors );
+ pageFont = new PageFont( itemFont );
+ pageRMBMenu = new PageRMBMenu( itemRMBMenu );
+ pageServChan = new PageServChan( itemServChan );
+ pageAutoConnect = new PageAutoConnect( itemAutoConnect );
+ pageShortcuts = new PageShortcuts( itemShortcuts );
+
+ connect(pageLooknFeel, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageGeneral, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageStartup, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageColors, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageIRCColors, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageFont, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageRMBMenu, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageServChan, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageAutoConnect, SIGNAL( modified() ), SLOT( modified() ) );
+ connect(pageShortcuts, SIGNAL( modified() ), SLOT( modified() ) );
+
+ connect(this, SIGNAL( applyClicked() ), this, SLOT( saveConfig() ) );
+ connect(this, SIGNAL( okClicked() ), this, SLOT( saveConfig() ) );
+ connect(this, SIGNAL( defaultClicked() ), this, SLOT(defaultConfig() ) );
+
+ looknfeelTopLayout->addWidget( pageLooknFeel );
+ generalTopLayout->addWidget( pageGeneral );
+ startupTopLayout->addWidget( pageStartup );
+ colorsTopLayout->addWidget( pageColors );
+ ircColorsTopLayout->addWidget( pageIRCColors );
+ fontTopLayout->addWidget( pageFont );
+ rmbMenuTopLayout->addWidget( pageRMBMenu );
+ servChanTopLayout->addWidget( pageServChan );
+ autoConnectTopLayout->addWidget( pageAutoConnect );
+ autoShortcutsTopLayout->addWidget( pageShortcuts );
+ //enableButtonSeperator( true );
+
+ readConfig();
+ enableButtonApply( false );
+
+ pSCDirty = 0;
+ pACDirty = 0;
+}
+
+KSPrefs::~KSPrefs()
+{
+}
+
+void KSPrefs::readConfig()
+{
+ // apply by calling readConfig in each page
+
+ pageLooknFeel->readConfig();
+ pageGeneral->readConfig();
+ pageColors->readConfig();
+ pageIRCColors->readConfig();
+ pageStartup->readConfig();
+ pageFont->readConfig();
+ pageRMBMenu->readConfig();
+ pageServChan->readConfig();
+ pageAutoConnect->readConfig();
+ pageShortcuts->readConfig();
+
+}
+
+void KSPrefs::saveConfig()
+{
+ // apply by calling saveConfig in each page
+ // use setDirty flag for each page and
+ // emit update() appropriate
+
+ if ( dirty & KSOptions::General )
+ pageGeneral->saveConfig();
+ if ( dirty & KSOptions::Startup )
+ pageStartup->saveConfig();
+ if ( dirty & KSOptions::Colors )
+ pageColors->saveConfig();
+ if ( dirty & KSOptions::Colors )
+ pageIRCColors->saveConfig();
+ if ( dirty & KSOptions::Colors )
+ pageFont->saveConfig();
+ if ( dirty & KSOptions::RMBMenu )
+ pageRMBMenu->saveConfig();
+ if ( dirty & pSCDirty )
+ pageServChan->saveConfig();
+ if ( dirty & pACDirty )
+ pageAutoConnect->saveConfig();
+ if ( dirty & pLFDirty )
+ pageLooknFeel->saveConfig();
+ if ( dirty & pShortDirty )
+ pageShortcuts->saveConfig();
+
+
+ ksopts->save( dirty );
+ emit update( dirty );
+ enableButtonApply( false );
+}
+
+
+void KSPrefs::defaultConfig()
+{
+ // apply by calling defaultConfig in current page
+
+ switch (activePageIndex())
+ {
+ case 0:
+ kdDebug(5008) << "Doing looknfeel" << endl;
+ pageLooknFeel->defaultConfig();
+ break;
+ case 1:
+ kdDebug(5008) << "Doing general" << endl;
+ pageGeneral->defaultConfig();
+ break;
+ case 2:
+ kdDebug(5008) << "Doing startup" << endl;
+ pageStartup->defaultConfig();
+ break;
+ case 3:
+ kdDebug(5008) << "Doing colors" << endl;
+ pageColors->defaultConfig();
+ break;
+ case 4:
+ kdDebug(5008) << "Doing IRC colors" << endl;
+ pageIRCColors->defaultConfig();
+ break;
+ case 5:
+ kdDebug(5008) << "Doing RMBMenu" << endl;
+ pageRMBMenu->defaultConfig();
+ break;
+ case 6:
+ kdDebug(5008) << "Doing ServerChan" << endl;
+ pageServChan->defaultConfig();
+ break;
+ case 7:
+ kdDebug(5008) << "Doing AutoConnect" << endl;
+ pageAutoConnect->defaultConfig();
+ case 8:
+ kdDebug(5008) << "Doing font" << endl;
+ pageFont->defaultConfig();
+ break;
+ case 9:
+ kdDebug(5008) << "Doing shortcuts" << endl;
+ pageShortcuts->defaultConfig();
+ break;
+
+ }
+}
+
+void KSPrefs::modified()
+{
+ if ( sender() == pageGeneral )
+ dirty |= static_cast<int>( KSOptions::General );
+ if ( sender() == pageStartup ) {
+ dirty |= static_cast<int>( KSOptions::Startup );
+ dirty |= static_cast<int>( KSOptions::Servers );
+ }
+ if ( sender() == pageColors )
+ dirty |= static_cast<int>( KSOptions::Colors );
+ if ( sender() == pageIRCColors )
+ dirty |= static_cast<int>( KSOptions::Colors );
+ if ( sender() == pageFont )
+ dirty |= static_cast<int>( KSOptions::Colors );
+ if ( sender() == pageRMBMenu )
+ dirty |= static_cast<int>( KSOptions::RMBMenu );
+ if ( sender() == pageServChan ) {
+ dirty |= 1;
+ pSCDirty = 1;
+ }
+ if ( sender() == pageAutoConnect ) {
+ dirty |= 1;
+ pACDirty = 1;
+ }
+ if ( sender() == pageLooknFeel ) {
+ dirty |= 1;
+ pLFDirty = 1;
+ }
+ if ( sender() == pageShortcuts ) {
+ dirty |= 1;
+ pShortDirty = 1;
+ }
+
+ enableButtonApply( dirty );
+}
diff --git a/ksirc/KSPrefs/ksprefs.h b/ksirc/KSPrefs/ksprefs.h
new file mode 100644
index 00000000..6c41fd9a
--- /dev/null
+++ b/ksirc/KSPrefs/ksprefs.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSPREFS_H
+#define KSPREFS_H
+
+#include <kdialogbase.h>
+
+class PageGeneral;
+class PageColors;
+class PageIRCColors;
+class PageStartup;
+class PageRMBMenu;
+class PageServChan;
+class PageAutoConnect;
+class PageLooknFeel;
+class PageShortcuts;
+
+class PageFont; /* For the font settings */
+
+
+class KSPrefs : public KDialogBase
+{
+
+Q_OBJECT
+public:
+ KSPrefs(QWidget * parent = 0, const char * name = 0);
+ ~KSPrefs();
+
+public slots:
+ void saveConfig();
+ void defaultConfig();
+ void readConfig();
+ void modified();
+
+signals:
+ void update(int);
+
+private:
+ PageColors *pageColors;
+ PageIRCColors *pageIRCColors;
+ PageGeneral *pageGeneral;
+ PageRMBMenu *pageRMBMenu;
+ PageStartup *pageStartup;
+ PageServChan *pageServChan;
+ PageAutoConnect *pageAutoConnect;
+ PageLooknFeel *pageLooknFeel;
+ PageShortcuts *pageShortcuts;
+
+ int pSCDirty;
+ int pACDirty;
+ int pLFDirty;
+ int pShortDirty;
+
+ PageFont *pageFont; /* Font settings page */
+ int dirty;
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_autoconnect.cpp b/ksirc/KSPrefs/page_autoconnect.cpp
new file mode 100644
index 00000000..a6532915
--- /dev/null
+++ b/ksirc/KSPrefs/page_autoconnect.cpp
@@ -0,0 +1,309 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "page_autoconnect.h"
+
+
+#include <qregexp.h>
+#include <klocale.h>
+#include <klistview.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <knuminput.h>
+
+#define NAME 0
+#define PK 1
+#define PASS 2
+#define SSL 3
+
+PageAutoConnect::PageAutoConnect( QWidget *parent, const char *name ) : PageAutoConnectBase( parent, name)
+{
+ KLVAutoConnect->setSorting( 0 );
+ //KLVAutoConnect->header()->hide();
+
+ AddPB->setEnabled(FALSE);
+ DeletePB->setEnabled(FALSE);
+ PortKI->setValue(6667);
+}
+
+PageAutoConnect::~PageAutoConnect()
+{
+}
+
+void PageAutoConnect::saveConfig()
+{
+
+ KConfig *conf = kapp->config();
+ conf->setGroup("AutoConnect");
+
+ QStringList servers;
+
+ for(QListViewItem *it = KLVAutoConnect->firstChild();
+ it != 0;
+ it = it->nextSibling()){
+
+ QString server = it->text(NAME);
+
+ if(it->text(PK).length() > 0)
+ server += ":" + it->text(1);
+ if(it->text(SSL).length() > 0)
+ server += " (SSL)";
+ if(it->text(PASS).length() > 0)
+ server += QString(" (pass: %1)").arg(it->text(PASS));
+
+ servers << server;
+
+ QStringList channels;
+
+ for(QListViewItem *ch = it->firstChild();
+ ch != 0;
+ ch = ch->nextSibling()){
+ QString channel;
+
+ channel = ch->text(NAME);
+
+ if(ch->text(PK).length() > 0)
+ channel += QString(" (key: %1)").arg(ch->text(PK));
+
+ channels << channel;
+
+ }
+
+ channels.sort();
+ conf->writeEntry(server, channels);
+
+ }
+
+ servers.sort();
+
+ conf->writeEntry("Servers", servers);
+
+}
+
+void PageAutoConnect::readConfig()
+{
+ KConfig *conf = kapp->config();
+ conf->setGroup("AutoConnect");
+ QStringList servers = conf->readListEntry("Servers");
+ servers.sort();
+ QStringList::ConstIterator ser = servers.begin();
+ for( ; ser != servers.end(); ser++){
+ QStringList channels = conf->readListEntry(*ser);
+ QString server = *ser;
+ QString port = "6667";
+ QString ssl = QString::null;
+ QString pass = QString::null;
+
+ QRegExp rx("(.+) \\(SSL\\)(.*)");
+ if(rx.search(server) >= 0){
+ server = rx.cap(1) + rx.cap(3);
+ ssl = i18n("SSL");
+ }
+ rx.setPattern("(.+) \\(pass: (\\S+)\\)(.*)");
+ if(rx.search(server) >= 0){
+ server = rx.cap(1) + rx.cap(3);
+ pass = rx.cap(2);
+ }
+ rx.setPattern("([^: ]+):(\\d+)");
+ if(rx.search(server) >= 0){
+ kdDebug(5008) << server << ": Has port:" << rx.cap(2) << endl;
+ server = rx.cap(1);
+ port = rx.cap(2);
+ }
+ kdDebug(5008) << server << ": Done " << port << " " << ssl << " " << pass << endl;
+ QListViewItem *s = new QListViewItem(KLVAutoConnect, server, port, pass, ssl);
+ s->setOpen(TRUE);
+ channels.sort();
+ QStringList::ConstIterator chan = channels.begin();
+ for(; chan != channels.end(); chan++){
+ QString channel = *chan;
+ QString key = QString::null;
+ QRegExp crx("(.+) \\(key: (\\S+)\\)");
+ if(crx.search(channel) >= 0){
+ channel = crx.cap(1);
+ key = crx.cap(2);
+ }
+ new QListViewItem(s, channel, key);
+ }
+ }
+}
+
+void PageAutoConnect::defaultConfig()
+{
+ KLVAutoConnect->clear();
+ readConfig( );
+}
+
+void PageAutoConnect::changed()
+{
+ emit modified();
+}
+
+void PageAutoConnect::add_pressed()
+{
+ int fnd = 0;
+ QListViewItem *s = 0;
+
+ s = KLVAutoConnect->selectedItem();
+ if(!s){ /* new item */
+ QString server = ServerLE->text();
+ QString ssl = QString::null;
+ QString port;
+
+ port.setNum(PortKI->value());
+ if(sslCB->isChecked())
+ ssl = i18n("SSL");
+
+ s = new QListViewItem(KLVAutoConnect, server, port, PassLE->text(), ssl);
+ s->setOpen(TRUE);
+ s = new QListViewItem(s, ChannelLE->text(), KeyLE->text());
+ KLVAutoConnect->setCurrentItem(s);
+ }
+ else { /* update the existing one */
+ QListViewItem *parent;
+ QListViewItem *child;
+
+ if(s->parent()){
+ parent = s->parent();
+ child = s;
+ }
+ else {
+ parent = s;
+ child = 0x0;
+ }
+
+ parent->setText(NAME, ServerLE->text());
+ parent->setText(PK, QString("%1").arg(PortKI->value()));
+ parent->setText(PASS, PassLE->text());
+ if(sslCB->isChecked())
+ parent->setText(SSL, i18n("SSL"));
+ else
+ parent->setText(SSL, QString::null);
+
+ if(child){
+ child->setText(NAME, ChannelLE->text());
+ child->setText(PK, KeyLE->text());
+ }
+ else {
+ if(ChannelLE->text().length() > 0){
+ fnd = 0;
+ QListViewItem *c = parent->firstChild();
+ for( ; c != 0 && fnd == 0; c = c->nextSibling()){
+ if(c->text(NAME) == ChannelLE->text()){
+ c->setText(PK, KeyLE->text());
+ fnd = 1;
+ }
+ }
+ if(fnd == 0){
+ new QListViewItem(parent, ChannelLE->text(), KeyLE->text());
+ }
+ }
+ }
+
+ }
+ changed();
+}
+
+void PageAutoConnect::new_pressed()
+{
+ AddPB->setText(i18n("&Add"));
+ ServerLE->clear();
+ ChannelLE->clear();
+ sslCB->setChecked(false);
+ PassLE->clear();
+ KeyLE->clear();
+ KLVAutoConnect->clearSelection();
+ PortKI->setValue(6667) ;
+}
+
+void PageAutoConnect::delete_pressed()
+{
+ for(QListViewItem *it = KLVAutoConnect->firstChild();
+ it != 0;
+ it = it->nextSibling()){
+
+ if(it->text(NAME) == ServerLE->text()){
+ if(ChannelLE->text().isEmpty() == FALSE){
+ for(QListViewItem *ch = it->firstChild();
+ ch != 0;
+ ch = ch->nextSibling()){
+ if(ch->text(NAME) == ChannelLE->text()){
+ delete ch;
+ changed();
+ ChannelLE->clear();
+ ServerLE->clear();
+ return;
+ }
+ }
+ }
+ else {
+ delete it;
+ changed();
+ ServerLE->clear();
+ return;
+ }
+ }
+ }
+ changed();
+}
+
+void PageAutoConnect::kvl_clicked(QListViewItem *it)
+{
+ if(it != 0){
+ if(it->parent() != 0){
+ ChannelLE->setText(it->text(NAME));
+ KeyLE->setText(it->text(PK));
+ AddPB->setText(i18n("&Update"));
+ /*
+ * Move it to the parent to setup parent/server
+ * values. This save writing this code
+ * in two places.
+ */
+ it = it->parent();
+ }
+ else {
+ AddPB->setText(i18n("&Update/Add"));
+ ChannelLE->clear();
+ KeyLE->clear();
+ }
+
+ if(it->parent() == 0){
+ ServerLE->setText(it->text(NAME));
+ PortKI->setValue(it->text(PK).toInt());
+ PassLE->setText(it->text(PASS));
+ if(it->text(SSL).length() > 0)
+ sslCB->setChecked(true);
+ else
+ sslCB->setChecked(false);
+ }
+ /*
+ * Make sure to do this after changing all the fields
+ */
+ AddPB->setEnabled(false);
+ DeletePB->setEnabled(true);
+
+
+ }
+ else {
+ AddPB->setEnabled(false);
+ DeletePB->setEnabled(false);
+ }
+ changed();
+}
+
+void PageAutoConnect::item_changed() {
+ AddPB->setEnabled(true);
+}
+
+#include "page_autoconnect.moc"
+
diff --git a/ksirc/KSPrefs/page_autoconnect.h b/ksirc/KSPrefs/page_autoconnect.h
new file mode 100644
index 00000000..efd9a4ed
--- /dev/null
+++ b/ksirc/KSPrefs/page_autoconnect.h
@@ -0,0 +1,36 @@
+#ifndef PAGEAUTOCONNECT_H
+#define PAGEAUTOCONNECT_H
+#include "page_autoconnectbase.h"
+
+#include "ksopts.h"
+
+class PageAutoConnect : public PageAutoConnectBase
+{
+ Q_OBJECT
+
+public:
+ PageAutoConnect( QWidget* parent = 0, const char* name = 0);
+ ~PageAutoConnect();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig();
+
+signals:
+ void modified();
+
+public slots:
+ virtual void changed();
+
+protected slots:
+ virtual void item_changed();
+
+ virtual void add_pressed();
+ virtual void new_pressed();
+ virtual void delete_pressed();
+
+ virtual void kvl_clicked(QListViewItem *);
+
+};
+
+#endif // PAGEAUTOCONNECT_H
diff --git a/ksirc/KSPrefs/page_autoconnectbase.ui b/ksirc/KSPrefs/page_autoconnectbase.ui
new file mode 100644
index 00000000..71aafb49
--- /dev/null
+++ b/ksirc/KSPrefs/page_autoconnectbase.ui
@@ -0,0 +1,391 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>PageAutoConnectBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PageAutoConnectBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>551</width>
+ <height>460</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Auto Connect</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Auto Connect List</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Port/Key</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Server Password</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>SSL</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>KLVAutoConnect</cstring>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>true</bool>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox12</cstring>
+ </property>
+ <property name="title">
+ <string>Auto Connect Setup</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabelSever</cstring>
+ </property>
+ <property name="text">
+ <string>Server:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>ServerLE</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabelPort</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Port:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>PortKI</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>PortKI</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabelPass</cstring>
+ </property>
+ <property name="text">
+ <string>Server password:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>PassLE</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabelSSL</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>PortKI</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>sslCB</cstring>
+ </property>
+ <property name="text">
+ <string>Use SS&amp;L</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabelChan</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Channel:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ChannelLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>ChannelLE</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabelKey</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Key:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>KeyLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>KeyLE</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout17</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>NewPB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;New</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>AddPB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>DeletePB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Delete</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>ServerLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>item_changed()</slot>
+ </connection>
+ <connection>
+ <sender>PortKI</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>item_changed()</slot>
+ </connection>
+ <connection>
+ <sender>PassLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>item_changed()</slot>
+ </connection>
+ <connection>
+ <sender>sslCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>item_changed()</slot>
+ </connection>
+ <connection>
+ <sender>ChannelLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>item_changed()</slot>
+ </connection>
+ <connection>
+ <sender>KeyLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>item_changed()</slot>
+ </connection>
+ <connection>
+ <sender>NewPB</sender>
+ <signal>pressed()</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>new_pressed()</slot>
+ </connection>
+ <connection>
+ <sender>AddPB</sender>
+ <signal>pressed()</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>add_pressed()</slot>
+ </connection>
+ <connection>
+ <sender>DeletePB</sender>
+ <signal>pressed()</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>delete_pressed()</slot>
+ </connection>
+ <connection>
+ <sender>KLVAutoConnect</sender>
+ <signal>clicked(QListViewItem*)</signal>
+ <receiver>PageAutoConnectBase</receiver>
+ <slot>kvl_clicked(QListViewItem*)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>KLVAutoConnect</tabstop>
+ <tabstop>ServerLE</tabstop>
+ <tabstop>PortKI</tabstop>
+ <tabstop>PassLE</tabstop>
+ <tabstop>sslCB</tabstop>
+ <tabstop>ChannelLE</tabstop>
+ <tabstop>KeyLE</tabstop>
+ <tabstop>NewPB</tabstop>
+ <tabstop>AddPB</tabstop>
+ <tabstop>DeletePB</tabstop>
+</tabstops>
+<slots>
+ <slot>item_changed()</slot>
+ <slot>new_pressed()</slot>
+ <slot>add_pressed()</slot>
+ <slot>delete_pressed()</slot>
+ <slot>KLVAutoConnect_clicked(QListViewItem*)</slot>
+ <slot>kcl_clicked(QListViewItem *)</slot>
+ <slot>kvl_clicked(QListViewItem*)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/ksirc/KSPrefs/page_colors.cpp b/ksirc/KSPrefs/page_colors.cpp
new file mode 100644
index 00000000..f6d68a52
--- /dev/null
+++ b/ksirc/KSPrefs/page_colors.cpp
@@ -0,0 +1,295 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "page_colors.h"
+
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qradiobutton.h>
+#include <qlabel.h>
+
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kcolorbutton.h>
+#include <kdebug.h>
+
+PageColors::PageColors( QWidget *parent, const char *name ) : PageColorsBase( parent, name)
+{
+ changing = 0;
+ m_dcol.setAutoDelete(true);
+}
+
+PageColors::~PageColors()
+{
+}
+
+void PageColors::saveConfig()
+{
+ ksopts->backgroundColor = backCBtn->color();
+ ksopts->selBackgroundColor = selBackCBtn->color();
+ ksopts->selForegroundColor = selForeCBtn->color();
+ ksopts->errorColor = errorCBtn->color();
+ ksopts->infoColor = infoCBtn->color();
+ ksopts->textColor = genericTextCBtn->color();
+ ksopts->channelColor = chanMsgCBtn->color();
+ ksopts->linkColor = linkCBtn->color();
+
+ ksopts->ownNickColor = ownNickCBtn->color();
+ ksopts->ownNickBold = ownNickBoldCB->isChecked();
+ ksopts->ownNickRev = ownNickRevCB->isChecked();
+ ksopts->ownNickUl = ownNickUlCB->isChecked();
+
+ if(fixedOtherColRB->isChecked()){
+ ksopts->nickColourization = false;
+ ksopts->nickForeground = nickFGCBtn->color();
+ ksopts->nickBackground = nickBGCBtn->color();
+ }
+ else if(autoOtherColRB->isChecked()){
+ ksopts->nickColourization = true;
+ ksopts->nickForeground = QColor();
+ ksopts->nickBackground = QColor();
+ }
+ else {
+ ksopts->nickColourization = false;
+ ksopts->nickForeground = QColor();
+ ksopts->nickBackground = QColor();
+ }
+
+ ksopts->msgContainNick = ownContainNickCBtn->color();
+ if(msg1LE->text().length() > 0){
+ ksopts->msg1Contain = msg1CBtn->color();
+ ksopts->msg1String = msg1LE->text();
+ ksopts->msg1Regex = msg1Regex->isChecked();
+ }
+ else {
+ ksopts->msg1Contain = QColor();
+ ksopts->msg1String = msg1LE->text();
+ ksopts->msg1Regex = false;
+ }
+ if(msg2LE->text().length() > 0){
+ ksopts->msg2Contain = msg2CBtn->color();
+ ksopts->msg2String = msg2LE->text();
+ ksopts->msg2Regex = msg2Regex->isChecked();
+ }
+ else {
+ ksopts->msg2Contain = QColor();
+ ksopts->msg2String = msg2LE->text();
+ ksopts->msg2Regex = false;
+ }
+
+ ksopts->ksircColors = allowKSircColorsCB->isChecked();
+ ksopts->mircColors = allowMIRCColorsCB->isChecked();
+ ksopts->colourTheme = themeLB->currentText();
+
+ KConfig *conf = kapp->config();
+ QDictIterator<KSOColors> it(m_dcol);
+ QStringList names;
+ for(; it.current(); ++it){
+ names << it.currentKey();
+ conf->setGroup("ColourSchemes-"+ it.currentKey());
+ conf->writeEntry("Background", it.current()->backgroundColor);
+ conf->writeEntry("SelBackground", it.current()->selBackgroundColor);
+ conf->writeEntry("SelForeground", it.current()->selForegroundColor);
+ conf->writeEntry("Error", it.current()->errorColor);
+ conf->writeEntry("Info", it.current()->infoColor);
+ conf->writeEntry("Text", it.current()->textColor);
+ conf->writeEntry("Channel", it.current()->channelColor);
+ conf->writeEntry("Link", it.current()->linkColor);
+ conf->writeEntry("OwnNick", it.current()->ownNickColor);
+ conf->writeEntry("NickForeground", it.current()->nickForeground);
+ conf->writeEntry("NickBackground", it.current()->nickBackground);
+ }
+ conf->setGroup("ColourSchemes");
+ conf->writeEntry("Names", names);
+
+}
+
+void PageColors::readConfig( const KSOColors *opts )
+{
+ backCBtn->setColor( opts->backgroundColor );
+ selBackCBtn->setColor( opts->selBackgroundColor );
+ selForeCBtn->setColor( opts->selForegroundColor );
+ errorCBtn->setColor( opts->errorColor );
+ infoCBtn->setColor( opts->infoColor );
+ genericTextCBtn->setColor( opts->textColor );
+ chanMsgCBtn->setColor( opts->channelColor );
+ linkCBtn->setColor( opts->linkColor );
+
+ ownNickCBtn->setColor( opts->ownNickColor );
+ ownNickBoldCB->setChecked( opts->ownNickBold );
+ ownNickRevCB->setChecked( opts->ownNickRev );
+ ownNickUlCB->setChecked( opts->ownNickUl );
+
+ if( opts->nickColourization ){
+ autoOtherColRB->setChecked( true );
+ nickFGCBtn->setColor( QColor() );
+ nickBGCBtn->setColor( QColor() );
+
+ }
+ else if( opts->nickForeground.isValid() ||
+ opts->nickBackground.isValid() ){
+ fixedOtherColRB->setChecked( true );
+ nickFGCBtn->setColor( opts->nickForeground );
+ nickBGCBtn->setColor( opts->nickBackground );
+ }
+ else {
+ noOtherColRB->setChecked( true );
+ nickFGCBtn->setColor( QColor() );
+ nickBGCBtn->setColor( QColor() );
+
+ }
+
+ ownContainNickCBtn->setColor( opts->msgContainNick );
+ msg1CBtn->setColor( opts->msg1Contain );
+ msg1LE->setText( opts->msg1String );
+ msg1Regex->setChecked( opts->msg1Regex );
+ msg2CBtn->setColor( opts->msg2Contain );
+ msg2LE->setText( opts->msg2String );
+ msg2Regex->setChecked( opts->msg2Regex );
+
+ coloursSetEnable();
+
+ allowKSircColorsCB->setChecked( opts->ksircColors );
+ allowMIRCColorsCB->setChecked( opts->mircColors );
+
+ KConfig *conf = kapp->config();
+ conf->setGroup("ColourSchemes");
+ themeLB->clear();
+ QStringList names = conf->readListEntry("Names");
+ if(names.contains("Custom")){
+ names.remove(names.find("Custom"));
+ }
+ names.prepend("Custom");
+ themeLB->insertStringList(names);
+ if(themeLB->findItem(ksopts->colourTheme, Qt::ExactMatch))
+ themeLB->setCurrentItem(themeLB->findItem(ksopts->colourTheme, Qt::ExactMatch));
+ else
+ themeLB->setCurrentItem(0);
+ themeLE->setText(themeLB->currentText());
+
+ m_dcol.clear();
+
+ QStringList::Iterator it = names.begin();
+ for( ; it != names.end(); ++it){
+ conf->setGroup("ColourSchemes-"+ *it);
+ m_dcol.insert(*it, new KSOColors);
+ m_dcol[*it]->backgroundColor = conf->readColorEntry( "Background");
+ m_dcol[*it]->selBackgroundColor = conf->readColorEntry( "SelBackground");
+ m_dcol[*it]->selForegroundColor = conf->readColorEntry( "SelForeground");
+ m_dcol[*it]->errorColor = conf->readColorEntry( "Error");
+ m_dcol[*it]->infoColor = conf->readColorEntry( "Info");
+ m_dcol[*it]->textColor = conf->readColorEntry( "Text");
+ m_dcol[*it]->channelColor = conf->readColorEntry( "Channel");
+ m_dcol[*it]->ownNickColor = conf->readColorEntry( "OwnNick");
+ m_dcol[*it]->nickForeground = conf->readColorEntry( "NickForeground");
+ m_dcol[*it]->nickBackground = conf->readColorEntry( "NickBackground");
+ m_dcol[*it]->linkColor = conf->readColorEntry("Link");
+ }
+}
+
+void PageColors::defaultConfig()
+{
+ KSOColors opts;
+ readConfig( &opts );
+}
+
+void PageColors::changed()
+{
+ if(changing == 0)
+ themeLB->setSelected(0, TRUE);
+ coloursSetEnable();
+ emit modified();
+}
+
+void PageColors::theme_clicked(QListBoxItem *li)
+{
+ if(li == 0x0)
+ return;
+
+ QString name = li->text();
+
+ changing = 1;
+ backCBtn->setColor( m_dcol[name]->backgroundColor );
+ selBackCBtn->setColor( m_dcol[name]->selBackgroundColor );
+ selForeCBtn->setColor( m_dcol[name]->selForegroundColor );
+ errorCBtn->setColor( m_dcol[name]->errorColor );
+ infoCBtn->setColor( m_dcol[name]->infoColor );
+ genericTextCBtn->setColor( m_dcol[name]->textColor );
+ chanMsgCBtn->setColor( m_dcol[name]->channelColor );
+ linkCBtn->setColor( m_dcol[name]->linkColor );
+
+ ownNickCBtn->setColor( m_dcol[name]->ownNickColor );
+ nickFGCBtn->setColor( m_dcol[name]->nickForeground );
+ nickBGCBtn->setColor( m_dcol[name]->nickBackground );
+ changing = 0;
+
+ themeLE->setText(li->text());
+}
+
+void PageColors::themeNewPB_clicked()
+{
+ themeLE->clear();
+}
+
+void PageColors::themeAddPB_clicked()
+{
+ QString name = themeLE->text();
+
+ kdDebug(5008) << "Got add: " << themeLB->currentText() << endl;
+
+ m_dcol.replace(name, new KSOColors());
+
+ m_dcol[name]->backgroundColor = backCBtn->color();
+ m_dcol[name]->selBackgroundColor = selBackCBtn->color();
+ m_dcol[name]->selForegroundColor = selForeCBtn->color();
+ m_dcol[name]->errorColor = errorCBtn->color();
+ m_dcol[name]->infoColor = infoCBtn->color();
+ m_dcol[name]->textColor = genericTextCBtn->color();
+ m_dcol[name]->channelColor = chanMsgCBtn->color();
+ m_dcol[name]->linkColor = linkCBtn->color();
+ m_dcol[name]->ownNickColor = ownNickCBtn->color();
+ m_dcol[name]->nickForeground = nickFGCBtn->color();
+ m_dcol[name]->nickBackground = nickBGCBtn->color();
+
+ if(themeLB->findItem(name, Qt::ExactMatch) == 0){
+ themeLB->insertItem(name);
+ }
+
+ themeLB->setCurrentItem(themeLB->findItem(name, Qt::ExactMatch));
+
+}
+
+void PageColors::themeDelPB_clicked()
+{
+ m_dcol.remove(themeLB->currentText());
+ themeLB->removeItem(themeLB->currentItem());
+}
+
+void PageColors::theme_sel()
+{
+ themeLE->setText(themeLB->currentText());
+}
+
+void PageColors::coloursSetEnable()
+{
+ nickFGCBtn->setEnabled( fixedOtherColRB->isChecked() );
+ nickBGCBtn->setEnabled( fixedOtherColRB->isChecked() );
+ nickFGColorLabel->setEnabled( fixedOtherColRB->isChecked() );
+ nickBGColorLabel->setEnabled( fixedOtherColRB->isChecked() );
+
+ bool msgEn = msg1LE->text().length() > 0;
+ msg1CBtn->setEnabled(msgEn);
+ msg1Regex->setEnabled(msgEn);
+ msgEn = msg2LE->text().length() > 0;
+ msg2CBtn->setEnabled(msgEn);
+ msg2Regex->setEnabled(msgEn);
+
+}
+
+#include "page_colors.moc"
diff --git a/ksirc/KSPrefs/page_colors.h b/ksirc/KSPrefs/page_colors.h
new file mode 100644
index 00000000..188fe0a8
--- /dev/null
+++ b/ksirc/KSPrefs/page_colors.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_COLORS_H
+#define PAGE_COLORS_H
+
+#include "page_colorsbase.h"
+#include "ksopts.h"
+
+#include <qlistbox.h>
+#include <qstringlist.h>
+#include <qdict.h>
+
+class PageColors : public PageColorsBase
+{
+Q_OBJECT
+
+public:
+ PageColors( QWidget *parent = 0, const char *name = 0 );
+ ~PageColors();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSOColors * = ksopts );
+
+protected slots:
+ void changed();
+
+public slots:
+ virtual void theme_clicked(QListBoxItem*);
+ virtual void themeNewPB_clicked();
+ virtual void themeAddPB_clicked();
+ virtual void themeDelPB_clicked();
+ virtual void theme_sel();
+
+signals:
+ void modified();
+
+private:
+ void coloursSetEnable();
+
+private:
+ int changing;
+ QDict<KSOColors> m_dcol;
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_colorsbase.ui b/ksirc/KSPrefs/page_colorsbase.ui
new file mode 100644
index 00000000..498c9c23
--- /dev/null
+++ b/ksirc/KSPrefs/page_colorsbase.ui
@@ -0,0 +1,1063 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>PageColorsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PageColorsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>617</width>
+ <height>545</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Colors</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Scheme</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>chatColorsGB</cstring>
+ </property>
+ <property name="title">
+ <string>Chat Colors</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>chanMsgLabel</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;hannel messages:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>chanMsgCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>genericTextLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Generic text:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>errorLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Errors:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>errorCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>infoLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Info:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>infoCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>backgrndLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Background:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>backCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>backgrndLabel_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Links:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>backCBtn</cstring>
+ </property>
+ </widget>
+ <spacer row="1" column="4">
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KColorButton" row="2" column="3">
+ <property name="name">
+ <cstring>linkCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="3">
+ <property name="name">
+ <cstring>backCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="3">
+ <property name="name">
+ <cstring>errorCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>backgrndLabel_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Selection backgr&amp;ound:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>backCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>infoCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>chanMsgCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="1">
+ <property name="name">
+ <cstring>selBackCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="3">
+ <property name="name">
+ <cstring>selForeCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>backgrndLabel_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Sele&amp;ction foreground:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>backCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>nickFGColorCB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use background color for links</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox11</cstring>
+ </property>
+ <property name="title">
+ <string>Sample Color Themes</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>themeLE</cstring>
+ </property>
+ </widget>
+ <widget class="QListBox" row="1" column="0" rowspan="4" colspan="1">
+ <property name="name">
+ <cstring>themeLB</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>themeNewPB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;New</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="2" column="1">
+ <property name="name">
+ <cstring>themeAddPB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>themeDelPB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Delete</string>
+ </property>
+ </widget>
+ <spacer row="4" column="1">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Highlighting</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox5</cstring>
+ </property>
+ <property name="title">
+ <string>Your Nick</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>nickMatchLabel_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Color: </string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ownNickCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>ownNickCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>ownNickBoldCB</cstring>
+ </property>
+ <property name="text">
+ <string>Bold</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>ownNickRevCB</cstring>
+ </property>
+ <property name="text">
+ <string>Reverse</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>ownNickUlCB</cstring>
+ </property>
+ <property name="text">
+ <string>Underline</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>202</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Other Nicks</string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="6">
+ <property name="name">
+ <cstring>noOtherColRB</cstring>
+ </property>
+ <property name="text">
+ <string>N&amp;o nick colors</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0" rowspan="1" colspan="6">
+ <property name="name">
+ <cstring>autoOtherColRB</cstring>
+ </property>
+ <property name="text">
+ <string>Au&amp;to nick colorization</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>fixedOtherColRB</cstring>
+ </property>
+ <property name="text">
+ <string>Fi&amp;xed</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>nickFGColorLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Foreground:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nickFGCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="2">
+ <property name="name">
+ <cstring>nickFGCBtn</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="3">
+ <property name="name">
+ <cstring>nickBGColorLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Backg&amp;round:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nickBGCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="4">
+ <property name="name">
+ <cstring>nickBGCBtn</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="2" column="5">
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>83</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>nickGB</cstring>
+ </property>
+ <property name="title">
+ <string>Highlight Messages</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>nickMatchLabel_2</cstring>
+ </property>
+ <property name="text">
+ <string>Containing &amp;your nick:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ownNickCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>ownContainNickCBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>169</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>nickMatchLabel_2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Containing:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ownNickCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>msg1LE</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>msg1CBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>msg1Regex</cstring>
+ </property>
+ <property name="text">
+ <string>Regex</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>104</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>nickMatchLabel_2_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Containing:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>ownNickCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>msg2LE</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>msg2CBtn</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>msg2Regex</cstring>
+ </property>
+ <property name="text">
+ <string>Regex</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>104</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>colorCodesGB</cstring>
+ </property>
+ <property name="title">
+ <string>Color Codes</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>allowKSircColorsCB</cstring>
+ </property>
+ <property name="text">
+ <string>Strip &amp;kSirc color codes</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>allowMIRCColorsCB</cstring>
+ </property>
+ <property name="text">
+ <string>Strip &amp;mIRC color codes</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>allowKSircColorsCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>allowMIRCColorsCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>backCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>chanMsgCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>errorCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>genericTextCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>infoCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>linkCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>nickBGCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>nickFGCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>nickFGColorCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>ownContainNickCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>themeAddPB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>themeAddPB_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>themeDelPB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>themeDelPB_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>themeLB</sender>
+ <signal>clicked(QListBoxItem*)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>theme_clicked(QListBoxItem*)</slot>
+ </connection>
+ <connection>
+ <sender>themeLB</sender>
+ <signal>selectionChanged()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>theme_sel()</slot>
+ </connection>
+ <connection>
+ <sender>themeLE</sender>
+ <signal>returnPressed()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>themeAddPB_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>themeNewPB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>themeNewPB_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>selBackCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>selForeCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>ownNickCBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>ownNickBoldCB</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>ownNickRevCB</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>ownNickUlCB</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>noOtherColRB</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>autoOtherColRB</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>fixedOtherColRB</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>msg1CBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>msg1LE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>msg1Regex</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>msg2CBtn</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>msg2Regex</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>msg2LE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>genericTextCBtn</tabstop>
+ <tabstop>errorCBtn</tabstop>
+ <tabstop>infoCBtn</tabstop>
+ <tabstop>backCBtn</tabstop>
+ <tabstop>chanMsgCBtn</tabstop>
+ <tabstop>linkCBtn</tabstop>
+ <tabstop>selBackCBtn</tabstop>
+ <tabstop>selForeCBtn</tabstop>
+ <tabstop>nickFGCBtn</tabstop>
+ <tabstop>nickBGCBtn</tabstop>
+ <tabstop>nickFGColorCB</tabstop>
+ <tabstop>ownContainNickCBtn</tabstop>
+ <tabstop>allowKSircColorsCB</tabstop>
+ <tabstop>allowMIRCColorsCB</tabstop>
+ <tabstop>themeLE</tabstop>
+ <tabstop>themeLB</tabstop>
+ <tabstop>themeNewPB</tabstop>
+ <tabstop>themeAddPB</tabstop>
+ <tabstop>themeDelPB</tabstop>
+</tabstops>
+<slots>
+ <slot>theme_clicked(QListBoxItem*)</slot>
+ <slot>themeNewPB_clicked()</slot>
+ <slot>themeDelPB_clicked()</slot>
+ <slot>themeAddPB_clicked()</slot>
+ <slot>theme_sel()</slot>
+ <slot>setColourEnabled()</slot>
+ <slot>coloursSetEnable()</slot>
+ <slot>changed()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksirc/KSPrefs/page_font.cpp b/ksirc/KSPrefs/page_font.cpp
new file mode 100644
index 00000000..e9f9e0e6
--- /dev/null
+++ b/ksirc/KSPrefs/page_font.cpp
@@ -0,0 +1,38 @@
+#include "page_font.h"
+#include "qapplication.h"
+PageFont::PageFont( QWidget *parent, const char *name ) :
+ QWidget( parent, name)
+{
+ layout = new QHBoxLayout(this);
+ fontchooser = new KFontChooser(this);
+ layout->addWidget(fontchooser);
+ connect(fontchooser,SIGNAL(fontSelected ( const QFont&)), this, SLOT(update()));
+}
+
+PageFont::~PageFont( )
+{
+
+}
+
+void PageFont::update( void ){
+ emit modified();
+}
+
+void PageFont::saveConfig( void )
+{
+ ksopts->defaultFont = fontchooser->font();
+ QApplication::setFont(fontchooser->font(), true, "KSirc::TextView" );
+}
+
+void PageFont::readConfig( const KSOColors * opts )
+{
+ /* Just set the font from the preferences */
+ fontchooser->setFont( opts->defaultFont );
+}
+
+void PageFont::defaultConfig( void )
+{
+ fontchooser->setFont( ksopts->defaultFont );
+}
+
+#include "page_font.moc"
diff --git a/ksirc/KSPrefs/page_font.h b/ksirc/KSPrefs/page_font.h
new file mode 100644
index 00000000..0d2fa673
--- /dev/null
+++ b/ksirc/KSPrefs/page_font.h
@@ -0,0 +1,62 @@
+#ifndef _PAGE_FONT
+#define _PAGE_FONT
+#include <kfontdialog.h> // For the font selection widget
+#include <qlayout.h> // For the layout
+#include "ksopts.h" // For storing the info.
+
+/**
+ * A page for the preferences dialog to set the standard font
+ *
+ * @author Markus Weimer <markus.weimer@web.de>
+ */
+class PageFont : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Create the Widget
+ */
+ PageFont( QWidget *parent = 0, const char *name = 0 );
+
+
+ /*
+ * Standard destructor
+ */
+ ~PageFont();
+
+
+ /**
+ * Save the config set by the user to the global ksopts object.
+ *
+ */
+ void saveConfig( void );
+
+
+ /**
+ * Reset the current user config to the one stored in the global
+ * ksopts object.
+ *
+ */
+ void defaultConfig( void );
+
+
+ /**
+ * Read the configuration from the given KSOptions object
+ *
+ * @param opts the KSOptions object to modify
+ */
+ void readConfig( const KSOColors* opts=ksopts );
+
+ public slots:
+ void update( void );
+
+ signals:
+ void modified();
+
+ private:
+ KFontChooser* fontchooser; /** The font choosing widget from kdelib */
+ QHBoxLayout* layout;
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_general.cpp b/ksirc/KSPrefs/page_general.cpp
new file mode 100644
index 00000000..d6256e2c
--- /dev/null
+++ b/ksirc/KSPrefs/page_general.cpp
@@ -0,0 +1,117 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qcheckbox.h>
+#include <qspinbox.h>
+
+#include <klocale.h>
+#include <kcharsets.h>
+#include "page_general.h"
+#include "../servercontroller.h"
+
+PageGeneral::PageGeneral( QWidget *parent, const char *name ) : PageGeneralBase( parent, name)
+{
+}
+
+PageGeneral::~PageGeneral()
+{
+}
+
+void PageGeneral::saveConfig()
+{
+ ksopts->runDocked = dockedOnlyCB->isChecked();
+ servercontroller::self()->checkDocking();
+ ksopts->autoCreateWin = autoCreateWindowCB->isChecked();
+ ksopts->autoCreateWinForNotice = autoCreateWindowForNoticeCB->isChecked();
+ ksopts->nickCompletion = nickCompletionCB->isChecked();
+ ksopts->displayTopic = displayTopicCB->isChecked();
+ ksopts->colorPicker = colorPickerPopupCB->isChecked();
+ ksopts->autoRejoin = autoRejoinCB->isChecked();
+ ksopts->oneLineEntry = oneLineEditCB->isChecked();
+ ksopts->useColourNickList = useColourNickListCB->isChecked();
+ ksopts->dockPopups = dockPopupsCB->isChecked();
+ ksopts->autoSaveHistory = autoSaveHistoryCB->isChecked();
+ ksopts->windowLength = historySB->value();
+
+ ksopts->channel["global"]["global"].timeStamp = timeStampCB->isChecked();
+ ksopts->channel["global"]["global"].beepOnMsg = beepCB->isChecked();
+ ksopts->channel["global"]["global"].topicShow = showTopicCB->isChecked();
+ ksopts->channel["global"]["global"].logging = enLoggingCB->isChecked();
+ ksopts->channel["global"]["global"].encoding = encodingsCB->currentText();
+ ksopts->channel["global"]["global"].filterJoinPart = joinPartCB->isChecked();
+
+ if(applyGloballyCB->isChecked()){
+ ksopts->applyChannelGlobal();
+ }
+
+ ksopts->publicAway = publicAway->isChecked();
+}
+
+void PageGeneral::readConfig( const KSOGeneral *opts )
+{
+ dockedOnlyCB->setChecked( opts->runDocked );
+ autoCreateWindowCB->setChecked( opts->autoCreateWin );
+ autoCreateWindowForNoticeCB->setChecked( opts->autoCreateWinForNotice );
+ nickCompletionCB->setChecked( opts->nickCompletion );
+ displayTopicCB->setChecked( opts->displayTopic );
+ colorPickerPopupCB->setChecked( opts->colorPicker );
+ autoRejoinCB->setChecked( opts->autoRejoin );
+ oneLineEditCB->setChecked( opts->oneLineEntry );
+ useColourNickListCB->setChecked( opts->useColourNickList );
+ dockPopupsCB->setChecked( opts->dockPopups );
+ dockPopupsCB->setEnabled(dockedOnlyCB->isChecked());
+
+ autoSaveHistoryCB->setChecked( opts->autoSaveHistory );
+
+ historySB->setValue( opts->windowLength );
+
+ timeStampCB->setChecked( ksopts->channel["global"]["global"].timeStamp );
+ beepCB->setChecked( ksopts->channel["global"]["global"].beepOnMsg );
+ showTopicCB->setChecked( ksopts->channel["global"]["global"].topicShow );
+ enLoggingCB->setChecked( ksopts->channel["global"]["global"].logging );
+ joinPartCB->setChecked( ksopts->channel["global"]["global"].filterJoinPart );
+
+ publicAway->setChecked( ksopts->publicAway );
+
+ encodingsCB->clear();
+
+
+ QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
+
+ // remove utf16/ucs2 as it just doesn't work for IRC
+ QStringList::Iterator encodingIt = encodings.begin();
+ while ( encodingIt != encodings.end() ) {
+ if ( ( *encodingIt ).find( "utf16" ) != -1 ||
+ ( *encodingIt ).find( "iso-10646" ) != -1 )
+ encodingIt = encodings.remove( encodingIt );
+ else
+ ++encodingIt;
+ }
+ encodings.prepend( i18n( "Default" ) );
+ encodingsCB->insertStringList(encodings);
+ int eindex = encodings.findIndex(ksopts->channel["global"]["global"].encoding);
+ if(eindex == -1)
+ encodingsCB->setCurrentItem(0);
+ else
+ encodingsCB->setCurrentItem(eindex);
+}
+
+void PageGeneral::defaultConfig()
+{
+ KSOGeneral opts;
+ readConfig( &opts );
+}
+
+void PageGeneral::changed()
+{
+ dockPopupsCB->setEnabled(dockedOnlyCB->isChecked());
+ emit modified();
+}
+
+#include "page_general.moc"
diff --git a/ksirc/KSPrefs/page_general.h b/ksirc/KSPrefs/page_general.h
new file mode 100644
index 00000000..ecf515ca
--- /dev/null
+++ b/ksirc/KSPrefs/page_general.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_GENERAL_H
+#define PAGE_GENERAL_H
+
+#include "page_generalbase.h"
+#include "ksopts.h"
+
+class PageGeneral : public PageGeneralBase
+{
+Q_OBJECT
+
+public:
+ PageGeneral( QWidget *parent = 0, const char *name = 0 );
+ ~PageGeneral();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSOGeneral * = ksopts );
+
+signals:
+ void modified();
+
+public slots:
+ virtual void changed();
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_generalbase.ui b/ksirc/KSPrefs/page_generalbase.ui
new file mode 100644
index 00000000..d3b4db06
--- /dev/null
+++ b/ksirc/KSPrefs/page_generalbase.ui
@@ -0,0 +1,540 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>PageGeneralBase</class>
+<widget class="QFrame">
+ <property name="name">
+ <cstring>PageGeneralBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>443</width>
+ <height>489</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>425</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>General</string>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>miscGB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>Global Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="5" column="1">
+ <property name="name">
+ <cstring>Layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>historyItemsLabel</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>120</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Histor&amp;y length:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>historySB</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>historySB</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> lines</string>
+ </property>
+ <property name="specialValueText">
+ <string>unlimited</string>
+ </property>
+ <property name="maxValue">
+ <number>1000</number>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Stores up to this many lines of chat from each window as history</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Stores up to this many lines of chat from each window, allowing you to scroll upwards and see what has already been said.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>publicAway</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Announce away messages</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>See the messages when a user selects the away option</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If this is checked, you will see the messages when a user selects the away option. By default this option is not checked.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>autoCreateWindowCB</cstring>
+ </property>
+ <property name="text">
+ <string>A&amp;uto create window</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Will auto create a window for each user who sends a /msg to you</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If selected, KSirc will automatically create a new window for each user who sends a /msg command to you. If not selected, any text sent to you with /msg is displayed in the current window and you can use /query username to create a window to chat to that user.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>autoCreateWindowForNoticeCB</cstring>
+ </property>
+ <property name="text">
+ <string>Auto create &amp;on notice</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>autoRejoinCB</cstring>
+ </property>
+ <property name="text">
+ <string>Auto-re&amp;join</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Rejoin channels automatically if you are disconnected.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If selected, it allows you to rejoin channels automatically if you are disconnected.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="1">
+ <property name="name">
+ <cstring>dockPopupsCB</cstring>
+ </property>
+ <property name="text">
+ <string>Dock &amp;passive popups</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="0">
+ <property name="name">
+ <cstring>displayTopicCB</cstring>
+ </property>
+ <property name="text">
+ <string>D&amp;isplay topic in caption</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Display the topic of the current channel in the window caption</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Displays the topic of the current channel in the window caption. If not selected, the topic is only displayed inside the window.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>colorPickerPopupCB</cstring>
+ </property>
+ <property name="text">
+ <string>Color pi&amp;cker popup</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Allow you to get the color pickup dialog with Ctrl K</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If selected, a popup window from which to select the color of your text is presented when you press Ctrl K. If not, you have to type the color codes manually.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="0">
+ <property name="name">
+ <cstring>oneLineEditCB</cstring>
+ </property>
+ <property name="text">
+ <string>One line te&amp;xt entry box</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="1">
+ <property name="name">
+ <cstring>useColourNickListCB</cstring>
+ </property>
+ <property name="text">
+ <string>Us&amp;e color nick list</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Use the colors set in the Colors tab of the Configure KSirc dialog for coloring the nicknames</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If selected, it will use the colors set in the Colors tab of the Configure KSirc dialog for coloring the nicknames.</string>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>nickCompletionCB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Nick completion</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Switch nickname completion on</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If selected, switches nickname completion on. Nickname completion works as follows: Type the first letters of a user's nickname, press the Tab key, the text you typed will be completed to match the username, including changes in capitalization if necessary.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>dockedOnlyCB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Dock in system tray</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Put the KSirc icon in the system tray</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This allows KSirc to be docked in the system tray. By default this is not enabled. When KSirc is docked in the system tray, you are able to access several options by clicking on the KSirc icon. When you close KSirc window, the icon stays in the systray until you quit KSirc.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="6" column="0">
+ <property name="name">
+ <cstring>autoSaveHistoryCB</cstring>
+ </property>
+ <property name="text">
+ <string>Auto save history</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Per Channel Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>timeStampCB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Time stamp</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Add the time and date on the left of each message</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Prepends each thing said in the channel with the time it was said, in the form [HH:MM:SS].</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>applyGloballyCB</cstring>
+ </property>
+ <property name="text">
+ <string>O&amp;verride existing channel options</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The settings in this tab will be applied and each channel settings will be ignored</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If this is selected, the settings in this tab will override each channel's options so these settings will be applied in each channel, independently of your channel settings in the Channel menu. This setting will only work until next time you open the configuration dialog and it will be reset unchecked then; this is because you probably do not want to override the existing channels options all the time.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>showTopicCB</cstring>
+ </property>
+ <property name="text">
+ <string>Sho&amp;w topic</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Displays the channel topic on top</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Displays the channel topic on top of each channel window.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>beepCB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Beep on change</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>joinPartCB</cstring>
+ </property>
+ <property name="text">
+ <string>Hide part/join messages</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="1">
+ <property name="name">
+ <cstring>enLoggingCB</cstring>
+ </property>
+ <property name="text">
+ <string>Enable lo&amp;gging</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>encodingsL</cstring>
+ </property>
+ <property name="text">
+ <string>Default en&amp;coding:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>encodingsCB</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>encodingsCB</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>71</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>autoCreateWindowCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>nickCompletionCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>displayTopicCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>beepCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>colorPickerPopupCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>autoRejoinCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>historySB</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>publicAway</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>showTopicCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>enLoggingCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>timeStampCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>applyGloballyCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>oneLineEditCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>useColourNickListCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>autoCreateWindowForNoticeCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>dockedOnlyCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>dockPopupsCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>encodingsCB</sender>
+ <signal>activated(int)</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>joinPartCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageGeneralBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>autoCreateWindowCB</tabstop>
+ <tabstop>nickCompletionCB</tabstop>
+ <tabstop>displayTopicCB</tabstop>
+ <tabstop>colorPickerPopupCB</tabstop>
+ <tabstop>autoRejoinCB</tabstop>
+ <tabstop>publicAway</tabstop>
+ <tabstop>historySB</tabstop>
+ <tabstop>timeStampCB</tabstop>
+ <tabstop>beepCB</tabstop>
+ <tabstop>showTopicCB</tabstop>
+ <tabstop>enLoggingCB</tabstop>
+</tabstops>
+<slots>
+ <slot access="protected">setPreviewPixmap(bool)</slot>
+ <slot access="protected">showWallpaperPixmap(const QString &amp;)</slot>
+ <slot>changed()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksirc/KSPrefs/page_irccolors.cpp b/ksirc/KSPrefs/page_irccolors.cpp
new file mode 100644
index 00000000..aa6ff351
--- /dev/null
+++ b/ksirc/KSPrefs/page_irccolors.cpp
@@ -0,0 +1,181 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "page_irccolors.h"
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <kconfig.h>
+#include <kcolorbutton.h>
+
+PageIRCColors::PageIRCColors( QWidget *parent, const char *name ) : PageIRCColorsBase( parent, name)
+{
+}
+
+PageIRCColors::~PageIRCColors()
+{
+}
+
+void PageIRCColors::saveConfig()
+{
+ ksopts->ircColors[0] = CBtn_0->color();
+ ksopts->ircColors[1] = CBtn_1->color();
+ ksopts->ircColors[2] = CBtn_2->color();
+ ksopts->ircColors[3] = CBtn_3->color();
+ ksopts->ircColors[4] = CBtn_4->color();
+ ksopts->ircColors[5] = CBtn_5->color();
+ ksopts->ircColors[6] = CBtn_6->color();
+ ksopts->ircColors[7] = CBtn_7->color();
+ ksopts->ircColors[8] = CBtn_8->color();
+ ksopts->ircColors[9] = CBtn_9->color();
+ ksopts->ircColors[10] = CBtn_10->color();
+ ksopts->ircColors[11] = CBtn_11->color();
+ ksopts->ircColors[12] = CBtn_12->color();
+ ksopts->ircColors[13] = CBtn_13->color();
+ ksopts->ircColors[14] = CBtn_14->color();
+ ksopts->ircColors[15] = CBtn_15->color();
+
+ ksopts->nickHighlight[0] = CBox_0->isChecked();
+ ksopts->nickHighlight[1] = CBox_1->isChecked();
+ ksopts->nickHighlight[2] = CBox_2->isChecked();
+ ksopts->nickHighlight[3] = CBox_3->isChecked();
+ ksopts->nickHighlight[4] = CBox_4->isChecked();
+ ksopts->nickHighlight[5] = CBox_5->isChecked();
+ ksopts->nickHighlight[6] = CBox_6->isChecked();
+ ksopts->nickHighlight[7] = CBox_7->isChecked();
+ ksopts->nickHighlight[8] = CBox_8->isChecked();
+ ksopts->nickHighlight[9] = CBox_9->isChecked();
+ ksopts->nickHighlight[10] = CBox_10->isChecked();
+ ksopts->nickHighlight[11] = CBox_11->isChecked();
+ ksopts->nickHighlight[12] = CBox_12->isChecked();
+ ksopts->nickHighlight[13] = CBox_13->isChecked();
+ ksopts->nickHighlight[14] = CBox_14->isChecked();
+ ksopts->nickHighlight[15] = CBox_15->isChecked();
+
+
+}
+
+void PageIRCColors::readConfig( const KSOColors *opts )
+{
+ CBtn_0->setColor(opts->ircColors[0]);
+ CBtn_1->setColor(opts->ircColors[1]);
+ CBtn_2->setColor(opts->ircColors[2]);
+ CBtn_3->setColor(opts->ircColors[3]);
+ CBtn_4->setColor(opts->ircColors[4]);
+ CBtn_5->setColor(opts->ircColors[5]);
+ CBtn_6->setColor(opts->ircColors[6]);
+ CBtn_7->setColor(opts->ircColors[7]);
+ CBtn_8->setColor(opts->ircColors[8]);
+ CBtn_9->setColor(opts->ircColors[9]);
+ CBtn_10->setColor(opts->ircColors[10]);
+ CBtn_11->setColor(opts->ircColors[11]);
+ CBtn_12->setColor(opts->ircColors[12]);
+ CBtn_13->setColor(opts->ircColors[13]);
+ CBtn_14->setColor(opts->ircColors[14]);
+ CBtn_15->setColor(opts->ircColors[15]);
+
+ CBox_0->setChecked(opts->nickHighlight[0]);
+ CBox_1->setChecked(opts->nickHighlight[1]);
+ CBox_2->setChecked(opts->nickHighlight[2]);
+ CBox_3->setChecked(opts->nickHighlight[3]);
+ CBox_4->setChecked(opts->nickHighlight[4]);
+ CBox_5->setChecked(opts->nickHighlight[5]);
+ CBox_6->setChecked(opts->nickHighlight[6]);
+ CBox_7->setChecked(opts->nickHighlight[7]);
+ CBox_8->setChecked(opts->nickHighlight[8]);
+ CBox_9->setChecked(opts->nickHighlight[9]);
+ CBox_10->setChecked(opts->nickHighlight[10]);
+ CBox_11->setChecked(opts->nickHighlight[11]);
+ CBox_12->setChecked(opts->nickHighlight[12]);
+ CBox_13->setChecked(opts->nickHighlight[13]);
+ CBox_14->setChecked(opts->nickHighlight[14]);
+ CBox_15->setChecked(opts->nickHighlight[15]);
+
+ TL_0->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_1->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_2->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_3->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_4->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_5->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_6->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_7->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_8->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_9->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_10->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_11->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_12->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_13->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_14->setPaletteBackgroundColor(opts->backgroundColor);
+ TL_15->setPaletteBackgroundColor(opts->backgroundColor);
+
+ TL_0->setPaletteForegroundColor(opts->ircColors[0]);
+ TL_1->setPaletteForegroundColor(opts->ircColors[1]);
+ TL_2->setPaletteForegroundColor(opts->ircColors[2]);
+ TL_3->setPaletteForegroundColor(opts->ircColors[3]);
+ TL_4->setPaletteForegroundColor(opts->ircColors[4]);
+ TL_5->setPaletteForegroundColor(opts->ircColors[5]);
+ TL_6->setPaletteForegroundColor(opts->ircColors[6]);
+ TL_7->setPaletteForegroundColor(opts->ircColors[7]);
+ TL_8->setPaletteForegroundColor(opts->ircColors[8]);
+ TL_9->setPaletteForegroundColor(opts->ircColors[9]);
+ TL_10->setPaletteForegroundColor(opts->ircColors[10]);
+ TL_11->setPaletteForegroundColor(opts->ircColors[11]);
+ TL_12->setPaletteForegroundColor(opts->ircColors[12]);
+ TL_13->setPaletteForegroundColor(opts->ircColors[13]);
+ TL_14->setPaletteForegroundColor(opts->ircColors[14]);
+ TL_15->setPaletteForegroundColor(opts->ircColors[15]);
+
+ TL_0->setFont(ksopts->defaultFont);
+ TL_1->setFont(ksopts->defaultFont);
+ TL_2->setFont(ksopts->defaultFont);
+ TL_3->setFont(ksopts->defaultFont);
+ TL_4->setFont(ksopts->defaultFont);
+ TL_5->setFont(ksopts->defaultFont);
+ TL_6->setFont(ksopts->defaultFont);
+ TL_7->setFont(ksopts->defaultFont);
+ TL_8->setFont(ksopts->defaultFont);
+ TL_9->setFont(ksopts->defaultFont);
+ TL_10->setFont(ksopts->defaultFont);
+ TL_11->setFont(ksopts->defaultFont);
+ TL_12->setFont(ksopts->defaultFont);
+ TL_13->setFont(ksopts->defaultFont);
+ TL_14->setFont(ksopts->defaultFont);
+ TL_15->setFont(ksopts->defaultFont);
+}
+
+void PageIRCColors::defaultConfig()
+{
+ KSOColors opts;
+ readConfig( &opts );
+}
+
+void PageIRCColors::changed()
+{
+ TL_0->setPaletteForegroundColor(CBtn_0->color());
+ TL_1->setPaletteForegroundColor(CBtn_1->color());
+ TL_2->setPaletteForegroundColor(CBtn_2->color());
+ TL_3->setPaletteForegroundColor(CBtn_3->color());
+ TL_4->setPaletteForegroundColor(CBtn_4->color());
+ TL_5->setPaletteForegroundColor(CBtn_5->color());
+ TL_6->setPaletteForegroundColor(CBtn_6->color());
+ TL_7->setPaletteForegroundColor(CBtn_7->color());
+ TL_8->setPaletteForegroundColor(CBtn_8->color());
+ TL_9->setPaletteForegroundColor(CBtn_9->color());
+ TL_10->setPaletteForegroundColor(CBtn_10->color());
+ TL_11->setPaletteForegroundColor(CBtn_11->color());
+ TL_12->setPaletteForegroundColor(CBtn_12->color());
+ TL_13->setPaletteForegroundColor(CBtn_13->color());
+ TL_14->setPaletteForegroundColor(CBtn_14->color());
+ TL_15->setPaletteForegroundColor(CBtn_15->color());
+ emit modified();
+}
+
+
+#include "page_irccolors.moc"
+
diff --git a/ksirc/KSPrefs/page_irccolors.h b/ksirc/KSPrefs/page_irccolors.h
new file mode 100644
index 00000000..a34045c3
--- /dev/null
+++ b/ksirc/KSPrefs/page_irccolors.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_IRCCOLORS_H
+#define PAGE_IRCCOLORS_H
+
+#include "page_irccolorsbase.h"
+#include "ksopts.h"
+
+class PageIRCColors : public PageIRCColorsBase
+{
+Q_OBJECT
+
+public:
+ PageIRCColors( QWidget *parent = 0, const char *name = 0 );
+ ~PageIRCColors();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSOColors * = ksopts );
+
+protected slots:
+ void changed();
+
+public slots:
+
+signals:
+ void modified();
+
+private:
+
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_irccolorsbase.ui b/ksirc/KSPrefs/page_irccolorsbase.ui
new file mode 100644
index 00000000..96fc18cc
--- /dev/null
+++ b/ksirc/KSPrefs/page_irccolorsbase.ui
@@ -0,0 +1,1275 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>PageIRCColorsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PageIRCColorsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>429</width>
+ <height>552</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>IRC Colors</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;p&gt;This selection allows you to control what the colors displayed inline in the channel look like. These colors are used for both mIRC style colors in channels and colorful nicks. The sample box beside the button gives you an example of what it will look like in the channel. The checkbox controls if the color is used for the colorful nick features. Checked means use it.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>dark</cstring>
+ </property>
+ <attribute name="title">
+ <string>Dark Colors</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox16</cstring>
+ </property>
+ <property name="title">
+ <string>Dark Colors</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_2</cstring>
+ </property>
+ <property name="text">
+ <string>Black:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>CBtn_1</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>TL_1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Black&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>genericTextLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>White:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>CBtn_0</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>TL_0</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;White&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_3</cstring>
+ </property>
+ <property name="text">
+ <string>Dark blue:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>CBtn_2</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>TL_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Dark Blue&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_5</cstring>
+ </property>
+ <property name="text">
+ <string>Red:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="4" column="1">
+ <property name="name">
+ <cstring>CBtn_4</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="2">
+ <property name="name">
+ <cstring>TL_4</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Red&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_4</cstring>
+ </property>
+ <property name="text">
+ <string>Dark green:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="1">
+ <property name="name">
+ <cstring>CBtn_3</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>TL_3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Dark Green&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_6</cstring>
+ </property>
+ <property name="text">
+ <string>Brown:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="5" column="1">
+ <property name="name">
+ <cstring>CBtn_5</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="2">
+ <property name="name">
+ <cstring>TL_5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Brown&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_7</cstring>
+ </property>
+ <property name="text">
+ <string>Magenta:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="6" column="1">
+ <property name="name">
+ <cstring>CBtn_6</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="2">
+ <property name="name">
+ <cstring>TL_6</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Magenta&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_8</cstring>
+ </property>
+ <property name="text">
+ <string>Orange:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="7" column="1">
+ <property name="name">
+ <cstring>CBtn_7</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="2">
+ <property name="name">
+ <cstring>TL_7</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Orange&lt;p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="3">
+ <property name="name">
+ <cstring>CBox_0</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="3">
+ <property name="name">
+ <cstring>CBox_1</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="3">
+ <property name="name">
+ <cstring>CBox_2</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="3">
+ <property name="name">
+ <cstring>CBox_3</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="3">
+ <property name="name">
+ <cstring>CBox_4</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="3">
+ <property name="name">
+ <cstring>CBox_5</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="6" column="3">
+ <property name="name">
+ <cstring>CBox_6</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="7" column="3">
+ <property name="name">
+ <cstring>CBox_7</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>41</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>light</cstring>
+ </property>
+ <attribute name="title">
+ <string>Light Colors</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>ircColorsGB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>IRC Channel Colors</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_11</cstring>
+ </property>
+ <property name="text">
+ <string>Dark cyan:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_12</cstring>
+ </property>
+ <property name="text">
+ <string>Cyan:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_13</cstring>
+ </property>
+ <property name="text">
+ <string>Blue:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_14</cstring>
+ </property>
+ <property name="text">
+ <string>Purple:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_15</cstring>
+ </property>
+ <property name="text">
+ <string>Gray:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_16</cstring>
+ </property>
+ <property name="text">
+ <string>Light gray:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>CBtn_8</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>CBtn_9</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>CBtn_10</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="1">
+ <property name="name">
+ <cstring>CBtn_11</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="4" column="1">
+ <property name="name">
+ <cstring>CBtn_12</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="5" column="1">
+ <property name="name">
+ <cstring>CBtn_13</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="6" column="1">
+ <property name="name">
+ <cstring>CBtn_14</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="7" column="1">
+ <property name="name">
+ <cstring>CBtn_15</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>60</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_10</cstring>
+ </property>
+ <property name="text">
+ <string>Green:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>TL_8</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Yellow&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>TL_9</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Green&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>TL_11</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Cyan&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>TL_10</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Dark Cyan&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="2">
+ <property name="name">
+ <cstring>TL_12</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Blue&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="2">
+ <property name="name">
+ <cstring>TL_13</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Purple&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="2">
+ <property name="name">
+ <cstring>TL_14</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Gray&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="2">
+ <property name="name">
+ <cstring>TL_15</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>LineEditPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>&lt;p align="center"&gt;Light Gray&lt;/p&gt;</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="3">
+ <property name="name">
+ <cstring>CBox_8</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="3">
+ <property name="name">
+ <cstring>CBox_9</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="3">
+ <property name="name">
+ <cstring>CBox_10</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="3">
+ <property name="name">
+ <cstring>CBox_11</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="3">
+ <property name="name">
+ <cstring>CBox_12</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="3">
+ <property name="name">
+ <cstring>CBox_13</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="6" column="3">
+ <property name="name">
+ <cstring>CBox_14</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="7" column="3">
+ <property name="name">
+ <cstring>CBox_15</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>genericTextLabel_9</cstring>
+ </property>
+ <property name="text">
+ <string>Yellow:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>genericTextCBtn</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>121</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>CBtn_8</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_9</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_10</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_11</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_12</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_13</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_14</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_15</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_0</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_1</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_2</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_3</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_4</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_5</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_6</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBtn_7</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_0</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_1</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_2</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_3</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_4</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_5</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_6</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_7</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_8</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_9</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_10</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_11</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_12</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_13</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_14</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>CBox_15</sender>
+ <signal>stateChanged(int)</signal>
+ <receiver>PageIRCColorsBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>chanaged()</slot>
+ <slot>changed()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/ksirc/KSPrefs/page_looknfeel.cpp b/ksirc/KSPrefs/page_looknfeel.cpp
new file mode 100644
index 00000000..931a897c
--- /dev/null
+++ b/ksirc/KSPrefs/page_looknfeel.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+#include <kfiledialog.h>
+#include "page_looknfeel.h"
+
+PageLooknFeel::PageLooknFeel( QWidget *parent, const char *name ) : PageLooknFeelBase( parent, name)
+{
+ modePreview->setPixmap(QPixmap(locate("data","ksirc/pics/sdi.png")));
+ wallpaperPathLE->fileDialog()->setFilter( "*.jpg *.png *.gif" );
+}
+
+PageLooknFeel::~PageLooknFeel()
+{
+}
+
+void PageLooknFeel::saveConfig()
+{
+ if ( mdiCB->isChecked() ) ksopts->displayMode = KSOptions::MDI;
+ if ( sdiCB->isChecked() ) ksopts->displayMode = KSOptions::SDI;
+
+ ksopts->backgroundFile = wallpaperPathLE->url();
+
+}
+
+void PageLooknFeel::readConfig( const KSOGeneral *opts )
+{
+ if ( opts->displayMode == KSOptions::MDI )
+ mdiCB->setChecked( true );
+ else
+ sdiCB->setChecked( true );
+
+ wallpaperPathLE->setURL( opts->backgroundFile );
+}
+
+void PageLooknFeel::defaultConfig()
+{
+ KSOGeneral opts;
+ readConfig( &opts );
+}
+
+void PageLooknFeel::setPreviewPixmap( bool isSDI )
+{
+ if (isSDI == true)
+ modePreview->setPixmap( QPixmap( locate("data", "ksirc/pics/sdi.png" ) ) );
+ else
+ modePreview->setPixmap( QPixmap( locate("data", "ksirc/pics/mdi.png" ) ) );
+}
+
+void PageLooknFeel::showWallpaperPixmap( const QString &url )
+{
+ wallpaperPreview->setPixmap( QPixmap( url ) );
+}
+
+void PageLooknFeel::changed()
+{
+ emit modified();
+}
+
+#include "page_looknfeel.moc"
diff --git a/ksirc/KSPrefs/page_looknfeel.h b/ksirc/KSPrefs/page_looknfeel.h
new file mode 100644
index 00000000..a5c7f96f
--- /dev/null
+++ b/ksirc/KSPrefs/page_looknfeel.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_LOOKNFEEL_H
+#define PAGE_LOOKNFEEL_H
+
+#include "page_looknfeelbase.h"
+#include "ksopts.h"
+
+class PageLooknFeel : public PageLooknFeelBase
+{
+Q_OBJECT
+
+public:
+ PageLooknFeel( QWidget *parent = 0, const char *name = 0 );
+ ~PageLooknFeel();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSOGeneral * = ksopts );
+
+signals:
+ void modified();
+
+public slots:
+ virtual void setPreviewPixmap( bool isSDI );
+ virtual void showWallpaperPixmap( const QString &url );
+ virtual void changed();
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_looknfeelbase.ui b/ksirc/KSPrefs/page_looknfeelbase.ui
new file mode 100644
index 00000000..6aee3a14
--- /dev/null
+++ b/ksirc/KSPrefs/page_looknfeelbase.ui
@@ -0,0 +1,323 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>PageLooknFeelBase</class>
+<widget class="QFrame">
+ <property name="name">
+ <cstring>PageLooknFeelBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>425</width>
+ <height>452</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>425</width>
+ <height>450</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>LooknFeel</string>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>windowModeGB</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>Window Mode</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="4" column="0">
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>mdiCB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Paged MDI mode (XChat)</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>Spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>wmLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Choose your favorite window mode:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignLeft</set>
+ </property>
+ <property name="vAlign" stdset="0">
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>sdiCB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;SDI mode (old behavior)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QFrame" row="1" column="1" rowspan="4" colspan="1">
+ <property name="name">
+ <cstring>Frame3</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>120</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>modePreview</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>100</width>
+ <height>100</height>
+ </rect>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>wallpaperGB</cstring>
+ </property>
+ <property name="title">
+ <string>Wallpaper</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>wallpaperPathLE</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>25</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>30</height>
+ </size>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>Frame3_2</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>120</width>
+ <height>120</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>wallpaperPreview</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>100</width>
+ <height>100</height>
+ </rect>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>sdiCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageLooknFeelBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>sdiCB</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>PageLooknFeelBase</receiver>
+ <slot>setPreviewPixmap(bool)</slot>
+ </connection>
+ <connection>
+ <sender>mdiCB</sender>
+ <signal>clicked()</signal>
+ <receiver>PageLooknFeelBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>wallpaperPathLE</sender>
+ <signal>textChanged(const QString &amp;)</signal>
+ <receiver>PageLooknFeelBase</receiver>
+ <slot>showWallpaperPixmap(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>wallpaperPathLE</sender>
+ <signal>textChanged(const QString &amp;)</signal>
+ <receiver>PageLooknFeelBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>sdiCB</tabstop>
+ <tabstop>wallpaperPathLE</tabstop>
+</tabstops>
+<slots>
+ <slot access="protected">setPreviewPixmap(bool)</slot>
+ <slot access="protected">showWallpaperPixmap(const QString &amp;)</slot>
+ <slot>changed()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/ksirc/KSPrefs/page_rmbmenu.cpp b/ksirc/KSPrefs/page_rmbmenu.cpp
new file mode 100644
index 00000000..7baf5da5
--- /dev/null
+++ b/ksirc/KSPrefs/page_rmbmenu.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License.
+ * *
+ ***************************************************************************/
+
+#include "page_rmbmenu.h"
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+
+#include <kdebug.h>
+
+#include "../usercontrolmenu.h"
+
+
+
+PageRMBMenu::PageRMBMenu( QWidget *parent, const char *name ) : PageRMBMenuBase( parent, name)
+{
+ UserControlMenu *ucm;
+
+ UserControlMenu::parseKConfig();
+
+ commandLB->clear();
+ for(ucm = UserControlMenu::UserMenu.first();
+ ucm != 0;
+ ucm = UserControlMenu::UserMenu.next()){
+
+ if(ucm->type == UserControlMenu::Seperator){
+ commandLB->insertItem("--------------", -1);
+ }
+ else{
+ commandLB->insertItem(ucm->title, -1);
+ }
+ }
+
+ changeItemPB->hide();
+
+ connect(commandLB, SIGNAL(highlighted( int )),
+ this, SLOT(highlighted( int )));
+ connect(moveUpPB, SIGNAL(clicked()),
+ this, SLOT(moveDown()));
+ connect(moveDownPB, SIGNAL(clicked()),
+ this, SLOT(moveUp()));
+
+ connect(insertSeperatorPB, SIGNAL(clicked()),
+ this, SLOT(insSeperator()));
+
+ connect(insertItemPB, SIGNAL(clicked()),
+ this, SLOT(insCommand()));
+
+ connect(deleteItemPB, SIGNAL(clicked()),
+ this, SLOT(delCommand()));
+
+}
+
+PageRMBMenu::~PageRMBMenu()
+{
+}
+
+void PageRMBMenu::saveConfig()
+{
+ UserControlMenu::writeKConfig();
+}
+
+void PageRMBMenu::readConfig( const KSORMBMenu * )
+{
+}
+
+void PageRMBMenu::defaultConfig()
+{
+}
+
+void PageRMBMenu::highlighted(int index)
+{
+ UserControlMenu *ucm;
+
+ ucm = UserControlMenu::UserMenu.at(index);
+
+ if(ucm == 0)
+ return;
+
+ if(ucm->type == UserControlMenu::Seperator){
+ entryLE->setEnabled(false);
+ commandLE->setEnabled(false);
+ opEnableCB->setEnabled(false);
+ opEnableCB->setChecked(false);
+ changeItemPB->setEnabled(false);
+ }
+ else{
+ entryLE->setEnabled(true);
+ commandLE->setEnabled(true);
+ opEnableCB->setEnabled(true);
+ opEnableCB->setChecked(true);
+ changeItemPB->setEnabled(true);
+
+ entryLE->setText(ucm->title);
+ commandLE->setText(ucm->action);
+ opEnableCB->setChecked(ucm->op_only);
+ }
+
+ if(index == 0){
+ moveUpPB->setEnabled(true);
+ moveDownPB->setEnabled(false);
+ }
+ else if((uint)index == (commandLB->count()-1)){
+ moveUpPB->setEnabled(false);
+ moveDownPB->setEnabled(true);
+ }
+ else {
+ moveUpPB->setEnabled(true);
+ moveDownPB->setEnabled(true);
+ }
+}
+
+void PageRMBMenu::moveUp()
+{
+ int item = commandLB->currentItem();
+
+ QString txt = commandLB->text(item);
+ commandLB->removeItem(item);
+
+ commandLB->insertItem(txt, item-1);
+ commandLB->setCurrentItem(item-1);
+
+ UserControlMenu *ucm = UserControlMenu::UserMenu.take(item);
+ UserControlMenu::UserMenu.insert(item-1,ucm);
+
+ highlighted(item-1);
+ emit modified();
+}
+
+void PageRMBMenu::moveDown()
+{
+ int item = commandLB->currentItem();
+
+ QString txt = commandLB->text(item);
+ commandLB->removeItem(item);
+
+ commandLB->insertItem(txt, item+1);
+ commandLB->setCurrentItem(item+1);
+
+ UserControlMenu *ucm = UserControlMenu::UserMenu.take(item);
+ UserControlMenu::UserMenu.insert(item+1,ucm);
+
+ highlighted(item+1);
+ emit modified();
+}
+
+void PageRMBMenu::insSeperator()
+{
+ int item = commandLB->currentItem();
+
+ QString txt = commandLB->text(item);
+
+ commandLB->insertItem("--------------", item);
+ commandLB->setCurrentItem(item);
+
+ UserControlMenu::UserMenu.insert(item,new UserControlMenu); // Defaults to a separator
+
+ highlighted(item);
+ emit modified();
+}
+
+void PageRMBMenu::insCommand()
+{
+ int item = commandLB->currentItem();
+
+ QString te = entryLE->text();
+ QString ce = commandLE->text();
+
+ commandLB->insertItem(te, item);
+ commandLB->setCurrentItem(item);
+
+ UserControlMenu::UserMenu.insert(item,
+ new UserControlMenu(
+ te,
+ ce,
+ 0x0,
+ UserControlMenu::Text
+ )); // Defaults to a separator
+
+ highlighted(item);
+ emit modified();
+}
+
+void PageRMBMenu::delCommand()
+{
+ int item = commandLB->currentItem();
+
+ QString txt = commandLB->text(item);
+ commandLB->removeItem(item);
+
+ UserControlMenu::UserMenu.remove(item);
+
+ highlighted(item);
+ emit modified();
+}
+
+
+#include "page_rmbmenu.moc"
diff --git a/ksirc/KSPrefs/page_rmbmenu.h b/ksirc/KSPrefs/page_rmbmenu.h
new file mode 100644
index 00000000..cb1de421
--- /dev/null
+++ b/ksirc/KSPrefs/page_rmbmenu.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_RMBMENU_H
+#define PAGE_RMBMENU_H
+
+#include "page_rmbmenubase.h"
+#include "ksopts.h"
+
+class PageRMBMenu : public PageRMBMenuBase
+{
+Q_OBJECT
+
+public:
+ PageRMBMenu( QWidget *parent = 0, const char *name = 0 );
+ ~PageRMBMenu();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSORMBMenu * = ksopts );
+protected slots:
+ void highlighted(int);
+ void moveUp();
+ void moveDown();
+ void insSeperator();
+ void insCommand();
+ void delCommand();
+signals:
+ void modified();
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_rmbmenubase.ui b/ksirc/KSPrefs/page_rmbmenubase.ui
new file mode 100644
index 00000000..1ef1e053
--- /dev/null
+++ b/ksirc/KSPrefs/page_rmbmenubase.ui
@@ -0,0 +1,252 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>PageRMBMenuBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PageRMBMenuBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Nick Option Menu</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>explLabel</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>This page allows configuration of the RMB Menu for the nicklist located on the right. You can define names for certain actions. Look at the predefined commands to learn how it works.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter|AlignLeft</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring></cstring>
+ </property>
+ <property name="wordwrap" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout28</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>commandLB</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout26</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>entryNameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Entry name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>entryLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>entryLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>commandLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Associated co&amp;mmand:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>commandLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>commandLE</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>opEnableCB</cstring>
+ </property>
+ <property name="text">
+ <string>Onl&amp;y enable on Op status</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout24</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>moveUpPB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Move Down</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>moveDownPB</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Move Up</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>10</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>insertSeperatorPB</cstring>
+ </property>
+ <property name="text">
+ <string>Insert &amp;Separator</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>insertItemPB</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Insert Command</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>changeItemPB</cstring>
+ </property>
+ <property name="text">
+ <string>M&amp;odify</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>deleteItemPB</cstring>
+ </property>
+ <property name="text">
+ <string>De&amp;lete Selected Command</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in declaration">kseparator.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksirc/KSPrefs/page_servchan.cpp b/ksirc/KSPrefs/page_servchan.cpp
new file mode 100644
index 00000000..4689bd2a
--- /dev/null
+++ b/ksirc/KSPrefs/page_servchan.cpp
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "page_servchan.h"
+
+#include <qlistbox.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <kapplication.h>
+#include <kconfig.h>
+
+PageServChan::PageServChan( QWidget *parent, const char *name ) : PageServChanBase( parent, name)
+{
+ connect(serverDeleteItemPB, SIGNAL(pressed()), this, SLOT(deletePressedSL()));
+ connect(ServerAddItemPB, SIGNAL(pressed()), this, SLOT(addPressedSL()));
+ connect(chanDeleteItmPB, SIGNAL(pressed()), this, SLOT(deletePressedCL()));
+ connect(ChanAddItemPB, SIGNAL(pressed()), this, SLOT(addPressedCL()));
+
+}
+
+PageServChan::~PageServChan()
+{
+}
+
+void PageServChan::saveConfig()
+{
+ QStringList sLB;
+ uint i;
+ for(i = 0; i < serverLB->count(); i++){
+ QString txt = serverLB->text(i);
+ if(!txt.isNull())
+ sLB << txt;
+ }
+ KConfig *conf = kapp->config();
+ conf->setGroup("ServerList");
+ conf->writeEntry("RecentServers", sLB);
+
+ QStringList sCL;
+ for(i = 0; i < channelLB->count(); i++){
+ QString txt = channelLB->text(i);
+ if(!txt.isNull())
+ sCL << txt;
+ }
+ conf->setGroup("Recent");
+ conf->writeEntry("Channels", sCL);
+}
+
+void PageServChan::readConfig( const KSOServChan * )
+{
+ KConfig *conf = kapp->config();
+ conf->setGroup("ServerList");
+ QStringList recent = conf->readListEntry("RecentServers");
+ recent.sort();
+ serverLB->insertStringList(recent);
+ conf->setGroup("Recent");
+ recent = conf->readListEntry("Channels");
+ recent.sort();
+ channelLB->insertStringList(recent);
+}
+
+void PageServChan::defaultConfig()
+{
+ readConfig();
+}
+
+void PageServChan::deletePressedSL() {
+ int item = serverLB->currentItem();
+ if(item >= 0){
+ serverLB->removeItem(item);
+ }
+ emit modified();
+}
+
+void PageServChan::addPressedSL() {
+ uint i;
+ QString txt = LineEdit6->text();
+
+ for(i = 0; i < serverLB->count(); i++){
+ if(txt == serverLB->text(i)){
+ qWarning("Server already in the list!");
+ return;
+ }
+ }
+
+ serverLB->insertItem(txt);
+ serverLB->sort();
+ LineEdit6->clear();
+ emit modified();
+ for(i = 0; i < serverLB->count(); i++){
+ if(txt == serverLB->text(i)){
+ serverLB->setCurrentItem(i);
+ serverLB->ensureCurrentVisible();
+ return;
+ }
+ }
+}
+
+void PageServChan::deletePressedCL() {
+ int item = channelLB->currentItem();
+ if(item >= 0){
+ channelLB->removeItem(item);
+ }
+ emit modified();
+}
+
+void PageServChan::addPressedCL() {
+ uint i;
+ QString txt = LineEdit6_2->text();
+
+ for(i = 0; i < channelLB->count(); i++){
+ if(txt == channelLB->text(i)){
+ qWarning("Server already in the list!");
+ return;
+ }
+ }
+
+ channelLB->insertItem(txt);
+ channelLB->sort();
+ LineEdit6_2->clear();
+ emit modified();
+ for(i = 0; i < channelLB->count(); i++){
+ if(txt == channelLB->text(i)){
+ channelLB->setCurrentItem(i);
+ channelLB->ensureCurrentVisible();
+ return;
+ }
+ }
+}
+#include "page_servchan.moc"
diff --git a/ksirc/KSPrefs/page_servchan.h b/ksirc/KSPrefs/page_servchan.h
new file mode 100644
index 00000000..07429f2b
--- /dev/null
+++ b/ksirc/KSPrefs/page_servchan.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_SERVCHAN_H
+#define PAGE_SERVCHAN_H
+
+#include "page_servchanbase.h"
+#include "ksopts.h"
+
+class PageServChan : public PageServChanBase
+{
+Q_OBJECT
+
+public:
+ PageServChan( QWidget *parent = 0, const char *name = 0 );
+ ~PageServChan();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSOServChan * = ksopts );
+
+signals:
+ void modified();
+
+public slots:
+ void deletePressedSL();
+ void addPressedSL();
+ void deletePressedCL();
+ void addPressedCL();
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_servchanbase.ui b/ksirc/KSPrefs/page_servchanbase.ui
new file mode 100644
index 00000000..b24ce9dc
--- /dev/null
+++ b/ksirc/KSPrefs/page_servchanbase.ui
@@ -0,0 +1,172 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>PageServChanBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PageServChanBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>382</width>
+ <height>465</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Server/Channels</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox33</cstring>
+ </property>
+ <property name="title">
+ <string>Server</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>serverLB</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout15</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>serverDeleteItemPB</cstring>
+ </property>
+ <property name="text">
+ <string>De&amp;lete Server From List</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>ServerAddItemPB</cstring>
+ </property>
+ <property name="text">
+ <string>Add &amp;Server to List</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>LineEdit6</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox34</cstring>
+ </property>
+ <property name="title">
+ <string>Channels</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>channelLB</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout15_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>chanDeleteItmPB</cstring>
+ </property>
+ <property name="text">
+ <string>D&amp;elete Channel From List</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>ChanAddItemPB</cstring>
+ </property>
+ <property name="text">
+ <string>Add Cha&amp;nnel to List</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>LineEdit6_2</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksirc/KSPrefs/page_shortcuts.cpp b/ksirc/KSPrefs/page_shortcuts.cpp
new file mode 100644
index 00000000..45a83beb
--- /dev/null
+++ b/ksirc/KSPrefs/page_shortcuts.cpp
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qgroupbox.h>
+
+#include <kglobalaccel.h>
+
+#include <kkeydialog.h>
+#include "page_shortcuts.h"
+#include "../servercontroller.h"
+
+PageShortcuts::PageShortcuts( QWidget *parent, const char *name ) : PageShortcutsBase( parent, name)
+{
+ globalGB->setColumnLayout( 0, Qt::Horizontal );
+
+ m_key = new KKeyChooser(servercontroller::self()->getGlobalAccel(), globalGB);
+ connect(m_key, SIGNAL(keyChange()), this, SLOT(changed()));
+ globalGB->layout()->add(m_key);
+}
+
+PageShortcuts::~PageShortcuts()
+{
+}
+
+void PageShortcuts::saveConfig()
+{
+ m_key->commitChanges();
+ servercontroller::self()->getGlobalAccel()->writeSettings();
+ servercontroller::self()->getGlobalAccel()->updateConnections();
+}
+
+void PageShortcuts::readConfig( const KSOGeneral *opts )
+{
+ servercontroller::self()->getGlobalAccel()->readSettings();
+}
+
+void PageShortcuts::defaultConfig()
+{
+ KSOGeneral opts;
+ readConfig( &opts );
+ m_key->allDefault();
+}
+
+
+void PageShortcuts::changed()
+{
+ emit modified();
+}
+
+#include "page_shortcuts.moc"
diff --git a/ksirc/KSPrefs/page_shortcuts.h b/ksirc/KSPrefs/page_shortcuts.h
new file mode 100644
index 00000000..4c16aa35
--- /dev/null
+++ b/ksirc/KSPrefs/page_shortcuts.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_SHORTCUTS_H
+#define PAGE_SHORTCUTS_H
+
+#include "page_shortcutsbase.h"
+#include "ksopts.h"
+
+class KKeyChooser;
+
+class PageShortcuts : public PageShortcutsBase
+{
+Q_OBJECT
+
+public:
+ PageShortcuts( QWidget *parent = 0, const char *name = 0 );
+ ~PageShortcuts();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSOGeneral * = ksopts );
+
+signals:
+ void modified();
+
+public slots:
+ virtual void changed();
+
+private:
+ KKeyChooser *m_key;
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_shortcutsbase.ui b/ksirc/KSPrefs/page_shortcutsbase.ui
new file mode 100644
index 00000000..57f21647
--- /dev/null
+++ b/ksirc/KSPrefs/page_shortcutsbase.ui
@@ -0,0 +1,57 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>PageShortcutsBase</class>
+<widget class="QFrame">
+ <property name="name">
+ <cstring>PageShortcutslBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>425</width>
+ <height>452</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>425</width>
+ <height>450</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Shortcuts</string>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>globalGB</cstring>
+ </property>
+ <property name="title">
+ <string>Global Shortcuts</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+</connections>
+<tabstops>
+</tabstops>
+<slots>
+ <slot access="protected">setPreviewPixmap(bool)</slot>
+ <slot access="protected">showWallpaperPixmap(const QString &amp;)</slot>
+ <slot>changed()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksirc/KSPrefs/page_startup.cpp b/ksirc/KSPrefs/page_startup.cpp
new file mode 100644
index 00000000..060da44d
--- /dev/null
+++ b/ksirc/KSPrefs/page_startup.cpp
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qlistbox.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <keditlistbox.h>
+
+#include <kdebug.h>
+
+#include "page_startup.h"
+
+PageStartup::PageStartup( QWidget *parent, const char *name ) : PageStartupBase( parent, name)
+{
+ notifyLB->upButton()->hide();
+ notifyLB->downButton()->hide();
+ serverLB->upButton()->hide();
+ serverLB->downButton()->hide();
+
+ QListBox *lb = serverLB->listBox();
+ connect(lb, SIGNAL(highlighted(int)),
+ this, SLOT(clickedLB(int)));
+
+ changing = false;
+
+}
+
+PageStartup::~PageStartup()
+{
+}
+
+void PageStartup::saveConfig()
+{
+ KSOServer glb = ksopts->server["global"];
+ QStringList items = serverLB->items();
+
+ ksopts->server.clear();
+
+ QStringList::iterator it = items.begin();
+ for( ; it != items.end(); ++it){
+ ksopts->server[*it] = server[*it];
+ }
+ if(!ksopts->server.contains("global")){
+ ksopts->server["global"] = glb;
+ }
+
+}
+
+void PageStartup::readConfig( const KSOptions *opts )
+{
+ server = opts->server;
+
+ changing = true;
+ ServerOpMap::Iterator it;
+ for ( it = server.begin(); it != server.end(); ++it ) {
+ if(it.data().globalCopy == false)
+ serverLB->insertItem(it.key());
+ }
+ QListBoxItem *item = serverLB->listBox()->findItem("global");
+ serverLB->listBox()->setSelected(item, true);
+ changing = false;
+ clickedLB(serverLB->listBox()->index(item));
+
+}
+
+void PageStartup::defaultConfig()
+{
+ KSOptions opts;
+ readConfig( &opts );
+}
+
+void PageStartup::changed()
+{
+ emit modified();
+
+ QString ser = serverLB->currentText();
+ if(ser.isEmpty())
+ return;
+
+ if(changing)
+ return;
+
+ kdDebug(5008) << "got changed for: " << ser <<endl;
+
+ server[ser].nick = nickLE->text();
+ server[ser].altNick = altNickLE->text();
+ server[ser].realName = rnLE->text();
+ server[ser].userID = uiLE->text();
+
+ server[ser].notifyList.clear();
+ for ( int i = 0; i < notifyLB->count(); ++i)
+ server[ser].notifyList.append( notifyLB->text( i ) );
+ server[ser].globalCopy = false;
+
+}
+
+void PageStartup::clickedLB(int index)
+{
+
+ QString text = serverLB->text(index);
+ if(!server.contains(text)){
+ server[text] = server["global"];
+ server[text].globalCopy = true;
+ }
+
+ changing = true;
+ notifyLB->clear();
+
+ nickLE->setText( server[text].nick );
+ altNickLE->setText( server[text].altNick );
+ rnLE->setText( server[text].realName );
+ uiLE->setText( server[text].userID );
+ notifyLB->insertStringList( server[text].notifyList );
+ changing = false;
+}
+
+#include "page_startup.moc"
diff --git a/ksirc/KSPrefs/page_startup.h b/ksirc/KSPrefs/page_startup.h
new file mode 100644
index 00000000..ecac8305
--- /dev/null
+++ b/ksirc/KSPrefs/page_startup.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PAGE_STARTUP_H
+#define PAGE_STARTUP_H
+
+#include "page_startupbase.h"
+#include "ksopts.h"
+
+class PageStartup : public PageStartupBase
+{
+Q_OBJECT
+
+public:
+ PageStartup( QWidget *parent = 0, const char *name = 0 );
+ ~PageStartup();
+
+ void saveConfig();
+ void defaultConfig();
+ void readConfig( const KSOptions * = ksopts );
+
+signals:
+ void modified();
+
+protected slots:
+ void changed();
+ void clickedLB(int index);
+
+private:
+ ServerOpMap server;
+ bool changing;
+};
+
+#endif
diff --git a/ksirc/KSPrefs/page_startupbase.ui b/ksirc/KSPrefs/page_startupbase.ui
new file mode 100644
index 00000000..1a248806
--- /dev/null
+++ b/ksirc/KSPrefs/page_startupbase.ui
@@ -0,0 +1,197 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>PageStartupBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PageStartupBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>420</width>
+ <height>578</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>StartUp</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KEditListBox">
+ <property name="name">
+ <cstring>serverLB</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Server</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>nickGB</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Name Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>nickLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>altNickLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>rnLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>nickLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Nick name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>nickLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>anLabel</cstring>
+ </property>
+ <property name="text">
+ <string>A&amp;lternative nick:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>altNickLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>uiLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>uiLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;User ID:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>rnLE</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>rnLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Real name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>rnLE</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="KEditListBox">
+ <property name="name">
+ <cstring>notifyLB</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Notify List</string>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>nickLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageStartupBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>altNickLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageStartupBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>notifyLB</sender>
+ <signal>changed()</signal>
+ <receiver>PageStartupBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>rnLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageStartupBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>uiLE</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PageStartupBase</receiver>
+ <slot>changed()</slot>
+ </connection>
+ <connection>
+ <sender>serverLB</sender>
+ <signal>changed()</signal>
+ <receiver>PageStartupBase</receiver>
+ <slot>server_changed()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>changed()</slot>
+ <slot>server_changed()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>keditlistbox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>keditlistbox.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/ksirc/KSProgress/Makefile.am b/ksirc/KSProgress/Makefile.am
new file mode 100644
index 00000000..b24cc64f
--- /dev/null
+++ b/ksirc/KSProgress/Makefile.am
@@ -0,0 +1,11 @@
+KDE_CXXFLAGS = $(USE_RTTI) $(USE_EXCEPTIONS)
+
+INCLUDES= $(all_includes)
+
+noinst_LTLIBRARIES = libksprogress.la
+
+libksprogress_la_SOURCES = ksprogress.cpp ksprogressdata.cpp
+libksprogress_la_METASOURCES = AUTO
+
+noinst_HEADERS = ksprogress.h ksprogressdata.h
+
diff --git a/ksirc/KSProgress/ksprogress.cpp b/ksirc/KSProgress/ksprogress.cpp
new file mode 100644
index 00000000..369b0742
--- /dev/null
+++ b/ksirc/KSProgress/ksprogress.cpp
@@ -0,0 +1,60 @@
+/**********************************************************************
+
+
+ *********************************************************************/
+
+#include "ksprogress.h"
+
+#undef Inherited
+#define Inherited ksprogressData
+
+KSProgress::KSProgress
+(
+ QWidget* parent,
+ const char* name
+)
+ :
+ Inherited( parent, name )
+{
+ setCaption("KSProgress");
+ id = "";
+ canceled = FALSE;
+}
+
+
+void KSProgress::setID(QString _id)
+{
+ id = _id;
+}
+
+void KSProgress::setRange(int minValue, int maxValue)
+{
+ progress->setRange(minValue, maxValue);
+}
+
+void KSProgress::setTopText(QString text)
+{
+ fileName->setText(text);
+}
+
+void KSProgress::setBotText(QString text)
+{
+ transferStatus->setText(text);
+}
+
+void KSProgress::setValue(int value)
+{
+ progress->setValue(value);
+}
+
+void KSProgress::cancelPressed()
+{
+ canceled = TRUE;
+ emit cancel();
+ emit cancel(id);
+}
+
+KSProgress::~KSProgress()
+{
+}
+#include "ksprogress.moc"
diff --git a/ksirc/KSProgress/ksprogress.dlg b/ksirc/KSProgress/ksprogress.dlg
new file mode 100644
index 00000000..5484c4d6
--- /dev/null
+++ b/ksirc/KSProgress/ksprogress.dlg
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<QtArch type="Dialog" version="2.1" nested="true" >
+ <Dialog supertype="true" nested="true" >
+ <DialogCommon nested="true" >
+ <SourceDir >.</SourceDir>
+ <ClassHeader >ksprogress.h</ClassHeader>
+ <ClassSource >ksprogress.cpp</ClassSource>
+ <ClassName >KSProgress</ClassName>
+ <DataHeader >ksprogressdata.h</DataHeader>
+ <DataSource >ksprogressdata.cpp</DataSource>
+ <DataName >ksprogressData</DataName>
+ <WindowBaseClass >QFrame</WindowBaseClass>
+ <ClassHeader >ksprogress.h</ClassHeader>
+ </DialogCommon>
+ <WidgetLayout nested="true" >
+ <WidgetLayoutCommon nested="true" >
+ <InitialPos type="qpoint" complex="true" nested="true" >
+ <X type="integer">-1</X>
+ <Y type="integer">-1</Y>
+ </InitialPos>
+ <Size type="qsize" complex="true" nested="true" >
+ <Height type="integer">130</Height>
+ <Width type="integer">250</Width>
+ </Size>
+ <MinSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">140</Height>
+ <Width type="integer">250</Width>
+ </MinSize>
+ <MaxSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">140</Height>
+ <Width type="integer">250</Width>
+ </MaxSize>
+ <GridSize type="integer">10</GridSize>
+ </WidgetLayoutCommon>
+ <Widgets list="true" nested="true" >
+ <User nested="true" >
+ <UserClassHeader >kprogress.h</UserClassHeader>
+ <UserClassName >KProgress</UserClassName>
+ <DlgWidget nested="true" >
+ <Rect type="qrect" complex="true" nested="true" >
+ <Height type="integer">20</Height>
+ <Width type="integer">230</Width>
+ <X type="integer">10</X>
+ <Y type="integer">60</Y>
+ </Rect>
+ <Name >User_1</Name>
+ <Variable >progress</Variable>
+ <SignalConnection list="true" nested="true" >
+ </SignalConnection>
+ <MinimumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">10</Height>
+ <Width type="integer">10</Width>
+ </MinimumSize>
+ <MaximumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">32767</Height>
+ <Width type="integer">32767</Width>
+ </MaximumSize>
+ <Enabled type="boolean">true</Enabled>
+ <FocusPolicy >NoFocus</FocusPolicy>
+ <BackgroundMode >PaletteBackground</BackgroundMode>
+ <BackgroundOrigin >WidgetOrigin</BackgroundOrigin>
+ </DlgWidget>
+ </User>
+ <PushButton nested="true" >
+ <Button nested="true" >
+ <Text >&amp;Cancel</Text>
+ <DlgWidget nested="true" >
+ <Rect type="qrect" complex="true" nested="true" >
+ <Height type="integer">30</Height>
+ <Width type="integer">100</Width>
+ <X type="integer">70</X>
+ <Y type="integer">90</Y>
+ </Rect>
+ <Name >PushButton_1</Name>
+ <SignalConnection list="true" nested="true" >
+ <Signal >[Protected] clicked --&gt; cancelPressed ()</Signal>
+ </SignalConnection>
+ <MinimumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">10</Height>
+ <Width type="integer">10</Width>
+ </MinimumSize>
+ <MaximumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">32767</Height>
+ <Width type="integer">32767</Width>
+ </MaximumSize>
+ <Enabled type="boolean">true</Enabled>
+ <FocusPolicy >TabFocus</FocusPolicy>
+ <BackgroundMode >PaletteButton</BackgroundMode>
+ <BackgroundOrigin >WidgetOrigin</BackgroundOrigin>
+ </DlgWidget>
+ </Button>
+ </PushButton>
+ <Label nested="true" >
+ <Text >fileName</Text>
+ <Alignment >AlignLeft|AlignVCenter|ExpandTabs</Alignment>
+ <Indent type="integer">-1</Indent>
+ <TextFormat type="qstring">AutoText</TextFormat>
+ <Frame nested="true" >
+ <LineWidth type="integer">1</LineWidth>
+ <DlgWidget nested="true" >
+ <Rect type="qrect" complex="true" nested="true" >
+ <Height type="integer">20</Height>
+ <Width type="integer">230</Width>
+ <X type="integer">10</X>
+ <Y type="integer">10</Y>
+ </Rect>
+ <Name >Label_1</Name>
+ <Variable >fileName</Variable>
+ <SignalConnection list="true" nested="true" >
+ </SignalConnection>
+ <MinimumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">10</Height>
+ <Width type="integer">10</Width>
+ </MinimumSize>
+ <MaximumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">32767</Height>
+ <Width type="integer">32767</Width>
+ </MaximumSize>
+ <Enabled type="boolean">true</Enabled>
+ <FocusPolicy >NoFocus</FocusPolicy>
+ <BackgroundMode >PaletteBackground</BackgroundMode>
+ <BackgroundOrigin >WidgetOrigin</BackgroundOrigin>
+ </DlgWidget>
+ </Frame>
+ </Label>
+ <Label nested="true" >
+ <Text >XferStatus</Text>
+ <Alignment >AlignLeft|AlignVCenter|ExpandTabs</Alignment>
+ <Indent type="integer">-1</Indent>
+ <TextFormat type="qstring">AutoText</TextFormat>
+ <Frame nested="true" >
+ <LineWidth type="integer">1</LineWidth>
+ <DlgWidget nested="true" >
+ <Rect type="qrect" complex="true" nested="true" >
+ <Height type="integer">20</Height>
+ <Width type="integer">230</Width>
+ <X type="integer">10</X>
+ <Y type="integer">35</Y>
+ </Rect>
+ <Name >Label_2</Name>
+ <Variable >transferStatus</Variable>
+ <SignalConnection list="true" nested="true" >
+ </SignalConnection>
+ <MinimumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">10</Height>
+ <Width type="integer">10</Width>
+ </MinimumSize>
+ <MaximumSize type="qsize" complex="true" nested="true" >
+ <Height type="integer">32767</Height>
+ <Width type="integer">32767</Width>
+ </MaximumSize>
+ <Enabled type="boolean">true</Enabled>
+ <FocusPolicy >NoFocus</FocusPolicy>
+ <BackgroundMode >PaletteBackground</BackgroundMode>
+ <BackgroundOrigin >WidgetOrigin</BackgroundOrigin>
+ </DlgWidget>
+ </Frame>
+ </Label>
+ </Widgets>
+ <TabOrder list="true" nested="true" >
+ <Widget type="qstring">PushButton_1</Widget>
+ </TabOrder>
+ <Layout list="true" nested="true" >
+ </Layout>
+ </WidgetLayout>
+ </Dialog>
+</QtArch>
diff --git a/ksirc/KSProgress/ksprogress.h b/ksirc/KSProgress/ksprogress.h
new file mode 100644
index 00000000..c3feb2c6
--- /dev/null
+++ b/ksirc/KSProgress/ksprogress.h
@@ -0,0 +1,47 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: ksprogress.h
+ Last generated: Thu Dec 18 08:01:39 1997
+
+ *********************************************************************/
+
+#ifndef KSProgress_included
+#define KSProgress_included
+
+#include "ksprogressdata.h"
+
+class KSProgress : public ksprogressData
+{
+ Q_OBJECT
+
+public:
+
+ KSProgress
+ (
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~KSProgress();
+
+ virtual void setID(QString);
+ virtual void setRange(int minValue, int maxValue);
+ virtual void setTopText(QString text);
+ virtual void setBotText(QString text);
+
+public slots:
+ virtual void setValue(int value);
+ virtual void cancelPressed();
+
+signals:
+ void cancel();
+ void cancel(QString);
+
+private:
+ QString id;
+ bool canceled;
+
+};
+#endif // KSProgress_included
diff --git a/ksirc/KSProgress/ksprogressdata.cpp b/ksirc/KSProgress/ksprogressdata.cpp
new file mode 100644
index 00000000..0feb524b
--- /dev/null
+++ b/ksirc/KSProgress/ksprogressdata.cpp
@@ -0,0 +1,72 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: ksprogressdata.cpp
+ Last generated: Thu Dec 18 09:09:53 1997
+
+ DO NOT EDIT!!! This file will be automatically
+ regenerated by qtarch. All changes will be lost.
+
+ *********************************************************************/
+
+#include "ksprogressdata.h"
+
+#undef Inherited
+#define Inherited QFrame
+
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include <klocale.h>
+
+ksprogressData::ksprogressData
+(
+ QWidget* parent,
+ const char* name
+)
+ :
+ Inherited( parent, name, 0 )
+{
+ progress = new KProgress( this, "User_1" );
+ progress->setGeometry( 10, 60, 230, 20 );
+ progress->setMinimumSize( 10, 10 );
+ progress->setMaximumSize( 32767, 32767 );
+
+ QPushButton* dlgedit_PushButton_1;
+ dlgedit_PushButton_1 = new KPushButton( KStdGuiItem::cancel(), this, "PushButton_1" );
+ dlgedit_PushButton_1->setGeometry( 70, 90, 100, 30 );
+ dlgedit_PushButton_1->setMinimumSize( 10, 10 );
+ dlgedit_PushButton_1->setMaximumSize( 32767, 32767 );
+ connect( dlgedit_PushButton_1, SIGNAL(clicked()), SLOT(cancelPressed()) );
+ dlgedit_PushButton_1->setAutoRepeat( FALSE );
+
+ fileName = new QLabel( this, "Label_1" );
+ fileName->setGeometry( 10, 10, 230, 20 );
+ fileName->setMinimumSize( 10, 10 );
+ fileName->setMaximumSize( 32767, 32767 );
+ fileName->setText( i18n("File Name") );
+ fileName->setAlignment( 289 );
+ fileName->setMargin( -1 );
+
+ transferStatus = new QLabel( this, "Label_2" );
+ transferStatus->setGeometry( 10, 35, 230, 20 );
+ transferStatus->setMinimumSize( 10, 10 );
+ transferStatus->setMaximumSize( 32767, 32767 );
+ transferStatus->setText( i18n("Transfer Status") );
+ transferStatus->setAlignment( 289 );
+ transferStatus->setMargin( -1 );
+
+ resize( 250,130 );
+ setMinimumSize( 250, 140 );
+ setMaximumSize( 250, 140 );
+}
+
+
+ksprogressData::~ksprogressData()
+{
+}
+void ksprogressData::cancelPressed()
+{
+}
+#include "ksprogressdata.moc"
diff --git a/ksirc/KSProgress/ksprogressdata.h b/ksirc/KSProgress/ksprogressdata.h
new file mode 100644
index 00000000..a2282baf
--- /dev/null
+++ b/ksirc/KSProgress/ksprogressdata.h
@@ -0,0 +1,48 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: ksprogressdata.h
+ Last generated: Thu Dec 18 09:09:53 1997
+
+ DO NOT EDIT!!! This file will be automatically
+ regenerated by qtarch. All changes will be lost.
+
+ *********************************************************************/
+
+#ifndef ksprogressData_included
+#define ksprogressData_included
+
+#include <qframe.h>
+#include <qlabel.h>
+#include "kprogress.h"
+
+class ksprogressData : public QFrame
+{
+ Q_OBJECT
+
+public:
+
+ ksprogressData
+ (
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~ksprogressData();
+
+public slots:
+
+
+protected slots:
+
+ virtual void cancelPressed();
+
+protected:
+ KProgress* progress;
+ QLabel* fileName;
+ QLabel* transferStatus;
+
+};
+
+#endif // ksprogressData_included
diff --git a/ksirc/KSTicker/Makefile.am b/ksirc/KSTicker/Makefile.am
new file mode 100644
index 00000000..ab937def
--- /dev/null
+++ b/ksirc/KSTicker/Makefile.am
@@ -0,0 +1,20 @@
+INCLUDES= $(all_includes)
+
+noinst_LTLIBRARIES = libksticker.la
+
+libksticker_la_SOURCES = ksticker.cpp speeddialog.cpp speeddialogData.cpp \
+ kspainter.cpp
+
+noinst_HEADERS = ksticker.h speeddialog.h speeddialogData.h \
+ kspainter.h
+
+METASOURCES = AUTO
+
+
+check_PROGRAMS = ksttest
+
+ksttest_SOURCES = ksttest.cpp
+ksttest_LDADD = libksticker.la ../ksopts.lo ../nickColourMaker.lo $(LIB_KDEUI)
+ksttest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+
diff --git a/ksirc/KSTicker/kspainter.cpp b/ksirc/KSTicker/kspainter.cpp
new file mode 100644
index 00000000..fe5fbf65
--- /dev/null
+++ b/ksirc/KSTicker/kspainter.cpp
@@ -0,0 +1,186 @@
+#include "kspainter.h"
+#include "../ksopts.h"
+#include <stdlib.h>
+
+const int KSPainter::optcolours = 8;
+const int KSPainter::startspecial = 16;
+const int KSPainter::maxcolour = 16+optcolours;
+
+const QColor KSPainter::brown ( 165, 42, 42 );
+const QColor KSPainter::orange ( 255, 165, 0 );
+const QColor KSPainter::lightCyan( 224, 255, 255 );
+const QColor KSPainter::lightBlue( 173, 216, 230 );
+const QColor KSPainter::pink ( 255, 192, 203 );
+
+QColor KSPainter::num2colour[KSPainter::maxcolour] = { Qt::white,
+ Qt::black,
+ Qt::darkBlue,
+ Qt::darkGreen,
+ Qt::red,
+ brown,
+ Qt::darkMagenta,
+ orange,
+ Qt::yellow,
+ Qt::green,
+ Qt::darkCyan,
+ Qt::cyan,
+ Qt::blue,
+ pink,
+ Qt::gray,
+ Qt::lightGray };
+
+void KSPainter::initOptColours()
+{
+ num2colour[startspecial+0] = ksopts->textColor;
+ num2colour[startspecial+1] = ksopts->infoColor;
+ num2colour[startspecial+2] = ksopts->channelColor;
+ num2colour[startspecial+3] = ksopts->errorColor;
+ num2colour[startspecial+4] = ksopts->ownNickColor;
+ num2colour[startspecial+5] = ksopts->nickForeground;
+ num2colour[startspecial+6] = ksopts->nickBackground;
+ num2colour[startspecial+7] = ksopts->backgroundColor;
+}
+
+int KSPainter::colour2num(const QColor &colour)
+{
+ for(int i = 0; i < maxcolour; i++)
+ if(num2colour[i] == colour)
+ return i;
+
+ return -1;
+}
+
+void KSPainter::colourDrawText(QPainter *p, int startx, int starty,
+ char *str, int length)
+{
+ int offset = 0;
+ int pcolour;
+ char buf[3];
+ int loc = 0, i;
+ buf[2] = 0;
+ bool ReverseText = FALSE;
+
+ // Default pen (colour)
+
+ const QPen qpDefPen = p->pen();
+
+ for(loc = 0; (str[loc] != 0x00) && (loc != length) ; loc++){
+ if(str[loc] == 0x03 || str[loc] == '~'){
+ i = loc;
+ p->drawText(startx, starty, str + offset, i-offset);
+ startx += p->fontMetrics().width(str + offset, i-offset);
+ offset = i;
+ // lastp = i;
+ if((str[i+1] >= 0x30) && (str[i+1] <= 0x39)){
+ i++;
+ buf[0] = str[i];
+ i++;
+ if((str[i] >= 0x30) && (str[i] <= 0x39)){
+ buf[1] = str[i];
+ i++;
+ }
+ else{
+ buf[1] = 0;
+ }
+
+ pcolour = atoi(buf);
+ if(pcolour < maxcolour)
+ p->setPen(num2colour[pcolour]);
+ else
+ i = loc;
+ if(str[i] == ','){
+ i++;
+ if((str[i] >= 0x30) && (str[i] <= 0x39)){
+ buf[0] = str[i];
+ i++;
+ if((str[i] >= 0x30) && (str[i] <= 0x39)){
+ buf[1] = str[i];
+ i++;
+ }
+ else{
+ buf[1] = 0;
+ }
+ int bcolour = atoi(buf);
+ if(pcolour == bcolour){
+ if(bcolour + 1 < maxcolour)
+ bcolour += 1;
+ else
+ bcolour -= 1;
+ }
+ if(bcolour < maxcolour ){
+ p->setBackgroundColor(num2colour[bcolour]);
+ p->setBackgroundMode(Qt::OpaqueMode);
+ }
+
+ }
+ }
+ }
+ else if(str[i] == 0x03){
+ i++;
+ p->setPen(qpDefPen);
+ p->setBackgroundMode(Qt::TransparentMode);
+ }
+ else if((str[i] == '~') && ((str[i+1] >= 0x61) || (str[i+1] <= 0x7a))){
+ QFont fnt = p->font();
+ QColor temppen;
+ switch(str[i+1]){
+ case 'c':
+ p->setPen(qpDefPen);
+ p->setBackgroundMode(Qt::TransparentMode);
+ break;
+ case 'C':
+ p->setPen(qpDefPen);
+ p->setBackgroundMode(Qt::TransparentMode);
+ fnt.setBold(FALSE);
+ fnt.setItalic(FALSE);
+ fnt.setUnderline(FALSE);
+ ReverseText = TRUE; // Force reverse removed, all fall through.
+ // FALL THROUGH.
+ case 'r':
+ if(ReverseText == TRUE) {
+ ReverseText = FALSE;
+ p->setBackgroundMode(Qt::TransparentMode);
+ }
+ else {
+ ReverseText = TRUE;
+ p->setBackgroundMode(Qt::OpaqueMode);
+ }
+ temppen = p->pen().color();
+ p->setPen( p->backgroundColor() );
+ p->setBackgroundColor( temppen );
+ break;
+ case 'b':
+ if(fnt.bold() == TRUE)
+ fnt.setBold(FALSE);
+ else
+ fnt.setBold(TRUE);
+ break;
+ case 'i':
+ if(fnt.italic() == TRUE)
+ fnt.setItalic(FALSE);
+ else
+ fnt.setItalic(TRUE);
+ break;
+ case 'u':
+ if(fnt.underline() == TRUE)
+ fnt.setUnderline(FALSE);
+ else
+ fnt.setUnderline(TRUE);
+ break;
+ case '~':
+ loc++; // Skip ahead 2 characters
+ break;
+ default:
+ i-=1;
+ offset -= 1;
+ }
+ p->setFont(fnt);
+ i += 2;
+ }
+ offset += i - loc;
+ }
+ }
+ p->drawText(startx, starty, str + offset, loc-offset);
+
+}
+
diff --git a/ksirc/KSTicker/kspainter.h b/ksirc/KSTicker/kspainter.h
new file mode 100644
index 00000000..21f9495d
--- /dev/null
+++ b/ksirc/KSTicker/kspainter.h
@@ -0,0 +1,25 @@
+#ifndef KSPAINTER_H
+#define KSPAINTER_H
+
+#include <qpainter.h>
+#include <qobject.h>
+
+class KSPainter
+{
+public:
+ static void initOptColours();
+ static void colourDrawText(QPainter *p, int startx, int starty, char *str, int length = -1);
+ static const int startspecial;
+ static const int maxcolour;
+ static const int optcolours;
+ static QColor num2colour[16+8];
+ static int colour2num(const QColor &colour);
+
+ static const QColor brown;
+ static const QColor orange;
+ static const QColor lightCyan;
+ static const QColor lightBlue;
+ static const QColor pink;
+};
+
+#endif
diff --git a/ksirc/KSTicker/ksticker.cpp b/ksirc/KSTicker/ksticker.cpp
new file mode 100644
index 00000000..dc65118a
--- /dev/null
+++ b/ksirc/KSTicker/ksticker.cpp
@@ -0,0 +1,548 @@
+#include <stdlib.h>
+#include <qpainter.h>
+#include <qframe.h>
+#include <qpaintdevice.h>
+#include <qcursor.h>
+#include <qtooltip.h>
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kfontdialog.h>
+#include <klocale.h>
+
+#include "ksticker.h"
+#include "speeddialog.h"
+
+#include "kspainter.h"
+#include "../ksopts.h"
+#include "../nickColourMaker.h"
+
+#include <kconfig.h>
+#include <kwin.h>
+#include <kdebug.h>
+
+KSTicker::KSTicker(QWidget * parent, const char * name, WFlags f)
+: QFrame(parent, name, f)
+{
+
+ pHeight = 1;
+
+ pic = new QPixmap(); // create pic map here, resize it later though.
+ // pic->setBackgroundMode(TransparentMode);
+
+ KConfig *conf = kapp->config();
+ conf->setGroup("KSTicker");
+ bScrollConstantly = conf->readNumEntry("ScollConst", FALSE);
+
+ bAtEnd = FALSE;
+ setFont(conf->readFontEntry("Font", &ksopts->defaultFont));
+ ourFont = font(); //QFont("Courier");
+ setFont(ourFont);
+ setMinimumSize(100, 10);
+ setFixedHeight((fontMetrics().height()+fontMetrics().descent()*2)*pHeight);
+ descent = fontMetrics().descent();
+ onechar = fontMetrics().width("X");
+
+ pic->resize(width() + onechar, height());
+ pic->fill(backgroundColor());
+
+ tickStep = 2;
+ cOffset = 0;
+
+ tickRate = 30;
+
+ currentChar = 0;
+ chars = this->width() / onechar;
+
+ popup = new QPopupMenu();
+ popup->insertItem(i18n( "Font..." ), this, SLOT(fontSelector()));
+ popup->insertItem(i18n( "Scroll Rate..." ), this, SLOT(scrollRate()));
+ iScrollItem = popup->insertItem(i18n( "Scroll Constantly" ), this, SLOT(scrollConstantly()));
+ popup->setItemChecked(iScrollItem, bScrollConstantly);
+ popup->insertSeparator();
+ popup->insertItem(i18n( "Return to Normal Mode" ), this, SIGNAL(doubleClick()));
+
+ currentStr = "";
+
+ /*
+ * Tell KWM to use only minimum decurations
+ */
+ // ### FIXME: port to kwin
+ //KWM::setDecoration(winId(), KWM::tinyDecoration);
+ // KWin::setType(winId(), NET::Override);
+
+ /*
+ * Setup basic colours and background status info for ticker.
+ */
+
+ KSPainter::initOptColours();
+
+ bold = FALSE;
+ underline = FALSE;
+ italics = FALSE;
+ defbg = ksopts->backgroundColor;
+ deffg = ksopts->textColor;
+ setBackgroundColor(defbg);
+ bg = ksopts->backgroundColor;
+ fg = ksopts->textColor;
+
+}
+
+KSTicker::~KSTicker()
+{
+ killTimers();
+ delete pic;
+}
+
+void KSTicker::show()
+{
+ /*
+ * Tell KWM to use only minimum decurations
+ */
+ // ### FIXME: port to kwin
+ //KWM::setDecoration(winId(), KWM::tinyDecoration);
+ QSize size = this->size();
+ size.setHeight(QFontMetrics(font()).height()+10);
+ setFixedHeight(QFontMetrics(font()).height()+10);
+ resize(size);
+
+ QFrame::show();
+ if(currentStr.length() != 0)
+ startTicker();
+ currentChar = 0;
+ repaint(TRUE);
+}
+
+void KSTicker::hide()
+{
+ killTimers();
+ QFrame::hide();
+}
+
+void KSTicker::iconify()
+{
+ QFrame::showMinimized();
+ killTimers();
+}
+
+void KSTicker::setString(QString str)
+{
+ strlist.clear();
+ strlist.append(str);
+ repaint(TRUE);
+ startTicker();
+}
+
+void KSTicker::mergeString(QString str, QColor c)
+{
+ int num = KSPainter::colour2num(c);
+
+ if(num != -1){
+ str.prepend(QString("~%1").arg(num));
+ }
+ mergeString(str);
+
+}
+
+void KSTicker::mergeString(QString str)
+{
+ QRegExp rx("~n(\\S+)~n");
+ if(rx.search(str) >= 0){
+ int value = nickColourMaker::colourMaker()->findIdx(rx.cap(1));
+ if(value >= 0){
+ QString newText = QString("~%1\\1~c").arg(value);
+ str.replace(rx, newText);
+ }
+ }
+
+ str.append("~C ");
+ strlist.append(str);
+
+ if(strlist.count() > 5){
+ int found = 0;
+ QStringList::Iterator it = strlist.begin();
+ for(; it != strlist.end(); it++){
+ if(((*it).find(ksopts->server["global"].nick, 0, FALSE) == -1) &&
+ ((*it).find(ksopts->server["global"].altNick, 0, FALSE) == -1)){
+ strlist.remove(it);
+ found = 1;
+ break;
+ }
+ else {
+ }
+ }
+ if(found == 0){
+ strlist.pop_front();
+ }
+ }
+
+ if(bScrollConstantly == FALSE)
+ startTicker();
+
+ QStringList sep = QStringList::split(" ", stripCols(str));
+ int len = 0;
+ QString brok;
+ QStringList::Iterator it = sep.begin();
+ for(; it != sep.end(); ++it) {
+ brok += *it + " ";
+ len += (*it).length();
+ if(len >= 50){
+ brok += "\n";
+ len = 0;
+ }
+ }
+ if(brok.endsWith("\n"))
+ brok.truncate(brok.length()-1);
+
+ tipbuffer.append(brok);
+ while(tipbuffer.count() > 10)
+ tipbuffer.pop_front();
+ QString tip = tipbuffer.join("\n");
+
+// QToolTip::remove(this);
+ QToolTip::add(this, tip);
+
+
+}
+
+void KSTicker::timerEvent(QTimerEvent *)
+{
+ if((uint)currentChar >= currentStr.length()){
+ if(strlist.isEmpty()){
+ if(bScrollConstantly == TRUE){
+ currentStr = strbuffer.first();
+ strbuffer.append(strbuffer.first());
+ strbuffer.pop_front();
+ currentChar = 0;
+ }
+ else{
+ stopTicker();
+ return;
+ }
+ }
+ else {
+ currentStr = strlist.first();
+ strlist.pop_front();
+ strbuffer.append(currentStr);
+ while(strbuffer.count() > 10)
+ strbuffer.pop_front();
+ currentChar = 0;
+ }
+ }
+
+ bAtEnd = FALSE;
+ static BGMode bgmode = TransparentMode;
+
+ bitBlt(pic, -tickStep, 0, pic);
+ QPainter p(pic);
+
+ cOffset += tickStep;
+ if(cOffset >= onechar){
+ int step = 1; // Used to check if we did anything, and hence
+ // catch ~c~c type things. Set to 1 to start loop
+ while(((currentStr[currentChar] == '~') || (currentStr[currentChar] == 0x03))
+ && (step > 0)){
+ step = 1; // reset in case it's our second, or more loop.
+ QString text = currentStr.mid(currentChar);
+ QString buf = "";
+
+ if((text[step] >= '0') &&
+ (text[step] <= '9')) {
+ buf += text[step];
+ step++;
+ if((text[step] >= '0') &&
+ (text[step] <= '9')) {
+ buf += text[step];
+ step++;
+ }
+ int col = buf.toInt();
+ if((col >= 0) || (col <= KSPainter::maxcolour)){
+ fg = KSPainter::num2colour[col];
+ }
+ bg = defbg;
+ buf = "";
+ if(text[step] == ','){
+ step++;
+ if((text[step] >= '0') &&
+ (text[step] <= '9')) {
+ buf += text[step];
+ step++;
+ if((text[step] >= '0') &&
+ (text[step] <= '9')) {
+ buf += text[step];
+ step++;
+ }
+ int col = buf.toInt();
+ if((col >= 0) || (col <= KSPainter::maxcolour)){
+ bg = KSPainter::num2colour[col];
+ bgmode = OpaqueMode;
+ }
+ }
+ }
+ else{
+ bgmode = TransparentMode;
+ }
+ }
+ else {
+ switch(text[step].latin1()){
+ case 'c':
+ fg = deffg;
+ bg = defbg;
+ step++;
+ break;
+ case 'C':
+ fg = deffg;
+ bg = defbg;
+ bold = FALSE;
+ underline = FALSE;
+ italics = FALSE;
+ step++;
+ break;
+ case '#':
+ fg.setNamedColor(text.mid(step, 7));
+ step += 7;
+ break;
+ case 'b':
+ bold == TRUE ? bold = FALSE : bold = TRUE;
+ step++;
+ break;
+ case 'u':
+ underline == TRUE ? underline = FALSE : underline = TRUE;
+ step++;
+ break;
+ case 'i':
+ italics == TRUE ? italics = FALSE : italics = TRUE;
+ step++;
+ break;
+ case 'n':
+ fg = ksopts->nickForeground;
+ bg = ksopts->nickBackground;
+ step++;
+ break;
+ case 'o':
+ fg = ksopts->msgContainNick;
+ step++;
+ break;
+ case '~':
+ currentChar++; // Move ahead 1, but...
+ step = 0; // Don't loop on next ~.
+ break;
+ default:
+ if(currentStr[currentChar] == 0x03){
+ fg = deffg;
+ bg = defbg;
+ }
+ else
+ step = 0;
+ }
+ }
+ currentChar += step;
+ }
+ if((uint)currentChar >= currentStr.length()){ // Bail out if we're
+ // at the end of the string.
+ return;
+ }
+
+
+ QFont fnt = font();
+ fnt.setBold(bold);
+ fnt.setUnderline(underline);
+ fnt.setItalic(italics);
+ p.setFont(fnt);
+
+ p.setPen(fg);
+ p.setBackgroundColor(bg);
+ p.setBackgroundMode(OpaqueMode);
+ p.drawText(this->width() - cOffset + onechar, // remove -onechar.
+ this->height() / 4 + p.fontMetrics().height() / 2,
+ currentStr.mid(currentChar, 1),
+ 1);
+ currentChar++; // Move ahead to next character.
+ cOffset -= onechar; // Set offset back one.
+ }
+ p.end();
+ bitBlt(this, 0, descent, pic);
+}
+
+void KSTicker::paintEvent( QPaintEvent *)
+{
+ if(isVisible() == FALSE)
+ return;
+ bitBlt(this, 0, descent, pic);
+}
+
+void KSTicker::resizeEvent( QResizeEvent *e)
+{
+ QFrame::resizeEvent(e);
+ onechar = fontMetrics().width("X");
+ chars = this->width() / onechar;
+ killTimers();
+ QPixmap *new_pic = new QPixmap(width() + onechar, height());
+ new_pic->fill(backgroundColor());
+ bitBlt(new_pic,
+ new_pic->width() - pic->width(), 0,
+ pic, 0, 0,
+ pic->width(), pic->height(),
+ CopyROP, TRUE);
+ delete pic;
+ pic = new_pic;
+ // if(ring.length() > (uint) chars)
+ startTicker();
+}
+
+void KSTicker::closeEvent( QCloseEvent *)
+{
+ emit closing();
+ killTimers();
+ // delete this;
+}
+
+void KSTicker::startTicker()
+{
+ killTimers();
+ startTimer(tickRate);
+}
+
+void KSTicker::stopTicker()
+{
+ killTimers();
+}
+
+void KSTicker::mouseDoubleClickEvent( QMouseEvent * )
+{
+ emit doubleClick();
+}
+
+void KSTicker::mousePressEvent( QMouseEvent *e)
+{
+ if(e->button() == RightButton){
+ popup->popup(this->cursor().pos());
+ }
+ else{
+ QFrame::mousePressEvent(e);
+ }
+}
+void KSTicker::fontSelector()
+{
+ int result = KFontDialog::getFont( ourFont, true );
+ if ( result == KFontDialog::Accepted ) {
+ updateFont(ourFont);
+ }
+}
+
+void KSTicker::scrollRate()
+{
+ SpeedDialog *sd = new SpeedDialog(tickRate, tickStep);
+ sd->setLimit(5, 200, 1, onechar);
+ connect(sd, SIGNAL(stateChange(int, int)),
+ this, SLOT(setSpeed(int, int)));
+ sd->show();
+}
+
+void KSTicker::scrollConstantly()
+{
+ bScrollConstantly = !bScrollConstantly;
+ popup->setItemChecked(iScrollItem, bScrollConstantly);
+ if(bScrollConstantly == TRUE)
+ startTicker();
+ KConfig *conf = kapp->config();
+ conf->setGroup("KSTicker");
+ conf->writeEntry("ScollConst", bScrollConstantly);
+ conf->sync();
+}
+
+void KSTicker::updateFont(const QFont &font){
+ setFont(font);
+ setFixedHeight((fontMetrics().height()+fontMetrics().descent()*2)*pHeight);
+ resize(fontMetrics().width("X")*chars,
+ (fontMetrics().height()+fontMetrics().descent())*pHeight);
+ KConfig *conf = kapp->config();
+ conf->setGroup("KSTicker");
+ conf->writeEntry("Font", font);
+ conf->sync();
+
+}
+
+void KSTicker::setSpeed(int _tickRate, int _tickStep){
+ tickRate = _tickRate;
+ tickStep = _tickStep;
+ startTicker();
+}
+
+void KSTicker::speed(int *_tickRate, int *_tickStep){
+ *_tickRate = tickRate;
+ *_tickStep = tickStep;
+}
+
+void KSTicker::setBackgroundColor ( const QColor &c )
+{
+ QFrame::setBackgroundColor(c);
+ pic->fill(c);
+ bitBlt(this, 0,0, pic);
+ defbg = backgroundColor();
+ bg = backgroundColor();
+}
+
+void KSTicker::setPalette ( const QPalette & p )
+{
+ QFrame::setPalette(p);
+
+ pic->fill(backgroundColor());
+ bitBlt(this, 0,0, pic);
+ defbg = backgroundColor();
+ bg = backgroundColor();
+ deffg = backgroundColor();
+ fg = foregroundColor();
+}
+
+QString KSTicker::stripCols( QString str )
+{
+ uint i = 0;
+ QString ret;
+ for(i = 0; i < str.length(); i++){
+ if(((str[i] == '~') || (str[i] == 0x03))){
+ if((str[i+1] >= '0') &&
+ (str[i+1] <= '9')) {
+ i+=1;
+ if((str[i+1] >= '0') &&
+ (str[i+1] <= '9')) {
+ i+=1;
+ }
+ if(str[i+1] == ','){
+ i+=1;
+ if((str[i+1] >= '0') &&
+ (str[i+1] <= '9')) {
+ i+=1;
+ if((str[i+1] >= '0') &&
+ (str[i+1] <= '9')) {
+ i+=1;
+ }
+ }
+ }
+ }
+ else {
+ switch(str[i+1].latin1()){
+ case 'c':
+ case 'C':
+ case 'b':
+ case 'u':
+ case 'i':
+ case 'n':
+ case 'o':
+ i+= 1;
+ break;
+ case '~':
+ i+= 0;
+ break;
+ default:
+ ret.append(str[i]);
+ }
+ }
+ }
+ else {
+ ret.append(str[i]);
+ }
+ }
+ return ret;
+}
+#include "ksticker.moc"
diff --git a/ksirc/KSTicker/ksticker.h b/ksirc/KSTicker/ksticker.h
new file mode 100644
index 00000000..d11d8a0f
--- /dev/null
+++ b/ksirc/KSTicker/ksticker.h
@@ -0,0 +1,106 @@
+#ifndef KSTICKER_H
+#define KSTICKER_H
+
+#include <qobject.h>
+#include <qframe.h>
+#include <qstring.h>
+#include <qptrlist.h>
+#include <qpopupmenu.h>
+
+class SInfo {
+public:
+ int length;
+};
+
+class KSTicker : public QFrame
+{
+ Q_OBJECT
+
+public:
+ KSTicker(QWidget * parent=0, const char * name=0, WFlags f=0);
+ virtual ~KSTicker();
+
+ void setString(QString);
+ void mergeString(QString);
+ void mergeString(QString, QColor);
+
+ virtual void show();
+ virtual void hide();
+
+ void speed(int *, int *);
+
+ virtual void setBackgroundColor ( const QColor & );
+ virtual void setPalette ( const QPalette & p );
+
+signals:
+ void doubleClick();
+ void closing();
+
+public slots:
+ virtual void setSpeed(int, int);
+
+protected slots:
+ virtual void fontSelector();
+ virtual void scrollRate();
+ virtual void updateFont(const QFont &font);
+ virtual void scrollConstantly();
+
+protected:
+ virtual void timerEvent ( QTimerEvent * );
+ virtual void paintEvent ( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+ virtual void closeEvent( QCloseEvent * );
+ virtual void mouseDoubleClickEvent( QMouseEvent * );
+ virtual void mousePressEvent ( QMouseEvent * );
+ virtual void iconify();
+
+
+private:
+
+ QString stripCols(QString);
+
+ QStringList strlist; /* everything left to parse */
+ QStringList strbuffer; /* fifo of the last 10 lines to scroll in scroll constantly mode */
+ QStringList tipbuffer; /* 5 lines for the tooltip */
+ QString currentStr; /* the string we are currently parsing */
+
+ QFont ourFont;
+
+ int onechar;
+ int chars;
+ int descent;
+
+ int tickStep;
+ int cOffset;
+
+ int tickRate;
+
+ int pHeight;
+
+ int currentChar;
+
+ void startTicker();
+ void stopTicker();
+
+ bool bScrollConstantly;
+ int iScrollItem;
+ bool bAtEnd;
+
+ QPixmap *pic;
+
+ QPopupMenu *popup;
+
+ /*
+ * Drawing settings and variables
+ */
+ bool bold;
+ bool underline;
+ bool italics;
+ QColor defbg;
+ QColor deffg;
+ QColor bg;
+ QColor fg;
+};
+
+#endif // KSTICKER_H
+
diff --git a/ksirc/KSTicker/ksttest.cpp b/ksirc/KSTicker/ksttest.cpp
new file mode 100644
index 00000000..81373bd8
--- /dev/null
+++ b/ksirc/KSTicker/ksttest.cpp
@@ -0,0 +1,93 @@
+#include <kapplication.h>
+#include <kconfig.h>
+#include <qapplication.h>
+#include <qsocketnotifier.h>
+#include <qregexp.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+#include <unistd.h>
+
+#include "ksticker.h"
+#include "ksttest.h"
+#include "../ksopts.h"
+
+KConfig *kConfig;
+
+StdInTicker::StdInTicker()
+ : KSTicker()
+{
+ kConfig->setGroup("defaults");
+ QFont font;
+ font = kConfig->readFontEntry("font");
+ font.setFixedPitch(TRUE);
+ setFont(font);
+ setSpeed(kConfig->readNumEntry("tick", 30),
+ kConfig->readNumEntry("step", 3));
+}
+
+StdInTicker::~StdInTicker()
+{
+ int tick, step;
+ speed(&tick, &step);
+ kConfig->setGroup("defaults");
+ kConfig->writeEntry("font", KSTicker::font());
+ kConfig->writeEntry("tick", tick);
+ kConfig->writeEntry("step", step);
+ kConfig->writeEntry("text", colorGroup().text() );
+ kConfig->writeEntry("background", colorGroup().background() );
+ kConfig->sync();
+}
+
+void StdInTicker::readsocket(int socket)
+{
+ char buf[1024];
+ int bytes = read(socket, buf, 1024);
+ if(bytes){
+ QCString str(buf, bytes);
+ str.replace(QRegExp("\n"), " // ");
+ mergeString(str);
+ }
+}
+
+void StdInTicker::end()
+{
+ delete this;
+}
+
+void StdInTicker::closeEvent ( QCloseEvent *e )
+{
+ KSTicker::closeEvent(e);
+ delete this;
+}
+
+
+int main(int argc, char **argv){
+ KAboutData aboutData( "ksirc", I18N_NOOP("KSirc"),
+ "2.0.0", "", KAboutData::License_Artistic,
+ I18N_NOOP("(c) 1997-2002, Andrew Stanley-Jones"));
+ aboutData.addAuthor("Andrew Stanley-Jones",I18N_NOOP("Original Author"), "asj-ksirc@cban.com");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+
+ KApplication a(argc, argv);
+
+ kConfig = a.config();
+
+ // Options
+ KSOptions opts;
+ opts.load();
+
+ StdInTicker *kst = new StdInTicker();
+ QSocketNotifier *sn = new QSocketNotifier(0, QSocketNotifier::Read);
+ QObject::connect(sn, SIGNAL(activated(int)),
+ kst, SLOT(readsocket(int)));
+ QObject::connect(kst, SIGNAL(doubleClick()), kst, SLOT(end()));
+ QObject::connect(kst, SIGNAL(closing()), kst, SLOT(end()));
+ a.setMainWidget(kst);
+ kst->show();
+ return a.exec();
+}
+
+#include "ksttest.moc"
+
diff --git a/ksirc/KSTicker/ksttest.h b/ksirc/KSTicker/ksttest.h
new file mode 100644
index 00000000..9d166b66
--- /dev/null
+++ b/ksirc/KSTicker/ksttest.h
@@ -0,0 +1,24 @@
+#ifndef _KST_STD_IN_
+#define _KST_STD_IN_
+
+
+#include "ksticker.h"
+
+class StdInTicker : public KSTicker
+{
+ Q_OBJECT
+public:
+ StdInTicker();
+ ~StdInTicker();
+
+protected:
+ void closeEvent ( QCloseEvent * );
+
+public slots:
+ void readsocket(int socket);
+ void end();
+
+};
+
+#endif
+
diff --git a/ksirc/KSTicker/libksticker.c b/ksirc/KSTicker/libksticker.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/ksirc/KSTicker/libksticker.c
diff --git a/ksirc/KSTicker/speeddialog.cpp b/ksirc/KSTicker/speeddialog.cpp
new file mode 100644
index 00000000..eb1ff462
--- /dev/null
+++ b/ksirc/KSTicker/speeddialog.cpp
@@ -0,0 +1,61 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: speeddialog.cpp
+ Last generated: Sun Dec 21 08:52:31 1997
+
+ *********************************************************************/
+
+#include <klocale.h>
+
+#include "speeddialog.h"
+
+SpeedDialog::SpeedDialog
+(
+ int tick,
+ int step,
+ QWidget* parent,
+ const char* name
+)
+ : speeddialogData( parent, name )
+{
+ setCaption(i18n( "Speed Setup") );
+ connect(sliderTick, SIGNAL(valueChanged(int)),
+ lcdTick, SLOT(display(int)));
+ connect(sliderStep, SIGNAL(valueChanged(int)),
+ lcdStep, SLOT(display(int)));
+ lcdTick->display(tick);
+ sliderTick->setValue(tick);
+ lcdStep->display(step);
+ sliderStep->setValue(step);
+}
+
+
+SpeedDialog::~SpeedDialog()
+{
+}
+
+
+void SpeedDialog::updateTick(int tick)
+{
+ emit stateChange(tick, sliderStep->value());
+}
+
+void SpeedDialog::updateStep(int step)
+{
+ emit stateChange(sliderTick->value(), step);
+}
+
+void SpeedDialog::terminate()
+{
+ delete this;
+}
+
+void SpeedDialog::setLimit(int tmin, int tmax, int smin, int smax)
+{
+ sliderTick->setRange(tmin, tmax);
+ sliderStep->setRange(smin, smax);
+}
+
+#include "speeddialog.moc"
diff --git a/ksirc/KSTicker/speeddialog.dlg b/ksirc/KSTicker/speeddialog.dlg
new file mode 100644
index 00000000..00e26c67
--- /dev/null
+++ b/ksirc/KSTicker/speeddialog.dlg
@@ -0,0 +1,117 @@
+DlgEdit:v1.2:Dialog:
+Dialog {
+ ClassHeader {speeddialog.h}
+ ClassSource {speeddialog.cpp}
+ ClassName {SpeedDialog}
+ DataHeader {speeddialogData.h}
+ DataSource {speeddialogData.cpp}
+ DataName {speeddialogData}
+ WindowBaseClass {QDialog}
+ IsModal {FALSE}
+ WindowFlags {0}
+}
+WidgetLayout {
+InitialPos {-1 -1}
+Size {270 120}
+MinSize {0 0}
+MaxSize {32767 32767}
+Grid {10}
+
+Slider {
+ Orientation {Horizontal}
+ MinValue {10}
+ MaxValue {200}
+ Initial {30}
+ LineStep {10}
+ PageStep {50}
+ Tracking {TRUE}
+ Tickmarks {NoMarks}
+ TickInterval {0}
+ Rect {90 10 100 20}
+ Name {Slider_1}
+ Variable {sliderTick}
+ Signal {[Protected] valueChanged --> updateTick (int)}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+Slider {
+ Orientation {Horizontal}
+ MinValue {1}
+ MaxValue {10}
+ Initial {3}
+ LineStep {1}
+ PageStep {2}
+ Tracking {TRUE}
+ Tickmarks {NoMarks}
+ TickInterval {0}
+ Rect {90 45 100 20}
+ Name {Slider_2}
+ Variable {sliderStep}
+ Signal {[Protected] valueChanged --> updateStep (int)}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+LCDNumber {
+ Digits {3}
+ SmallDecimalPoint {FALSE}
+ Mode {Dec}
+ SegmentStyle {Outline}
+ Style {33}
+ Rect {200 5 60 30}
+ Name {LCDNumber_1}
+ Variable {lcdTick}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+LCDNumber {
+ Digits {3}
+ SmallDecimalPoint {FALSE}
+ Mode {Dec}
+ SegmentStyle {Outline}
+ Style {33}
+ Rect {200 40 60 30}
+ Name {LCDNumber_2}
+ Variable {lcdStep}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+Label {
+ Text {Tick Interval}
+ AutoResize {FALSE}
+ Margin {-1}
+ Rect {10 5 80 30}
+ Name {Label_1}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+Label {
+ Text {Step Size}
+ AutoResize {FALSE}
+ Margin {-1}
+ Rect {10 40 80 30}
+ Name {Label_2}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {FALSE}
+ Text {&Close}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {140 80 120 30}
+ Name {PushButton_2}
+ Signal {[Protected] pressed --> terminate ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+Layout {None}
+}
diff --git a/ksirc/KSTicker/speeddialog.h b/ksirc/KSTicker/speeddialog.h
new file mode 100644
index 00000000..4efdb2a8
--- /dev/null
+++ b/ksirc/KSTicker/speeddialog.h
@@ -0,0 +1,42 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: speeddialog.h
+ Last generated: Sun Dec 21 08:52:31 1997
+
+ *********************************************************************/
+
+#ifndef SpeedDialog_included
+#define SpeedDialog_included
+
+#include "speeddialogData.h"
+
+class SpeedDialog : public speeddialogData
+{
+ Q_OBJECT
+
+public:
+
+ SpeedDialog
+ (
+ int tick,
+ int step,
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~SpeedDialog();
+ void setLimit(int, int, int, int);
+
+signals:
+ void stateChange(int, int);
+
+protected slots:
+ virtual void updateTick(int);
+ virtual void updateStep(int);
+ virtual void terminate();
+
+
+};
+#endif // SpeedDialog_included
diff --git a/ksirc/KSTicker/speeddialogData.cpp b/ksirc/KSTicker/speeddialogData.cpp
new file mode 100644
index 00000000..0dbb1c0b
--- /dev/null
+++ b/ksirc/KSTicker/speeddialogData.cpp
@@ -0,0 +1,107 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: speeddialogData.cpp
+ Last generated: Sun Dec 21 09:13:46 1997
+
+ DO NOT EDIT!!! This file will be automatically
+ regenerated by qtarch. All changes will be lost.
+
+ *********************************************************************/
+
+#include "speeddialogData.h"
+
+#include <qlabel.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+#include <qlayout.h>
+#include <kdialog.h>
+
+speeddialogData::speeddialogData ( QWidget* parent, const char* name )
+ :QDialog( parent, name, 0 )
+{
+ QGridLayout *grid = new QGridLayout( this, 3, 2 , KDialog::marginHint(), KDialog::spacingHint());
+ sliderTick = new QSlider( this, "Slider_1" );
+ grid->addWidget( sliderTick, 0, 1 );
+ connect( sliderTick, SIGNAL(valueChanged(int)), SLOT(updateTick(int)) );
+ sliderTick->setOrientation( QSlider::Horizontal );
+ sliderTick->setRange( 10, 200 );
+ sliderTick->setSteps( 10, 50 );
+ sliderTick->setValue( 30 );
+ sliderTick->setTracking( TRUE );
+ sliderTick->setTickmarks( QSlider::NoMarks );
+ sliderTick->setTickInterval( 0 );
+
+ sliderStep = new QSlider( this, "Slider_2" );
+ grid->addWidget( sliderStep, 1, 1 );
+
+ connect( sliderStep, SIGNAL(valueChanged(int)), SLOT(updateStep(int)) );
+ sliderStep->setOrientation( QSlider::Horizontal );
+ sliderStep->setRange( 1, 10 );
+ sliderStep->setSteps( 1, 2 );
+ sliderStep->setValue( 3 );
+ sliderStep->setTracking( TRUE );
+ sliderStep->setTickmarks( QSlider::NoMarks );
+ sliderStep->setTickInterval( 0 );
+
+ lcdTick = new QLCDNumber( this, "LCDNumber_1" );
+ lcdTick->setFrameStyle( 33 );
+ lcdTick->setSmallDecimalPoint( FALSE );
+ lcdTick->setNumDigits( 3 );
+ lcdTick->setMode( QLCDNumber::DEC );
+ lcdTick->setSegmentStyle( QLCDNumber::Outline );
+ grid->addWidget( lcdTick, 0, 2 );
+
+ lcdStep = new QLCDNumber( this, "LCDNumber_2" );
+ lcdStep->setFrameStyle( 33 );
+ lcdStep->setSmallDecimalPoint( FALSE );
+ lcdStep->setNumDigits( 3 );
+ lcdStep->setMode( QLCDNumber::DEC );
+ lcdStep->setSegmentStyle( QLCDNumber::Outline );
+ grid->addWidget( lcdStep, 1, 2 );
+
+
+ QLabel* dlgedit_Label_1;
+ dlgedit_Label_1 = new QLabel( this, "Label_1" );
+ dlgedit_Label_1->setText( i18n("Tick interval:") );
+ dlgedit_Label_1->setAlignment( 289 );
+ dlgedit_Label_1->setMargin( -1 );
+ grid->addWidget( dlgedit_Label_1, 0, 0 );
+
+
+ QLabel* dlgedit_Label_2;
+ dlgedit_Label_2 = new QLabel( this, "Label_2" );
+ dlgedit_Label_2->setText( i18n("Step size:") );
+ dlgedit_Label_2->setAlignment( 289 );
+ dlgedit_Label_2->setMargin( -1 );
+ grid->addWidget( dlgedit_Label_2, 1, 0 );
+
+
+ QPushButton* dlgedit_PushButton_2;
+ dlgedit_PushButton_2 = new KPushButton( KStdGuiItem::close(), this, "PushButton_2" );
+ connect( dlgedit_PushButton_2, SIGNAL(pressed()), SLOT(terminate()) );
+// dlgedit_PushButton_2->setAutoRepeat( FALSE );
+// dlgedit_PushButton_2->setAutoResize( FALSE );
+ grid->addWidget( dlgedit_PushButton_2, 2, 2 );
+
+ //resize( 270,120 );
+ setMinimumSize( 0, 0 );
+ setMaximumSize( 32767, 32767 );
+}
+
+
+speeddialogData::~speeddialogData()
+{
+}
+void speeddialogData::updateTick(int)
+{
+}
+void speeddialogData::updateStep(int)
+{
+}
+void speeddialogData::terminate()
+{
+}
+#include "speeddialogData.moc"
diff --git a/ksirc/KSTicker/speeddialogData.h b/ksirc/KSTicker/speeddialogData.h
new file mode 100644
index 00000000..6e9f06f9
--- /dev/null
+++ b/ksirc/KSTicker/speeddialogData.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: speeddialogData.h
+ Last generated: Sun Dec 21 09:13:46 1997
+
+ DO NOT EDIT!!! This file will be automatically
+ regenerated by qtarch. All changes will be lost.
+
+ *********************************************************************/
+
+#ifndef speeddialogData_included
+#define speeddialogData_included
+
+#include <qdialog.h>
+#include <qslider.h>
+#include <qlcdnumber.h>
+
+class speeddialogData : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ speeddialogData
+ (
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~speeddialogData();
+
+public slots:
+
+
+protected slots:
+
+ virtual void terminate();
+ virtual void updateTick(int);
+ virtual void updateStep(int);
+
+protected:
+ QSlider* sliderTick;
+ QSlider* sliderStep;
+ QLCDNumber* lcdTick;
+ QLCDNumber* lcdStep;
+
+};
+
+#endif // speeddialogData_included
diff --git a/ksirc/Makefile.am b/ksirc/Makefile.am
new file mode 100644
index 00000000..103472c1
--- /dev/null
+++ b/ksirc/Makefile.am
@@ -0,0 +1,146 @@
+
+KDE_CXXFLAGS = $(USE_RTTI) $(USE_EXCEPTIONS)# -UQT_NO_ASCII_CAST
+
+# set the include path for X, qt and KDE
+INCLUDES= -IKSOpenkSirc -IKSPrefs $(all_includes)
+
+# claim, which subdirectories you want to install
+SUBDIRS = KSTicker KSProgress KSPrefs KSOpenkSirc img icons
+
+METASOURCES = AUTO
+
+check_PROGRAMS = testview dccMgrTest
+
+testview_SOURCES = kstextviewtest.cpp
+testview_LDADD = kstextview.lo dccNew.lo dccNewbase.lo alistbox.lo objFinder.lo ksopts.lo nickColourMaker.lo $(LIB_KUTILS) $(LIB_KDEUI)
+testview_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+dccMgrTest_SOURCES = dccMgrTest.cpp
+dccMgrTest_LDADD = dccManager.lo dccManagerbase.lo dccNew.lo dccNewbase.lo alistbox.lo objFinder.lo ksopts.lo nickColourMaker.lo $(LIB_KUTILS) $(LIB_KDEUI)
+dccMgrTest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = ksirc.la
+
+noinst_PROGRAMS = getdate
+
+# Which sources should be compiled for ksirc.
+
+ksirc_la_SOURCES = \
+ toplevel.cpp \
+ charSelector.cpp \
+ chanButtons.cpp \
+ ksirc.cpp \
+ alistbox.cpp \
+ ahistlineedit.cpp \
+ iocontroller.cpp \
+ NewWindowDialog.cpp \
+ messageReceiver.cpp \
+ ioBroadcast.cpp \
+ ksircprocess.cpp \
+ servercontroller.cpp \
+ FilterRuleWidget.ui FilterRuleEditor.cpp \
+ ioDiscard.cpp \
+ ioDCC.cpp \
+ ioLAG.cpp \
+ ioNotify.cpp \
+ ssfeprompt.cpp ssfepromptdata.cpp \
+ usercontrolmenu.cpp \
+ baserules.cpp \
+ chanparser.cpp \
+ objFinder.cpp \
+ displayMgrSDI.cpp \
+ displayMgrMDI.cpp \
+ mditoplevel.cpp \
+ ksopts.cpp \
+ topic.cpp \
+ ksview.cpp \
+ logfile.cpp \
+ kstextview.cpp \
+ colorpicker.cpp \
+ ksparser.cpp \
+ dccManagerbase.ui \
+ dccManager.cpp \
+ dccToplevel.cpp \
+ dockservercontroller.cpp \
+ nickColourMaker.cpp \
+ dccNewbase.ui \
+ dccNew.cpp
+
+# the library search path
+ksirc_la_LDFLAGS = $(all_libraries) -module -avoid-version
+ksirc_la_COMPILE_FIRST = cdate.h
+
+all_ksirc_libraries = \
+ ./KSPrefs/libksprefs.la \
+ ./KSProgress/libksprogress.la \
+ ./KSOpenkSirc/libksopenksirc.la \
+ ./KSTicker/libksticker.la \
+ $(LIB_KIO) $(LIBDL)
+
+# the libraries to link against. Be aware of the order. First the libraries,
+# that depend on the following ones.
+ksirc_la_LIBADD = $(all_ksirc_libraries)
+
+kdoc:
+ kdoc -ddoc ksirc *.h
+
+getdate_SOURCES = getdate.c
+
+cdate.h: getdate
+ ./getdate > cdate.h
+
+# this option you can leave out. Just, if you use "make dist", you need it
+#
+# DSIRC is on the bottom so make dist includes it!!!!!!!!!
+#
+noinst_HEADERS = \
+ FilterRuleEditor.h \
+ control_message.h \
+ FilterRuleWidget.h \
+ messageReceiver.h \
+ ioBroadcast.h \
+ ioDCC.h \
+ usercontrolmenu.h \
+ ioDiscard.h \
+ ahistlineedit.h \
+ iocontroller.h \
+ servercontroller.h \
+ alistbox.h \
+ chanparser.h \
+ toplevel.h \
+ ksircprocess.h \
+ cdate.h \
+ ioLAG.h \
+ ioNotify.h \
+ ssfeprompt.h \
+ ssfepromptdata.h \
+ objFinder.h \
+ baserules.h \
+ displayMgr.h \
+ displayMgrSDI.h \
+ NewWindowDialog.h \
+ ksopts.h \
+ ksview.h \
+ boundscheckingarray.h \
+ ksparser.h \
+ dccManager.h \
+ dccToplevel.h \
+ dockservercontroller.h \
+ dccNew.h
+
+messages: rc.cpp
+ $(EXTRACTRC) KSOpenkSirc/*.ui >> rc.cpp
+ $(EXTRACTRC) KSPrefs/*.ui >> rc.cpp
+ $(XGETTEXT) *.cpp */*.cpp -o $(podir)/ksirc.pot
+
+bin_SCRIPTS = dsirc
+
+xdg_apps_DATA = ksirc.desktop
+
+misc_DATA = ksirc.pl filters.pl autodcc.pl sirc.help.gz relnotes eventsrc
+miscdir = $(kde_datadir)/ksirc
+
+conf_DATA = ksircrc
+confdir = $(kde_confdir)
diff --git a/ksirc/NewWindowDialog.cpp b/ksirc/NewWindowDialog.cpp
new file mode 100644
index 00000000..c4af16f1
--- /dev/null
+++ b/ksirc/NewWindowDialog.cpp
@@ -0,0 +1,73 @@
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <klineedit.h>
+#include "NewWindowDialog.h"
+
+NewWindowDialog::NewWindowDialog(const KSircChannel &channelInfo, QWidget * parent, const char * name)
+ : KDialogBase(parent, name, true, i18n("New Window For"), Ok|Cancel, Ok, true),
+ m_channelInfo(channelInfo)
+{
+ QHBox * w = makeHBoxMainWidget();
+
+ QLabel * l = new QLabel(i18n("C&hannel/Nick:"), w);
+
+ m_combo = new KHistoryCombo(w);
+ m_combo->setFocus();
+
+ // we don't need duplicated channel into the list
+ m_combo->setDuplicatesEnabled( false );
+
+ l->setBuddy(m_combo);
+
+ QLabel * l2 = new QLabel(i18n("&Key:"), w);
+ m_le = new KLineEdit(w);
+ m_le->setEnabled(false);
+ l2->setBuddy(m_le);
+
+ connect(
+ m_combo, SIGNAL(activated(const QString &)),
+ m_combo, SLOT(addToHistory(const QString &)));
+ connect( m_combo->lineEdit(), SIGNAL(textChanged ( const QString & )),
+ this, SLOT( slotTextChanged( const QString &)));
+
+ KConfig *kConfig = kapp->config();
+ KConfigGroupSaver saver(kConfig, "Recent");
+ m_combo->setHistoryItems(kConfig->readListEntry("Channels"));
+ slotTextChanged( m_combo->lineEdit()->text());
+}
+
+NewWindowDialog::~NewWindowDialog()
+{
+ KConfig *kConfig = kapp->config();
+ KConfigGroupSaver saver(kConfig, "Recent");
+ kConfig->writeEntry("Channels", m_combo->historyItems());
+}
+
+void NewWindowDialog::slotTextChanged( const QString &text)
+{
+ enableButtonOK( !text.isEmpty() );
+
+ if(text[0] == "#" || text[0] == "&")
+ m_le->setEnabled(true);
+ else
+ m_le->setEnabled(false);
+}
+
+
+ void
+NewWindowDialog::slotOk()
+{
+ m_channelInfo.setChannel(m_combo->lineEdit()->text().lower());
+ if(m_le->isEnabled())
+ m_channelInfo.setKey(m_le->text());
+ emit(openTopLevel(m_channelInfo));
+ KDialogBase::slotOk();
+}
+
+#include "NewWindowDialog.moc"
+
diff --git a/ksirc/NewWindowDialog.h b/ksirc/NewWindowDialog.h
new file mode 100644
index 00000000..37449e0e
--- /dev/null
+++ b/ksirc/NewWindowDialog.h
@@ -0,0 +1,35 @@
+#ifndef NEW_WINDOW_DIALOG_H
+#define NEW_WINDOW_DIALOG_H
+
+#include <kdialogbase.h>
+
+#include "ksircchannel.h"
+
+class KHistoryCombo;
+class KLineEdit;
+
+class NewWindowDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+
+ NewWindowDialog(const KSircChannel &, QWidget * parent = 0, const char * name = 0);
+ ~NewWindowDialog();
+
+ protected slots:
+
+ void slotOk();
+ void slotTextChanged( const QString &);
+ signals:
+
+ void openTopLevel(const KSircChannel &);
+
+ private:
+
+ KHistoryCombo * m_combo;
+ KLineEdit * m_le;
+ KSircChannel m_channelInfo;
+};
+
+#endif
diff --git a/ksirc/advfollow.pl b/ksirc/advfollow.pl
new file mode 100644
index 00000000..c7254641
--- /dev/null
+++ b/ksirc/advfollow.pl
@@ -0,0 +1,125 @@
+#
+#
+&print("*** Loading advance follow...");
+
+@K_VAL_COL = (0,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
+
+print "*** Using colours:";
+foreach (@K_VAL_COL) {
+ print "~$_ $_";
+}
+print "\n";
+
+%K_FOLLOW = ();
+
+$KADV_ON = 1;
+
+sub sum_nick {
+ my $n = shift;
+ my $sum = 0;
+
+ $n =~ s/^(.*)[-_|].*$/$1/;
+
+ foreach (split(//, $n)) {
+ $sum += ord;
+ }
+ return $sum;
+
+}
+
+sub hook_ksircadvfollow {
+ if($_[0] =~ /<~n(\w+)~c>/){
+ my $n = $1;
+ return if $n eq $nick;
+ if(!defined($K_FOLLOW{$n})){
+ $K_FOLLOW{$n} = $K_VAL_COL [ &sum_nick($n) % $#K_VAL_COL];
+ }
+ my $c = $K_FOLLOW{$n};
+ $_[0] =~ s/<~n\w+~c>/<~$c$n~c>/;
+ }
+ elsif ($_[0] =~ /~\* (\w+) \w+/) {
+ my $n = $1;
+ return if $n eq $nick;
+ if(!defined($K_FOLLOW{$n})){
+ $K_FOLLOW{$n} = $K_VAL_COL [ &sum_nick($n) % $#K_VAL_COL];
+ }
+ my $c = $K_FOLLOW{$n};
+ $_[0] =~ s/\* \w+ (\w+)/\* ~$c$n~c $1/;
+ }
+}
+addhook("print", "ksircadvfollow");
+
+$K_ADV_LENGTH = 0;
+
+sub kadv_save {
+ &kadv_load();
+ return if($K_ADV_LENGTH == (scalar %K_FOLLOW));
+
+ open(SAVE, ">$ENV{HOME}/.adv_follow") || return;
+ my $n, $v;
+ while(($n, $v) = each %K_FOLLOW){
+ print SAVE "$n\t$v\n";
+ }
+ close SAVE;
+ $K_ADV_LENGTH = scalar %K_FOLLOW;
+}
+
+sub kadv_load {
+ open(SAVE, "<$ENV{HOME}/.adv_follow") || return;
+ while(<SAVE>){
+ chomp;
+ my ($n, $v) = split(/\t/, $_);
+ if(!defined($K_FOLLOW{$n})){
+ $K_FOLLOW{$n} = $v;
+ }
+
+ }
+ close SAVE;
+}
+
+&kadv_load();
+sub kadv_timer_save {
+ &timer(300, "&kadv_timer_save()", 324325);
+ &kadv_save();
+}
+&timer(300, "&kadv_timer_save()", 324325);
+
+
+sub cmd_afflush {
+ %K_FOLLOW = ();
+}
+
+addhelp("afflush", "Usaage: afflush\nDelete all coloured nicks");
+addcmd("afflush");
+
+
+sub cmd_afnick {
+ &getarg;
+ my $n = $newarg;
+ &getarg;
+ if($newarg){
+ $K_FOLLOW{$n} = $newarg;
+ }
+ else {
+ $K_FOLLOW{$n} = $K_VAL_COL [int (rand scalar (@K_VAL_COL))];
+ }
+}
+
+addhelp("afnick", "Usage: afnick nick <col>\nResets the colour for nick. If col is specefied it is set to col. Random otherwise.");
+addcmd("afnick");
+
+sub cmd_afoff {
+ remhook("print", "ksircadvfollow");
+}
+addhelp("afoff", "Usage: afoff\nTurn off advance follow");
+addcmd("afoff");
+
+sub cmd_afon {
+ addhook("print", "ksircadvfollow");
+}
+addhelp("afon", "Usage: afon\nTurn on advange follow");
+addcmd("afon");
+
+print "*** Advance follow Loaded\n";
+print "*** New commands: /afflush /afnick /afoff /afon\n";
+
diff --git a/ksirc/ahistlineedit.cpp b/ksirc/ahistlineedit.cpp
new file mode 100644
index 00000000..72e6da35
--- /dev/null
+++ b/ksirc/ahistlineedit.cpp
@@ -0,0 +1,437 @@
+/************************************************************************
+
+ AHistLineEdit
+
+ $$Id$$
+
+ An extended KLineEdit with history scroll back and focus controls.
+
+ Function:
+
+ Each time a line is saved, to a max of 256, when the user hits enter.
+ The arrow keys are used to scroll through the history list, rolling
+ around at the end.
+
+ When focus is gained or lost it emits the appropriate signals. This
+ is so the toplevel can track who has focus.
+
+ signals:
+ gotFocus: duh!
+
+ lostFocus: no shit sherlock
+
+ Implementation:
+
+ protected:
+
+ keyPressEvent: Filter key presses looking for up arrow, down
+ arrow or enter. UpArrow saves the current line at the end then
+ scroll. No more processing. DownArrow does the opposite. Enter
+ saves the line, but then passes on the event for normal
+ processing.
+
+ focusInEvent: emits needed signal
+ focusOutEvent: ditto
+
+ Variables:
+ QStrList: current list of history items.
+ current: what I think is the current list item.
+
+*************************************************************************/
+
+
+#include "ahistlineedit.h"
+#include "colorpicker.h"
+#include "ksopts.h"
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qpen.h>
+#include <qpainter.h>
+#include <kdebug.h>
+#include <kstdaction.h>
+#include <kstdaccel.h>
+#include <kshortcut.h>
+
+
+aHistLineEdit::aHistLineEdit(QWidget *parent, const char *name)
+ : QTextEdit(parent, name)
+{
+
+ m_drawrect = false;
+ m_height = 0;
+ current = hist.append(QString::null); // Set the current as blank
+ setWrapPolicy(QTextEdit::AtWordOrDocumentBoundary);
+ setVScrollBarMode( AlwaysOff );
+ setHScrollBarMode( AlwaysOff );
+
+// connect( this, SIGNAL( returnPressed () ), this, SLOT( slotReturn() ) );
+ connect( this, SIGNAL( textChanged () ), this, SLOT( slotMaybeResize() ) );
+
+ setTabChangesFocus(true);
+ setTextFormat(PlainText);
+
+ slotMaybeResize(); // setup initial size.
+
+ setLineWidth(2);
+
+}
+
+void aHistLineEdit::setCursorPosition ( int index )
+{
+ QTextEdit::setCursorPosition(0, index);
+}
+
+int aHistLineEdit::cursorPosition() const
+{
+ int par, index;
+ QTextEdit::getCursorPosition(&par, &index);
+ return index;
+}
+
+void aHistLineEdit::slotMaybeResize()
+{
+/*
+ if(QTextEdit::text().contains("\n")){
+ setText(text());
+ setCursorPosition(text().length());
+ }
+*/
+
+ if(text().length() > IRC_SAFE_MAX_LINE){
+ if(m_drawrect == false){
+ m_drawrect = true;
+ repaint();
+ }
+ }
+ else {
+ if(m_drawrect == true){
+ m_drawrect = false;
+ repaint();
+ }
+ }
+
+ QFontMetrics metrics( currentFont() );
+ // int h = metrics.height() * lines();
+ int h = metrics.lineSpacing() * lines()+8;
+ // only grow if we are less than 1/4 the size of the toplevel
+ if(h > (topLevelWidget()->height() >> 2)) {
+ if(this != topLevelWidget()) {
+ h = topLevelWidget()->height() >> 2;
+ setVScrollBarMode( Auto );
+ }
+ }
+ else {
+ setVScrollBarMode( AlwaysOff );
+ }
+ if(h != m_height){
+ m_height = h;
+ QSize s = size();
+ s.setHeight(h);
+ resize(s);
+ setFixedHeight( h );
+ QLayout *l = topLevelWidget()->layout();
+ if(l){
+ l->invalidate();
+ l->activate();
+ }
+ emit resized();
+ }
+}
+
+void aHistLineEdit::keyPressEvent( QKeyEvent *e )
+{
+ bool accept = true;
+ bool ignore = false;
+ bool callKeyPressEvent = false;
+
+// kdDebug(5008) << "Got key: " << e->text() << "/" << e->key() << "-" << e->state() << endl;
+
+ if ( ! (e->key() == Key_Tab || e->key() == Key_Shift || e->state() == ShiftButton || e->key() == 0)) {
+// kdDebug(5008) << "Sending notTab() " << e->text() << endl;
+ emit notTab();
+ }
+
+ // those keycodes correspond to the ones in ksirc.pl in sub hook_fixcolours
+ if ( e->state() == ControlButton ) {
+ QString s = text();
+ int curPos = cursorPosition();
+ switch ( e->key() ) {
+ case Key_K:
+ if ( ksopts->colorPicker )
+ ColourPickerPopUp();
+ else
+ {
+ s.insert( cursorPosition(), 0x03 );
+ setText(s);
+ setCursorPosition(curPos + 1);
+ }
+ break;
+ case Key_I:
+ s.insert( cursorPosition(), "~i");
+ setText(s);
+ setCursorPosition(curPos + 2);
+ break;
+ case Key_Return:
+ case Key_Enter:
+ doEnterKey();
+ callKeyPressEvent = false;
+ break;
+ default:
+ accept = false;
+ ignore = false;
+ callKeyPressEvent = true;
+ }
+ }
+ else if(e->state() == 0){
+ switch(e->key()){
+ case Key_Return:
+ case Key_Enter:
+ doEnterKey();
+ callKeyPressEvent = false;
+ break;
+ case Key_Up:
+ if(ksopts->oneLineEntry){
+ if ((*current) != text()) { // change in hist <-> text() then save text
+ *current = text();
+ }
+ if (current == hist.begin()) { // if at begin of list then wrap around
+ current = hist.fromLast();
+ } else --current; // previous entry
+ setText(*current);
+ setCursorPosition((*current).length());
+ break;
+ }
+ case Key_Down:
+ if(ksopts->oneLineEntry){
+ if ((*current) != text()) { // change in hist <-> text() then save text
+ *current = text();
+ }
+ if (current == hist.fromLast()) { // if at end of list then wrap around
+ current = hist.begin();
+ } else ++current; // next entry
+ setText(*current);
+ setCursorPosition((*current).length());
+ break;
+ }
+ default:
+ accept = false;
+ ignore = false;
+ callKeyPressEvent = true;
+ }
+ }
+ // QLineEdit falsely converts Alt+C to the character 'c', so to work around
+ // this, we just don't pass any Alt+? key on to the keyPressEvent() method.
+ else if (e->state() == AltButton) {
+ switch(e->key()){
+ case Key_Return:
+ case Key_Enter:
+ doEnterKey();
+ callKeyPressEvent = false;
+ break;
+ case Key_Up:
+ if ((*current) != text()) { // change in hist <-> text() then save text
+ *current = text();
+ }
+ if (current == hist.begin()) { // if at begin of list then wrap around
+ current = hist.fromLast();
+ } else --current; // previous entry
+ setText(*current);
+ setCursorPosition((*current).length());
+ break;
+ case Key_Down:
+ if ((*current) != text()) { // change in hist <-> text() then save text
+ *current = text();
+ }
+ if (current == hist.fromLast()) { // if at end of list then wrap around
+ current = hist.begin();
+ } else ++current; // next entry
+ setText(*current);
+ setCursorPosition((*current).length());
+ break;
+ default:
+ accept = false;
+ callKeyPressEvent = true;
+ }
+ }
+ else if (e->state() == ShiftButton){
+ switch(e->key()){
+ case Key_Return:
+ case Key_Enter:
+ doEnterKey();
+ callKeyPressEvent = false;
+ break;
+ default:
+ accept = false;
+ ignore = false;
+ callKeyPressEvent = true;
+ }
+ }
+ else {
+ switch(e->key()){
+ case Key_Return:
+ case Key_Enter:
+ doEnterKey();
+ callKeyPressEvent = false;
+ break;
+ default:
+ accept = false;
+ ignore = false;
+ callKeyPressEvent = true;
+
+ }
+ }
+
+// kdDebug(5008) << "Accept: " << accept << " Ignore: " << ignore << " callKPE: " << callKeyPressEvent << endl;
+ if ( accept ) {
+ e->accept();
+ }
+ else {
+ if ( ignore ) {
+ e->ignore();
+ }
+ else {
+ if ( callKeyPressEvent ) {
+ QTextEdit::keyPressEvent(e);
+ }
+ }
+ }
+}
+
+bool aHistLineEdit::processKeyEvent( QKeyEvent *e )
+{
+ /*
+ * Only put key sequences in here you
+ * want us to ignore and to pass upto
+ * parent widgets for handling
+ */
+
+ bool eat = false;
+
+// kdDebug(5008) << "Key: " << KShortcut( KKey( e ) ).toString() << " StdAccel: " << KStdAccel::paste().toString() << endl;
+
+ if ( KStdAccel::paste().contains(KKey( e ))) {
+ e->ignore();
+ eat = true;
+ }
+
+ return eat;
+}
+
+void aHistLineEdit::ColourPickerPopUp()
+{
+ ColorPicker picker( this );
+ if ( picker.exec() == QDialog::Accepted )
+ {
+ QString s = text();
+ // int curPos = cursorPosition();
+ int curPos, p;
+ getCursorPosition(&p, &curPos);
+ QString colString = picker.colorString();
+ colString.prepend( 0x03 );
+ s.insert( curPos, colString );
+ setText( s );
+ setCursorPosition( curPos + colString.length() );
+ }
+}
+
+void aHistLineEdit::focusInEvent(QFocusEvent *e)
+{
+ QTextEdit::focusInEvent(e);
+ emit gotFocus();
+}
+
+void aHistLineEdit::focusOutEvent(QFocusEvent *e)
+{
+ QTextEdit::focusOutEvent(e);
+ emit lostFocus();
+}
+#if 0
+void aHistLineEdit::mousePressEvent ( QMouseEvent *e )
+{
+ if(e->button() == MidButton){
+ /*
+ * emit pasteText(QApplication::clipboard()->text(QClipboard::Selection));
+ */
+ }
+ else{
+ QTextEdit::mousePressEvent(e);
+ }
+}
+#endif
+bool aHistLineEdit::eventFilter( QObject *o, QEvent *e )
+{
+ if ( o == this && e->type() == QEvent::AccelOverride )
+ if(processKeyEvent( static_cast<QKeyEvent*>( e ) ) == true)
+ return true;
+
+ return QTextEdit::eventFilter( o, e );
+}
+
+QString aHistLineEdit::text() const
+{
+ QString s = QTextEdit::text();
+ s.remove("\n");
+ return s;
+}
+
+// Called upon MMB on the lineedit
+void aHistLineEdit::paste()
+{
+ /* we let the top level take it */
+ if(ksopts->oneLineEntry) {
+ emit pasteText(QApplication::clipboard()->text(QClipboard::Selection));
+ }
+ else {
+ QString paste = QApplication::clipboard()->text(QClipboard::Selection);
+ paste.replace("\n", " ~ ");
+ insert(paste);
+ }
+}
+
+void aHistLineEdit::paintEvent ( QPaintEvent *p )
+{
+ QTextEdit::paintEvent(p);
+
+ if(m_drawrect == true){
+ QPainter paint(this);
+ QPen pen = paint.pen();
+ pen.setWidth(5);
+ pen.setStyle(Qt::SolidLine);
+ pen.setColor(palette().active().highlight());
+ paint.setPen(pen);
+ QRect r = frameRect();
+ paint.drawRect(r);
+ }
+
+}
+
+void aHistLineEdit::doEnterKey()
+{
+ // strategy: always append an empty line to the end
+ if ((*current).isEmpty()) { // current is empty
+ if (!text().isEmpty()) {
+ // text() has something -> store it in current and add a new empty one
+ *current = text();
+ hist.append(QString::null); // always add empty line at end
+ if (hist.count() >= 256) { // if appended check if it will go beyond the max number of entries
+ hist.remove(hist.begin()); // if so then delete the first entry
+ }
+ }
+ } else { // current has content
+ if (!text().isEmpty()) {
+ // both !isEmpty() and != -> append at end
+ current = hist.fromLast(); // goto last entry which is empty
+ *current = text(); // change content to text()
+ hist.append(QString::null); // always add empty line at end
+ if (hist.count() >= 256) { // if appended check if it will go beyond the max number of entries
+ hist.remove(hist.begin()); // if so then delete the first entry
+ }
+ }
+ }
+ current = hist.fromLast(); // set current history item back to the last item in the list
+ emit gotReturnPressed();
+}
+
+#include "ahistlineedit.moc"
diff --git a/ksirc/ahistlineedit.h b/ksirc/ahistlineedit.h
new file mode 100644
index 00000000..a273791f
--- /dev/null
+++ b/ksirc/ahistlineedit.h
@@ -0,0 +1,56 @@
+#ifndef AHISTLINEEDIT_H
+#define AHISTLINEEDIT_H
+
+#include <qtextedit.h>
+#include <qstringlist.h>
+#include <qsize.h>
+
+class aHistLineEdit : public QTextEdit
+{
+Q_OBJECT
+public:
+ aHistLineEdit(QWidget *parent = 0, const char *name = 0);
+
+ int cursorPosition () const;
+ void setCursorPosition(int);
+
+ QString text() const;
+
+signals:
+ // Don't use returnPressed from the textEdit
+ void gotReturnPressed();
+ void gotFocus();
+ void lostFocus();
+ void pasteText(const QString&);
+ void notTab();
+ void resized();
+
+public slots:
+ virtual void paste();
+ virtual void slotMaybeResize();
+
+protected:
+ bool processKeyEvent( QKeyEvent * );
+ virtual void keyPressEvent ( QKeyEvent * );
+ virtual void focusInEvent ( QFocusEvent * );
+ virtual void focusOutEvent ( QFocusEvent * );
+// virtual void mousePressEvent ( QMouseEvent * );
+
+ virtual bool eventFilter( QObject *o, QEvent *e );
+
+ virtual void paintEvent ( QPaintEvent * );
+
+private:
+
+ void doEnterKey();
+
+ QStringList hist;
+ QStringList::Iterator current;
+ void ColourPickerPopUp();
+ int m_height;
+
+ bool m_drawrect;
+
+};
+
+#endif
diff --git a/ksirc/alistbox.cpp b/ksirc/alistbox.cpp
new file mode 100644
index 00000000..9b632676
--- /dev/null
+++ b/ksirc/alistbox.cpp
@@ -0,0 +1,508 @@
+/*******************************************************************
+
+ aListBox
+
+ $$Id$$
+
+ List box that outputs a right click mouse so I can popup a qpopupmenu.
+
+ Does special sorting, and maintains a two part list, one for ops,
+ other for users.
+
+ nothing special.
+
+*******************************************************************/
+
+#include "alistbox.h"
+#include "nickColourMaker.h"
+
+#include <qdragobject.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kurldrag.h>
+
+aListBox::aListBox(QWidget *parent, const char *name )
+ : QListBox(parent,name)
+{
+ clear();
+ p_scroll = palette().copy();
+ setAcceptDrops( true );
+ connect(this, SIGNAL(selected (const QString&)),
+ this, SIGNAL(selectedNick(const QString&)));
+
+ m_nickListDirty = true;
+
+ updateNickPrefixWidth();
+
+ connect( this, SIGNAL( contextMenuRequested( QListBoxItem *, const QPoint & ) ),
+ this, SLOT( reEmitContextMenuRequest( QListBoxItem * ) ) );
+}
+
+aListBox::~aListBox()
+{
+}
+
+void aListBox::reEmitContextMenuRequest( QListBoxItem *item )
+{
+ emit contextMenuRequested( index( item ) );
+}
+
+void aListBox::clear()
+{
+ QListBox::clear();
+}
+
+
+void aListBox::inSort ( nickListItem *lbi)
+{
+ int insert;
+ bool found;
+ insert = searchFor(lbi->text(), found, lbi->op());
+ if(found == TRUE){
+ //kdDebug(5008) << lbi->text() << " is already in nick list!" << endl;
+ return;
+ }
+ insertItem(lbi, insert);
+// for(uint index = 0; index < count(); index++){
+// debug("%d is %s", index, text(index));
+// }
+
+ m_nickListDirty = true;
+}
+
+void aListBox::inSort ( QString text, bool top)
+{
+ nickListItem *nli = new nickListItem();
+ nli->setText(text);
+ if(top == TRUE)
+ nli->setOp(TRUE);
+ inSort(nli);
+}
+
+int aListBox::findSep()
+{
+ uint i = 0;
+ for(; i < count(); i++)
+ if(item(i)->op() == FALSE)
+ break; // stop now
+
+ return i;
+
+}
+int aListBox::searchFor(const QString &nick, bool &found, bool top)
+{
+ int min = 0, max = 0;
+ int current = 0, compare = 0;
+ int real_max = 0;
+ int insert;
+
+ found = FALSE;
+
+ // If there's nothing in the list, don't try and search it, etc
+
+ if(count() == 0){
+ insert = 0;
+ }
+ else{
+ int sep = findSep();
+ if(sep >= 0){
+ if(top == TRUE){
+ min = 0;
+ max = (sep >= 1) ? sep - 1 : 0;
+ }
+ else{
+ min = sep;
+ max = count() - 1;
+ }
+ }
+ else
+ current = -1;
+
+ real_max = max;
+ current = (min + max)/2; // + (max-min)%2;
+ insert = current;
+ int last_current = -1;
+ uint loop = 0; // Most loops should be log_2 count(), but...
+ do {
+ if(current == last_current){
+// debug("Insert looping on %s", nick.data());
+ // current++;
+ break; // we're looping, so stop
+ }
+ if(current >= max)
+ break; // Don't go too far
+ last_current = current;
+
+ compare = text(current).lower().compare(nick.lower());
+ if(compare < 0){
+ min = current;
+ insert = current + 1;
+// debug("1 < 0: %s is greater then: %s, min: %d max: %d current: %d", nick.data(), text(current), min, max, current);
+ }
+ else if(compare > 0){
+ max = current;
+ insert = current;
+// debug("1 > 0: %s is less then: %s, min: %d max: %d current: %d", nick.data(), text(current), min, max, current);
+ }
+ else {// We got a match?
+ insert = current;
+ min = current;
+ found = TRUE;
+ break;
+ }
+ current = (min + max)/2;
+ loop++; // Infinite loop detector increment
+ } while(max != min && loop < count());
+
+ if(current >= real_max - 1){
+ compare = text(real_max).lower().compare(nick.lower());
+ if(compare < 0){
+ min = current;
+ insert = real_max + 1;
+// debug("End check got one!");
+ }
+ else if (compare == 0){// We got a match
+ insert = real_max + 1;
+ min = real_max;
+ found = TRUE;
+ }
+ }
+
+ // Sanity check
+ if((top == TRUE && insert > sep) ||
+ (top == FALSE && insert < sep)){
+ insert = sep;
+ }
+
+ if(loop == count())
+ {
+// debug("Loop inifitly on: %s", nick.data());
+ }
+
+ if(found == TRUE){
+// debug("Found %s", nick.data());
+ return min; // We found one, so return the number found
+ }
+ }
+// debug("%s is at %d", nick.data(), insert);
+ return insert;
+
+}
+bool aListBox::isTop(int index)
+{
+ if(index >= findSep())
+ return FALSE;
+ else
+ return TRUE;
+}
+
+int aListBox::findNick(const QString &str)
+{
+ bool found;
+ int index;
+ index = searchFor(str, found, TRUE);
+ if(found == TRUE)
+ return index;
+ index = searchFor(str, found, FALSE);
+ if(found == TRUE)
+ return index;
+// debug("Did not find: %s", str.data());
+ return -1;
+}
+
+nickListItem *aListBox::item(int index){
+ return (nickListItem *) QListBox::item(index);
+}
+
+void aListBox::dragMoveEvent( QDragMoveEvent *e )
+{
+ bool ok = (count() > 0 && KURLDrag::canDecode( e ));
+
+ if(!ok)
+ ok = QTextDrag::canDecode(e);
+
+ e->accept( ok );
+ if ( ok )
+ setCurrentItem( itemAt( e->pos() ));
+}
+
+
+void aListBox::dropEvent( QDropEvent *e )
+{
+ QListBoxItem *item = itemAt( e->pos() );
+ if ( !item )
+ return;
+
+ setCurrentItem( item );
+
+ QStringList urls;
+ KURLDrag::decodeLocalFiles( e, urls );
+
+ QString text;
+
+ if ( !urls.isEmpty() )
+ emit urlsDropped( urls, item->text() );
+ else if(QTextDrag::decode(e, text)){
+ emit textDropped( item, text);
+ }
+}
+
+bool aListBox::needNickPrefix() const
+{
+ if ( m_nickListDirty ) {
+ updateNeedNickPrefixFlag();
+ const_cast<aListBox *>( this )->updateNickPrefixWidth();
+ }
+
+ return m_needNickPrefix;
+}
+
+void aListBox::updateNeedNickPrefixFlag() const
+{
+ m_needNickPrefix = false;
+
+ if(ksopts->useColourNickList == false){
+ QListBoxItem *item = firstItem();
+ for (; item; item = item->next() )
+ {
+ nickListItem *nickItem = static_cast<nickListItem *>( item );
+ if ( nickItem->op() ||
+ nickItem->voice() ||
+ nickItem->away() ||
+ nickItem->ircOp() )
+ {
+ m_needNickPrefix = true;
+ break;
+ }
+ }
+ }
+
+ m_nickListDirty = false;
+}
+
+void aListBox::fontChange( const QFont &f )
+{
+ QListBox::fontChange( f );
+ updateNickPrefixWidth();
+}
+
+void aListBox::updateNickPrefixWidth()
+{
+ QFontMetrics metrics( font() );
+
+ m_nickPrefixWidth = 0;
+
+ if(ksopts->useColourNickList == false){
+ nickListItem *item = static_cast<nickListItem *>( firstItem() );
+ for ( ; item; item = static_cast<nickListItem *>( item->next() ) )
+ m_nickPrefixWidth = kMax( m_nickPrefixWidth, metrics.width( item->nickPrefix() ) );
+
+ // padding
+ }
+ m_nickPrefixWidth += metrics.width( " " );
+}
+
+void aListBox::clearAdvOps()
+{
+ nickListItem *item = static_cast<nickListItem *>( firstItem() );
+ for ( ; item; item = static_cast<nickListItem *>( item->next() ) ){
+ if(item->away() || item->ircOp()){
+ item->setIrcOp(false);
+ item->setAway(false);
+ updateItem(item);
+ }
+ }
+ triggerUpdate(false);
+ m_nickListDirty = true;
+
+}
+
+nickListItem::nickListItem()
+ : QListBoxItem()
+{
+ is_op = FALSE;
+ is_voice = FALSE;
+ is_away = FALSE;
+ is_ircop = FALSE;
+ forcedCol = 0x0;
+}
+
+nickListItem::nickListItem(const nickListItem &old)
+ : QListBoxItem()
+{
+ is_op = old.is_op;
+ is_voice = old.is_voice;
+ is_away = old.is_away;
+ is_ircop = old.is_ircop;
+ string = old.string;
+ forcedCol = old.forcedCol;
+}
+
+nickListItem::~nickListItem()
+{
+ string.truncate(0);
+}
+
+void nickListItem::setOp(bool _op)
+{
+ is_op = _op;
+ if ( listBox() )
+ static_cast<aListBox *>( listBox() )->setNickListDirty();
+}
+
+void nickListItem::setVoice(bool _voice)
+{
+ is_voice = _voice;
+ if ( listBox() )
+ static_cast<aListBox *>( listBox() )->setNickListDirty();
+}
+void nickListItem::setAway(bool _away)
+{
+ is_away = _away;
+ if ( listBox() )
+ static_cast<aListBox *>( listBox() )->setNickListDirty();
+}
+
+void nickListItem::setIrcOp(bool _ircop)
+{
+ is_ircop = _ircop;
+ if ( listBox() )
+ static_cast<aListBox *>( listBox() )->setNickListDirty();
+}
+
+void nickListItem::forceColour(const QColor *col)
+{
+ forcedCol = col;
+}
+
+void nickListItem::paint(QPainter *p)
+{
+ QFontMetrics fm = p->fontMetrics();
+ int yPos; // vertical text position
+
+ int nickPosX = 3;
+ yPos = fm.ascent() + fm.leading()/2;
+ QPen pen = p->pen();
+ QFont font = p->font();
+ if(ksopts->useColourNickList == true) {
+ if(ksopts->nickColourization){
+
+ if(!isSelected()) {
+ if(forcedCol && forcedCol->isValid())
+ p->setPen(*forcedCol);
+ else
+ p->setPen(nickColourMaker::colourMaker()->findFg(text()));
+ }
+ else {
+ p->setPen(ksopts->selForegroundColor);
+ }
+
+ if(is_voice == TRUE){
+ QPen open = p->pen();
+ p->setPen(ksopts->channelColor);
+ p->drawText( nickPosX, yPos, "+" );
+ nickPosX += fm.width( "+" );
+ p->setPen(open);
+// p->fillRect(0,0, listBox()->maxItemWidth(), height(listBox()), QBrush(ksopts->channelColor, Qt::Dense7Pattern));
+ }
+ if(is_op == TRUE) {
+ QPen open = p->pen();
+ p->setPen(ksopts->errorColor);
+ p->drawText( nickPosX, yPos, "@" );
+ nickPosX += fm.width( "@" );
+ p->setPen(open);
+// p->fillRect(0,0, listBox()->maxItemWidth(), height(listBox()), QBrush(ksopts->errorColor, Qt::Dense7Pattern));
+ }
+ if(is_away == TRUE)
+ p->setPen(p->pen().color().dark(150));
+ if(is_ircop == TRUE){
+ QPen open = p->pen();
+ p->setPen(ksopts->errorColor);
+ p->drawText( nickPosX, yPos, "*" );
+ nickPosX += fm.width( "*" );
+ p->setPen(open);
+
+ }
+
+ }
+ else {
+ if(is_voice == TRUE)
+ p->setPen(ksopts->channelColor);
+ if(is_op == TRUE)
+ p->setPen(ksopts->errorColor);
+ if(is_away == TRUE)
+ p->setPen(p->pen().color().dark(150));
+ if(is_ircop == TRUE){
+ QFont bfont = font;
+ bfont.setBold(TRUE);
+ p->setFont(bfont);
+ }
+ }
+ }
+ else {
+ }
+
+ if(ksopts->useColourNickList == false) {
+ aListBox *lb = static_cast<aListBox *>( listBox() );
+
+ if ( lb->needNickPrefix() )
+ {
+ p->drawText( 3, yPos, nickPrefix() );
+
+ nickPosX += lb->nickPrefixWidth();
+ }
+ }
+ p->drawText( nickPosX, yPos, text() );
+
+ p->setPen(pen);
+ p->setFont(font);
+}
+
+QString nickListItem::nickPrefix() const
+{
+ QString prefix;
+
+ if ( voice() )
+ prefix += aListBox::nickPrefixVoice();
+ if ( op() )
+ prefix += aListBox::nickPrefixOp();
+ if ( away() )
+ prefix += aListBox::nickPrefixAway();
+ if ( ircOp() )
+ prefix += aListBox::nickPrefixIrcOp();
+
+ if ( !prefix.isEmpty() )
+ prefix.prepend( "+" );
+
+ return prefix;
+}
+
+int nickListItem::height(const QListBox *lb ) const
+{
+ return lb->fontMetrics().lineSpacing() + 1;
+}
+
+int nickListItem::width(const QListBox *lb ) const
+{
+ return
+ static_cast<const aListBox *>( lb )->nickPrefixWidth() +
+ lb->fontMetrics().width( text() ) + 6;
+}
+
+const QPixmap* nickListItem::pixmap() const
+{
+ return 0l;
+}
+
+nickListItem &nickListItem::operator= (const nickListItem &nli)
+{
+ string = nli.string;
+ is_op = nli.is_op;
+ is_voice = nli.is_voice;
+ is_away = nli.is_away;
+ is_ircop = nli.is_ircop;
+ return (*this);
+}
+#include "alistbox.moc"
diff --git a/ksirc/alistbox.h b/ksirc/alistbox.h
new file mode 100644
index 00000000..0f818bba
--- /dev/null
+++ b/ksirc/alistbox.h
@@ -0,0 +1,112 @@
+#ifndef ALISTBOX_H
+#define ALISTBOX_H
+
+#include <qlistbox.h>
+#include "ksopts.h"
+
+class nickListItem : public QListBoxItem
+{
+ public:
+ nickListItem();
+ nickListItem(const nickListItem &old);
+ virtual ~nickListItem();
+
+ virtual int height ( const QListBox * ) const;
+ virtual int width ( const QListBox * ) const;
+ QString text () const { return string; }
+ const QPixmap* pixmap () const;
+
+ bool op() const { return is_op; }
+ bool voice() const { return is_voice; }
+ bool away() const { return is_away; }
+ bool ircOp() const { return is_ircop; }
+
+ void setOp(bool _op = FALSE);
+ void setVoice(bool _voice = FALSE);
+ void setAway(bool _away = FALSE);
+ void setIrcOp(bool _ircop = FALSE);
+
+ void setText(const QString &str) { string = str; }
+
+ QString nickPrefix() const;
+
+ void forceColour(const QColor *col);
+
+ nickListItem &operator= ( const nickListItem & nli );
+
+protected:
+ virtual void paint ( QPainter * );
+
+ private:
+ bool is_op:1;
+ bool is_voice:1;
+ bool is_away:1;
+ bool is_ircop:1;
+
+ QString string;
+ const QColor *forcedCol;
+};
+
+class aListBox : public QListBox
+{
+ Q_OBJECT
+
+public:
+ aListBox(QWidget *parent = 0, const char *name = 0);
+
+ virtual ~aListBox();
+
+ void clear();
+
+ void inSort ( nickListItem *);
+ void inSort ( QString text, bool top=FALSE);
+
+ nickListItem *item(int index);
+
+ bool isTop(int index);
+
+ int findNick(const QString &str);
+
+ void clearAdvOps();
+
+ bool needNickPrefix() const;
+
+ void setNickListDirty()
+ { m_nickListDirty = true; }
+
+ unsigned short int nickPrefixWidth() const
+ { return m_nickPrefixWidth; }
+
+ virtual void fontChange( const QFont &f );
+
+ static QString nickPrefixOp() { return QString::fromLatin1( "o" ); }
+ static QString nickPrefixVoice() { return QString::fromLatin1( "v" ); }
+ static QString nickPrefixAway() { return QString::fromLatin1( "a" ); }
+ static QString nickPrefixIrcOp() { return QString::fromLatin1( "O" ); }
+
+signals:
+ void contextMenuRequested(int index);
+ void selectedNick(const QString&);
+ void urlsDropped( const QStringList& urls, const QString& nick );
+ void textDropped( const QListBoxItem *item, const QString& text );
+
+protected:
+ virtual int findSep();
+ virtual int searchFor(const QString &nick, bool &found, bool top);
+ virtual void dragMoveEvent( QDragMoveEvent * );
+ virtual void dropEvent( QDropEvent * );
+
+private slots:
+ void reEmitContextMenuRequest( QListBoxItem *item );
+
+private:
+ void updateNeedNickPrefixFlag() const;
+ void updateNickPrefixWidth();
+
+ QPalette p_scroll;
+ mutable bool m_nickListDirty;
+ mutable bool m_needNickPrefix;
+ int m_nickPrefixWidth;
+};
+
+#endif
diff --git a/ksirc/autodcc.pl b/ksirc/autodcc.pl
new file mode 100644
index 00000000..f075cbcd
--- /dev/null
+++ b/ksirc/autodcc.pl
@@ -0,0 +1,71 @@
+#
+#
+&print("*** Loading auto dcc...");
+
+%A_DCC = ();
+
+sub cmd_anick {
+ &getarg;
+ $A_DCC{$newarg} = 1;
+ &print("*\cbI\cb* Added $newarg to auto dcc");
+}
+
+&addcmd("anick");
+
+sub cmd_dnick {
+ &getarg;
+ delete $A_DCC{$newarg};
+ &print("*\cbI\cb* Removed $newarg from auto dcc");
+}
+
+&addcmd("dnick");
+
+sub cmd_lnick {
+ my $key;
+ my $str;
+ foreach $key (keys %A_DCC){
+ $str .= "$key ";
+ }
+ &print("*\cbI\cb* Nicks allowed to auto dcc: $str");
+}
+
+&addcmd("lnick");
+
+sub set_autoresume {
+ $set{'AUTORESUME'}="on", $a_autoresume=1 if $_[0] =~ /^on$/i;
+ $set{'AUTORESUME'}="off", $a_autoresume=0 if $_[0] =~ /^off$/i;
+}
+&addset("autoresume");
+$set{"AUTORESUME"}="on";
+$n_autoresume=1;
+
+my %A_AUTOSTART = ();
+
+sub hook_adcc_do {
+ my $cmd = shift;
+
+ if($cmd eq "SEND"){
+ if($A_DCC{$who} == 1){
+ my $host = shift;
+ my $dport = shift;
+ my $file = shift;
+ my $size = shift;
+ if(-e $file){
+ if(($n_autoresume == 1) && ((-s $file) < $size)){
+ &docommand("resume $who $file");
+ $A_AUTOSTART{$dport} = "dcc get $who $file";
+ }
+ else {
+ &tell("*E* Autodcc rejected. File exists and no auto resume, or size mismatch");
+ }
+ }
+ else {
+ &docommand("dcc get $who $file");
+ }
+ }
+ }
+}
+
+&addhook("dcc_request", "adcc_do");
+
+
diff --git a/ksirc/baserules.cpp b/ksirc/baserules.cpp
new file mode 100644
index 00000000..11e5850c
--- /dev/null
+++ b/ksirc/baserules.cpp
@@ -0,0 +1,167 @@
+
+#include "baserules.h"
+#include "ksopts.h"
+#include "ksircprocess.h"
+
+#include <qregexp.h>
+
+#include <stdio.h>
+
+void KSMBaseRules::sirc_receive(QCString, bool)
+{
+}
+
+void KSMBaseRules::control_message(int, QString)
+{
+}
+
+filterRuleList *KSMBaseRules::defaultRules()
+{
+ filterRule *fr;
+ filterRuleList *frl = new filterRuleList();
+ frl->setAutoDelete(TRUE);
+ if( ksopts->ksircColors ){
+ // 3 stage rule to filter:
+ // ~blah~<something> stuff with ~ here and ~ there
+ // Here's the path follows
+ // =>~blah~;;;<something> with ~ here and ~ there
+ // =>~blah~;;;<something> with ~~ here and ~~ there
+ // =>~blah~<something> with ~~ here and ~ there
+ // Basic problem was getting it not to change ~blah~ into ~~blah~~
+ fr = new filterRule();
+ fr->desc = "Add marker to second ~";
+ fr->search = "^~\\S+~";
+ fr->from = "^~(\\S+)~";
+ fr->to = "~;;;$1~;;;";
+ frl->append(fr);
+ fr = new filterRule();
+ fr->desc = "Escape kSirc Control Codes";
+ fr->search = "~";
+ fr->from = "(?g)~(?!;;;)";
+ fr->to = "$1~~";
+ frl->append(fr);
+ fr = new filterRule();
+ fr->desc = "Remove marker to second";
+ fr->search = "^~;;;\\S+~;;;";
+ fr->from = "^~;;;(\\S+)~;;;";
+ fr->to = "~$1~";
+ frl->append(fr);
+
+ }
+ else{
+ // If we don't escape all ~'s at least esacpe the ones in
+ // email/part joins etc.
+ fr = new filterRule();
+ fr->desc = "Search for dump ~'s";
+ fr->search = "\\W~\\S+@\\S+\\W";
+ fr->from = "~(\\S+@)";
+ fr->to = "~~$1";
+ frl->append(fr);
+ }
+ if(ksopts->mircColors){
+ fr = new filterRule();
+ fr->desc = "Remove mirc Colours";
+ fr->search = "\\x03";
+ fr->from = "(?g)\\x03(?:\\d{0,2},{0,1}\\d{0,2})";
+ fr->to = "";
+ frl->append(fr);
+ }
+ if( ksopts->nickForeground.isValid() || ksopts->nickColourization){
+ fr = new filterRule();
+ fr->desc = "Highlight nicks in colour";
+ fr->search = "(?:~\\S+~)[<>|\\[\\]\\-]\\S+[<>|\\[\\]\\-]";
+ fr->from = "^((?:~\\S+~))([<>|\\[\\]\\-])(\\S+)([<>|\\[\\]\\-])";
+ fr->to = "$1$2~n$3~n$4";
+ frl->append(fr);
+ fr = new filterRule();
+ fr->desc = "Highlight nicks in colour in CTCP ACTION";
+ fr->search = "(?:~\\S+~)\\* (\\S+)";
+ fr->from = "^((?:~\\S+~))\\* (\\S+)";
+ fr->to = "$1* ~n$2~n";
+ frl->append(fr);
+ }
+ if( ksopts->msgContainNick.isValid() ){
+ //QString nick = ksopts->nick;
+ QString nick = ksircProcess()->getNick();
+ if ( !nick.isEmpty() ) {
+ if(nick.length() > 83){
+ qDebug("Nick too long");
+ nick.truncate( 83 );
+ }
+ /*
+ * Since the nick is used in the regex we must
+ * escape all regex words
+ */
+ nick = QRegExp::escape(nick);
+
+ sprintf(match_us,
+ "(?i)<\\S+>.*\\s%s(,.*|\02:.*|:.*|\\s.*|$)", nick.latin1());
+ sprintf(to_us,
+ "$1~o");//, ksopts->ownNickColor);
+ fr = new filterRule();
+ fr->desc = "Highlight our nick";
+ fr->search = match_us;
+ fr->from = "(<\\S+>)";
+ fr->to = to_us;
+ frl->append(fr);
+ }
+ }
+ if( ksopts->msg1Contain.isValid() ){
+ //QString nick = ksopts->nick;
+ /*
+ * Since the nick is used in the regex we must
+ * escape all regex words
+ */
+ QString msg = ksopts->msg1String;
+
+ if(msg.length() > 0){
+ if(ksopts->msg1Regex == false)
+ msg = QRegExp::escape(msg);
+
+ snprintf(msg1_match, 100,
+ "(?i)<\\S+>.*\\s%s(,.*|\02:.*|:.*|\\s.*|$)", msg.latin1());
+ snprintf(msg1_to, 100,
+ "$1~%s", ksopts->msg1Contain.name().latin1());//, ksopts->ownNickColor);
+ fr = new filterRule();
+ fr->desc = "Highlight our msg1";
+ fr->search = msg1_match;
+ fr->from = "(<\\S+>)";
+ fr->to = msg1_to;
+ frl->append(fr);
+ }
+ }
+ if( ksopts->msg2Contain.isValid() ){
+ //QString nick = ksopts->nick;
+ /*
+ * Since the nick is used in the regex we must
+ * escape all regex words
+ */
+ QString msg = ksopts->msg2String;
+
+ if(msg.length() > 0){
+ if(ksopts->msg2Regex == false)
+ msg = QRegExp::escape(msg);
+
+ snprintf(msg2_match, 100,
+ "(?i)<\\S+>.*\\s%s(,.*|\02:.*|:.*|\\s.*|$)", msg.latin1());
+ snprintf(msg2_to, 100,
+ "$1~%s", ksopts->msg2Contain.name().latin1());//, ksopts->ownNickColor);
+ fr = new filterRule();
+ fr->desc = "Highlight our msg2";
+ fr->search = msg2_match;
+ fr->from = "(<\\S+>)";
+ fr->to = msg2_to;
+ frl->append(fr);
+ }
+ }
+
+ // Default rules alays in place
+ fr = new filterRule();
+ fr->desc = "Remove Just bold in parts and joins";
+ fr->search = "\\*\\x02\\S+\\x02\\*";
+ fr->from = "\\*\\x02(\\S+)\\x02\\*";
+ fr->to = "\\*$1\\*";
+ frl->append(fr);
+
+ return frl;
+}
diff --git a/ksirc/baserules.h b/ksirc/baserules.h
new file mode 100644
index 00000000..690ed28e
--- /dev/null
+++ b/ksirc/baserules.h
@@ -0,0 +1,35 @@
+#ifndef KBASERULES_H
+#define KBASERULES_H
+
+#include "messageReceiver.h"
+
+class KSMBaseRules : public KSircMessageReceiver
+{
+public:
+ KSMBaseRules(KSircProcess *proc)
+ : KSircMessageReceiver(proc)
+ {
+ broadcast = FALSE;
+ }
+ virtual ~KSMBaseRules()
+ {
+ }
+
+ virtual void sirc_receive(QCString str, bool broadcast);
+
+ virtual void control_message(int, QString);
+
+ filterRuleList *defaultRules();
+
+private:
+ bool broadcast;
+ char to[101];
+ char match_us[101];
+ char to_us[101];
+ char msg1_match[101];
+ char msg1_to[101];
+ char msg2_match[101];
+ char msg2_to[101];
+};
+
+#endif
diff --git a/ksirc/boundscheckingarray.h b/ksirc/boundscheckingarray.h
new file mode 100644
index 00000000..0146efde
--- /dev/null
+++ b/ksirc/boundscheckingarray.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+#ifndef __boundscheckingarray__
+#define __boundscheckingarray__
+
+#include <assert.h>
+#include <qvaluevector.h>
+
+/* I wish QValueVector would check bounds upon extraction.. */
+
+template <typename T, const unsigned int size>
+class BoundsCheckingArray
+{
+public:
+ BoundsCheckingArray() {}
+ BoundsCheckingArray( const BoundsCheckingArray<T, size> &rhs )
+ { (*this) = rhs; }
+ BoundsCheckingArray &operator=( const BoundsCheckingArray<T, size> &rhs )
+ {
+ unsigned int i = 0;
+ for (; i < size; ++i )
+ m_data[ i ] = rhs.m_data[ i ];
+ return *this;
+ }
+
+ T &operator[]( unsigned int index )
+ {
+ assert( index < size );
+ return m_data[ index ];
+ }
+
+ const T &operator[]( unsigned int index ) const
+ {
+ assert( index < size );
+ return m_data[ index ];
+ }
+
+ QValueVector<T> toValueVector() const
+ {
+ QValueVector<T> vector( size );
+ for ( unsigned int i = 0; i < size; ++i )
+ vector[ i ] = m_data[ i ];
+ return vector;
+ }
+
+private:
+ T m_data[ size ];
+};
+
+#endif
+
diff --git a/ksirc/chanButtons.cpp b/ksirc/chanButtons.cpp
new file mode 100644
index 00000000..f40c7176
--- /dev/null
+++ b/ksirc/chanButtons.cpp
@@ -0,0 +1,268 @@
+/* mode buttons for ksirc - Robbie Ward <linuxphreak@gmx.co.uk>*/
+
+#include "chanButtons.h"
+#include "chanButtons.moc"
+
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <knuminput.h>
+#include <kstdguiitem.h>
+#include <kpushbutton.h>
+
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qlineedit.h>
+
+#include "ksircprocess.h"
+
+static void makeSquare(QWidget *w)
+{
+ QSize sh = w->sizeHint();
+ int s = sh.height();
+ w->setFixedSize(s,s);
+}
+
+chanButtons::chanButtons(KSircProcess *proc, QWidget *parent, const char *name)
+: QWidget(parent, name),
+ m_proc(proc)
+{
+ Popupmenu = new KPopupMenu( this );
+ Popupmenu->insertTitle(i18n("Channel Modes"));
+ toggleMenu[0] = Popupmenu->insertItem(i18n("i (invite-only)"), this, SLOT(invite()));
+ toggleMenu[1] = Popupmenu->insertItem(i18n("l (limited users)"), this, SLOT(limited()));
+ toggleMenu[2] = Popupmenu->insertItem(i18n("k (key to join)"), this, SLOT(key()));
+ toggleMenu[3] = Popupmenu->insertItem(i18n("s (secret)"), this, SLOT(secret()));
+ Popupmenu->insertSeparator();
+ Popupmenu->insertTitle(i18n("User Modes"));
+ toggleMenu[4] = Popupmenu->insertItem(i18n("i (be invisible)"), this, SLOT(invisible()));
+ toggleMenu[5] = Popupmenu->insertItem(i18n("w (receive wallops)"), this, SLOT(wallops()));
+ toggleMenu[6] = Popupmenu->insertItem(i18n("s (get server notices)"), this, SLOT(serverNotices()));
+
+ layout = new QHBoxLayout(this);
+ layout->setSpacing(0);
+ layout->setMargin(0);
+
+ protectButton = new QPushButton(i18n("T"), this);
+ protectButton->setToggleButton(true);
+ makeSquare(protectButton);
+ QToolTip::add(protectButton, i18n("Only op'ed users can change the topic"));
+ connect(protectButton, SIGNAL(clicked()), this, SLOT(protectMode()));
+ layout->addWidget(protectButton);
+
+ outsideButton = new QPushButton(i18n("N"), this);
+ outsideButton->setToggleButton(true);
+ makeSquare(outsideButton);
+ QToolTip::add(outsideButton, i18n("No outside messages"));
+ connect(outsideButton, SIGNAL(clicked()), this, SLOT(outsideMode()));
+ layout->addWidget(outsideButton);
+
+ moderateButton = new QPushButton(i18n("M"), this);
+ moderateButton->setToggleButton(true);
+ makeSquare(moderateButton);
+ QToolTip::add(moderateButton, i18n("Only op'ed users and voiced users (+v) can speak"));
+ connect(moderateButton, SIGNAL(clicked()), this, SLOT(moderateMode()));
+ layout->addWidget(moderateButton);
+
+ menuButton = new QPushButton(i18n("..."), this);
+ makeSquare(menuButton);
+ menuButton->setFixedWidth(menuButton->width()*2);
+ menuButton->setPopup(Popupmenu);
+ QToolTip::add(menuButton, i18n("More mode commands"));
+ layout->addWidget(menuButton);
+}
+
+void chanButtons::invite()
+{
+ if (Popupmenu->isItemChecked(toggleMenu[0])) {
+ Popupmenu->setItemChecked(toggleMenu[0], false);
+ emit mode(QString("-i"), 0);
+ }
+ else {
+ Popupmenu->setItemChecked(toggleMenu[0], true);
+ emit mode(QString("+i"), 0);
+ }
+}
+
+void chanButtons::limited()
+{
+ chanDialog = new chanbuttonsDialog(chanbuttonsDialog::limited);
+ chanDialog->exec();
+ if (chanDialog->sendLimitedUsers() == 0) {
+ Popupmenu->setItemChecked(toggleMenu[1], false);
+ emit mode(QString("-l"), 0);
+ }
+ else {
+ Popupmenu->setItemChecked(toggleMenu[1], true);
+ emit mode(QString("+l %1").arg(chanDialog->sendLimitedUsers()), 0);
+ }
+ delete chanDialog;
+}
+
+void chanButtons::key()
+{
+ chanDialog = new chanbuttonsDialog(chanbuttonsDialog::key);
+ if (Popupmenu->isItemChecked(toggleMenu[2])) {
+ chanDialog->exec();
+ Popupmenu->setItemChecked(toggleMenu[2], false);
+ emit mode(QString("-k %1").arg(chanDialog->sendKey()), 0);
+ }
+ else {
+ chanDialog->exec();
+ Popupmenu->setItemChecked(toggleMenu[2], true);
+ emit mode(QString("+k %1").arg(chanDialog->sendKey()), 0);
+ }
+ delete chanDialog;
+}
+
+void chanButtons::secret()
+{
+ if (Popupmenu->isItemChecked(toggleMenu[3])) {
+ Popupmenu->setItemChecked(toggleMenu[3], false);
+ emit mode(QString("-s"), 0);
+ }
+ else {
+ Popupmenu->setItemChecked(toggleMenu[3], true);
+ emit mode(QString("+s"), 0);
+ }
+}
+
+void chanButtons::invisible()
+{
+ if (Popupmenu->isItemChecked(toggleMenu[4])) {
+ Popupmenu->setItemChecked(toggleMenu[4], false);
+ emit mode(QString("-i"), 1, m_proc->getNick());
+ }
+ else {
+ Popupmenu->setItemChecked(toggleMenu[4], true);
+ emit mode(QString("+i"), 1, m_proc->getNick());
+ }
+}
+
+void chanButtons::wallops()
+{
+ if (Popupmenu->isItemChecked(toggleMenu[5])) {
+ Popupmenu->setItemChecked(toggleMenu[5], false);
+ emit mode(QString("-w"), 1, m_proc->getNick());
+ }
+ else {
+ Popupmenu->setItemChecked(toggleMenu[5], true);
+ emit mode(QString("+w"), 1, m_proc->getNick());
+ }
+}
+
+void chanButtons::serverNotices()
+{
+ if (Popupmenu->isItemChecked(toggleMenu[6])) {
+ Popupmenu->setItemChecked(toggleMenu[6], false);
+ emit mode(QString("-s"), 1, m_proc->getNick());
+ }
+ else {
+ Popupmenu->setItemChecked(toggleMenu[6], true);
+ emit mode(QString("+s"), 1, m_proc->getNick());
+ }
+}
+
+void chanButtons::protectMode()
+{
+ if (protectButton->isOn())
+ emit mode(QString("+t"), 0);
+ else
+ emit mode(QString("-t"), 0);
+}
+
+void chanButtons::outsideMode()
+{
+ if (outsideButton->isOn())
+ emit mode(QString("+n"), 0);
+ else
+ emit mode(QString("-n"), 0);
+}
+
+void chanButtons::moderateMode()
+{
+ if (moderateButton->isOn())
+ emit mode(QString("+m"), 0);
+ else
+ emit mode(QString("-m"), 0);
+}
+
+void chanButtons::setButtonsEnabled(bool enabled)
+{
+ // Set all the channel mode entries disabled if non-op else enable them
+ protectButton->setEnabled(enabled);
+ outsideButton->setEnabled(enabled);
+ moderateButton->setEnabled(enabled);
+ Popupmenu->setItemEnabled(toggleMenu[0], enabled);
+ Popupmenu->setItemEnabled(toggleMenu[1], enabled);
+ Popupmenu->setItemEnabled(toggleMenu[2], enabled);
+ Popupmenu->setItemEnabled(toggleMenu[3], enabled);
+}
+
+void chanButtons::setMenuItemMode(int id, bool value)
+{
+ Popupmenu->setItemChecked(toggleMenu[id], value);
+}
+
+chanbuttonsDialog::chanbuttonsDialog(const type &modeType, QWidget *parent,
+ const char *name, bool modal) : KDialog(parent, name, modal)
+{
+ m_sendKey = "";
+ m_sendLimitedUsers = 0;
+ resize(190, 82);
+ setCaption(i18n("Limit Number of Users"));
+ LimitedLayout = new QVBoxLayout(this);
+ LimitedLayout->setSpacing(9);
+ LimitedLayout->setMargin(11);
+
+ switch (modeType) {
+ case limited:
+ SpinBox = new KIntSpinBox(this);
+ LimitedLayout->addWidget(SpinBox);
+ break;
+ case key:
+ EditBox = new QLineEdit(this);
+ LimitedLayout->addWidget(EditBox);
+ break;
+ }
+
+ Layout = new QHBoxLayout;
+ Layout->setSpacing(6);
+ Layout->setMargin(0);
+
+ okButton = new KPushButton(KStdGuiItem::ok(), this);
+ okButton->setSizePolicy(QSizePolicy((QSizePolicy::SizeType)1, (QSizePolicy::SizeType)1,
+ okButton->sizePolicy().hasHeightForWidth()));
+ Layout->addWidget(okButton);
+ switch (modeType) {
+ case limited:
+ connect(okButton, SIGNAL(clicked()), SLOT(limitedUsers()));
+ break;
+ case key:
+ connect(okButton, SIGNAL(clicked()), SLOT(keyString()));
+ break;
+ }
+
+ Layout->addWidget(okButton);
+
+ cancelButton = new KPushButton(KStdGuiItem::cancel(), this);
+ cancelButton->setSizePolicy(QSizePolicy((QSizePolicy::SizeType)1, (QSizePolicy::SizeType)1,
+ cancelButton->sizePolicy().hasHeightForWidth()));
+ Layout->addWidget(cancelButton);
+ connect(cancelButton, SIGNAL(clicked()), SLOT(reject()));
+ LimitedLayout->addLayout(Layout);
+
+ QSpacerItem *spacer = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
+ LimitedLayout->addItem(spacer);
+}
+
+void chanbuttonsDialog::keyString()
+{
+ m_sendKey = EditBox->text();
+ accept();
+}
+
+void chanbuttonsDialog::limitedUsers()
+{
+ m_sendLimitedUsers = SpinBox->value();
+ accept();
+}
diff --git a/ksirc/chanButtons.h b/ksirc/chanButtons.h
new file mode 100644
index 00000000..2b7edc3a
--- /dev/null
+++ b/ksirc/chanButtons.h
@@ -0,0 +1,85 @@
+/* mode buttons for ksirc - Robbie Ward <linuxphreak@gmx.co.uk>*/
+
+#ifndef CHANBUTTONS_H
+#define CHANBUTTONS_H
+
+#include <qwidget.h>
+#include <qpushbutton.h>
+#include <kdialog.h>
+
+class QHBoxLayout;
+class QVBoxLayout;
+class KPopupMenu;
+class chanbuttonsDialog;
+class KIntSpinBox;
+class QLineEdit;
+class KSircProcess;
+class KPushButton;
+
+class chanButtons : public QWidget
+{
+ Q_OBJECT
+ friend class KSircTopLevel;
+ public:
+ chanButtons(KSircProcess *proc, QWidget* parent=0, const char* name=0);
+ ~chanButtons() {};
+
+ void setProtectMode(bool value) { protectButton->setOn(value); }
+ void setModerateMode(bool value) { moderateButton->setOn(value); }
+ void setNooutsideMode(bool value) { outsideButton->setOn(value); }
+ void setButtonsEnabled(bool);
+ void setMenuItemMode(int, bool);
+
+ signals:
+ void mode(QString, int, QString nick = QString::null); /// int == 0 channel mode, int == 1 user nick mode
+
+ private slots:
+ void protectMode();
+ void outsideMode();
+ void moderateMode();
+ void invite();
+ void limited();
+ void key();
+ void secret();
+ void invisible();
+ void wallops();
+ void serverNotices();
+
+ private:
+ int toggleMenu[7];
+ QHBoxLayout *layout;
+ QPushButton *protectButton;
+ QPushButton *moderateButton;
+ QPushButton *outsideButton;
+ QPushButton *menuButton;
+ KPopupMenu *Popupmenu;
+ chanbuttonsDialog *chanDialog;
+ KSircProcess *m_proc;
+};
+
+class chanbuttonsDialog : public KDialog
+{
+ Q_OBJECT
+ friend class chanButtons;
+ public:
+ enum type { limited, key };
+ chanbuttonsDialog(const type &modeType, QWidget *parent=0, const char *name=0, bool modal=true);
+ ~chanbuttonsDialog() {};
+
+ private slots:
+ void keyString();
+ void limitedUsers();
+ QString sendKey() { return m_sendKey; }
+ int sendLimitedUsers() { return m_sendLimitedUsers; };
+
+ private:
+ QString m_sendKey;
+ int m_sendLimitedUsers;
+ QVBoxLayout *LimitedLayout;
+ QHBoxLayout *Layout;
+ KIntSpinBox *SpinBox;
+ QLineEdit *EditBox;
+ KPushButton *okButton;
+ KPushButton *cancelButton;
+};
+#endif
diff --git a/ksirc/chanparser.cpp b/ksirc/chanparser.cpp
new file mode 100644
index 00000000..8429a6f5
--- /dev/null
+++ b/ksirc/chanparser.cpp
@@ -0,0 +1,1047 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "alistbox.h"
+#include "chanparser.h"
+#include "ksopts.h"
+#include "control_message.h"
+#include "ssfeprompt.h"
+#include "toplevel.h"
+#include "ksircprocess.h"
+#include "ksview.h"
+
+#include <stdio.h>
+
+#include <qregexp.h>
+#include <qapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <qptrlist.h>
+
+// Static parser table is "initialized"
+QDict<parseFunc> ChannelParser::parserTable;
+
+
+ChannelParser::ChannelParser(KSircTopLevel *_top)
+{
+ top = _top;
+
+ /*
+ * Initial helper variables
+ */
+ prompt_active = false;
+ current_item = -1;
+ top_item = 0;
+
+ if(parserTable.isEmpty() == TRUE){
+ parserTable.setAutoDelete(TRUE);
+ parserTable.insert("`l`", new parseFunc(&ChannelParser::parseSSFEClear));
+ parserTable.insert("`s`", new parseFunc(&ChannelParser::parseSSFEStatus));
+ parserTable.insert("`i`", new parseFunc(&ChannelParser::parseSSFEInit));
+ parserTable.insert("`t`", new parseFunc(&ChannelParser::parseSSFEMsg));
+ parserTable.insert("`o`", new parseFunc(&ChannelParser::parseSSFEOut));
+ parserTable.insert("`p`", new parseFunc(&ChannelParser::parseSSFEPrompt));
+ parserTable.insert("`P`", new parseFunc(&ChannelParser::parseSSFEPrompt));
+ parserTable.insert("`R`", new parseFunc(&ChannelParser::parseSSFEReconnect));
+ // The rest are *** info message
+ parserTable.insert("***", new parseFunc(&ChannelParser::parseINFOInfo));
+ parserTable.insert("*E*", new parseFunc(&ChannelParser::parseINFOError));
+ parserTable.insert("*!*", new parseFunc(&ChannelParser::parseINFONicks)); // Normal
+ parserTable.insert("*C*", new parseFunc(&ChannelParser::parseINFONicks)); // 1st line
+ parserTable.insert("*c*", new parseFunc(&ChannelParser::parseINFONicks)); // Last line
+ parserTable.insert("*#*", new parseFunc(&ChannelParser::parseINFONicks)); // Non enhanced
+ parserTable.insert("*$*", new parseFunc(&ChannelParser::parseINFONicks)); // Enhanced turned off
+ parserTable.insert("*>*", new parseFunc(&ChannelParser::parseINFOJoin));
+ parserTable.insert("*<*", new parseFunc(&ChannelParser::parseINFOPart));
+ parserTable.insert("*N*", new parseFunc(&ChannelParser::parseINFOChangeNick));
+ parserTable.insert("*+*", new parseFunc(&ChannelParser::parseINFOMode));
+ parserTable.insert("*T*", new parseFunc(&ChannelParser::parseINFOTopic));
+ // End of info message
+ parserTable.insert("* ", new parseFunc(&ChannelParser::parseCTCPAction));
+ }
+
+}
+
+parseResult *ChannelParser::parse(QString string)
+{
+ // for older Qts
+
+ parseFunc *pf;
+ if(string.length() < 3){
+ return new parseError(string, QString("Dumb string, too short"));
+ }
+
+ /**
+ * Start pre-parsing the strings to make them fit the 3 character
+ * parser codes, etc
+ */
+
+ /*
+ * SSFE control messages are too long, so we convert the
+ * messges into a 3 character code, `#ssfe#\S becomes `\S`
+ */
+
+ if ((string[0] == '`') & (string.length() > 7))
+ {
+ QString prefix = "`"+string[7]+"`";
+ string = prefix + QString(" ") + string.mid(8).stripWhiteSpace();
+ }
+ else if((string[0] == '*') && (string[1] == ' ')) {
+ string.insert(1, ' ');
+ }
+ // Pre-parsing is now complete
+
+ pf = parserTable[string.mid(0, 3)];
+ if(pf != 0x0){
+ parseResult *result = (this->*(pf->parser))(string);
+
+ if (result)
+ return result;
+ }
+ else
+ {
+ // debug("No handler for: %s", string.data());
+ }
+
+ // Little bit of past parsing to catch one we've missed
+ if((string[0] == '*') && (string[2] == '*')) {
+ string.remove(0, 3);
+ return new parseSucc(string, ksopts->infoColor, "user|servinfo");
+ }
+ // If it's unkown we just fall out of the function
+ return 0;
+}
+
+parseResult * ChannelParser::parseSSFEClear(QString string)
+{
+// top->mainw->clear();
+ top->clearWindow();
+// top->mainw->repaint(TRUE);
+ string.truncate(0);
+ return new parseSucc(QString::null); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseSSFEStatus(QString string)
+{
+ string.remove(0, 12); // strip off the first 12 characters "<junk> [sirc] "
+ if(string.length() == 0)
+ return new parseError("", i18n("Unable to parse status string"));
+
+ //kdDebug(5008) << "String: " << string << endl;
+ QRegExp rx("(\\S+).*\\(*([+-]*[+-\\w\\d]*)\\)*.*on (\\S+) \\((\\S+)\\)");
+ if(rx.search(string) == -1){
+ return new parseError("", i18n("Unable to parse status (no known format) string"));
+ }
+
+ QString nick = rx.cap(1);
+ QString modes = rx.cap(2);
+ QString chan = rx.cap(3);
+ QString chanmode = rx.cap(4);
+
+ /*
+ * fix up modes which may have gotten the (away) part
+ */
+ if(modes.contains("away")){
+ modes = "";
+ }
+
+ bool away = false;
+ if(string.contains("(away)"))
+ away = true;
+
+ if(away){
+ chan.prepend(i18n("Away-"));
+ }
+
+ nickListItem *nickItem = top->nicks->item( top->nicks->findNick( nick ) );
+ if ( nickItem ) {
+ if(nickItem->away() != away){
+ nickItem->setAway( away );
+ top->nicks->viewport()->repaint( top->nicks->itemRect( nickItem ), false );
+ }
+ nickItem->forceColour(&ksopts->ownNickColor);
+ }
+
+ top->ksircProcess()->setNick(nick);
+ if (chanmode.findRev("t") != -1)
+ top->channelButtons->setProtectMode(true);
+ else top->channelButtons->setProtectMode(false);
+ if (chanmode.findRev("m") != -1)
+ top->channelButtons->setModerateMode(true);
+ else top->channelButtons->setModerateMode(false);
+ if (chanmode.findRev("n") != -1)
+ top->channelButtons->setNooutsideMode(true);
+ else top->channelButtons->setNooutsideMode(false);
+ if (chanmode.findRev("i") != -1)
+ top->channelButtons->setMenuItemMode(0, true);
+ else top->channelButtons->setMenuItemMode(0, false);
+ if (chanmode.findRev("s") != -1)
+ top->channelButtons->setMenuItemMode(3, true);
+ else top->channelButtons->setMenuItemMode(3, false);
+
+ if (modes.findRev("i") != -1)
+ top->channelButtons->setMenuItemMode(4, true);
+ else top->channelButtons->setMenuItemMode(4, false);
+ if (modes.findRev("w") != -1)
+ top->channelButtons->setMenuItemMode(5, true);
+ else top->channelButtons->setMenuItemMode(5, false);
+ if (modes.findRev("s") != -1)
+ top->channelButtons->setMenuItemMode(6, true);
+ else top->channelButtons->setMenuItemMode(6, false);
+
+ QString status_line = QString("%1 (%2) %3 (%4) ").arg(chan).arg(chanmode).arg(nick).arg(modes);
+
+ /*
+ * Go srearching for key and limit messages
+ */
+ QRegExp rxKey("<key: (\\S+)>");
+ if(rxKey.search(string) >= 0){
+ top->channelButtons->setMenuItemMode(2, true);
+ status_line += QString("<key: %1>").arg(rxKey.cap(1));
+ }
+ else {
+ top->channelButtons->setMenuItemMode(2, false);
+ }
+
+ QRegExp rxLimit("<limit: (\\S+)>");
+ if(rxLimit.search(string) >= 0){
+ top->channelButtons->setMenuItemMode(1, true);
+ status_line += QString("<limit: %1>").arg(rxLimit.cap(1));
+ }
+ else {
+ top->channelButtons->setMenuItemMode(1, false);
+ }
+
+ if(ksopts->displayTopic){
+ if(top->topic().length() > 0)
+ status_line += "T: " + top->topic();
+ else
+ status_line += "T: " + i18n("<No Topic Set>");
+ }
+
+ if(top->caption != status_line){
+ if(nick[0] == '@' || (nick[0] == '*' && nick[1] == '@')) {
+ // If we're an op,,
+ // update the nicks popup menu
+ top->channelButtons->setButtonsEnabled(true); // set the buttons enabled if were an op
+ top->opami = TRUE;
+ } // opami = true sets us to an op
+ else {
+ top->channelButtons->setButtonsEnabled(false); // set the buttons enabled if were an op
+ top->opami = FALSE;
+ } // FALSE, were not an ops
+ top->UserUpdateMenu(); // update the menu
+ top->setCaption(status_line);
+ top->setIconText(status_line);
+ if(top->ticker) {
+ top->ticker->setCaption(status_line);
+ }
+ top->caption = status_line; // Make copy so we're not
+ // constantly changing the title bar
+ }
+ return new parseSucc(QString::null); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseSSFEInit(QString)
+{
+ return new parseSucc(QString::null); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseSSFEOut(QString)
+{
+ return new parseSucc(QString::null); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseSSFEMsg(QString string)
+{
+
+ if(string.length() > 100)
+ return new parseError(QString::null, i18n("String length for nick is greater than 100 characters. This is unacceptably long."));
+
+ int l = string.length();
+ if (l <= 0)
+ return new parseError(string, i18n("String not long enough"));
+
+ return new parseSucc(QString::null); // Null string, don't display anything
+}
+
+
+parseResult * ChannelParser::parseSSFEPrompt(QString string)
+{
+
+ if(prompt_active == FALSE){
+ QString prompt, caption;
+ ssfePrompt *sp;
+
+ // Flush the screen.
+ // First remove the prompt message from the Buffer.
+ // (it's garunteed to be the first one)
+ top->LineBuffer.remove( *top->LineBuffer.begin() );
+ top->Buffer = FALSE;
+ top->sirc_receive(QString(""));
+
+ // "'[pP]' " gives 4 spaces
+ if(string.length() < 5)
+ caption = i18n("");
+ else
+ caption = string.mid(3);
+ prompt_active = TRUE;
+
+ // If we use this, then it blows up
+ // if we haven't popped up on the remote display yet.
+
+ KSirc::TextParagIterator it = top->mainw->firstParag();
+ QString last;
+ while(it.atEnd() == FALSE) {
+ last = it.plainText();
+ ++it;
+ }
+
+ if(last[0] == '['){ /* strip time stamp */
+ prompt = last.mid(last.find(' '));
+ }
+ else {
+ prompt = last;
+ }
+
+ sp = new ssfePrompt(prompt, 0);
+ sp->setCaption(caption);
+ if(string[1] == 'P')
+ sp->setPassword(TRUE);
+ sp->exec();
+ // cerr << "Entered: " << sp->text() << endl;
+ prompt = sp->text();
+ prompt += "\n";
+ emit top->outputUnicodeLine(prompt);
+ delete sp;
+ prompt_active = FALSE;
+ }
+
+ return new parseSucc(QString::null); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseSSFEReconnect(QString)
+{
+
+ if(top->channelInfo().channel()[0] == '#' ||
+ top->channelInfo().channel()[0] == '&'){
+ QString str = "/join " + QString(top->channelInfo().channel()) + "\n";
+ emit top->outputUnicodeLine(str);
+ }
+
+ return new parseSucc(QString::null); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseINFOInfo(QString string)
+{
+ string.remove(0, 3); // takes off the junk
+
+ return new parseSucc(string, ksopts->infoColor, "user|servinfo"); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseINFOError(QString string)
+{
+ string.remove(0, 3); // strip the junk
+
+ return new parseSucc(string,ksopts->errorColor, "user|error"); // Null string, don't display anything
+}
+
+parseResult * ChannelParser::parseINFONicks(QString in_string)
+{
+ QString string = in_string;
+ QString channel_name;
+ bool clear_box = FALSE;
+
+ // Check to see if it's a continued line
+ if(string[1] == 'C'){
+ string[1] = '!';
+ clear_box = TRUE;
+ }
+ if(string[1] == '#'){
+ string[1] = '!';
+ clear_box = FALSE;
+ }
+ else if(string[1] == 'c'){
+ if(current_item > 0)
+ top->nicks->setCurrentItem(current_item);
+ top->nicks->setTopItem(top_item);
+ top->nicks->repaint(TRUE);
+ return new parseSucc(QString::null); // Parsing ok, don't print anything though
+ }
+ else if(string[1] == '$'){
+ top->nicks->clearAdvOps();
+ //kdDebug(5008) << "Turning off advanced ops" << endl;
+ return new parseSucc(QString::null); // Parsing ok, don't print anything though
+ }
+
+
+ // Get the channel name portion of the string
+ // Search for the first space, since : can be embeded into channel names.
+ //count = sscanf(string, "*!* Users on %100[^ ]", channelInfo().channel());
+ // *!* Users on #TEST: boren asj asj_
+ QRegExp rx("\\*\\S\\* Users on (\\S+): (.+)");
+ if(rx.search(string) == -1){
+ return new parseError(string, i18n("Could not find channel name"));
+ }
+ channel_name = rx.cap(1);
+
+
+ if (channel_name.lower() != top->channelInfo().channel().lower()){
+ string.remove(0,3);
+ return new parseSucc(string,ksopts->infoColor,"user|misc4");
+ }
+
+ if(clear_box == TRUE){
+ current_item = top->nicks->currentItem();
+ top_item = top->nicks->topItem();
+ top->nicks->clear();
+ }
+
+ //int start = string.find(": ", 0, FALSE); // Find start of nicks
+ //if (start < 0)
+ // return new parseError(string, i18n("Could not find start of nicks"));
+ //
+ //place_holder = new char[string.length()];
+ //strcpy(place_holder, string.ascii()+start+2);
+ //nick = strtok(place_holder, " ");
+ // while(nick != 0x0){ // While there's nick to go...
+ QStringList nicks = QStringList::split(QRegExp("\\s+"), rx.cap(2));
+
+ for ( QStringList::Iterator it = nicks.begin(); it != nicks.end(); ++it ) {
+ QString nick = *it;
+ nickListItem *irc = new nickListItem();
+
+ bool done = FALSE;
+ uint i;
+
+ for(i = 0; i < nick.length();i++){
+ switch(nick[0].unicode()){
+ case '@':
+ irc->setOp(TRUE);
+ nick.remove(0,1);
+ break;
+ case '+':
+ irc->setVoice(TRUE);
+ nick.remove(0,1);
+ break;
+ case '#':
+ irc->setAway(TRUE);
+ nick.remove(0,1);
+ break;
+ case '*':
+ irc->setIrcOp(TRUE);
+ nick.remove(0,1);
+ break;
+ default:
+ done = TRUE;
+ }
+ if(done == TRUE)
+ break;
+ }
+
+ if(nick == top->ksircProcess()->getNick()){
+ irc->forceColour(&ksopts->ownNickColor);
+ }
+ irc->setText(nick);
+ top->nicks->inSort(irc);
+ }
+
+ return new parseSucc(QString::null); // Parsing ok, don't print anything though
+}
+
+parseResult * ChannelParser::parseINFOJoin(QString string)
+{
+ string.remove(0, 4); // strip *>* to save a few compares
+ // You have joined channel #Linux
+ QRegExp rx("You have joined channel (\\S+)");
+ if(rx.search(string) != -1){
+ //QString channel = rx.cap(1).lower();
+ QString channel = rx.cap(1);
+ //kdDebug(5008) << "Channel: " << channel << endl;
+
+ if(top->channelInfo().channel() != channel) {
+ KSircChannel ci(top->channelInfo().server(), channel);
+ kdDebug(5008) << "Warning: we got a channel join yet me don't belong to it!!! Assuming no key!" << endl;
+ kdDebug(5008) << "String was: " << string << endl;
+ kdDebug(5008) << "We think the channel is: " << channel << " we are: " << top->channelInfo().channel()<< endl;
+ emit top->open_toplevel(ci);
+ }
+ return new parseJoinPart(" " + string, ksopts->channelColor, "user|join");
+ }
+
+ // reef-diddy (nenernener@xnet-3B34A9E2.snet.net) has joined channel #aquaria
+ rx.setPattern("(\\S+) .+ has joined channel (\\S+)");
+ if(rx.search(string) != -1){
+ QString nick = rx.cap(1);
+ QString channel = rx.cap(2).lower();
+ //kdDebug(5008) << "Channel: " << channel << " nick: " << nick << endl;
+ if(top->channelInfo().channel().lower() != channel){
+ return new parseWrongChannel(" " + string, ksopts->errorColor, "user|join");
+ }
+ // nicks->insertItem(s3, 0); // add the sucker
+ top->nicks->inSort(nick);
+ top->addCompleteNick(nick);
+ highlightNick(string, nick);
+ return new parseJoinPart(" " + string, ksopts->channelColor, "user|join");
+ }
+
+ return 0; // ??
+}
+
+parseResult * ChannelParser::parseINFOPart(QString string)
+{
+
+ bool foundNick = false;
+ QString pixname = "user|kick";
+ QString nick("");
+
+ string.remove(0, 4); // clear junk
+
+ // Multiple type of parts, a signoff or a /part
+ // Each get's get nick in a diffrent localtion
+ // Set we search and find the nick and the remove it from the nick list
+ // 1. /quit, signoff, nick after "^Singoff: "
+ // 2. /part, leave the channek, nick after "has left \w+$"
+ // 3. /kick, kicked off the channel, nick after "kicked off \w+$"
+ //
+ // Signoff: looser
+ QRegExp rx("Signoff: (\\S+)");
+ if(rx.search(string) != -1) {
+ nick = rx.cap(1);
+ foundNick = true;
+ pixname = "user|X";
+ highlightNick(string, nick);
+ }
+ /*
+ * Check for "You" before everyone else or else the next
+ * case will match it
+ * You have left channel <channel>
+ */
+ rx.setPattern("You have left channel (\\S+)");
+ if((foundNick == false) && (rx.search(string) != -1)) {
+ QString channel = rx.cap(1);
+ if(top->channelInfo().channel().lower() == channel.lower()) {
+ QApplication::postEvent(top, new QCloseEvent());
+ // WE'RE DEAD
+ return new parseSucc(QString::null);
+ }
+ pixname = "user|part";
+ }
+ /*
+ * Same as above, check your own state first
+ * You have been kicked off channel <channel>
+ */
+ rx.setPattern("You have been kicked off channel (\\S+)");
+ if((foundNick == false) && (rx.search(string) != -1)) {
+ QString channel = rx.cap(1);
+ if(top->channelInfo().channel().lower() != channel.lower())
+ return new parseWrongChannel(string, ksopts->errorColor, "user|kick");
+ if (ksopts->autoRejoin == TRUE)
+ {
+ QString str = QString("/join %1\n").arg(top->channelInfo().channel());
+ emit top->outputUnicodeLine(str);
+ /* if(top->ticker)
+ top->ticker->show();
+ else*/
+ top->show();
+ }
+ else
+ {
+ if(top->KickWinOpen != false)
+ return new parseError(" " + string, i18n("Kick window open"));
+ top->KickWinOpen = true;
+ int result = KMessageBox::questionYesNo(top, string, i18n("You Have Been Kicked"), i18n("Rejoin"), i18n("Leave"));
+ if (result == KMessageBox::Yes)
+ {
+ QString str = QString("/join %1\n").arg(top->channelInfo().channel());
+ emit top->outputUnicodeLine(str);
+ /* if(top->ticker)
+ * top->ticker->show();
+ * else*/
+ top->show();
+ return new parseJoinPart(" " + string, ksopts->channelColor, "user|kick");
+ }
+ else
+ {
+ // WE'RE DEAD
+ QApplication::postEvent(top, new QCloseEvent());
+ top->KickWinOpen = false;
+ }
+ }
+ pixname = "user|kick";
+ }
+ /*
+ * <nick> has left channel <channel>
+ */
+ rx.setPattern("(\\S+) has left channel (\\S+)");
+ if((foundNick == false) && (rx.search(string) != -1)) {
+ nick = rx.cap(1);
+ QString channel = rx.cap(2);
+// kdDebug(5008) << "Nick: " << nick << " Channel: " << channel << " top: " << top->channelInfo().channel() << endl;
+ if(top->channelInfo().channel().lower() == channel.lower()) {
+ foundNick = true;
+ }
+ else{
+ return new parseWrongChannel(QString::null);
+ }
+ pixname = "user|part";
+ highlightNick(string, nick);
+ }
+ /*
+ * "<nick> has been kicked off channel <channel>"
+ */
+ rx.setPattern("(\\S+) has been kicked off channel (\\S+)");
+ if((foundNick == false) && (rx.search(string) != -1)) {
+ nick = rx.cap(1);
+ QString channel = rx.cap(2);
+ if(top->channelInfo().channel().lower() == channel.lower()) {
+ foundNick = true;
+ } else {
+ return new parseWrongChannel(QString::null);
+ }
+ highlightNick(string, nick);
+ pixname = "user|kick";
+ }
+
+ if (foundNick) {
+
+ top->removeCompleteNick(nick);
+
+ int index = top->nicks->findNick(nick);
+ if(index >= 0){
+ top->nicks->removeItem(index);
+ return new parseJoinPart(" " + string, ksopts->channelColor, pixname);
+ }
+ else {
+ return new parseJoinPart(QString::null);
+ }
+ }
+ else {
+ return new parseError(" " + string, i18n("Failed to parse part/kick/leave/quit message"));
+ }
+
+ return 0;
+}
+
+parseResult * ChannelParser::parseINFOChangeNick(QString string)
+{
+ //char old_nick[101], new_nick[101];
+ QString old_nick, new_nick;
+
+ string.remove(0, 4); // Remove the leading *N* and space
+
+ /*
+ * *N* asj_ is now known as bleh
+ */
+ //kdDebug(5008) << "Nick change: " << string << endl;
+ QRegExp rx("(\\S+) is now known as (\\S+)");
+ if(rx.search(string) == -1){
+ if(string.contains("already taken")){
+ return new parseSucc(" " + string, ksopts->errorColor, "user|error");
+ }
+
+ return new parseError(i18n("Unable to parse: %1").arg(string), i18n("Unable to parse change nick code"));
+ }
+
+ old_nick = rx.cap(1);
+ new_nick = rx.cap(2);
+
+ // If we have a window open talking to the nick
+ // Change the nick to the new one.
+ if((top->channelInfo().channel()[0] != '#' || top->channelInfo().channel()[0] != '&') &&
+ (top->channelInfo().channel() == old_nick)){
+ if(!top->ksircProcess()->mrList()[new_nick.lower()]){
+ top->control_message(CHANGE_CHANNEL, new_nick.lower());
+ }
+ }
+
+ highlightNick(string, old_nick);
+ highlightNick(string, new_nick);
+
+ // search the list for the nick and remove it
+ // since the list is source we should do a binary search...
+ int found = top->nicks->findNick(old_nick);
+ if(found >= 0){ // If the nick's in the nick list, change it and display the change
+ // save current selection
+ int selection = top->nicks->currentItem();
+
+ // Get the old item, and create a new one
+ nickListItem *it = top->nicks->item(found);
+ nickListItem *irc = new nickListItem(*it);
+ irc->setText(new_nick);
+
+ top->nicks->removeItem(found); // remove old nick
+ top->nicks->inSort(irc);
+
+ top->changeCompleteNick(old_nick, new_nick);
+
+ top->nicks->setCurrentItem(selection);
+ top->nicks->repaint(TRUE);
+ // We're done, so let's finish up
+ return new parseSucc(" " + string, ksopts->channelColor, "user|join");
+ }
+ else {
+ if(top->channelInfo().channel() == new_nick ||
+ top->channelInfo().channel() == old_nick)
+ return new parseSucc(" " + string, ksopts->channelColor, "user|elipsis");
+ else
+ return new parseSucc(QString::null);
+
+ }
+
+ // warning("Toplevel-N: nick change search failed on %s", s3.data());
+ // return new parseSucc(QString::null);
+}
+
+class mode_info {
+public:
+ mode_info(bool op, QChar mode, QString arg);
+
+ bool op() const;
+ QChar mode() const;
+ QString arg() const;
+
+private:
+ const bool m_op;
+ const QChar m_mode;
+ const QString m_arg;
+};
+
+mode_info::mode_info(bool op, QChar mode, QString arg) :
+ m_op(op),
+ m_mode(mode),
+ m_arg(arg)
+{
+}
+
+bool mode_info::op() const {
+ return m_op;
+}
+
+QChar mode_info::mode() const {
+ return m_mode;
+}
+
+QString mode_info::arg() const {
+ return m_arg;
+}
+
+
+parseResult * ChannelParser::parseINFOMode(QString string)
+{
+ // Basic idea here is simple, go through the mode change and
+ // assign each mode a + or a - and an argument or "" if there is
+ // none. After that each mode change it looked at to see if
+ // we should handle it in any special way.
+
+ // Strip off leading sirc info
+
+ string.remove(0, 4);
+
+
+ /*
+ * 1k is pretty safe since KProcess returns 1 k blocks, and lines don't get split between reads. This is emprical
+ */
+ QString modes, args, channel;
+ int found = 0;
+
+ if(string.find("for user") >= 0)
+ return new parseSucc(" " + string, ksopts->infoColor, "user|mode");
+
+ /*
+ * We need to 2 scanf's, one for the case of arguments, and one for no args.
+ */
+ QRegExp rx("Mode change \"(\\S+) *([^\"]*)\" on channel (\\S+)");
+ if(rx.search(string) >= 0){
+ modes = rx.cap(1);
+ args = rx.cap(2);
+ channel = rx.cap(3);
+ found = 1;
+ }
+
+ rx.setPattern("Mode for channel (\\S+) is \"([^\" ]+)\"");
+ if(found == 0 &&
+ rx.search(string) >= 0){
+ channel = rx.cap(1);
+ modes = rx.cap(2);
+ found = 1;
+ }
+
+ rx.setPattern("Your user mode is");
+ if(found == 0 &&
+ rx.search(string) >= 0){
+ /*
+ * Don't parse user mode requests
+ */
+ return new parseSucc(" " + string, ksopts->infoColor, "user|mode");
+ }
+
+
+ if(found == 0)
+ return new parseError(" Failed to parse mode change: " + string, QString::null);
+
+ /*
+ * op specifie if it's a + or -. tru is + false is -
+ */
+ bool op = true;
+ /*
+ * arglist is the list of argument
+ * we use the itirator to tstep through the list
+ * as need be
+ */
+ QStringList arglist = QStringList::split(" ", args);
+ QStringList::Iterator ai = arglist.begin();
+
+ /*
+ * the ptr list structure contains the parsed contents
+ */
+ QPtrList<const mode_info> pmList;
+ pmList.setAutoDelete(true);
+
+ for(uint pos = 0; pos < modes.length(); pos++){
+ switch(modes.at(pos).unicode()){
+ case '+':
+ op = true;
+ break;
+ case '-':
+ op = false;
+ break;
+ case 'l': // Chan limits
+ /*
+ * -l doesn't take any arguments, so just add the mode and break
+ * +l otoh does, so read the argument
+ */
+ if(op == false){
+ pmList.append(new mode_info(op, 'l', QString::null));
+ break;
+ }
+ case 'o': // Op, arg is the nick
+ case 'v': // Voice, arg is the nick
+ case 'b': // Ban, arg is mask banned
+ case 'k': // kcik, arg is nick
+ if(ai == NULL)
+ return new parseError(i18n("Unable to parse mode change: %1").arg(string), QString::null);
+ pmList.append(new mode_info(op, modes.at(pos), *ai));
+ ai++;
+ break;
+ case 'i': // Invite only
+ case 'n': // No message to chan
+ case 'p': // Private
+ case 'm': // Moderated
+ case 's': // Secret
+ case 't': // Topic setable by ops
+ case 'R': // (Dalnet) only registered may join
+ case 'r': // (Dalnet) only registered may join or something
+ /*
+ * Mode changes which don't take args
+ */
+ pmList.append(new mode_info(op, modes.at(pos), QString::null));
+ break;
+ default:
+ kdDebug(5008) << "Unknown mode change: " << modes.mid(pos, 1) << " Assume no args" << endl;
+ pmList.append(new mode_info(op, modes.at(pos), QString::null));
+ }
+ }
+ // We have the modes set in mode and arg, now we go though
+ // looking at each mode seeing if we should handle it.
+ bool mode_o_plus = false;
+ bool mode_o_minus = false;
+ bool mode_b_plus = false;
+ bool mode_b_minus = false;
+
+ QPtrListIterator<const mode_info> it(pmList);
+ const mode_info *mi;
+ while ( (mi = it.current()) != 0 ) {
+ ++it;
+ /*
+ * Look at the second character, it's uniq, check for +,- latter
+ */
+ if(mi->mode().unicode() == 'o'){
+ mode_o_plus = mi->op();
+ mode_o_minus = !mi->op();
+
+ if(top->ksircProcess()->getNick() == mi->arg())
+ top->channelButtons->setButtonsEnabled(mi->op());
+
+ if(mi->arg().length() == 0){
+ qWarning("Invalid nick in +/- o mode change");
+ continue;
+ }
+
+ int offset = top->nicks->findNick(mi->arg());
+ if(offset >= 0){
+ nickListItem *irc = new nickListItem();
+ *irc = *top->nicks->item(offset);
+ top->nicks->removeItem(offset); // remove old nick
+ irc->setOp(mi->op());
+ // add new nick in sorted pass,with colour
+ top->nicks->inSort(irc);
+ top->nicks->repaint(TRUE);
+ }
+ else{
+ kdDebug(5008) << "Toplevel+o: nick search failed on " << mi->arg() << endl;
+ }
+ }
+ else if(mi->mode() == 't'){
+ if(mi->op())
+ top->channelButtons->setProtectMode(true); // set on
+ else
+ top->channelButtons->setProtectMode(false); // set off
+ }
+ else if(mi->mode() == 'm'){
+ if(mi->op())
+ top->channelButtons->setModerateMode(true); // set on
+ else
+ top->channelButtons->setModerateMode(false); // set off
+ }
+ else if(mi->mode() == 'n'){
+ if(mi->op())
+ top->channelButtons->setNooutsideMode(true); // set on
+ else
+ top->channelButtons->setNooutsideMode(false); // set off
+ }
+ else if(mi->mode() == 'v'){
+ bool voice;
+ if(mi->op())
+ voice = TRUE;
+ else
+ voice = FALSE;
+
+ if(mi->arg().length() == 0){
+ qWarning("Invalid nick in +-v mode change");
+ continue;
+ }
+
+ int offset = top->nicks->findNick(mi->arg());
+ if(offset >= 0){
+ nickListItem *irc = new nickListItem();
+ *irc = *top->nicks->item(offset);
+ top->nicks->removeItem(offset); // remove old nick
+ irc->setVoice(voice) ;
+ // add new nick in sorted pass,with colour
+ top->nicks->inSort(irc);
+ top->nicks->repaint();
+ }
+ }
+ else if(mi->mode() == 'b'){
+ if(mi->op())
+ mode_b_plus = true;
+ else
+ mode_b_minus = true;
+ }
+ else if(mi->mode() == 'k'){
+ if(mi->op()){
+ if(mi->arg().length() == 0){
+ qWarning("Invalid +k mode set, no argument!");
+ continue;
+ }
+ top->m_channelInfo.setKey(mi->arg());
+ }
+ else {
+ top->m_channelInfo.setKey(""); /* no key set anymore */
+ }
+ }
+ else{
+ QChar c(mi->mode());
+ QString m(&c, 1);
+ QString o;
+ if(mi->op())
+ o = "+";
+ else
+ o = "-";
+ kdDebug(5008) << "Did not handle: " << o << m << " arg: " << mi->arg() << endl;
+ }
+ }
+ /*
+ * We're all done, so output the message and be done with it
+ */
+ QString pixname = "user|mode";
+
+ if(mode_o_plus)
+ pixname = "user|oplus";
+ else if(mode_o_minus)
+ pixname = "user|ominus";
+ else if(mode_b_plus)
+ pixname ="user|bplus";
+ else if(mode_b_minus)
+ pixname = "user|bminus";
+
+ return new parseSucc(" " + string, ksopts->infoColor, pixname);
+}
+
+parseResult * ChannelParser::parseCTCPAction(QString string)
+{
+
+ string.remove(0, 2); // * <something> use fancy * pixmap. Remove 2, leave one for space after te *
+ // why? looks cool for dorks
+ return new parseSucc(string, ksopts->textColor, "user|action");
+}
+
+parseResult * ChannelParser::parseINFOTopic(QString string)
+{
+
+ int found = 0;
+
+ string.remove(0, 4); // Remove the leading *T* and space
+
+ //kdDebug(5008) << "Topic parser: " << string << endl;
+
+ // Topic for #boo: this is a nice test
+ QRegExp rx( "Topic for (\\S+): (.*)" );
+ if(rx.search( string ) != -1){
+ QString channel = rx.cap(1);
+ QString topic = rx.cap(2);
+ topic.replace( QRegExp( "~~" ), "~" );
+
+ /*
+ * check where it's going.
+ * topic's maybe for other channels since they have no channel routing
+ * information, so route it to the right place if need be.
+ * If we're not on the channnel just fall through and display it
+ * on our channel, maybe the user asked for a topic of a different channel
+ */
+
+ if(channel.lower() != top->channelInfo().channel().lower()){
+ if(top->ksircProcess()->mrList()[channel.lower()]){
+ KSircTopLevel *t = dynamic_cast<KSircTopLevel *>(top->ksircProcess()->mrList()[channel.lower()]);
+ if(t)
+ t->setTopic(topic);
+ }
+ }
+ else {
+ //kdDebug(5008) << "New topic: " << topic << endl;
+ top->setTopic( topic );
+ }
+ found = 1;
+ }
+
+ rx.setPattern("(\\S+) has changed the topic on channel (\\S+) to (.+)");
+ if(found == 0 && rx.search(string) != -1){
+ QString nick = rx.cap(1);
+ QString channel = rx.cap(2);
+ //kdDebug(5008) << "Channel: " << channel << endl;
+ if(top->channelInfo().channel().lower() == channel.lower()){
+ QString topic = rx.cap(3);
+ //kdDebug(5008) << "Topic: " << topic << endl;
+ topic.replace(QRegExp("~~"), "~");
+ /*
+ * topic is in double quotes, so remove them
+ */
+ top->setTopic( topic.mid(1, topic.length()-2) );
+ QString cmd = "/eval &dostatus();\n";
+ top->sirc_write(cmd);
+ }
+ highlightNick(string, nick);
+ }
+ return new parseSucc(" " + string, ksopts->infoColor, "user|topic");
+}
+
+
+void ChannelParser::highlightNick(QString &string, QString &nick)
+{
+ QRegExp rx(QString("(^|\\s+)%1(\\s+|$)").arg(QRegExp::escape(nick)));
+ string.replace(rx, "\\1~n" + nick + "~n\\2");
+}
+
diff --git a/ksirc/chanparser.h b/ksirc/chanparser.h
new file mode 100644
index 00000000..ef130680
--- /dev/null
+++ b/ksirc/chanparser.h
@@ -0,0 +1,289 @@
+#ifndef CHAN_PARSER_H
+#define CHAN_PARSER_H
+
+#include <qcolor.h>
+#include <qdict.h>
+
+/*
+ * This file defines the parser, and all exceptions generated
+ * by the toplevel parse_input function.
+ */
+
+class ChannelParser; // Main class defined
+class QString;
+class KSircTopLevel;
+
+class parseResult
+{
+public:
+ parseResult() { }
+ virtual ~parseResult() { }
+ // Empty
+};
+
+/*
+ * Parsing is ok, this is the string to display
+ */
+class parseSucc : public parseResult
+{
+public:
+ QString string; // String to display
+ QColor colour;
+ QString pm;
+
+ parseSucc(const QString &_s, const QColor &_c = QColor(), const QString &_pm = QString::null){
+ string = _s;
+ colour = _c;
+ pm = _pm;
+ }
+};
+
+/*
+ * parseError is a fatal error message.
+ * arg0: if it is not empty, it will get displayed to the channel screen (in error colour with mad smile)
+ * arg1: if none empty goes to stderr
+ */
+class parseError : public parseResult
+{
+public:
+ QString str;
+ QString err;
+
+ parseError(const QString &_s, const QString &_e)
+ {
+ str = _s;
+ err = _e;
+ }
+};
+
+class parseWrongChannel : public parseSucc
+{
+public:
+ parseWrongChannel(const QString &_s, const QColor &_c = QColor(), const QString &_pm = QString::null)
+ : parseSucc(_s, _c, _pm)
+ {
+ }
+
+};
+
+class parseJoinPart : public parseSucc
+{
+public:
+ parseJoinPart(const QString &_s, const QColor &_c = QColor(), const QString &_pm = QString::null)
+ : parseSucc(_s, _c, _pm)
+ {
+ }
+
+};
+
+class infoFoundNick {
+public:
+ char nick[101];
+ infoFoundNick(char *_n){
+ strncpy(nick, _n, 100);
+ nick[100]='\0';
+ }
+};
+
+class badModeChangeError // Mode change barfed up, exit out
+{
+public:
+ QString str;
+ char *msg;
+
+ badModeChangeError(QString _str, char *_msg)
+ {
+ str = _str;
+ msg = _msg;
+ }
+};
+
+class wrongChannelError // Message was not intended for us, display str and continue
+{
+public:
+ int display;
+
+ wrongChannelError(int _display)
+ {
+ display = _display;
+ }
+};
+
+class doneModes // Finished parsing modes from the extModes string
+{
+public:
+ doneModes(int /*i*/)
+ {
+ }
+};
+
+// End of exceptions
+
+class parseFunc
+{
+public:
+ parseResult *(ChannelParser::*parser)(QString);
+ parseFunc(parseResult *(ChannelParser::*_parser)(QString)){
+ parser = _parser;
+ }
+
+private:
+ parseFunc(); // Disable the default no argument constructor
+};
+
+
+class ChannelParser {
+
+public:
+ /**
+ * ChannelParser takes a KSircTopLevel as it's first argument so
+ * we can refrence it latter.
+ *
+ * NOTE: the KSircTopLevel befriends the parser so we can have access to.
+ * NOTE2: don't abuse this you little wanker.
+ */
+ ChannelParser(KSircTopLevel *_top);
+
+
+ /**
+ * parse() thanks the string to be parsed and parses it.
+ * It returns a class of type 'parseResult' or 0.
+ */
+ parseResult *parse(QString string);
+
+private:
+ KSircTopLevel *top;
+
+ /**
+ * These are helper variables used internally in the parsing functions
+ */
+
+ bool prompt_active;
+ int current_item;
+ int top_item;
+
+ /**
+ * The parser Table holds a list of functions with parse
+ * sepecific commands and arguments. The key for the dict is the
+ * first 3 characters of the "search key" for the string type.
+ *
+ * Even through the parserTable is static, the functions called manipulate
+ * this object.
+ *
+ * The functions do the following:
+ * - On succesfull compleion: generte a parseSucc exception
+ * - On failure generate: parseFailed, etc
+ */
+
+ static QDict<parseFunc> parserTable;
+
+ /*
+ * Note regarding ssfe control messages:
+ *
+ * They are converted from the form `#ssfe#<COMMAND> to `<COMMAND>`
+ * t/m is converted to t
+ */
+
+ /**
+ * Start of the praser function definitions
+ *
+ * Each function returns void (since they never return it does matter)
+ * 1 argument, the string to parse
+ *
+ */
+
+ /**
+ * SSFE clear 'l' function, clears main window
+ */
+ parseResult * parseSSFEClear(QString string);
+
+ /**
+ * SSFE Status is used to update caption, and op status
+ *
+ */
+ parseResult * parseSSFEStatus(QString string);
+
+ /**
+ * SSFE Init is called by ssfe when it's time to init and setup
+ */
+ parseResult * parseSSFEInit(QString string);
+
+ /**
+ * SSFE msg is called for each /msg sent to a diffrent user
+ */
+ parseResult * parseSSFEMsg(QString string);
+
+ /**
+ * SSFE Out, not used
+ */
+ parseResult * parseSSFEOut(QString string);
+
+ /**
+ * SSFE Prompt, same function used for p and P, gives a password prompt
+ */
+ parseResult * parseSSFEPrompt(QString string);
+
+ /**
+ * SSFE Reconnect called when (re)connected to a server
+ */
+ parseResult * parseSSFEReconnect(QString string);
+
+ /**
+ * That's all the SSFE control messages, the rest are info *\S* message
+ */
+
+ /**
+ * *** is a generic infomation messge
+ */
+ parseResult * parseINFOInfo(QString string);
+
+ /**
+ * *E* is a error message
+ */
+ parseResult * parseINFOError(QString string);
+
+ /**
+ * *#* is a list of nicks, used to update the nick list if it's for
+ * the current channel.
+ */
+ parseResult * parseINFONicks(QString in_string);
+
+ /**
+ * *>* is a join message. If it's for the current channel
+ */
+ parseResult * parseINFOJoin(QString string);
+
+ /**
+ * *<* is a part message, if it's for the current channel remove it.
+ * There's multiple part types, so parsing it more complicated.
+ */
+ parseResult * parseINFOPart(QString string);
+
+ /**
+ * *N* Is a nick change, update the nick list if needed
+ * Nick changes go outto all windows, so the nick may not be on
+ * out current channel.
+ */
+ parseResult * parseINFOChangeNick(QString string);
+
+ /*
+ * *M* is a mode change. Parsing is mode changes is probably the most
+ * complicated of all the parsings
+ */
+ parseResult * parseINFOMode(QString string);
+
+ /*
+ * * is a ctcp actiion. Simply print a pretty * for the user
+ */
+ parseResult * parseCTCPAction(QString string);
+
+ /*
+ * *T* is a topic message, catch it and update the status is required
+ */
+ parseResult * parseINFOTopic(QString string);
+
+private:
+ void highlightNick(QString &string, QString &nick);
+};
+
+#endif
diff --git a/ksirc/charSelector.cpp b/ksirc/charSelector.cpp
new file mode 100644
index 00000000..6cfe09a4
--- /dev/null
+++ b/ksirc/charSelector.cpp
@@ -0,0 +1,77 @@
+/* ascii table for ksirc - Robbie Ward <linuxphreak@gmx.co.uk>*/
+
+#include "charSelector.h"
+#include "charSelector.moc"
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+
+#include <klocale.h>
+
+charSelector::charSelector(QWidget *parent, const char* name)
+ : KDialog(parent, name, false)
+{
+ testLayout = new QVBoxLayout(this);
+ testLayout->setSpacing( spacingHint() );
+ testLayout->setMargin( marginHint() );
+
+ charSelect = new KCharSelect(this, QCString(name) + "_kcharselector", "", 0);
+ testLayout->addWidget(charSelect);
+ charSelect->installEventFilter(this);
+
+ connect(charSelect, SIGNAL(doubleClicked()), SLOT(insertText()));
+
+ QHBoxLayout *buttonLayout = new QHBoxLayout;
+ buttonLayout->setSpacing( spacingHint() );
+
+ insertButton = new QPushButton(i18n("&Insert Char"), this);
+ connect(insertButton, SIGNAL(clicked()), SLOT(insertText()));
+ buttonLayout->addWidget(insertButton);
+
+ QSpacerItem *spacer = new QSpacerItem(50, 20, QSizePolicy::Expanding, QSizePolicy::Expanding);
+ buttonLayout->addItem(spacer);
+
+ testLayout->addLayout(buttonLayout);
+}
+
+charSelector::~charSelector()
+{
+ delete charSelect;
+ charSelect = 0x0;
+}
+
+void charSelector::insertText()
+{
+ emit clicked();
+}
+
+void charSelector::setFont( const QString &font )
+{
+ charSelect->setFont(font);
+}
+
+void charSelector::reject()
+{
+ KDialog::reject();
+ close();
+}
+
+void charSelector::keyPressEvent(QKeyEvent *e)
+{
+ KDialog::keyPressEvent(e);
+}
+
+bool charSelector::eventFilter ( QObject *, QEvent * e )
+{
+ if ( e->type() == QEvent::AccelOverride ) {
+ // special processing for key press
+ QKeyEvent *k = (QKeyEvent *)e;
+ if(k->key() == Key_Escape){
+ keyPressEvent(k);
+ return TRUE; // eat event
+ }
+ }
+ // standard event processing
+ return FALSE;
+}
+
diff --git a/ksirc/charSelector.h b/ksirc/charSelector.h
new file mode 100644
index 00000000..927cb5e5
--- /dev/null
+++ b/ksirc/charSelector.h
@@ -0,0 +1,42 @@
+/* ascii table for ksirc - Robbie Ward <linuxphreak@gmx.co.uk>*/
+
+#ifndef CHARSELECTOR_H
+#define CHARSELECTOR_H
+
+#include <kdialog.h>
+#include <kdebug.h>
+#include <kcharselect.h>
+
+class QVBoxLayout;
+class QPushButton;
+
+class charSelector : public KDialog
+{
+ Q_OBJECT
+ public:
+ charSelector(QWidget *parent=0, const char *name=0);
+ ~charSelector();
+
+ virtual bool eventFilter ( QObject * watched, QEvent * e );
+
+ public slots:
+ void insertText();
+ QString currentText() { return charSelect->chr(); }
+
+ void setFont( const QString &font );
+
+ protected slots:
+ virtual void reject();
+
+ signals:
+ void clicked();
+
+ protected:
+ virtual void keyPressEvent(QKeyEvent *e);
+
+ private:
+ KCharSelect *charSelect;
+ QVBoxLayout* testLayout;
+ QPushButton *insertButton;
+};
+#endif
diff --git a/ksirc/colorpicker.cpp b/ksirc/colorpicker.cpp
new file mode 100644
index 00000000..57b3de60
--- /dev/null
+++ b/ksirc/colorpicker.cpp
@@ -0,0 +1,342 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "colorpicker.h"
+#include "ksopts.h"
+
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qvbox.h>
+#include <qstyle.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+
+#include <klocale.h>
+
+ColorPicker::ColorPicker( QWidget *parent, const char *name )
+ : KDialogBase( parent, name, true /*modal*/, i18n( "Pick Color" ),
+ KDialogBase::Ok | KDialogBase::Cancel,
+ KDialogBase::Cancel ),
+ m_foregroundColor( -1 ), m_backgroundColor( -1 )
+{
+ QVBox *mainWidget = makeVBoxMainWidget();
+
+ QWidget *sampleBox = new QWidget( mainWidget );
+ QHBoxLayout *sampleLayout = new QHBoxLayout( sampleBox );
+
+ QLabel *preview = new QLabel( i18n( "Preview:" ), sampleBox );
+ sampleLayout->addWidget( preview );
+
+ m_sample = new QLineEdit( i18n( "Sample Text" ), sampleBox );
+ m_sample->setFocusPolicy( NoFocus );
+ m_sample->setSizePolicy( QSizePolicy( QSizePolicy::Minimum,
+ m_sample->sizePolicy().verData() ) );
+ sampleLayout->addWidget( m_sample );
+ sampleLayout->addStretch();
+
+ QHBox *box = new QHBox( mainWidget );
+ QLabel *description = new QLabel( i18n( "&Foreground:" ), box );
+ ColorBar *foregroundColor = new ColorBar( ksopts->ircColors.toValueVector(), box );
+ description->setBuddy( foregroundColor );
+
+ box = new QHBox( mainWidget );
+ description = new QLabel( i18n( "&Background:" ), box );
+ ColorBar *backgroundColor = new ColorBar( ksopts->ircColors.toValueVector(), box );
+ description->setBuddy( backgroundColor );
+
+ QPushButton *ok = actionButton( KDialogBase::Ok );
+ QPushButton *cancel = actionButton( KDialogBase::Cancel );
+
+ setTabOrder( foregroundColor, backgroundColor );
+ setTabOrder( backgroundColor, ok );
+ setTabOrder( ok, cancel );
+
+ ok->setAutoDefault( false );
+ cancel->setAutoDefault( false );
+
+ connect( foregroundColor, SIGNAL( colorPicked( int ) ),
+ this, SLOT( setForegroundColor( int ) ) );
+ connect( backgroundColor, SIGNAL( colorPicked( int ) ),
+ this, SLOT( setBackgroundColor( int ) ) );
+
+ ok->setEnabled( false );
+
+ updateSample();
+}
+
+QString ColorPicker::colorString() const
+{
+ assert( m_foregroundColor != -1 );
+ QString res( QString::number( m_foregroundColor ) );
+ if ( m_backgroundColor != -1 )
+ {
+ res += ',';
+ res += QString::number( m_backgroundColor );
+ }
+ return res;
+}
+
+void ColorPicker::setForegroundColor( int col )
+{
+ QPushButton * ok =actionButton( KDialogBase::Ok );
+ assert( ok );
+ ok->setEnabled( true );
+
+ m_foregroundColor = col;
+ updateSample();
+}
+
+void ColorPicker::setBackgroundColor( int col )
+{
+ m_backgroundColor = col;
+ updateSample();
+}
+
+void ColorPicker::updateSample()
+{
+ QColorGroup cg( colorGroup() );
+
+ QColor col = ksopts->textColor;
+ if ( m_foregroundColor != -1 )
+ col = ksopts->ircColors[ m_foregroundColor ];
+
+ cg.setColor( QColorGroup::Foreground, col );
+ cg.setColor( QColorGroup::Text, col );
+
+ if ( m_backgroundColor != -1 )
+ {
+ col = ksopts->ircColors[ m_backgroundColor ];
+ cg.setColor( QColorGroup::Background, col );
+ cg.setColor( QColorGroup::Base, col );
+ }
+
+ m_sample->setPalette( QPalette( cg, cg, cg ) );
+}
+
+ColorBar::ColorBar( const QValueVector<QColor> &colors, QWidget *parent,
+ const char *name )
+ : QFrame( parent, name, WStaticContents | WRepaintNoErase ),
+ m_currentCell( -1 ), m_focusedCell( - 1 ), m_colors( colors ),
+ m_cellSize( 0 )
+{
+ setFrameStyle( StyledPanel | Sunken );
+
+ updateCellSize();
+
+ setFocusPolicy( StrongFocus );
+}
+
+void ColorBar::drawContents( QPainter *p )
+{
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ for ( unsigned int i = 0; i < m_colors.size(); ++i, x += m_cellSize )
+ {
+ bool isCurrentCell = ( m_currentCell != -1 &&
+ i == static_cast<uint>( m_currentCell ) );
+ bool isFocusedCell = ( m_focusedCell != -1 &&
+ i == static_cast<uint>( m_focusedCell ) );
+ drawCell( p, x, y, m_colors[ i ], QString::number( i ),
+ isFocusedCell, isCurrentCell );
+ }
+}
+
+void ColorBar::keyPressEvent( QKeyEvent *ev )
+{
+ if ( m_focusedCell == -1 ) {
+ QFrame::keyPressEvent( ev );
+ return;
+ }
+
+ switch ( ev->key() )
+ {
+ case Key_Left:
+ if ( m_focusedCell > 1 )
+ m_focusedCell--;
+ update();
+ ev->accept();
+ return;
+ case Key_Right:
+ if ( static_cast<uint>( m_focusedCell ) < m_colors.size() - 1 )
+ m_focusedCell++;
+ update();
+ ev->accept();
+ return;
+ case Key_Enter:
+ case Key_Return:
+ case Key_Space:
+ setCurrentCell( m_focusedCell );
+ update();
+ ev->accept();
+ return;
+ default: break;
+ }
+
+ QFrame::keyPressEvent( ev );
+}
+
+void ColorBar::focusInEvent( QFocusEvent *ev )
+{
+ if ( ev->reason() == QFocusEvent::Tab ||
+ ev->reason() == QFocusEvent::Backtab )
+ m_focusedCell = 0;
+ QFrame::focusInEvent( ev );
+}
+
+void ColorBar::focusOutEvent( QFocusEvent *ev )
+{
+ if ( ev->reason() == QFocusEvent::Tab ||
+ ev->reason() == QFocusEvent::Backtab ||
+ ev->reason() == QFocusEvent::Mouse )
+ m_focusedCell = -1;
+ QFrame::focusOutEvent( ev );
+}
+
+void ColorBar::fontChange( const QFont &oldFont )
+{
+ updateCellSize();
+ QFrame::fontChange( oldFont );
+}
+
+void ColorBar::styleChange( QStyle &oldStyle )
+{
+ updateCellSize();
+ QFrame::styleChange( oldStyle );
+}
+
+bool ColorBar::focusNextPrevChild( bool next )
+{
+ if ( next )
+ {
+ assert( m_focusedCell != -1 );
+
+ if ( static_cast<uint>( m_focusedCell ) < m_colors.size() - 1 )
+ {
+ m_focusedCell++;
+ update();
+ return true;
+ }
+ return QFrame::focusNextPrevChild( next );
+ }
+
+ if ( m_focusedCell > 1 )
+ {
+ m_focusedCell--;
+ update();
+ return true;
+ }
+
+ return QFrame::focusNextPrevChild( next );
+}
+
+void ColorBar::mousePressEvent( QMouseEvent *ev )
+{
+ const QPoint &p = ev->pos();
+ if ( contentsRect().contains( p ) )
+ {
+ m_focusedCell = p.x() / m_cellSize;
+ update();
+ }
+
+ QFrame::mousePressEvent( ev );
+}
+
+void ColorBar::mouseReleaseEvent( QMouseEvent *ev )
+{
+ if ( m_focusedCell != -1 )
+ {
+ setCurrentCell( m_focusedCell );
+ update();
+ }
+ QFrame::mouseReleaseEvent( ev );
+}
+
+void ColorBar::updateCellSize()
+{
+ setLineWidth( style().pixelMetric( QStyle::PM_DefaultFrameWidth, this ) );
+
+ QFontMetrics metrics( font() );
+
+ m_cellSize = metrics.width( QString::number( m_colors.size() ) ) +
+ ( s_indicatorSize * 2 ) +
+ ( s_focusSize * 2 ) +
+ ( s_innerMargin * 2 );
+
+ setFixedSize( QSize( ( m_colors.size() * m_cellSize ) + ( frameWidth() * 2 ),
+ m_cellSize + ( frameWidth() * 2 ) ) );
+}
+
+void ColorBar::setCurrentCell( int cell )
+{
+ m_currentCell = cell;
+ emit colorPicked( cell );
+}
+
+void ColorBar::drawCell( QPainter *p, int x, int y, const QColor &color,
+ const QString &text, bool isFocusedCell,
+ bool isCurrentCell )
+{
+ p->fillRect( x, y, m_cellSize, m_cellSize, color );
+
+ QColor penColor = black;
+ // ### hack
+ if ( color.red() < 127 && color.green() < 127 && color.blue() < 127 )
+ penColor = white;
+
+ p->setPen( penColor );
+
+ if ( isCurrentCell )
+ {
+ p->fillRect( x, y, m_cellSize, s_indicatorSize, penColor );
+ p->fillRect( x, y + s_indicatorSize,
+ s_indicatorSize, m_cellSize - ( 2 * s_indicatorSize ), penColor );
+ p->fillRect( x, y + m_cellSize - s_indicatorSize,
+ m_cellSize, s_indicatorSize, penColor );
+ p->fillRect( x + m_cellSize - s_indicatorSize, y + s_indicatorSize,
+ s_indicatorSize, m_cellSize - ( 2 * s_indicatorSize ), penColor );
+ }
+
+ if ( isFocusedCell )
+ {
+ int focusRectSize = m_cellSize - ( 2 * s_indicatorSize );
+
+ p->fillRect( x + s_indicatorSize, y + s_indicatorSize,
+ focusRectSize, s_focusSize, penColor );
+ p->fillRect( x + s_indicatorSize, y + s_indicatorSize + s_focusSize,
+ s_focusSize, focusRectSize - ( 2 * s_focusSize ), penColor );
+ p->fillRect( x + s_indicatorSize,
+ y + m_cellSize - s_indicatorSize - s_focusSize,
+ focusRectSize, s_focusSize, penColor );
+ p->fillRect( x + m_cellSize - s_indicatorSize - s_focusSize,
+ y + s_indicatorSize + s_focusSize,
+ s_focusSize, focusRectSize - ( 2 * s_focusSize ), penColor );
+ }
+
+ QFontMetrics metrics( p->font() );
+
+ int offset = ( m_cellSize / 2 ) - ( metrics.width( text ) / 2 );
+ p->drawText( x + offset, y + s_focusSize + s_indicatorSize +
+ + metrics.ascent(), text );
+}
+
+#include "colorpicker.moc"
+
+/* vim: et sw=4
+ */
diff --git a/ksirc/colorpicker.h b/ksirc/colorpicker.h
new file mode 100644
index 00000000..67d199ae
--- /dev/null
+++ b/ksirc/colorpicker.h
@@ -0,0 +1,91 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+#ifndef __colorpicker_h__
+#define __colorpicker_h__
+
+#include <qvaluevector.h>
+#include <qcolor.h>
+
+#include <kdialogbase.h>
+
+class QLineEdit;
+
+class ColorPicker : public KDialogBase
+{
+ Q_OBJECT
+public:
+ ColorPicker( QWidget *parent, const char *name = 0 );
+
+ QString colorString() const;
+
+private slots:
+ void setForegroundColor( int col );
+ void setBackgroundColor( int col );
+
+private:
+ void updateSample();
+
+ QLineEdit *m_sample;
+ int m_foregroundColor;
+ int m_backgroundColor;
+};
+
+class ColorBar : public QFrame
+{
+ Q_OBJECT
+public:
+ ColorBar( const QValueVector<QColor> &colors, QWidget *parent, const char *name = 0 );
+
+signals:
+ void colorPicked( int col );
+
+protected:
+ virtual void drawContents( QPainter *p );
+ virtual void keyPressEvent( QKeyEvent *ev );
+ virtual void focusInEvent( QFocusEvent *ev );
+ virtual void focusOutEvent( QFocusEvent *ev );
+ virtual void fontChange( const QFont &oldFont );
+ virtual void styleChange( QStyle &oldStyle );
+ virtual bool focusNextPrevChild( bool next );
+ virtual void mousePressEvent( QMouseEvent *ev );
+ virtual void mouseReleaseEvent( QMouseEvent *ev );
+
+private:
+ void updateCellSize();
+ void setCurrentCell( int cell );
+
+ void drawCell( QPainter *p, int x, int y, const QColor &color,
+ const QString &text, bool isFocusedCell,
+ bool isCurrentCell );
+
+ int m_currentCell;
+ int m_focusedCell;
+ const QValueVector<QColor> m_colors;
+ int m_cellSize;
+
+ // ### style me
+ static const int s_indicatorSize = 2;
+ static const int s_focusSize = 1;
+ static const int s_innerMargin = 1;
+};
+
+#endif
+
+/* vim: et sw=4
+ */
diff --git a/ksirc/control_message.h b/ksirc/control_message.h
new file mode 100644
index 00000000..cae8dd1b
--- /dev/null
+++ b/ksirc/control_message.h
@@ -0,0 +1,15 @@
+#ifndef CONTROL_MESSAGE_H
+#define CONTROL_MESSAGE_H
+
+ // 001 is change channel
+ // 002 is stop writting to mainw
+ // 003 is resume updating mainw and flush buffer
+
+#define CHANGE_CHANNEL 001
+#define STOP_UPDATES 002
+#define RESUME_UPDATES 003
+#define REREAD_CONFIG 004
+#define SET_LAG 005
+#define RESET_NOTIF 006
+
+#endif
diff --git a/ksirc/dccManager.cpp b/ksirc/dccManager.cpp
new file mode 100644
index 00000000..44d85dee
--- /dev/null
+++ b/ksirc/dccManager.cpp
@@ -0,0 +1,403 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Andrew Stanley-Jones <asj-kde@cban.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Artistic License.
+*/
+
+#include "dccManager.h"
+#include "dccNew.h"
+
+#include <qobject.h>
+#include <qsignal.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+
+#define COL_FILE 1
+#define COL_WHO 0
+#define COL_STAT 2
+#define COL_SIZE 3
+#define COL_CPS 4
+#define COL_PER 5
+
+dccItem::dccItem( KListView *parent, dccManager *manager, enum dccType type, const QString &file, const QString& who, enum dccStatus status, unsigned int size )
+ : QObject(), KListViewItem(parent), m_who(who), m_file(file), m_type(type)
+{
+ m_percent = 0;
+ m_status = status;
+ m_size = size;
+ m_stime = 0;
+ m_lasttime = 0;
+ m_manager = manager;
+
+ setText(COL_FILE, file);
+ setText(COL_WHO, who);
+ setText(COL_STAT, enumToStatus(status));
+ if(m_type == dccChat)
+ setText(COL_SIZE, "");
+ else
+ setText(COL_SIZE, QString("%1").arg(size));
+ setText(COL_PER, "");
+
+}
+
+dccItem::dccItem( KListViewItem *parent, dccManager *manager, enum dccType type, const QString &file, const QString& who, enum dccStatus status, unsigned int size )
+: QObject(), KListViewItem(parent), m_who(who), m_file(file), m_type(type)
+{
+ m_percent = 0;
+ m_status = status;
+ m_size = size;
+ m_stime = 0;
+ m_manager = manager;
+
+ setText(COL_FILE, file);
+ setText(COL_WHO, who);
+ setText(COL_STAT, enumToStatus(status));
+ if(type != dccChat)
+ setText(COL_SIZE, QString("%1").arg(size));
+ setText(COL_PER, "");
+
+}
+
+dccItem::~dccItem()
+{
+}
+
+QString dccItem::enumToStatus(enum dccStatus status)
+{
+ QString str;
+ switch(status){
+ case dccRecving:
+ str = i18n("Receiving");
+ break;
+ case dccGotOffer:
+ str = i18n("Got Offer");
+ break;
+ case dccSentOffer:
+ str = i18n("Sent Offer");
+ break;
+ case dccWaitOnResume:
+ str = i18n("Resume Requested");
+ break;
+ case dccResumed:
+ str = i18n("Did Resume");
+ break;
+ case dccSending:
+ str = i18n("Sending");
+ break;
+ case dccOpen:
+ str = i18n("dcc status", "Open");
+ break;
+ case dccDone:
+ str = i18n("Done");
+ break;
+ case dccCancel:
+ str = i18n("Canceled");
+ break;
+ case dccError:
+ str = i18n("Error");
+ break;
+ default:
+ str = i18n("Unknown State");
+ break;
+ }
+ return str;
+}
+
+void dccItem::setWhoPostfix(const QString &post) {
+ m_post = post;
+ setText(COL_WHO, QString("%1 %2").arg(m_who).arg(post));
+}
+
+void dccItem::changeFilename(const QString &file) {
+ setText(COL_FILE, file);
+ m_file = file;
+}
+
+void dccItem::changeWho(const QString &who) {
+ setText(COL_WHO, who);
+ m_who = who;
+}
+
+void dccItem::changeStatus(enum dccStatus status)
+{
+ m_manager->doChanged();
+ setText(COL_STAT, enumToStatus(status));
+ m_status = status;
+ emit statusChanged(this);
+}
+
+void dccItem::setReceivedBytes(int bytes)
+{
+ int per;
+ time_t ctime = time(NULL);
+
+ if(m_stime == 0)
+ m_stime = ctime-1;
+
+ if(m_size)
+ per = (100*bytes)/m_size;
+ else
+ per = 100;
+
+ if((per != (int)m_percent) ||
+ (ctime >= (m_lasttime + 2))
+ ){
+ m_lasttime = ctime;
+ setText(COL_SIZE, QString("%1/%2").arg(bytes).arg(m_size));
+ setText(COL_PER, QString("%1%").arg(per));
+ m_percent = per;
+ if(m_status == dccResumed)
+ m_stime = 0; /* if we are got a resume request don't update CPS, reset it */
+ else
+ setText(COL_CPS, QString("%1").arg(1.0*bytes/(time(NULL) - m_stime), 2));
+ }
+
+
+}
+
+void dccItem::doRename()
+{
+
+ if(type() == dccGet){
+ setRenameEnabled(COL_FILE, true);
+ startRename(COL_FILE);
+ }
+ else if(type() == dccChat){
+ setText(COL_WHO, m_who);
+ setRenameEnabled(COL_WHO, true);
+ startRename(COL_WHO);
+ }
+
+}
+
+void dccItem::okRename(int col)
+{
+ KListViewItem::okRename(col);
+ if(type() == dccGet){
+ QString oldfile = m_file;
+ changeFilename(text(COL_FILE));
+ emit itemRenamed(this, m_who, oldfile);
+ setRenameEnabled(COL_FILE, false);
+ }
+ else if(type() == dccChat){
+ QString oldwho = m_who;
+ changeWho(text(COL_WHO));
+ emit itemRenamed(this, oldwho, m_file);
+ setRenameEnabled(COL_WHO, false);
+ setWhoPostfix(m_post);
+ }
+}
+
+void dccItem::cancelRename(int col)
+{
+ KListViewItem::cancelRename(col);
+ if(type() == dccChat){
+ setWhoPostfix(m_post);
+ }
+}
+
+dccManager::dccManager( QWidget *parent, const char *name ) : dccManagerbase( parent, name)
+{
+ dccNewDialog = 0x0;
+
+ m_getit = new KListViewItem(klvBox, i18n("Get"));
+ m_sendit = new KListViewItem(klvBox, i18n("Send"));
+ m_chatit = new KListViewItem(klvBox, i18n("Chat"));
+
+ m_getit->setOpen(true);
+ m_sendit->setOpen(true);
+ m_chatit->setOpen(true);
+
+ m_getit->setSelectable(false);
+ m_sendit->setSelectable(false);
+ m_chatit->setSelectable(false);
+
+// connect(klvBox, SIGNAL(clicked(QListViewItem *)),
+// this, SLOT(getSelChange(QListViewItem *)));
+ connect(klvBox, SIGNAL(currentChanged(QListViewItem *)),
+ this, SLOT(getSelChange(QListViewItem *)));
+
+ klvBox->setCurrentItem(m_chatit);
+ getSelChange(klvBox->currentItem());
+}
+
+dccManager::~dccManager()
+{
+}
+
+dccItem *dccManager::newSendItem(QString file, QString who, enum dccItem::dccStatus status, unsigned int size)
+{
+ emit changed(false, i18n("dcc activity"));
+ dccItem *it = new dccItem(m_sendit, this, dccItem::dccSend, file, who, status, size);
+ connect(it, SIGNAL(statusChanged(QListViewItem *)),
+ this, SLOT(getSelChange(QListViewItem *)));
+ return it;
+}
+
+dccItem *dccManager::newGetItem(QString file, QString who, enum dccItem::dccStatus status, unsigned int size)
+{
+ emit changed(false, i18n("dcc activity"));
+ dccItem *it = new dccItem(m_getit, this, dccItem::dccGet, file, who, status, size);
+ connect(it, SIGNAL(statusChanged(QListViewItem *)),
+ this, SLOT(getSelChange(QListViewItem *)));
+ return it;
+
+}
+
+dccItem *dccManager::newChatItem(QString who, enum dccItem::dccStatus status)
+{
+ emit changed(false, i18n("dcc activity"));
+ dccItem *it = new dccItem(m_chatit, this, dccItem::dccChat, "", who, status, 0);
+ connect(it, SIGNAL(statusChanged(QListViewItem *)),
+ this, SLOT(getSelChange(QListViewItem *)));
+ return it;
+
+}
+
+void dccManager::kpbNew_clicked()
+{
+ if(dccNewDialog){
+ dccNewDialog->show();
+ dccNewDialog->raise();
+ return;
+ }
+
+ dccNewDialog = new dccNew();
+ dccNewDialog->show();
+
+ connect(dccNewDialog, SIGNAL(accepted(int, QString, QString)),
+ this, SLOT(dccNewAccepted(int, QString, QString)));
+
+}
+
+void dccManager::dccNewAccepted(int type, QString nick, QString file){
+ kdDebug(5008) << "Type: " << type << " nick: " << nick << " file: " << file << endl;
+ if(type == dccNew::Chat){
+ QCString cstr = QCString("/dcc chat ") + nick.latin1() + "\n";
+ kdDebug(5008) << "Output: " << cstr << endl;
+ emit outputLine(cstr);
+ }
+ else if(type == dccNew::Send){
+ QCString cstr = QCString("/dcc send ") + nick.latin1() + " " + file.latin1() + "\n";
+ emit outputLine(cstr);
+ }
+ delete dccNewDialog;
+ dccNewDialog = 0x0;
+}
+
+void dccManager::kpbConnect_clicked()
+{
+ dccItem *it = dynamic_cast<dccItem *>(klvBox->currentItem());
+ if(it){
+ emit dccConnectClicked(it);
+ }
+
+}
+void dccManager::kpbResume_clicked()
+{
+ dccItem *it = dynamic_cast<dccItem *>(klvBox->currentItem());
+ if(it){
+ emit dccResumeClicked(it);
+ }
+}
+void dccManager::kpbRename_clicked()
+{
+ dccItem *it = dynamic_cast<dccItem *>(klvBox->currentItem());
+ if(it){
+ emit dccRenameClicked(it);
+ }
+}
+void dccManager::kpbAbort_clicked()
+{
+ dccItem *it = dynamic_cast<dccItem *>(klvBox->currentItem());
+ if(it){
+ emit dccAbortClicked(it);
+ }
+}
+
+void dccManager::getSelChange(QListViewItem *_i) {
+ kpbAbort->setEnabled(false);
+ kpbResume->setEnabled(false);
+ kpbRename->setEnabled(false);
+ kpbConnect->setEnabled(false);
+
+ if(_i == 0)
+ return;
+ dccItem *it = dynamic_cast<dccItem *>(_i);
+ if(!it)
+ return;
+
+ /*
+ * Everything is off by default
+ * We need to turn on what we want
+ */
+ switch(it->type()){
+ case dccItem::dccChat:
+ kdDebug(5008) << "is a chat" << endl;
+ kpbAbort->setEnabled(true);
+ switch(it->status()){
+ case dccItem::dccGotOffer:
+ kpbConnect->setEnabled(true);
+ break;
+ case dccItem::dccOpen:
+ kpbRename->setEnabled(true);
+ break;
+ default:
+ break;
+ }
+ break;
+ case dccItem::dccGet:
+ kdDebug(5008) << "is a get" << endl;
+ kpbAbort->setEnabled(true);
+ switch(it->status()){
+ case dccItem::dccGotOffer:
+ case dccItem::dccWaitOnResume:
+ case dccItem::dccResumed:
+ kpbResume->setEnabled(true);
+ kpbConnect->setEnabled(true);
+ kpbRename->setEnabled(true);
+ break;
+ default:
+ break;
+ }
+ break;
+ case dccItem::dccSend:
+ kdDebug(5008) << "is a send" << endl;
+ kpbAbort->setEnabled(true);
+ break;
+ default:
+ break;
+ }
+
+
+}
+void dccManager::sendSelChange(QListViewItem *) {
+ /*
+ if(_i == 0)
+ return;
+ dccItem *it = static_cast<dccItem *>(_i);
+
+ kdDebug(5008) << "got: " << it->who() << " file: " << it->file() << endl;
+
+ switch(it->status()){
+ case dccItem::dccSending:
+ case dccItem::dccRecving:
+ kpbSendStop->setText(i18n("Abort"));
+ break;
+ case dccItem::dccOffer:
+ kpbSendStop->setText(i18n("Forget"));
+ break;
+ case dccItem::dccDone:
+ kpbSendStop->setText(i18n("Clear"));
+ break;
+ }
+ */
+
+}
+
+
+#include "dccManager.moc"
+
diff --git a/ksirc/dccManager.h b/ksirc/dccManager.h
new file mode 100644
index 00000000..41412479
--- /dev/null
+++ b/ksirc/dccManager.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _DCCMANAGER_H
+#define _DCCMANAGER_H
+
+#include <time.h>
+
+#include <qobject.h>
+
+#include "dccManagerbase.h"
+#include "klistview.h"
+
+
+class dccManager;
+class QSignal;
+class QObject;
+
+class dccItem : public QObject,
+ public KListViewItem
+{
+Q_OBJECT
+public:
+ enum dccStatus {
+ dccRecving,
+ dccOpen,
+ dccWaitOnResume,
+ dccResumed,
+ dccSentOffer,
+ dccGotOffer,
+ dccSending,
+ dccDone,
+ dccCancel,
+ dccError
+ };
+
+ enum dccType {
+ dccGet,
+ dccChat,
+ dccSend
+ };
+
+ dccItem( KListView *, dccManager *, enum dccType, const QString &file, const QString &who, enum dccStatus, unsigned int size );
+ dccItem( KListViewItem *, dccManager *, enum dccType, const QString &file, const QString &who, enum dccStatus, unsigned int size );
+ virtual ~dccItem();
+
+ void changeStatus(enum dccStatus);
+ void setReceivedBytes(int bytes);
+
+ void setWhoPostfix(const QString &post);
+ void changeFilename(const QString &file);
+ void changeWho(const QString &who);
+
+ const QString who() { return m_who; }
+ const QString file() { return m_file; }
+ enum dccStatus status() { return m_status; }
+ enum dccType type() { return m_type; }
+ double getPercent() { return m_percent; }
+
+ void doRename();
+
+signals:
+ void statusChanged(QListViewItem *);
+ void itemRenamed(dccItem *, QString oldNick, QString oldFile);
+
+protected:
+ QString enumToStatus(enum dccStatus);
+
+ virtual void okRename ( int col );
+ virtual void cancelRename ( int col );
+
+private:
+
+ dccManager *m_manager;
+ QString m_who;
+ QString m_file;
+ QString m_post;
+ int m_percent;
+ unsigned int m_size;
+ enum dccStatus m_status;
+ const enum dccType m_type;
+ time_t m_stime;
+ time_t m_lasttime;
+};
+
+
+class dccNew;
+
+class dccManager : public dccManagerbase
+{
+Q_OBJECT
+
+public:
+ dccManager( QWidget *parent = 0, const char *name = 0 );
+ ~dccManager();
+
+ dccItem *newSendItem(QString file, QString who, enum dccItem::dccStatus, unsigned int size);
+ dccItem *newGetItem(QString file, QString who, enum dccItem::dccStatus, unsigned int size);
+ dccItem *newChatItem(QString who, enum dccItem::dccStatus);
+
+ void doChanged() { emit changed(false, QString("dcc activity")); };
+
+public slots:
+ virtual void kpbNew_clicked();
+ virtual void kpbConnect_clicked();
+ virtual void kpbResume_clicked();
+ virtual void kpbRename_clicked();
+ virtual void kpbAbort_clicked();
+
+signals:
+ void outputLine(QCString);
+ void changed(bool, QString);
+ virtual void dccConnectClicked(dccItem *);
+ virtual void dccResumeClicked(dccItem *);
+ virtual void dccRenameClicked(dccItem *);
+ virtual void dccAbortClicked(dccItem *);
+
+protected slots:
+ virtual void getSelChange(QListViewItem *);
+ virtual void sendSelChange(QListViewItem *);
+ virtual void dccNewAccepted(int type, QString nick, QString file);
+
+private:
+
+ KListViewItem *m_getit;
+ KListViewItem *m_sendit;
+ KListViewItem *m_chatit;
+
+ dccNew *dccNewDialog;
+};
+
+#endif
diff --git a/ksirc/dccManagerbase.ui b/ksirc/dccManagerbase.ui
new file mode 100644
index 00000000..b925b1b2
--- /dev/null
+++ b/ksirc/dccManagerbase.ui
@@ -0,0 +1,202 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>dccManagerbase</class>
+<widget class="QFrame">
+ <property name="name">
+ <cstring>dccManagerbase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>717</width>
+ <height>318</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>DCC Manager</string>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Who</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>File</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Status</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Size</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>KB/s</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Progress</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>klvBox</cstring>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbNew</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;New...</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbConnect</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Connect</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbResume</cstring>
+ </property>
+ <property name="text">
+ <string>R&amp;esume</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbRename</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Rename</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbAbort</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Disconnect</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kpbRename</sender>
+ <signal>clicked()</signal>
+ <receiver>dccManagerbase</receiver>
+ <slot>kpbRename_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>kpbConnect</sender>
+ <signal>clicked()</signal>
+ <receiver>dccManagerbase</receiver>
+ <slot>kpbConnect_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>kpbResume</sender>
+ <signal>clicked()</signal>
+ <receiver>dccManagerbase</receiver>
+ <slot>kpbResume_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>kpbAbort</sender>
+ <signal>clicked()</signal>
+ <receiver>dccManagerbase</receiver>
+ <slot>kpbAbort_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>kpbNew</sender>
+ <signal>clicked()</signal>
+ <receiver>dccManagerbase</receiver>
+ <slot>kpbNew_clicked()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>kpbResume_clicked()</slot>
+ <slot>kpbConnect_clicked()</slot>
+ <slot>kpbRename_clicked()</slot>
+ <slot>kpbAbort_clicked()</slot>
+ <slot>kpbNew_clicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/ksirc/dccMgrTest.cpp b/ksirc/dccMgrTest.cpp
new file mode 100644
index 00000000..77d5fdac
--- /dev/null
+++ b/ksirc/dccMgrTest.cpp
@@ -0,0 +1,44 @@
+#include <kapplication.h>
+
+#include "dccManager.h"
+
+class Timer : public QObject
+{
+public:
+ Timer( dccManager *view )
+ : m_view( view )
+ {
+ m_it = m_view->newSendItem("test", "boren", dccItem::dccSentOffer, 123523);
+ m_view->newSendItem("test2", "boren", dccItem::dccSentOffer, 123523);
+ m_view->newSendItem("test3", "boren", dccItem::dccSentOffer, 123523);
+ m_view->newGetItem("test4", "boren", dccItem::dccGotOffer, 123523);
+ m_view->newGetItem("test4", "boren", dccItem::dccGotOffer, 123523);
+ m_view->newGetItem("test4", "boren", dccItem::dccGotOffer, 123523);
+ bytes = 0;
+ startTimer( 100 );
+ }
+ void timerEvent( QTimerEvent * )
+ {
+ m_it->changeStatus(dccItem::dccSending);
+ bytes += 1000;
+ m_it->setReceivedBytes(bytes);
+
+ }
+private:
+ dccManager *m_view;
+ int bytes;
+ dccItem *m_it;
+};
+
+
+int main(int argc, char **argv){
+ KApplication a(argc, argv, "dccMgrTest" );
+
+ dccManager kst(0, "toplevel");
+ Timer t(&kst);
+
+ a.setMainWidget(&kst);
+ kst.show();
+ return a.exec();
+}
+
diff --git a/ksirc/dccNew.cpp b/ksirc/dccNew.cpp
new file mode 100644
index 00000000..fe44fae6
--- /dev/null
+++ b/ksirc/dccNew.cpp
@@ -0,0 +1,162 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qspinbox.h>
+#include <qstringlist.h>
+#include <qlistbox.h>
+
+#include <kapplication.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kurlrequester.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+
+#include "alistbox.h"
+#include "dccNew.h"
+#include "objFinder.h"
+
+dccNew::dccNew( QWidget *parent, const char *name, int type, QString nick )
+ : dccNewBase( parent, name)
+{
+
+ QColorGroup cg_mainw = kapp->palette().active();
+ cg_mainw.setColor(QColorGroup::Base, ksopts->backgroundColor);
+ cg_mainw.setColor(QColorGroup::Text, ksopts->textColor);
+ cg_mainw.setColor(QColorGroup::Link, ksopts->linkColor);
+ cg_mainw.setColor(QColorGroup::Highlight, ksopts->selBackgroundColor);
+ cg_mainw.setColor(QColorGroup::HighlightedText, ksopts->selForegroundColor);
+ nickList->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw));
+
+ QStringList allalist = objFinder::allObjects().grep(I18N_NOOP("aListBox::"));
+
+ for ( QStringList::Iterator it = allalist.begin();
+ it != allalist.end();
+ ++it ) {
+ QString name = (*it).section("::", 1);
+ kdDebug(5008) << "Looking at: " << *it << "/" << name << endl;
+
+ aListBox *a = static_cast<aListBox *>(objFinder::find(name.latin1(), "aListBox"));
+ if(a){
+ QListBoxItem *i;
+ for(i = a->firstItem(); i != 0x0; i = i->next()){
+ nickListItem *it = new nickListItem(*a->item(a->index(i)));
+ nickList->inSort(it);
+ }
+ }
+ else {
+ kdDebug(5008) << "Didn't find: " << name << endl;
+ }
+ }
+
+ KCompletion *comp = cbNicks->completionObject();
+
+ QListBoxItem *i;
+ for(i = nickList->firstItem(); i != 0x0; i = i->next()){
+ comp->addItem(i->text());
+ cbNicks->insertItem(i->text());
+ }
+ cbNicks->setCurrentText(nick);
+
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("dccNew");
+
+ bool chatChecked = kConfig->readBoolEntry("chatChecked", false);
+
+ /*
+ * allow type to override
+ * the config setting
+ */
+ if(type == Chat){
+ chatChecked = true;
+ }
+ else if(type == Send){
+ chatChecked = false;
+ }
+
+ if(chatChecked) {
+ rbChat->setChecked(true);
+ chatClicked();
+ }
+ else {
+ rbFileSend->setChecked(true);
+ fileSendClicked();
+ }
+
+ connect(nickList, SIGNAL(highlighted(const QString &)),
+ cbNicks, SLOT(setEditText(const QString &)));
+
+ connect(pbCancel, SIGNAL(clicked()),
+ this, SLOT(reject()));
+
+ connect(pbSend, SIGNAL(clicked()),
+ this, SLOT(accept()));
+
+
+}
+
+dccNew::~dccNew()
+{
+}
+
+
+void dccNew::chatClicked()
+{
+ gbFile->setEnabled(false);
+}
+
+void dccNew::fileSendClicked()
+{
+ gbFile->setEnabled(true);
+}
+
+void dccNew::sendClicked()
+{
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("dccNew");
+ kConfig->writeEntry("chatChecked",rbChat->isChecked());
+ int type = Chat;
+ if(rbFileSend->isChecked())
+ type = Send;
+ emit accepted(type, cbNicks->currentText(), leFile->text());
+}
+
+void dccNew::fileClicked()
+{
+ QString file =
+ KFileDialog::getOpenFileName();
+
+ leFile->setText(file);
+}
+
+QString dccNew::getFile() {
+ return leFile->text() ;
+}
+
+QString dccNew::getNick() {
+ return cbNicks->currentText();
+}
+
+int dccNew::getType() {
+ int type = Chat; if(rbFileSend->isChecked()) type = Send;
+ return type;
+}
+
+void dccNew::reject()
+{
+ emit accepted(-1, QString::null, QString::null);
+}
+
+
+#include "dccNew.moc"
diff --git a/ksirc/dccNew.h b/ksirc/dccNew.h
new file mode 100644
index 00000000..e0adcf80
--- /dev/null
+++ b/ksirc/dccNew.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation version 2 of the License. *
+ * *
+ ***************************************************************************/
+
+#ifndef DCC_NEW_H
+#define DCC_NEW_H
+
+#include "dccNewbase.h"
+
+class dccNew : public dccNewBase
+{
+Q_OBJECT
+
+public:
+ dccNew( QWidget *parent = 0,
+ const char *name = 0,
+ int type = -1,
+ QString nick = QString::null );
+ ~dccNew();
+
+ enum { Chat, Send };
+
+ QString getFile();
+ QString getNick();
+ int getType();
+
+
+signals:
+ void modified();
+ void accepted(int type, QString nick, QString file);
+
+protected slots:
+ virtual void chatClicked();
+ virtual void fileSendClicked();
+ virtual void sendClicked();
+ virtual void fileClicked();
+ virtual void reject();
+};
+
+#endif
diff --git a/ksirc/dccNewbase.ui b/ksirc/dccNewbase.ui
new file mode 100644
index 00000000..32106e48
--- /dev/null
+++ b/ksirc/dccNewbase.ui
@@ -0,0 +1,237 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>dccNewBase</class>
+<author>Andrew Stanley-Jones</author>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>dccNewBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>424</width>
+ <height>386</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New DCC</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>DCC Type</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rbFileSend</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;File send</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rbChat</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;hat</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Nick</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="aListBox">
+ <property name="name">
+ <cstring>nickList</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>100</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>cbNicks</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>gbFile</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>File Name</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>leFile</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pbFile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;...</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pbSend</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Send</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pbCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>aListBox</class>
+ <header location="local">alistbox.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="4462">789c9d97c76e24490e86effd1442f3d65870d2451a0ce6206f5adeb4cc620f8c34f2553225b5a4c1befb46927fe6a1d4c0ccac4287fa8a0c26834193f5dbb785b3fd9d856fbf7d799ec9ecba5ea8afe469e15bf3727ffffeeffffcf1e797af49b2d0ffc7d142f2f55f5fbe1ecc16ea85dde9a4ed81290045faa77ca49cf4ab67ba1e3953969173651ab9d4fdf1c8a27c3872ad7c3c72d3b32c2a67c3f3444636fbef23eb7e590267e68fcc4656395d8dacf6d938ef97eaef289781cddebdb2846fccff44b989ba58e3411f3dc75158e6df1d3889539517ca49bf54fe43398d1dec4f46567f685fd9c539f43fc025f80c1c3ce8d93f28e77185f8bf0c6cfae4c0b5f9c3c6e5c0542a4b5876fe13708df39d2bd7716372aa8c93c4e4723bb2f977aadc26ceec4bdb7310e6b0bfab9c2445ecd49f1370694cebca65d260ffa6711a41aef14d24e94cee6be3348e0ae5e9c8765f07ca3e8db17f0f9c825794eb3489351fe9bb7217e4969f29388bd51ee9fda5715a19730696b852fea95c6471647ca95cf64bcf43e0cef4657b647bfe6acf213d6bb32f9a9f5992b5a64f9a8f990b6cf9ecc15d6cf9acf6b2da55a8a75cb973dee4b2d1b38b5c05de02434e87e01aacfb351df5bebddea74b5c67f9c795711ea15e357e2ecde358fb87efc0a867df8cac728a074e62e527706afb59f3cf6583be5c28bb3c35f693812d1fbdc6dbe57966fec932d899ffa4f7e38adca17e34beaeca4b9c271a18f1d5fc739257b0d70d9c68be7bed7fcee7827ab91cd8e4740cf6b19d4ffb87ab07b9bf516e72d4a3ac821b9cef6e60d84f47367ded2fae1d9f7704f6163f79000ffde27660f387ed3c5dbf54dfeebb0bf6acbe6b706bfa5ef32f8f8b18f5bf0f463f20edb77956a4e68fbc80b3c4facd163847be6bfde72ec86dbeac82715fbc0286be683cf3bc081d44f7df80d344fb0b6b7de64581fb916765297263d6fccd9b7ee97e566e8b06cfdb1f59cf2bda2f8bbc2c11df0c5c41aefdb328ca22b1feb0012eedbce24736f91b18fb796d64eb87cb60817dcdafb07d906bfd14d22f659d8785ef97b2f6d7b2df6ef1d6fb2babaac6f92e8c25b27ecc1f239b7f3a5fca5a8678ea7c2d9bc0e6ef1238b3fca2c7814d5f4cbf9334b5f833384bed3c7a5f5514f4adbe2ec07962e7590457f06f6f649b977afe2a16f42f5e070bfc591e18f7a5f1a812a9e0df39d827da4fbd8c6ccfd7785569bf945f953371a9d5a3de67950bfa2d75c63eb2fb15bdcfaaf011e6c7263846bf8f4636f91618f3c7d3c0f047fb69550efab2074e12bd6fd27957553ec33c5b043bcc7f9d0795f818fdb501a3df8ae673e507ff69021eea37063bc45ffb73550736ff36c0a84f3e0317a86f8b5f139e6ffe1f821de6d9127898ff3be00a7c3ab2cd03e3d697560ff40016e47b3bb2e96bbd559d8f32bbff4b7065f193042c98873acf240af6adbf3c83c5f2954bb0c7bcd77c107d81d2fdebc63e33ff640aaecc9e1c8151df5c803dfaadc64b52dfa03ed64636ffb4ff4b2867f453ede7227586fcd3f9264ded91fffafe236d5da37fe83c91ceb7b9e5b7f6731ff92ed7f747d6fbf7e185cf58347e3e6932e47b3430fa893edf87d795c2fc3f003b67f5f902cec17abfde0dfa3c053b3c5ffb832fc2eb8fddcf233887fc195c801f46b6f3cdc02558fba72f7d2d1a7f7e321ee58fe0cad86bbff24dd3e2fe74fef836b0c6eb60d62fa6bf5e07b3419f853dd7dc70fb8bd5f1255fd90ed30f9f3c5ff30ddff21ddff384a7fcc08ffcc4cf61cdf8855ff9e79c7e1db4dff89d3f7891977899577895d7789d377893b7f83b6fcfe937bc13b477798ff7f9800ff928ac633ee11f7cca6761d7f99c7e1b3cb908da11c7413be1943376e153cc39175c72f549ff9e17c31744429e6a6aa8a58e2ee98aaee9866e7f617fc24b7417a4f734a1293dd0233dd133cd8285177aa5f9f3b63ca5377aa78f607b919668995682e62aadd17ab0b1419b9ff41f682b48bed336edd02eed05ed7d5ea3033a0cdf1ed1f127fd273ae123fa41a774a6b685cee982228a837e42e927fd47caf8985c38651eb40b2ac38e4a5842658a97fab33fd248cb87d2c9a55cc9b5dcc82d1fc99ddccb44a6f230af2f8ff224cf417f262ff22a3fe54ddee543166549966545567f617f4dd66523dc6b2c9bb225df655b7682f692ecca9eeccfe97772c09b722847722c27c1f3eb70f66bf9116c9fca999ccbc59cfe25bf4a143a5ef8992561324a78bd92522acf9ebc78efe7cf7b153276db37bef59dbff457fedadff85b7f27abfede4ffcd4cf9ff76faeff4fffefeff8c7f5fedfdfbffc0fa355c495</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>rbChat</sender>
+ <signal>clicked()</signal>
+ <receiver>dccNewBase</receiver>
+ <slot>chatClicked()</slot>
+ </connection>
+ <connection>
+ <sender>rbFileSend</sender>
+ <signal>clicked()</signal>
+ <receiver>dccNewBase</receiver>
+ <slot>fileSendClicked()</slot>
+ </connection>
+ <connection>
+ <sender>pbSend</sender>
+ <signal>clicked()</signal>
+ <receiver>dccNewBase</receiver>
+ <slot>sendClicked()</slot>
+ </connection>
+ <connection>
+ <sender>pbFile</sender>
+ <signal>clicked()</signal>
+ <receiver>dccNewBase</receiver>
+ <slot>fileClicked()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>chatClicked()</slot>
+ <slot>radioButton4_clicked()</slot>
+ <slot>fileSendClicked()</slot>
+ <slot>send()</slot>
+ <slot>sendClicked()</slot>
+ <slot>fileClicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>alistbox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/ksirc/dccToplevel.cpp b/ksirc/dccToplevel.cpp
new file mode 100644
index 00000000..5e5437d2
--- /dev/null
+++ b/ksirc/dccToplevel.cpp
@@ -0,0 +1,49 @@
+
+#include <qvbox.h>
+#include <qpopupmenu.h>
+
+#include <kaction.h>
+#include <kstdaction.h>
+#include <klocale.h>
+#include <kmenubar.h>
+
+#include "dccManager.h"
+#include "dccToplevel.h"
+#include "displayMgr.h"
+
+extern DisplayMgr *displayMgr;
+
+#define DTL_WINDOW_ID 10
+
+dccTopLevel::dccTopLevel(QWidget *parent, const char *name)
+ : KMainWindow(parent, name, Qt::WDestructiveClose)
+{
+ m_mgr = new dccManager(this, QCString(QObject::name()) + "_dccManager");
+// m_mgr->show();
+ setCentralWidget(m_mgr);
+
+ connect(m_mgr, SIGNAL(changed(bool, QString)), this, SIGNAL(changed(bool, QString)));
+
+ QPopupMenu *win = new QPopupMenu(this, QCString(QObject::name()) + "_popup_window");
+ KAction *act = KStdAction::close(this, SLOT( close() ), actionCollection() );
+ act->plug(win);
+
+ menuBar()->insertItem(i18n("&File"), win, DTL_WINDOW_ID, -1);
+ menuBar()->setAccel(Key_F, DTL_WINDOW_ID);
+
+
+}
+
+dccTopLevel::~dccTopLevel()
+{
+}
+
+void dccTopLevel::close()
+{
+
+ displayMgr->hide(this);
+
+}
+
+#include "dccToplevel.moc"
+
diff --git a/ksirc/dccToplevel.h b/ksirc/dccToplevel.h
new file mode 100644
index 00000000..db9f3f67
--- /dev/null
+++ b/ksirc/dccToplevel.h
@@ -0,0 +1,33 @@
+
+#ifndef _DCCTOPLEVEL_H_
+#define _DCCTOPLEVEL_H_
+
+#include <kmainwindow.h>
+
+class dccManager;
+
+
+class dccTopLevel : public KMainWindow
+{
+Q_OBJECT
+public:
+
+ dccTopLevel(QWidget *parent = 0, const char *name = 0);
+ virtual ~dccTopLevel();
+
+ dccManager *mgr() { return m_mgr; }
+
+signals:
+ void changeChannel(const QString&,const QString&);
+ void changed(bool, QString);
+
+
+public slots:
+ void close(void);
+
+private:
+ dccManager *m_mgr;
+};
+
+#endif
+
diff --git a/ksirc/default.pl b/ksirc/default.pl
new file mode 100644
index 00000000..7b42dd18
--- /dev/null
+++ b/ksirc/default.pl
@@ -0,0 +1,867 @@
+$n_isaway='';
+$n_svefile=$ENV{"HOME"}."/.n0thing-pl.sve";
+&docommand("^alias fing ctcp \$0 finger");
+&docommand("^alias ver ctcp \$0 version");
+&docommand("^alias tim ctcp \$0 time");
+&docommand("^alias wallop wallops");
+&docommand("^alias printuh set printuh");
+&docommand("^alias printchan set printchan");
+&docommand("^alias localhost set localhost");
+&docommand("^alias logfile set logfile");
+&docommand("^alias log set log");
+&docommand("^alias ex system");
+&docommand("^alias ls system ls -al");
+&docommand("^alias cat system cat");
+&docommand("^alias rm system rm");
+&docommand("^alias ps system ps");
+&docommand("^alias mail system mail");
+&docommand("^alias setfing set finger");
+sub cmd_open {
+ &getarg;
+ $newarg=$talkchannel unless $newarg;
+ &tell("*\cbE\cb* Huh? what channel?"), return unless $newarg;
+ $newarg =~ tr/A-Z/a-z/;
+ &sl("MODE $newarg -lsmpik ".$chankey{$newarg});
+}
+&addcmd("open");
+sub cmd_l {
+ if ($talkchannel) {
+ &sl("LIST $talkchannel");
+ &sl("NAMES $talkchannel");
+ }
+}
+&addcmd("l");
+sub cmd_a {
+ if ($n_lastmsg) {
+ &msg($n_lastmsg, $args);
+ } else {
+ &tell("*\cbE\cb* How about sending a first /m to someone?");
+ }
+}
+&addcmd("a");
+sub cmd_pj {
+ if ($talkchannel) {
+ &sl("PART $talkchannel");
+ &sl("JOIN $talkchannel");
+ }
+}
+&addcmd("pj");
+&docommand("^alias ds dcc send");
+&docommand("^alias dl dcc list");
+&docommand("^alias cdc dcc close chat");
+&docommand("^alias cdg dcc close get");
+&docommand("^alias cds dcc close send");
+&docommand("^alias dcrename dcc rchat");
+&docommand("^alias dcren dcc rchat");
+&docommand("^alias rdc dcc rchat");
+sub cmd_dc {
+ &getarg;
+ if ($newarg) {
+ &docommand("dcc chat $newarg");
+ } elsif ($n_lastdc) {
+ &docommand("dcc chat $n_lastdc");
+ $n_lastdc='';
+ }
+}
+&addcmd("dc");
+sub cmd_dg {
+ &getarg;
+ if ($newarg) {
+ &docommand("dcc get $newarg $args");
+ } elsif ($n_lastdcc) {
+ &docommand("dcc get $n_lastdcc");
+ $n_lastdcc='';
+ }
+}
+&addcmd("dg");
+sub hook_disc {
+ if ($n_rejoinchannels) {
+ $n_old_when=time;
+ $n_old_umode=$umode;
+ @n_old_channels=grep(!&eq($_, $talkchannel), @channels);
+ push(@n_old_channels, $talkchannel) if $talkchannel;
+ %n_old_chankey=%chankey;
+ }
+ &docommand("server 1"), $n_lastreconnect=time if
+ $n_reconnect && time-$n_lastreconnect>15;
+}
+&addhook("disconnect", "disc");
+sub hook_reconnect {
+ if ($n_rejoinchannels && ($n_old_umode || @n_old_channels) &&
+ time <= $n_old_when+15) {
+ $n_old_umode =~ tr/o//d;
+ &sl("MODE $nick +$n_old_umode") if $n_old_umode ne '';
+ local($chans, $keys)=('', '');
+ foreach $c (keys (%n_old_chankey)) {
+ $chans .= $c.",";
+ $keys .= $n_old_chankey{$c}.",";
+ }
+ foreach $c (@n_old_channels) {
+ $c =~ tr/A-Z/a-z/;
+ $chans .= $c."," unless defined($n_old_chankey{$c});
+ }
+ $chans =~ s/,$//;
+ $keys =~ s/,$//;
+ &sl("JOIN $chans $keys") if $chans;
+ $n_old_umode='';
+ @n_old_channels=();
+ %n_old_chankey=();
+ }
+}
+&addhook("001", "reconnect");
+sub hook_ctcp {
+ if ($_[1] eq 'DCC') {
+ $n_lastdcc=$who if $_[2] =~ /^SEND /;
+ $n_lastdc=$who if $_[2] =~ /^CHAT /;
+ }
+}
+&addhook("ctcp", "ctcp");
+sub hook_kicked {
+ local($kicked, $where_from, $reason)=@_;
+ if ($n_autorejoin && &eq($kicked, $nick)) {
+ &sl("JOIN $where_from $chankey{$where_from}");
+ }
+}
+&addhook("kick", "kicked");
+sub hook_uhnotify {
+ unless ($n_slowserver) {
+ &userhost($_[0], "&tell(\"*\cb)\cb* Signon by $_[0] (\$user\\\@\$host) detected!\");", "");
+ $silent=1;
+ }
+}
+&addhook("notify_signon", "uhnotify");
+sub hook_lastmsg {
+ $n_lastmsg=$_[0] unless $_[0] =~ /^[\#\+]/;
+}
+&addhook("send_text", "lastmsg");
+&addhook("send_action", "lastmsg");
+sub hook_away {
+ if ($n_awayonce && $_[0] =~ /^\S+\s+(\S+)\s/) {
+ local($l)=$1;
+ $l =~ tr/A-Z/a-z/;
+ $silent=1 if $n_aways{$l} eq $_[0];
+ $n_aways{$l}=$_[0];
+ }
+}
+&addhook("301", "away");
+sub hook_whois {
+ if ($_[0] =~ /^\S+\s+(\S+)\s/) {
+ local($l)=$1;
+ $l =~ tr/A-Z/a-z/;
+ delete $n_aways{$l};
+ }
+}
+&addhook("311", "whois");
+sub set_autorejoin {
+ $set{'AUTOREJOIN'}="on", $n_autorejoin=1 if $_[0] =~ /^on$/i;
+ $set{'AUTOREJOIN'}="off", $n_autorejoin=0 if $_[0] =~ /^off$/i;
+}
+&addset("autorejoin");
+$set{"AUTOREJOIN"}="on";
+$n_autorejoin=1;
+&docommand("^alias rejoin set autorejoin");
+sub set_rejoinchannels {
+ $set{'REJOINCHANNELS'}="on", $n_rejoinchannels=1 if $_[0] =~ /^on$/i;
+ $set{'REJOINCHANNELS'}="off", $n_rejoinchannels=0 if $_[0] =~ /^off$/i;
+}
+&addset("rejoinchannels");
+$set{"REJOINCHANNELS"}="on";
+$n_rejoinchannels=1;
+&docommand("^alias rejoinchan set rejoinchannels");
+sub set_reconnect {
+ $set{'RECONNECT'}="on", $n_reconnect=1 if $_[0] =~ /^on$/i;
+ $set{'RECONNECT'}="off", $n_reconnect=0 if $_[0] =~ /^off$/i;
+}
+&addset("reconnect");
+$set{"RECONNECT"}="on";
+$n_reconnect=1;
+&docommand("^alias reconnect set reconnect");
+sub set_awayonce {
+ $set{'AWAYONCE'}="on", $n_awayonce=1 if $_[0] =~ /^on$/i;
+ $set{'AWAYONCE'}="off", $n_awayonce=0 if $_[0] =~ /^off$/i;
+ %n_awayonce=();
+}
+&addset("awayonce");
+$set{"AWAYONCE"}="on";
+$n_awayonce=1;
+&docommand("^alias awayonce set awayonce");
+sub set_slowserver {
+ $set{'SLOWSERVER'}="on", $n_slowserver=1 if $_[0] =~ /^on$/i;
+ $set{'SLOWSERVER'}="off", $n_slowserver=0 if $_[0] =~ /^off$/i;
+}
+&addset("slowserver");
+$set{"SLOWSERVER"}="off";
+$n_slowserver=0;
+&docommand("^alias ss set slowserver");
+sub set_wallv {
+ $set{"WALLV"}="on", $n_wallv=1 if $_[0] =~ /^on$/i;
+ $set{"WALLV"}="off", $n_wallv=0 if $_[0] =~ /^off$/i;
+}
+&addset("wallv");
+$set{"WALLV"}="off";
+$n_wallv=0;
+&docommand("^alias wallv set wallv");
+sub set_quitmsg {
+ $n_quitmsg=$set{"QUITMSG"}=$_[0];
+}
+&addset("quitmsg");
+$set{"QUITMSG"}=$n_quitmsg='';
+&docommand("^alias setquit set quitmsg");
+sub set_autoop {
+ $set{"AUTOOP"}="off", $n_autoops=0 if $_[0] =~ /^(off|none)$/i;
+ $set{"AUTOOP"}="on", $n_autoops=1 if $_[0] =~ /^(on|all)$/i;
+ $set{"AUTOOP"}="oppass", $n_autoops=2 if $_[0] =~ /^op(pass)?$/i;
+}
+&addset("autoop");
+$set{"AUTOOP"}="on";
+$n_autoops=1;
+&docommand("^alias autoop set autoop");
+sub set_opdelay {
+ $set{"OPDELAY"}=$n_opdelay=$_[0] if $_[0] =~ /^\d+$/;
+}
+&addset("opdelay");
+$set{"OPDELAY"}="on";
+$n_opdelay=5;
+&docommand("^alias delay set opdelay");
+sub set_oppass {
+ $set{"OPPASS"}=$_[0];
+}
+&addset("oppass");
+$set{"OPPASS"}="";
+&docommand("^alias oppass set oppass");
+sub cmd_ig {
+ &docommand("ignore $args"), return if (!$args || $args =~ /^-/);
+ &getarg;
+ if ($newarg =~ /\@/) {
+ $n_lastignore=$newarg;
+ &docommand("ignore $newarg");
+ } else {
+ &userhost($newarg, "\$host=&n_hostpat(\$host); \$user =~ s/^\\~//; \$n_lastignore=\"*\$user\\\@\$host\"; &docommand(\"ignore *\$user\\\@\$host\");");
+ }
+}
+&addcmd("ig");
+sub cmd_sig {
+ &getarg;
+ &userhost($newarg, "\$host=&n_hostpat(\$host); \$n_lastignore=\"*\\\@\$host\"; &docommand(\"ignore *\\\@\$host\");");
+}
+&addcmd("sig");
+sub cmd_unig {
+ &getarg;
+ if ($newarg eq '') {
+ &docommand("ignore -$n_lastignore") if $n_lastignore ne '';
+ } elsif ($newarg =~ /\@/) {
+ &docommand("ignore -$newarg");
+ } else {
+ &userhost($newarg, "\$host=&n_hostpat(\$host); \$user =~ s/^\\~//; &docommand(\"ignore -*\$user\\\@\$host\");");
+ }
+}
+&addcmd("unig");
+sub n_hostpat {
+ if ($_[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
+ return "${1}.${2}.${3}.*";
+ } elsif ($_[0] =~ /^([^. \t]+)\.([^. \t]+)\.(.*)$/) {
+ return "*.${2}.${3}";
+ } else {
+ return $_[0];
+ }
+}
+sub cmd_kb {
+ &getarg;
+ local($why)=($args);
+ $why="game over, man. game over." unless $why;
+ &tell("*\cb0\cb* Must specify a nick to kickban"), return unless $newarg;
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ &userhost($newarg, "\$host=&n_hostpat(\$host); \$user =~ s/^\\~//;
+&sl(\"MODE $talkchannel -o+b $newarg *!*\$user\\\@\$host\");
+&sl(\"KICK $talkchannel $newarg :$why\");");
+&addcmd("kb");
+sub cmd_ksb {
+ &getarg;
+ local($why)=($args);
+ $why="d0rks suck big m00se ballZ" unless $why;
+ &tell("*\cb0\cb* Must specify a nick to kicksiteban"), return unless $newarg;
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ &userhost($newarg, "\$host=&n_hostpat(\$host);
+&sl(\"MODE $talkchannel -o+b $newarg *!*\\\@\$host\");
+&sl(\"KICK $talkchannel $newarg :$why\");");
+}
+&addcmd("ksb");
+sub cmd_ban {
+ &tell("*\cb0\cb* Must specify a nick to ban"), return unless $args;
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ while (&getarg, $newarg ne '') {
+ &userhost($newarg, "\$host=&n_hostpat(\$host); \$user =~ s/^\\~//;
+ &sl(\"MODE $talkchannel +b *!*\$user\\\@\$host\");");
+ }
+}
+&addcmd("ban");
+sub cmd_sban {
+ &getarg;
+ &tell("*\cb0\cb* Must specify a nick to site ban"), return unless $newarg;
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ &userhost($newarg, "\$host=&n_hostpat(\$host);
+&sl(\"MODE $talkchannel +b *!*\\\@\$host\");");
+}
+&addcmd("sban");
+sub n_unbans {
+ local($n, $l)=('0', '');
+ foreach (@n0thing_banlist) {
+ if ($n<4) {
+ $l.=" ".$_;
+ $n++;
+ } else {
+ &sl("MODE $n0thing_channel -bbbb $l");
+ $l=$_;
+ $n=1;
+ }
+ }
+ &sl("MODE $n0thing_channel -".("b" x $n)." $l");
+}
+sub cmd_sb {
+ &dosplat;
+ &getarg;
+ $newarg=$talkchannel unless $newarg;
+ return unless $newarg;
+ $n_svbanchannel=$newarg;
+ @n_svbanlist=();
+ $n_nxbannb=1;
+ &sl("MODE $newarg b");
+}
+&addcmd("sb");
+sub hook_nbbans {
+ local($c, $theban, $by)=((split(/ +/, $_[0]))[1, 2, 3]);
+ if ($n_nxbannb && &eq($c, $n_svbanchannel)) {
+ push(@n_svbanlist, $theban);
+ &tell("*\cbb\cb* $c $n_nxbannb: $theban $by");
+ $silent=1;
+ $n_nxbannb++;
+ }
+}
+&addhook("367", "nbbans");
+sub hook_endofbans {
+ $n_nxbannb=0;
+}
+&addhook("368", "endofbans");
+sub cmd_cb {
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ &addhook("367", "onecbban");
+ &addhook("368", "donebans");
+ @n0thing_banlist=();
+ $n0thing_channel=$talkchannel;
+ &sl("MODE $talkchannel b");
+}
+&addcmd("cb");
+sub hook_onecbban {
+ local($theban)=((split(/ +/, $_[0]))[2]);
+ push(@n0thing_banlist, $theban);
+ $silent=1;
+}
+sub hook_donebans {
+ &remhook("367", "onecbban");
+ &remhook("367", "oneubban");
+ &remhook("368", "donebans");
+ &n_unbans;
+}
+sub cmd_unban {
+ &getarg;
+ &tell("*\cb0\cb* Must specify a nick or address to unban"), return
+ unless $newarg;
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ if ($newarg =~ /^\d+$/) {
+ $n0thing_channel=$talkchannel;
+ @n0thing_banlist=();
+ while(1) {
+ $newarg--;
+ &tell("*\cb0\cb* No banlist available for $talkchannel"), return
+ unless &eq($talkchannel, $n_svbanchannel);
+ &tell("*\cb0\cb* No such ban"), return unless $n_svbanlist[$newarg];
+ push(@n0thing_banlist, $n_svbanlist[$newarg]);
+ &getarg;
+ last unless $newarg;
+ &tell("*\cb0\cb* Cannot mix nicks and numbers"), last
+ unless $newarg =~ /^\d+$/;
+ }
+ &n_unbans;
+ } else {
+ @n0thing_banlist=();
+ $n0thing_channel=$talkchannel;
+ if ($newarg =~ /\@/) {
+ $newarg="*!".$newarg unless $newarg =~ /\!/;
+ $n_pat=$newarg;
+ &addhook("367", "oneubban");
+ &addhook("368", "donebans");
+ &sl("MODE $talkchannel b");
+ } else {
+ &userhost($newarg, "&n_dounban;");
+ }
+ }
+}
+&addcmd("unban");
+&docommand("^alias ub unban");
+sub n_dounban {
+ $n_pat=$who."!".$user."\@".$host;
+ &addhook("368", "donebans");
+ @n0thing_banlist=();
+ $n0thing_channel=$talkchannel;
+ &sl("MODE $talkchannel b");
+}
+sub hook_oneubban {
+ local($theban)=((split(/ +/, $_[0]))[2]);
+ local($tb0)=($theban);
+ &slashify($theban);
+ push(@n0thing_banlist, $tb0) if ($n_pat =~ /^${theban}$/i);
+ $silent=1;
+}
+sub cmd_fkb {
+ &getarg;
+ &tell("*\cb0\cb* Must specify a nick to filter kick ban"), return unless $newarg;
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ &userhost($newarg, "\$host=&n_hostpat(\$host);
+&sl(\"MODE $talkchannel +b *!*\\\@\$host\"); &docommand(\"fk \$host $args\");");
+}
+&addcmd("fkb");
+sub cmd_fk {
+ &getarg;
+ &tell("*\cb0\cb* Must specify a pattern to kick"), return unless $newarg;
+ &tell("*\cb0\cb* You're not on a channel"), return unless $talkchannel;
+ $n0thing_channel=$talkchannel;
+ $n0thing_kickpat=$newarg;
+ &slashify($n0thing_kickpat);
+ $n0thing_kickmsg=$args || "though names may change each face retains the mask it wore";
+ &addhook("352", "dofklist");
+ &addhook("315", "donefk");
+ &sl("WHO $talkchannel");
+}
+&addcmd("fk");
+sub hook_dofklist {
+ local($a)=@_;
+ local($c, $c, $u, $h, $s, $n)=split(/ +/, $a);
+ (($n."!".$u."\@".$h) =~ /${n0thing_kickpat}/i) && $n ne $nick &&
+ &sl("KICK $n0thing_channel $n :$n0thing_kickmsg");
+ $silent=1;
+}
+sub hook_donefk {
+ &remhook("352", "dofklist");
+ &remhook("315", "donefk");
+}
+sub cmd_setaway {
+ &me("is away - $args - messages will be logged") if $talkchannel;
+ push(@n_savemsg, "-- set away on " . &date(time) . " -- $args");
+ %n_awaysent=();
+ $args="\cb\cb" if $args eq '';
+ &sl("AWAY :$args");
+ $n_isaway=1;
+}
+&addcmd("setaway");
+sub cmd_qsetaway {
+ push(@n_savemsg, "-- set away on " . &date(time) . " -- $args");
+ %n_awaysent=();
+ $args="\cb\cb" if $args eq '';
+ &sl("AWAY :$args");
+ $n_isaway=1;
+}
+&addcmd("qsetaway");
+ if ($n_isaway) {
+ local($sec, $min, $hour)=localtime(time);
+ local($w)=$who;
+ $min="0".$min if $min =~ /^\d$/;
+ push(@n_savemsg, ":\cb${who}\cb!${user}\@${host} (${hour}:${min}): $_[0]\n");
+ $w =~ tr/A-Z/a-z/;
+ &sl("NOTICE $who :Your messages are being logged - n0thing.pl"),
+ $n_awaysent{$w}=1 unless $n_awaysent{$w};
+ }
+}
+&addhook("msg", "messages");
+sub hook_dmessages {
+ if ($n_isaway) {
+ local($sec, $min, $hour)=localtime(time);
+ $min="0".$min if $min =~ /^\d$/;
+ push(@n_savemsg, "=\cb".$_[0]."\cb (${hour}:${min})= ".$_[1]."\n");
+ }
+}
+&addhook("dcc_chat", "dmessages");
+sub cmd_setback {
+ $n_isaway='';
+ &sl("AWAY");
+ foreach (@n_savemsg) {
+ &tell($_);
+ }
+ if ($#n_savemsg>0) {
+ &getuserline("*** Forget saved messages (y/n)? ", "clear? ");
+ @n_savemsg=() if /^y/i;
+ } else {
+ @n_savemsg=();
+ }
+}
+&addcmd("setback");
+sub cmd_clearmes {
+ $n_isaway='';
+ @n_savemsg=();
+}
+&addcmd("clearmes");
+sub cmd_wall {
+ &tell("*\cbE\cb* No text to send"), return unless $args;
+ &tell("*\cbE\cb* You're not on a channel"), return unless $talkchannel;
+ $wallop_text=$args;
+ $wallop_channel=$talkchannel;
+ &addhook("353", "wallopnames");
+ &sl("NAMES $talkchannel");
+}
+&addcmd("wall");
+
+sub hook_wallopnames {
+ local($wallop, $n, $s, @wallop)=("", 0, 0, split(/ +/, $_[0]));
+ shift @wallop; shift @wallop; shift @wallop;
+ $wallop[0] =~ s/^://;
+ foreach (@wallop) {
+ $wallop.=$_.",", $n++ if s/^\@// || ($n_wallv && s/^\+//) || &eq($_, $nick);
+ if ($n>=9) {
+ $wallop =~ s/,$//;
+ &sl("NOTICE $wallop :\cb[WallOp/$wallop_channel]\cb $wallop_text");
+ $n=0;
+ $s=1;
+ $wallop='';
+ }
+ }
+ if ($wallop eq '' && !$s) {
+ &tell("*\cbE\cb* No ops to wallop");
+ } elsif ($wallop ne '') {
+ $wallop =~ s/,$//;
+ &sl("NOTICE $wallop :\cb[WallOp/$wallop_channel]\cb $wallop_text");
+ }
+ &remhook("353", "wallopnames");
+ $silent=1;
+}
+sub n_addwaitop {
+ local($nck, $channel)=@_;
+ if ($n_opdelay) {
+ local($n)=($nck);
+ $channel =~ tr/A-Z/a-z/;
+ $n =~ s/(\W)/\\$1/g;
+ if ($n_waitops{$channel} !~ /:${n}:/i) {
+ $n_waitops{$channel} || ($n_waitops{$channel}=":");
+ $n_waitops{$channel}.=$nck.":";
+ }
+ unless ($n_timerdue) {
+ $n_timerdue=1;
+ &timer($n_opdelay, "&n_doautoops");
+ }
+ } else {
+ &sl("MODE $channel +o $nck");
+ }
+}
+
+sub n_remwaitop {
+ local($nck, $channel)=@_;
+ $channel =~ tr/A-Z/a-z/;
+ $nck =~ s/(\W)/\\$1/g;
+ $n_waitops{$channel} =~ s/:${nck}:/:/gi;
+ delete $n_waitops{$channel} if $n_waitops{$channel} eq ":";
+}
+
+sub n_doautoops {
+ local($l);
+ foreach $c (keys(%n_waitops)) {
+ if ($n_waitops{$c} ne ":" && $n_waitops{$c}) {
+ $l=$n_waitops{$c};
+ $l =~ s/^://;
+ $l =~ s/:$//;
+ $l =~ tr/:/ /;
+ &docommand("o ".$c." ".$l);
+ }
+ delete $n_waitops{$c};
+ }
+ $n_timerdue='';
+}
+
+sub hook_n_nickchange {
+ local($oldnick)=$who;
+ $oldnick =~ s/(\W)/\\$1/g;
+ foreach $c (keys(%n_waitops)) {
+ $n_waitops{$c} =~ s/:${oldnick}:/:$_[0]:/gi;
+ }
+}
+&addhook("nick", "n_nickchange");
+
+sub hook_n_parted {
+ &n_remwaitop($who, $_[0]);
+}
+&addhook("leave", "n_parted");
+
+sub hook_n_quitted {
+ local($w)=$who;
+ $w =~ s/(\W)/\\$1/g;
+ foreach $c (keys(%n_waitops)) {
+ $n_waitops{$c} =~ s/:${w}:/:/gi;
+ delete $n_waitops{$c} if $n_waitops{$c} eq ":";
+ }
+}
+&addhook("signoff", "n_quitted");
+
+sub hook_n_modechange {
+# we only deal with +o, +oo and the like; the worst that can happen
+# is that we op someone again
+ local ($l)=$_[1];
+ return unless $_[0] =~ /^[\#\&\+]/;
+ return unless $l =~ s/^\+o+\s+//;
+ foreach $n (split(/ /, $l)) {
+ &n_remwaitop($n, $_[0]);
+ }
+}
+&addhook("mode", "n_modechange");
+
+sub slashify {
+ $_[0] =~ s/([^\\])\./$1\\./g;
+ $_[0] =~ s/\*/\.\*/g;
+ $_[0] =~ s/([^\.\*\?\\\w])/\\$1/g;
+ $_[0] =~ tr/?/./;
+}
+sub autoopped {
+ local($nuh, $chan, $asked)=@_;
+# chan = what chan for, $asked = whether it was asked
+ local($p);
+ foreach $p (@n_autooplist) {
+ return 1 if ($asked.":".$chan.":".$nuh) =~ /^${p}$/i;
+ }
+ return '';
+}
+
+sub addtoops {
+ local($chan, $auto)=@_;
+ if (&autoopped($who."!".$user."\@".$host, $chan, 1)) {
+ &tell("*\cb0\cb* $who is already on your list");
+ } else {
+ $host=&n_hostpat($host);
+ $user =~ s/^\~//;
+ local($pat)=("*!*".$user."\@".$host);
+ &tell("*\cb0\cb* Adding $who as $pat to your autoop list for $chan");
+ &sl("NOTICE $who :You have been added to ${nick}'s autoop list for ".
+ ($chan eq '*' ? "all channels" : "$chan"));
+ &sl("NOTICE $who :You should feel *very* honored");
+ &slashify($pat);
+ &slashify($chan);
+ push(@n_autooplist, $auto.":".$chan.":".$pat);
+ }
+}
+
+sub cmd_addop {
+ if ($args =~ /^([01])\s+(\S+)\s+(\S+)\s*$/) {
+ local($auto, $chan, $uh)=($1, $2, $3);
+ if ($chan ne '*' && $chan !~ /^[#&]/) {
+ &tell("*\cbE\cb* Invalid channel - use '*' or a #channel name");
+ return;
+ }
+ $chan =~ s/\'//g;
+ $uh="*!".$uh if $uh =~ /\@/ && $uh !~ /\!/;
+ $auto=($auto==0 ? "1" : ".");
+ if ($uh =~ /\!.*\@/) {
+ if (&autoopped($uh, $chan, 1)) {
+ &tell("*\cb0\cb* $uh is already on your list");
+ return;
+ }
+ &tell("*\cb0\cb* Adding $uh to your auto-op list for $chan");
+ &slashify($uh);
+ &slashify($chan);
+ push(@n_autooplist, $auto.":".$chan.":".$uh);
+ } else {
+ &userhost($uh, "&addtoops('$chan', '$auto');");
+ }
+ } else {
+ &tell("*\cb0\cb* Format: /addop (0 or 1) (#chan or *) (nick or user\@host)");
+ }
+}
+&addcmd("addop");
+
+sub hook_joined {
+ local($c)=($_[0]);
+ $c =~ tr/A-Z/a-z/;
+ &n_addwaitop($who, $c) if ($n_autoops==1 && $haveops{$c} &&
+ &autoopped($who."!".$user."\@".$host, $c, 0));
+}
+&addhook("join", "joined");
+
+sub hook_opbeg {
+ if ($_[1] =~ /^op$/i && $n_autoops && &eq($nick, $_[0])) {
+ local($chn, $pass)=split(/ +/, $_[2]);
+ $chn =~ tr/A-Z/a-z/;
+ &sl("MODE $chn +o $who")
+ if $haveops{$chn} && $pass eq $set{"OPPASS"} &&
+ &autoopped($who."!".$user."\@".$host, $chn, 1);
+ }
+}
+&addhook("ctcp", "opbeg");
+
+sub cmd_listop {
+ local($n, $p, $q, $c, $a, $ch)=(0);
+ &getarg;
+ $ch=$newarg || '*';
+ &tell("*\cb0\cb* That's the people in your autoop list:");
+ foreach $p (@n_autooplist) {
+ ($a, $c, $q)=split(/:/, $p);
+ $c =~ s/\\//g;
+ $c =~ s/\.\*/*/g;
+ next if (!&eq($c, $ch) && $c ne '*' && $ch ne '*');
+ $n++;
+ $q =~ s/\\//g;
+ $q =~ s/\.\*/*/g;
+ &tell("*\cb0\cb* ".($a eq '.' ? "1 " : "0 ").$c." ".$q);
+ }
+ &tell("*\cb0\cb* which makes.. uhm... $n people, I think");
+}
+&addcmd("listop");
+
+sub rem_matches {
+ local($nuh, $ent)=@_;
+ $ent=$' if $ent =~ /:.*:/;
+ return 1 if $nuh =~ /${ent}$/i;
+ # not exactly the same as slashify
+ $nuh =~ s/\*/\.\*/g;
+ $nuh =~ s/([^\\])\.([^\*])/$1\\\\*\\.$2/g;
+ $nuh =~ s/([^\.\*\?\\\w])/\\\\*\\$1/g;
+ $nuh =~ tr/?/./;
+ return ($ent =~ /${nuh}$/i);
+}
+
+sub n_remop {
+ local($nuh)=($who."!".$user."\@".$host);
+ @n_autooplist=grep(!&rem_matches($nuh, $_), @n_autooplist);
+}
+
+sub cmd_remop {
+ &getarg;
+ if (!$newarg) {
+ &tell("*\cb0\cb* Must specify a nick or address");
+ } elsif ($newarg =~ /[\@\*]/) {
+ # $newarg='*!'.$newarg if ($newarg !~ /\!/);
+ &tell("*\cb0\cb* Time to remove $newarg from the autoop list");
+ @n_autooplist=grep(!&rem_matches($newarg, $_), @n_autooplist);
+ } else {
+ &tell("*\cb0\cb* Time to remove $newarg from the autoop list");
+ &userhost($newarg, "&n_remop;");
+ }
+}
+&addcmd("remop");
+
+sub cmd_clearop {
+ @n_autooplist=();
+ &tell("*\cb0\cb* Auto-op list cleared!");
+}
+&addcmd("clearop");
+sub cmd_sve {
+ local($p);
+ if (!open(SVE, "> ".$n_svefile)) {
+ &tell("*\cbE\cb* can't write to save file");
+ return;
+ }
+ print SVE $n_autoops+0, "\n";
+ print SVE ($n_autorejoin ? "1" : "0"), "\n";
+ print SVE "\n"; # deprecated, pong reply
+ print SVE $set{"FINGER"}, "\n";
+ print SVE join(" ", keys(%notify)), "\n";
+ print SVE join(" ", @n_autooplist), "\n";
+ print SVE ($n_slowserver ? "1" : "0"), "\n";
+ print SVE $n_opdelay, "\n";
+ print SVE $n_quitmsg, "\n";
+ print SVE "^\n"; # deprecated, command char
+ print SVE ($n_reconnect ? "1" : "0"), "\n";
+ print SVE $set{"AWAYONCE"}, "\n";
+ print SVE $set{"REJOINCHANNELS"}, "\n";
+ print SVE $set{"CTCP"}, "\n";
+ print SVE $set{"PRINTCHAN"}, "\n";
+ print SVE $set{"PRINTUH"}, "\n";
+ print SVE $set{"SENDAHEAD"}, "\n";
+ print SVE $set{"USERINFO"}, "\n";
+ print SVE $set{"WALLV"}, "\n";
+ print SVE $set{"OPPASS"}, "\n";
+ print SVE $set{"IRCNAME"}, "\n";
+ close SVE;
+ &tell("*\cb0\cb* save completed!");
+}
+&addcmd("sve");
+
+sub cmd_quit {
+ if ($args eq '') {
+ &docommand("/QUIT $n_quitmsg");
+ } else {
+ &docommand("/QUIT $args");
+ }
+}
+&addcmd("quit");
+&docommand("^alias bye quit");
+&docommand("^alias exit quit");
+&docommand("^alias signoff quit");
+if (open(NOTHING, "< ".$n_svefile)) {
+ local($n, $l);
+
+ chop($l=<NOTHING>);
+ &doset("AUTOOP", ($l ? "on" : "off"));
+
+ chop($l=<NOTHING>);
+ &doset("AUTOREJOIN", ($l ? "on" : "off"));
+
+ <NOTHING>;
+
+ chop($l=<NOTHING>);
+ &doset("FINGER", $l) if $l ne '';
+
+ chop($l=<NOTHING>);
+ %notify=();
+ foreach $n (split(' ', $l)) {
+ &docommand("^NOTIFY ".$n);
+ }
+
+ chop($l=<NOTHING>);
+ @n_autooplist=split(' ', $l);
+ foreach (@n_autooplist) {
+ $_=".:.*:".$_ unless /:.*:/;
+ }
+
+ chop($l=<NOTHING>);
+ &doset("SLOWSERVER", ($l ? "on" : "off"));
+
+ chop($l=<NOTHING>);
+ $l=5 if $l !~ /^\d+$/;
+ &doset("OPDELAY", $l);
+
+ chop($l=<NOTHING>);
+ &doset("QUITMSG", $l);
+
+ <NOTHING>;
+
+ chop($l=<NOTHING>);
+ $l=1 unless defined $l;
+ &doset("RECONNECT", ($l ? "on" : "off"));
+
+ chop($l=<NOTHING>);
+ &doset("AWAYONCE", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("REJOINCHANNELS", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("CTCP", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("PRINTCHAN", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("PRINTUH", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("SENDAHEAD", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("USERINFO", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("WALLV", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("OPPASS", $l) if $l;
+
+ chop($l=<NOTHING>);
+ &doset("IRCNAME", $l) if $l;
+
+ close(NOTHING);
+}
+
diff --git a/ksirc/displayMgr.h b/ksirc/displayMgr.h
new file mode 100644
index 00000000..e0838ba0
--- /dev/null
+++ b/ksirc/displayMgr.h
@@ -0,0 +1,28 @@
+#ifndef DISPLAYMGR_H
+#define DISPLAYMGR_H
+
+#include <qstring.h>
+
+class QWidget;
+
+class DisplayMgr {
+public:
+ virtual ~DisplayMgr() {};
+
+ virtual void newTopLevel(QWidget *, bool show = false) = 0;
+
+ virtual void removeTopLevel(QWidget *) = 0;
+
+ virtual void show(QWidget *) = 0;
+
+ virtual void hide(QWidget *) = 0;
+
+ virtual void raise(QWidget *, bool takefocus = false) = 0;
+
+ virtual void setCaption(QWidget *, const QString&) = 0;
+
+};
+
+
+#endif
+
diff --git a/ksirc/displayMgrMDI.cpp b/ksirc/displayMgrMDI.cpp
new file mode 100644
index 00000000..ae1e5b39
--- /dev/null
+++ b/ksirc/displayMgrMDI.cpp
@@ -0,0 +1,306 @@
+#include "displayMgrMDI.h"
+#include "toplevel.h"
+
+#include <unistd.h>
+
+#include <assert.h>
+#include <qpopupmenu.h>
+#include <kwin.h>
+#include <kaccel.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <kmenubar.h>
+
+DisplayMgrMDI::DisplayMgrMDI()
+{
+}
+
+DisplayMgrMDI::~DisplayMgrMDI()
+{
+ kdDebug(5008) << "~DisplayMgrMDI in" << endl;
+ if ( m_topLevel )
+ delete static_cast<MDITopLevel *>( m_topLevel );
+ kdDebug(5008) << "~DisplayMgrMDI out" << endl;
+}
+
+#define DMM_MDI_ID 2351
+#define DMM_DEATCH_ID 50
+#define DMM_MOVEL_ID 51
+#define DMM_MOVER_ID 52
+
+void DisplayMgrMDI::newTopLevel( QWidget *w, bool show )
+{
+ topLevel()->addWidget( w, show );
+ if(w->inherits("KSircTopLevel")){
+ KSircTopLevel *t = static_cast<KSircTopLevel *>(w);
+ connect(m_topLevel->tabWidget(), SIGNAL(currentChanged(QWidget *)), t, SLOT(focusChange(QWidget *)));
+ }
+ if(w->inherits("KMainWindow")){
+ KMainWindow *t = static_cast<KMainWindow *>(w);
+
+ QMenuBar *cmenu = t->menuBar();
+ if(cmenu){
+ QPopupMenu *m = new QPopupMenu(t, QCString(t->name()) + "_popup_MDI");
+ m->setCheckable(true);
+ m->insertItem(i18n("Detach Window"), this, SLOT(reparentReq()), 0, DMM_DEATCH_ID, 0);
+ m->insertSeparator(0);
+ m->insertItem(i18n("Move Tab Left"), this, SLOT(moveWindowLeft()), ALT+SHIFT+Key_Left, DMM_MOVEL_ID, 0);
+ m->insertItem(i18n("Move Tab Right"), this, SLOT(moveWindowRight()), ALT+SHIFT+Key_Right, DMM_MOVER_ID, 0);
+ /*
+ * By using an posisiton of 4 this works for KSircTopLevel
+ * and DCCTopLevel but will cause problems when we have
+ * new top level windows with different menus.
+ * BEWARE THIS IS BAD, we should have a better way of doing this
+ */
+ cmenu->insertItem(i18n("&Window"), m, DMM_MDI_ID, 4);
+ cmenu->setAccel(Key_M, DMM_MDI_ID);
+
+ QPopupMenu *sm = new QPopupMenu(t, "settings" );
+
+ KToggleAction *showmenu = KStdAction::showMenubar( 0, 0, t->actionCollection() );
+ showmenu->plug( sm );
+ connect( showmenu, SIGNAL(toggled(bool)), cmenu, SLOT(setShown(bool)) );
+
+ KSelectAction *selectTabbar = new KSelectAction(i18n("&Tab Bar"), 0, this, "tabbar" );
+ QStringList tabbaritems;
+ tabbaritems << i18n("&Top") << i18n("&Bottom");
+ selectTabbar->setItems(tabbaritems);
+ selectTabbar->setCurrentItem(1);
+ selectTabbar->plug( sm );
+ connect( selectTabbar, SIGNAL(activated(int)), this, SLOT(setTabPosition(int)) );
+
+ KToggleAction *showfull = KStdAction::fullScreen( 0, 0, t->actionCollection(), t );
+ showfull->plug( sm );
+ connect( showfull, SIGNAL(toggled(bool)), this, SLOT(setFullScreen(bool)) );
+
+ cmenu->insertItem( i18n("&Settings"), sm, -1, 5 );
+ }
+ }
+ topLevel()->show();
+}
+
+void DisplayMgrMDI::removeTopLevel(QWidget *w )
+{
+ if ( !m_topLevel )
+ return;
+
+ assert( w );
+
+ kdDebug(5008) << "DisplayMgrMDI: got removeToplevel" << endl;
+
+ m_topLevel->removeWidget( w );
+
+ if ( m_topLevel->widgets().count() == 0 ) {
+ kdDebug(5008) << "DisplayMgrMDI: count == 0 nuking all" << endl;
+ if ( !m_topLevel->closing() ) {
+ kdDebug(5008) << "DisplayMgrMDI: delete m_topLevel" << endl;
+ delete static_cast<MDITopLevel *>( m_topLevel );
+ }
+ m_topLevel = 0;
+ }
+ else if(m_topLevel->tabWidget()->count() == 0){
+ m_topLevel->hide();
+ }
+}
+
+void DisplayMgrMDI::show(QWidget *w)
+{
+ if ( !m_topLevel )
+ return;
+
+ m_topLevel->showWidget(w);
+ m_topLevel->show();
+}
+
+void DisplayMgrMDI::hide(QWidget *w)
+{
+ if ( !m_topLevel )
+ return;
+
+ m_topLevel->hideWidget(w);
+ if(m_topLevel->tabWidget()->count() == 0){
+ m_topLevel->hide();
+ }
+}
+
+void DisplayMgrMDI::raise(QWidget *w, bool takefocus)
+{
+ assert( m_topLevel );
+ if(takefocus){
+ KWin::setCurrentDesktop(KWin::KWin::windowInfo(m_topLevel->winId()).desktop());
+
+ m_topLevel->show();
+ m_topLevel->raise();
+ m_topLevel->setActiveWindow();
+#if KDE_IS_VERSION(3,1,92)
+ KWin::activateWindow(m_topLevel->winId());
+#else
+ KWin::setActiveWindow(m_topLevel->winId());
+#endif
+ }
+ m_topLevel->tabWidget()->showPage( w );
+}
+
+
+void DisplayMgrMDI::setCaption(QWidget *w, const QString& cap)
+{
+ assert( m_topLevel );
+
+ w->setCaption(cap);
+
+ QString esc = cap;
+ esc.replace("&", "&&");
+ kdDebug(5008) << "Set caption: " << esc << endl;
+
+ m_topLevel->tabWidget()->setTabLabel( w, esc );
+}
+
+void DisplayMgrMDI::slotCycleTabsLeft()
+{
+
+ assert( m_topLevel );
+
+ m_topLevel->previous();
+}
+
+void DisplayMgrMDI::slotCycleTabsRight()
+{
+
+ assert( m_topLevel );
+
+ m_topLevel->next();
+}
+
+void DisplayMgrMDI::reparentReq()
+{
+ kdDebug(5008) << "got reparent" << endl;
+
+ QWidget *o = kapp->focusWidget();
+ QWidget *s;
+
+ if(o == NULL){
+ kdDebug(5008) << "Kapp says no widget has focus!" << endl;
+ o = kapp->activeWindow();
+
+ if(o->inherits("KMainWindow") == false)
+ return;
+
+ s = o;
+ }
+ else {
+
+ kdDebug(5008) << "QWidget is: " << o->className() << " name: " << o->name("none give") << endl;
+
+
+ s = o;
+ while(s->parentWidget()){
+ kdDebug(5008) << "Got a: " << s->className() << endl;
+ s = s->parentWidget();
+ if(s->inherits("KMainWindow"))
+ break;
+
+ }
+ }
+
+
+// QWidget *s = m_topLevel->tabWidget()->currentPage(); can't do this since you can never reattach
+ if(s){
+ KMainWindow *kst = static_cast<KMainWindow *>(s);
+ kdDebug(5008) << "Top is: " << kst->name("none give") <<endl;
+
+ QMenuData *tmenu = kst->menuBar();
+ if(tmenu){
+ QMenuItem *menui = tmenu->findItem(DMM_MDI_ID);
+ if(menui){
+ QMenuData *cmenu = menui->popup();
+ if(cmenu->findItem(DMM_DEATCH_ID) && cmenu->isItemChecked(DMM_DEATCH_ID)){
+ kst->reparent( topLevel()->tabWidget(), 0, QPoint( 0, 0 ), true );
+ show(kst);
+ cmenu->setItemChecked(DMM_DEATCH_ID, false);
+ }
+ else {
+ hide(kst);
+ kst->reparent( 0, QPoint(0,0), true );
+ cmenu->setItemChecked(DMM_DEATCH_ID, true);
+ }
+ }
+ }
+ }
+}
+
+MDITopLevel *DisplayMgrMDI::topLevel()
+{
+ if ( !m_topLevel )
+ {
+ m_topLevel = new MDITopLevel(0x0, "MDITopLevel");
+ m_topLevel->show();
+
+ KAccel *a = new KAccel( m_topLevel );
+ a->insert( "cycle left", i18n("Cycle left"), QString::null, ALT+Key_Left, ALT+Key_Left, this, SLOT(slotCycleTabsLeft()) );
+ a->insert( "cycle right", i18n("Cycle right"), QString::null, ALT+Key_Right, ALT+Key_Right, this, SLOT(slotCycleTabsRight()) );
+ }
+
+ return m_topLevel;
+}
+
+void DisplayMgrMDI::setTabPosition( int idx ) {
+
+ switch ( idx ) {
+ case 0:
+ m_topLevel->tabWidget()->setTabPosition(QTabWidget::Top);
+ break;
+ case 1:
+ m_topLevel->tabWidget()->setTabPosition(QTabWidget::Bottom);
+ break;
+ }
+}
+
+
+void DisplayMgrMDI::setFullScreen( bool full ) {
+ if ( full )
+ m_topLevel->showFullScreen();
+ else
+ m_topLevel->showNormal();
+}
+
+
+
+void DisplayMgrMDI::moveWindowLeft() {
+ moveWindow(-1);
+}
+
+void DisplayMgrMDI::moveWindowRight() {
+ moveWindow(1);
+}
+
+void DisplayMgrMDI::moveWindow(int step)
+{
+ if(m_topLevel->tabWidget()->count() == 0){
+ return;
+ }
+
+ QWidget *w = m_topLevel->tabWidget()->currentPage();
+ if(w != 0x0){
+ int index = m_topLevel->tabWidget()->currentPageIndex();
+ index += step;
+ if(index < 0)
+ return;
+ if(index >= m_topLevel->tabWidget()->count())
+ return;
+
+ m_topLevel->setUpdatesEnabled(false);
+ m_topLevel->hideWidget(w);
+ int space = w->caption().find(" ");
+ QString esc = space < 1 ? w->caption():w->caption().left(space);
+ esc.replace("&", "&&");
+ kdDebug(5008) << "Insert tab: " << esc << endl;
+ m_topLevel->tabWidget()->insertTab( w, esc, index );
+ m_topLevel->tabWidget()->showPage( w );
+ m_topLevel->setUpdatesEnabled(true);
+ }
+}
+
+#include "displayMgrMDI.moc"
diff --git a/ksirc/displayMgrMDI.h b/ksirc/displayMgrMDI.h
new file mode 100644
index 00000000..81528421
--- /dev/null
+++ b/ksirc/displayMgrMDI.h
@@ -0,0 +1,48 @@
+#ifndef __displaymgrmdi_h__
+#define __displaymgrmdi_h__
+
+#include "displayMgr.h"
+#include "mditoplevel.h"
+
+class DisplayMgrMDI : public QObject, public DisplayMgr
+{
+ Q_OBJECT
+public:
+ DisplayMgrMDI();
+ virtual ~DisplayMgrMDI();
+
+ virtual void newTopLevel(QWidget *, bool show = FALSE);
+ virtual void removeTopLevel(QWidget *);
+
+ virtual void show(QWidget *);
+ virtual void hide(QWidget *);
+ virtual void raise(QWidget *, bool takefocus = false);
+
+ virtual void setCaption(QWidget *, const QString&);
+
+public slots:
+ virtual void slotCycleTabsLeft();
+ virtual void slotCycleTabsRight();
+
+protected slots:
+ void reparentReq();
+ void moveWindowLeft();
+ void moveWindowRight();
+ void setTabPosition(int);
+ void setFullScreen(bool);
+
+protected:
+ void moveWindow(int step);
+ void refreshMenuEntry();
+
+private:
+ MDITopLevel *topLevel();
+
+ QGuardedPtr<MDITopLevel> m_topLevel;
+ int m_moveRightTab, m_moveLeftTab;
+ QPopupMenu *m_popupWindows;
+};
+
+
+#endif
+
diff --git a/ksirc/displayMgrSDI.cpp b/ksirc/displayMgrSDI.cpp
new file mode 100644
index 00000000..ee5de75b
--- /dev/null
+++ b/ksirc/displayMgrSDI.cpp
@@ -0,0 +1,40 @@
+#include "displayMgrSDI.h"
+
+#include <qwidget.h>
+
+DisplayMgrSDI::DisplayMgrSDI()
+{
+}
+
+DisplayMgrSDI::~DisplayMgrSDI(){
+}
+
+void DisplayMgrSDI::newTopLevel(QWidget *w, bool show){
+ if(show == TRUE)
+ w->show();
+}
+
+void DisplayMgrSDI::removeTopLevel(QWidget *){
+}
+
+void DisplayMgrSDI::show(QWidget *w){
+ w->show();
+}
+
+void DisplayMgrSDI::hide(QWidget *w){
+ w->hide();
+}
+
+void DisplayMgrSDI::raise(QWidget *w, bool takefocus){
+ w->show();
+ w->raise();
+ if(takefocus)
+ w->setActiveWindow();
+
+}
+
+
+void DisplayMgrSDI::setCaption(QWidget *w, const QString& cap){
+ w->setCaption(cap);
+}
+
diff --git a/ksirc/displayMgrSDI.h b/ksirc/displayMgrSDI.h
new file mode 100644
index 00000000..04bf21fe
--- /dev/null
+++ b/ksirc/displayMgrSDI.h
@@ -0,0 +1,25 @@
+#ifndef DISPLAYMGRSDI_H
+#define DISPLAYMGRSDI_H
+
+#include "displayMgr.h"
+
+class DisplayMgrSDI : public DisplayMgr {
+public:
+ DisplayMgrSDI();
+ virtual ~DisplayMgrSDI();
+
+ virtual void newTopLevel(QWidget *, bool show = FALSE);
+ virtual void removeTopLevel(QWidget *);
+
+ virtual void show(QWidget *);
+ virtual void hide(QWidget *);
+ virtual void raise(QWidget *, bool takefocus = false);
+
+ virtual void setCaption(QWidget *, const QString&);
+
+private:
+};
+
+
+#endif
+
diff --git a/ksirc/dockservercontroller.cpp b/ksirc/dockservercontroller.cpp
new file mode 100644
index 00000000..f83f5ada
--- /dev/null
+++ b/ksirc/dockservercontroller.cpp
@@ -0,0 +1,451 @@
+/**********************************************************************
+
+ $$Id$$
+
+ Dock Server Controller. Displays server connection window, and makes
+ new server connection on demand.
+
+ *********************************************************************/
+
+#include "dockservercontroller.h"
+
+#include <qpopupmenu.h>
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qregexp.h>
+#include <qtimer.h>
+#include <qcursor.h>
+#include <kpassivepopup.h>
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kaction.h>
+#include <kwin.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kpassivepopup.h>
+#include <kmessagebox.h>
+#include <kglobalaccel.h>
+#include <kkeydialog.h>
+#include <kdeversion.h>
+
+#include "KSPrefs/ksprefs.h"
+
+#include "servercontroller.h"
+#include "toplevel.h"
+#include "ksopts.h"
+
+#include "objFinder.h"
+#include "displayMgr.h"
+#include "objFinder.h"
+
+#include "dccNew.h"
+
+extern DisplayMgr *displayMgr;
+
+dscNickInfo::dscNickInfo(QString nick, QString server) :
+ m_nick(nick),
+ m_server(server)
+{
+}
+
+dscNickInfo::~dscNickInfo()
+{
+}
+
+
+dockServerController::dockServerController(servercontroller *sc, QWidget *parent, const char *_name)
+: KSystemTray(parent, _name),
+ m_sc(sc)
+{
+
+ m_nicks.setAutoDelete(true);
+ KPopupMenu *pop = contextMenu();
+ pop->setName("dockServerController_menu_pop");
+
+#ifndef NDEBUG
+ pop->insertItem(i18n("Dump Object Tree"), sc, SLOT(dump_obj()));
+ pop->insertItem(i18n("Server Debug Window"), sc, SLOT(server_debug()));
+ pop->insertSeparator();
+#endif
+
+
+ pop->insertItem(SmallIcon( "filter" ), i18n("&Filter Rule Editor..."),
+ m_sc, SLOT(filter_rule_editor()));
+
+ KStdAction::preferences(m_sc, SLOT(general_prefs()),
+ m_sc->actionCollection())->plug(pop);
+ KStdAction::configureNotifications(m_sc, SLOT(notification_prefs()), actionCollection())->plug(pop);
+
+ pop->insertSeparator();
+ pop->insertItem(i18n("New &Server..."),
+ m_sc, SLOT(new_connection()));
+ pop->insertItem(i18n("&Do Autoconnect..."), m_sc, SLOT(start_autoconnect_check()));
+ connect(this, SIGNAL(quitSelected()), m_sc, SLOT(endksirc()));
+
+#if KDE_IS_VERSION(3,1,92)
+ m_pic_dock = KSystemTray::loadIcon( "ksirc" );
+#else
+ m_pic_dock = UserIcon("ksirc_dock");
+#endif
+ m_pic_info = UserIcon("info");
+
+ if ( !m_pic_dock.isNull() )
+ setPixmap( m_pic_dock );
+
+ mainPop = 0x0;
+ m_mainPopVisible = false;
+ createMainPopup();
+
+ m_blinkTimer = new QTimer( this );
+ connect( m_blinkTimer, SIGNAL(timeout()), this, SLOT( blinkDockedIcon() ) );
+ m_blinkStatus = false;
+ m_blinkActive = false;
+
+ servercontroller::self()
+ ->getGlobalAccel()
+ ->insert("Raise Last Window", i18n("Raise Last Window"),
+ i18n("If someone said your nick in a window, this action "
+ "will make that window active for you."),
+ ALT+CTRL+Key_A, KKey::QtWIN+CTRL+Key_A, this,
+ SLOT(raiseLastActiveWindow()));
+ servercontroller::self()
+ ->getGlobalAccel()
+ ->insert("Clear Blink", i18n("Clear Blinking Dock Icon"),
+ i18n("If the dock icon is blinking, but you don't want "
+ "to go to the window this will clear the blinking."),
+ ALT+CTRL+Key_Down, KKey::QtWIN+CTRL+Key_Down, this,
+ SLOT(blinkClear()));
+
+// mainPop = new KPopupMenu(this, "dockServerController_main_pop");
+// mainPop->setTitle(i18n("KSirc Dock Menu"));
+
+}
+
+
+
+dockServerController::~dockServerController()
+{
+kdDebug(5008) << "~dockServerController in" << endl;
+ m_sc = 0x0;
+kdDebug(5008) << "~dockServerController out" << endl;
+}
+
+int dockServerController::intoPopupSorted(QString str, QPopupMenu *what)
+{
+ uint i = 0;
+
+ for(i = 0; i < mainPop->count(); i++){
+ if(mainPop->text(mainPop->idAt(i)) > str){
+ break;
+ }
+ }
+ return mainPop->insertItem(str, what, -1, i);
+
+}
+
+void dockServerController::mainPopShow()
+{
+ m_mainPopVisible = true;
+}
+
+void dockServerController::mainPopHide()
+{
+ m_mainPopVisible = false;
+}
+
+void dockServerController::createMainPopup()
+{
+ if(m_mainPopVisible == true)
+ return;
+
+ if(mainPop)
+ delete mainPop;
+ mainPop = new KPopupMenu(this, "dockservercontrller_main_pop");
+ connect(mainPop, SIGNAL(activated(int)),
+ this, SLOT(mainActivated(int)));
+ connect(mainPop, SIGNAL(aboutToShow()),
+ this, SLOT(mainPopShow()));
+ connect(mainPop, SIGNAL(aboutToHide()),
+ this, SLOT(mainPopHide()));
+
+
+ QDictIterator<dscNickInfo> it( m_nicks );
+ for( ; it.current(); ++it){
+ KPopupMenu *sub = new KPopupMenu(mainPop);
+ if(it.current()->status() == dscNickInfo::isOnline){
+ sub->insertItem(i18n("Came Online: ") + it.current()->online().toString("hh:mm"));
+ if( ! it.current()->offline().isNull() ){
+ sub->insertItem(i18n("Last Offline: ") + it.current()->offline().toString("hh:mm"));
+ }
+ int pid = sub->insertItem(i18n("Ping"));
+ int wid = sub->insertItem(i18n("Whois"));
+ int cid = sub->insertItem(i18n("Chat"));
+ int dcid = sub->insertItem(i18n("DCC Chat"));
+
+ int id = intoPopupSorted(it.current()->server() +" -> " + it.current()->nick() + " " + i18n("online"), sub);
+ sub->setItemParameter(pid, id);
+ sub->setItemParameter(cid, id);
+ sub->setItemParameter(wid, id);
+ sub->setItemParameter(dcid, id);
+ connect(sub, SIGNAL(activated(int)),
+ this, SLOT(subItemActivated(int)));
+ }
+ else {
+ sub->insertItem(i18n("Went Offline: ") + it.current()->offline().toString("hh:mm"));
+ if( ! it.current()->online().isNull() ){
+ sub->insertItem(i18n("Last Online: ") + it.current()->online().toString("hh:mm"));
+ }
+
+ intoPopupSorted(it.current()->server() +" -> " + it.current()->nick() + i18n(" offline"), sub);
+ }
+ }
+ if(m_blink_reason.count() > 0){
+ mainPop->insertSeparator();
+ for ( QStringList::Iterator it = m_blink_reason.begin(); it != m_blink_reason.end(); ++it ) {
+ mainPop->insertItem(*it);
+ }
+ }
+ if(mainPop->count() == 0){
+ mainPop->insertItem(i18n("Help on Notify Popup..."), this, SLOT(helpNotice()));
+ mainPop->insertItem(i18n("Configure Notify..."), this, SLOT(configNotify()));
+ }
+}
+
+void dockServerController::subItemActivated(int sub_id)
+{
+ const QPopupMenu *sub = dynamic_cast<const QPopupMenu *>(sender());
+ if(!sub){
+ kdDebug(5008) << "subItemActivated by non QPopupMenu" << endl;
+ return;
+ }
+ int main_id = sub->itemParameter(sub_id);
+ QString mainText = mainPop->text(main_id);
+ if(mainText.isNull()){
+ kdDebug(5008) << "failed to get mainPop text" << endl;
+ }
+ QRegExp rx("(\\S+) -> (\\S+) ");
+ if(rx.search(mainText) >= 0){
+ QString mserver = rx.cap(1);
+ QString mnick = rx.cap(2);
+
+ QString ns = mserver + "/" + mnick;
+
+ if(m_nicks[ns]){
+ kdDebug(5008) << "Got " << sub->text(sub_id) << " request for " << ns << endl;
+ QString cmd = sub->text(sub_id);
+ QString server = m_nicks[ns]->server();
+ QString nick = m_nicks[ns]->nick();
+
+ if(cmd == i18n("Chat")){
+ servercontroller::self()->new_toplevel(KSircChannel(server, nick));
+ }
+ else {
+ KSircProcess *kp = servercontroller::self()->processes().find(server);
+ if(kp){
+ KSircTopLevel *wm = dynamic_cast<KSircTopLevel *>(kp->getWindowList().find("!default"));
+ if(wm){
+ if(cmd == i18n("Ping")){
+ wm->sirc_line_return("/ping " + nick + "\n");
+ } else if(cmd == i18n("Whois")){
+ wm->sirc_line_return("/whois " + nick + "\n");
+ } else if(cmd == i18n("DCC Chat")){
+ wm->sirc_line_return("/dcc chat " + nick + "\n");
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
+
+void dockServerController::mousePressEvent( QMouseEvent *e )
+{
+ if(e->button() == LeftButton){
+ showPopupMenu(mainPop);
+ }
+ else {
+ KSystemTray::mousePressEvent(e);
+ }
+}
+
+void dockServerController::showPopupMenu( QPopupMenu *menu )
+{
+ Q_ASSERT( menu != 0L );
+
+ menu->popup(QCursor::pos());
+
+}
+
+void dockServerController::nickOnline(QString server, QString nick)
+{
+ QString sn = server + "/" + nick;
+ if(!m_nicks[sn])
+ m_nicks.insert(sn, new dscNickInfo(nick, server));
+ m_nicks[sn]->setOnline();
+ createMainPopup();
+}
+
+void dockServerController::nickOffline(QString server, QString nick)
+{
+ QString sn = server + "/" + nick;
+ if(!m_nicks[sn])
+ m_nicks.insert(sn, new dscNickInfo(nick, server));
+ m_nicks[sn]->setOffline();
+ createMainPopup();
+}
+
+void dockServerController::serverOpen(QString)
+{
+}
+
+void dockServerController::serverClose(QString server)
+{
+ QDictIterator<dscNickInfo> it( m_nicks );
+ while(it.current()){
+ if(it.current()->server() == server)
+ m_nicks.remove(it.currentKey());
+ else
+ ++it;
+ }
+ createMainPopup();
+}
+
+void dockServerController::startBlink(const QString& reason, const QString& text)
+{
+ if(m_blinkActive == false){
+ // change icon (to "someone's talking to you" icon)
+ setPixmap( m_pic_info );
+ m_blinkStatus = true;
+ m_blinkActive = true;
+ m_blinkTimer->start( 500 ); // half a second
+ }
+ if(!reason.isNull()){
+ QString br(reason);
+ if(text.isNull() && ksopts->runDocked && ksopts->dockPopups)
+ KPassivePopup::message(QString("Notify: %1").arg(reason), this);
+ else {
+ QStringList sl;
+ QString cutup = text;
+ int i = 0;
+ br = reason + " " + text.left(50);
+ if(text.length() > 50)
+ br.append("...");
+ while(!cutup.isEmpty() && i++ < 3){
+ sl.append(cutup.left(50));
+ cutup.remove(0, 50);
+ }
+ cutup = sl.join("\n");
+ cutup.truncate(cutup.length()-1);
+ if(ksopts->runDocked && ksopts->dockPopups)
+ KPassivePopup::message(QString("%1").arg(reason), cutup, this);
+ }
+ m_blink_reason.append(br);
+ createMainPopup();
+ kdDebug(5008) << "Blink reason: " << br << endl;
+
+ QRegExp rx("(\\S+) -> (\\S+)");
+ if(rx.search(reason) >= 0){
+ QString server = rx.cap(1);
+ QString nick = rx.cap(2);
+
+ m_last_server = server;
+ m_last_nick = nick;
+ }
+ }
+}
+
+void dockServerController::stopBlink(const QString& reason, bool clear)
+{
+ if(clear == true){
+ m_blinkActive = false;
+ m_blinkTimer->stop();
+ setPixmap( m_pic_dock );
+ m_blink_reason.clear();
+ }
+ else {
+ if(!reason.isNull())
+ m_blink_reason.remove(reason);
+ }
+ createMainPopup();
+}
+
+void dockServerController::blinkClear()
+{
+ m_sc->resetNotification();
+}
+
+void dockServerController::mainActivated(int id)
+{
+ QRegExp rx("(\\S+) -> (\\S+) ");
+ if(rx.search(mainPop->text(id)) >= 0){
+ QString server = rx.cap(1);
+ QString nick = rx.cap(2);
+
+ raiseWindow(server, nick);
+
+ }
+}
+
+void dockServerController::raiseLastActiveWindow()
+{
+ if((!m_last_server.isNull()) && (!m_last_nick.isNull()))
+ raiseWindow(m_last_server, m_last_nick);
+}
+
+void dockServerController::blinkDockedIcon()
+{
+ m_blinkStatus = !m_blinkStatus;
+ setPixmap( m_blinkStatus ? m_pic_info : m_pic_dock );
+}
+
+void dockServerController::helpNotice()
+{
+ KMessageBox::information(0x0,
+ i18n("This popup menu can show a list of "
+ "people you have in your notify "
+ "list, and their status. You can configure "
+ "this list by going to Configure KSirc->"
+ "Startup->Notify and adding people to the "
+ "list. This will take effect the next "
+ "time you connect to a server. "
+ "This message appears when "
+ "there is nothing in your notify "
+ "list or when no one in your "
+ "list is online."
+ ),
+ i18n("Help for Notification Popup"));
+
+}
+
+void dockServerController::configNotify()
+{
+ KSPrefs *kp = new KSPrefs();
+ connect(kp, SIGNAL(update(int)),
+ m_sc, SLOT(configChange()));
+ kp->resize(550, 450);
+ kp->showPage(2); /* Show auto connect page */
+ kp->show();
+
+}
+
+
+void dockServerController::raiseWindow(QString server, QString name)
+{
+ QCString txt = server.utf8() + "_" + name.utf8() + "_toplevel";
+ QWidget *obj = dynamic_cast<QWidget *>( objFinder::find(txt, "KSircTopLevel"));
+ if(obj == 0x0){
+ txt = server.utf8() + "_!" + name.utf8() + "_toplevel";
+ obj = dynamic_cast<QWidget *>( objFinder::find(txt, "KSircTopLevel"));
+ }
+
+ if(obj != 0x0){
+ displayMgr->raise(obj, true);
+ }
+ else {
+ kdWarning() << "Did not find widget ptr to raise it" << endl;
+ }
+}
+
+#include "dockservercontroller.moc"
+
diff --git a/ksirc/dockservercontroller.h b/ksirc/dockservercontroller.h
new file mode 100644
index 00000000..5c5bdb59
--- /dev/null
+++ b/ksirc/dockservercontroller.h
@@ -0,0 +1,110 @@
+
+#ifndef dockservercontroller_included
+#define dockservercontroller_included
+
+#include <ksystemtray.h>
+#include <qdict.h>
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qpixmap.h>
+#include <qstringlist.h>
+
+class QPopupMenu;
+class QWidget;
+class servercontroller;
+class QMouseEvent;
+class KPopupMenu;
+class QTimer;
+
+class dscNickInfo
+{
+public:
+ dscNickInfo(QString nick, QString server);
+ ~dscNickInfo();
+
+ enum status {
+ isOnline,
+ isOffline
+ };
+
+ QString nick() { return m_nick; }
+ QString server() { return m_server; }
+
+ void setOnline() { m_status = isOnline; m_online = QTime::currentTime(); }
+ const QTime &online() { return m_online; }
+
+ void setOffline() { m_status = isOffline; m_offline = QTime::currentTime(); }
+ const QTime offline() { return m_offline; }
+
+ void setStatus(enum status stat) { m_status = stat; }
+ enum status status() { return m_status; }
+
+private:
+ QString m_nick;
+ QString m_server;
+ enum status m_status;
+ QTime m_online;
+ QTime m_offline;
+
+};
+
+class dockServerController : public KSystemTray
+{
+ Q_OBJECT
+public:
+ dockServerController(servercontroller *_sc, QWidget *parent = 0x0, const char *_name = 0x0);
+ ~dockServerController();
+
+ void startBlink(const QString& reason = QString::null, const QString& text = QString::null);
+ void stopBlink(const QString& reason = QString::null, bool clear = false);
+
+ void nickOnline(QString server, QString nick);
+ void nickOffline(QString server, QString nick);
+
+ void serverOpen(QString server);
+ void serverClose(QString server);
+
+protected:
+ void mousePressEvent( QMouseEvent *);
+ virtual void showPopupMenu( QPopupMenu *);
+
+public slots:
+ void raiseLastActiveWindow();
+
+protected slots:
+ void subItemActivated(int);
+ void blinkDockedIcon(void);
+ void blinkClear(void);
+ void mainActivated(int id);
+ void helpNotice();
+ void configNotify();
+
+ void mainPopShow();
+ void mainPopHide();
+
+private:
+ int intoPopupSorted(QString, QPopupMenu *);
+ void createMainPopup();
+ void raiseWindow(QString server, QString name);
+ QDict<dscNickInfo> m_nicks;
+ servercontroller *m_sc;
+ KPopupMenu *mainPop;
+
+ QString m_last_nick;
+ QString m_last_server;
+
+ QPixmap m_pic_dock;
+ QPixmap m_pic_info;
+
+ bool m_mainPopVisible;
+
+ bool m_blinkActive;
+ bool m_blinkStatus; // true: blue icon, false: normal icon
+ QTimer* m_blinkTimer;
+
+ QStringList m_blink_reason;
+
+};
+
+#endif
+
diff --git a/ksirc/dsirc b/ksirc/dsirc
new file mode 100755
index 00000000..c6e0b63c
--- /dev/null
+++ b/ksirc/dsirc
@@ -0,0 +1,2721 @@
+#!/usr/bin/perl
+
+# dsirc: dumb-mode small irc client in perl
+# by orabidoo <roger.espel.llima@pobox.com>
+#
+# Copyright (C) 1995-1997 Roger Espel Llima
+#
+# for a full-screen termcap interface, use this with ssfe
+#
+# use: dsirc [options] [nick [server[:port[:password]]]]
+# options are:
+# -p = specify port number
+# -i = specify IRCNAME
+# -n = specify nickname (quite useless as an option)
+# -s = specify server (quite useless as an option)
+# -l = specify file to be loaded instead of ~/.sircrc.pl
+# -L = specify file to be loaded instead of ~/.sircrc
+# -H = specify virtual host to bind to
+# -q = don't load ~/.sircrc or ~/.sircrc.pl
+# -Q = don't load system sircrc or sircrc.pl
+# -R = run in restricted (secure) mode
+# -r = raw mode (no control-char filtering)
+# -8 = 8-bit mode
+# -S = connect using SSL
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation. See the file LICENSE for more details.
+#
+# If you make improvements to sirc, please send me the modifications
+# (context diffs appreciated) and they might make it to the next release.
+#
+# For bug reports, comments, questions, email roger.espel.llima@pobox.com
+#
+# You can always find the latest version of sirc at the following URL:
+# http://www.eleves.ens.fr:8080/home/espel/sirc/sirc.html
+
+# Concerning the use in ksirc you'll find a mail from the author below:
+#
+# Subject: Re: dsirc in kde
+# Date: Thu, 7 Sep 2000 13:16:30 -0400
+# From: Roger Espel Llima <espel@iagora.net>
+# To: Harri Porten <porten@kde.org>
+#
+# On Thu, Sep 07, 2000 at 07:12:33PM +0200, Harri Porten wrote:
+# [....]
+# > Ok. Your dsirc script is used in ksirc. I haven't checked how it is
+# > invoked and what legal ramifications that would have licensing wise but
+# > I would like to "officially" ask you anyway:
+# >
+# > Do you have oppose to your code being used this way in the past and in
+# > the future ? Do you "forgive" us [for use in prev. versions of KDE] ? :)
+#
+# I "officially" find it perfectly fine that dsirc is used in KDE. I knew
+# of ksirc when it started, and found it very flattering that someone
+# would write 200k of C++ to interface with my 62k of perl :=)
+
+$version='2.211';
+$date='10 Mar 1998';
+$add_ons='';
+
+$libdir=$ENV{"SIRCLIB"} || ".";
+push(@INC, $libdir, $ENV{"HOME"});
+@loadpath=($ENV{"HOME"}."/.sirc", $libdir, ".");
+$ENV{"SIRCWAIT"} or $ready=1;
+
+$|=1;
+
+$publicAway = 1;
+
+if (!eval "require 'getopts.pl';") {
+ print "\n\n\
+Your perl interpreter is *really* screwed up: the getopts.pl library is not
+even there! Have you even bothered to run 'install'?\n";
+ exit;
+}
+
+if ($] >= 5 && (eval "use Socket;", $@ eq '')) {
+ $sock6 = eval ("require Socket6;") and eval("use Socket6;");
+} elsif (-f "$libdir/sircsock.ph") {
+ do "$libdir/sircsock.ph";
+} elsif (-f $ENV{'HOME'}."/sircsock.ph") {
+ do $ENV{'HOME'}."/sircsock.ph";
+} elsif (!eval "require 'sys/socket.ph';") {
+ print "\n\n\
+Your perl installation is wrong somewhere, the sys/socket.ph include file
+couldn't be found. Have you even bothered to run 'install'?\n";
+ exit;
+}
+
+$hasPOSIX = 1;
+eval "use POSIX;";
+if($@) {
+ $hasPOSIX = 0;
+ print "*** No Posix library, falling back to blocking IO (dcc will suck)\n";
+}
+
+
+&Getopts('n:s:p:u:i:l:L:H:rqQR78S');
+
+%set=("LOGFILE", "", "LOG", "off", "PRINTUH", "none", "PRINTCHAN", "off",
+ "LOCALHOST", "", "CTCP", "noflood", "SENDAHEAD", 4096,
+ "USERINFO", "", "FINGER", "", "IRCNAME", "", "EIGHT_BIT", "on",
+ "LOADPATH", join(":", @loadpath), "CTRL_T", "/next");
+
+$raw_mode=$opt_r || (!-t STDOUT);
+$ansi=!$raw_mode && $ENV{"TERM"} =~ /^vt|^xterm|^ansi/i;
+$server=$opt_s || $ARGV[1] || $ENV{"SIRCSERVER"} || $ENV{"IRCSERVER"} ||
+ "irc.primenet.com";
+$port0=$opt_p || $ENV{"SIRCPORT"} || $ENV{"IRCPORT"} || 6667;
+$username=$opt_u || $ENV{"SIRCUSER"} || $ENV{"IRCUSER"} || (getpwuid($<))[0] ||
+ $ENV{"USER"} || "blah";
+$set{"IRCNAME"}=$opt_i || $ENV{"SIRCNAME"} || $ENV{"IRCNAME"} || "sirc user";
+$nick=$opt_n || $ARGV[0] || $ENV{"SIRCNICK"} || $ENV{"IRCNICK"} || $username;
+$set{"FINGER"}=$ENV{"IRCFINGER"} || "keep your fingers to yourself";
+$set{"USERINFO"}=$ENV{"USERINFO"} || "yep, I'm a user";
+if ($server =~ /^\[([^\]]+)\]:([0-9]*):?([^:]*)$/
+ or $server =~ /^([^:]+):([0-9]*):?([^:]*)$/)
+{
+ ($server, $port, $pass)=($1, $2, $3);
+}
+$port || ($port=$port0);
+$server0=$server1=$server;
+$port0=$port1=$port;
+$pass0=$pass1=$pass;
+$initfile=$opt_l || $ENV{"SIRCRCPL"} || $ENV{'HOME'}."/.sircrc.pl"
+ if $opt_l || !$opt_q;
+$sysinit=$libdir."/sircrc.pl" if $libdir ne '.' && !$opt_Q;
+$rcfile=$opt_L || $ENV{"SIRCRC"} || $ENV{'HOME'}."/.sircrc"
+ if $opt_L || !$opt_q;
+$sysrc=$libdir."/sircrc" if $libdir ne '.' && !$opt_Q;
+$set{"LOGFILE"}=$logfile=$ENV{'HOME'}."/sirc.log";
+$opt_8 || ($set{"EIGHT_BIT"}="off");
+$restrict=$opt_R;
+$set{"LOCALHOST"}=$opt_H || $ENV{"SIRCHOST"} || $ENV{"IRCHOST"} ||
+ $ENV{"LOCALHOST"} || "";
+$SSL=$opt_S;
+
+@ARGV=(); # ignore any more arguments
+
+if (open(H, "$libdir/sirc.help") || ((-f "$libdir/sirc.help.gz") &&
+ open(H, "gzip -cd $libdir/sirc.help.gz |"))) {
+ @help=<H>;
+ close H;
+ foreach (@help) {
+ chop;
+ s/\$version/$version/g;
+ s/\$date/$date/g;
+ }
+} else {
+ print "*** Warning: help file ($libdir/sirc.help) not found!\n";
+}
+$floodtimer=0;
+
+sub exit {
+ &dohooks("quit");
+ &sl("QUIT :using sirc version $version$add_ons") if $connected;
+ close LOG if $logging;
+ exit 0;
+}
+
+$SIG{'PIPE'}='IGNORE';
+$SIG{'QUIT'}='IGNORE';
+$SIG{'INT'}='exit';
+$SIG{'TERM'}='exit'; # KSIRC MOD
+
+sub eq {
+ local($a, $b)=@_;
+ $a =~ tr/A-Z/a-z/;
+ $b =~ tr/A-Z/a-z/;
+ return ($a eq $b);
+}
+
+sub tilde {
+ $_[0] =~ s|^\~(\w+)|(getpwnam($1))[7]|e;
+ $_[0] =~ s/^\~/$ENV{'HOME'}/;
+ $_[0]="." if $_[0] eq '';
+}
+
+sub sigquit {
+ # really ugly hack, but it works...
+ &dohooks("quit");
+ close($trysock);
+}
+
+sub resolve {
+ if ($sock6) {
+ my $addr = $_[0];
+ if ("$addr" =~ /^\d+$/)
+ {
+ $addr = pack("N", $addr);
+ my @i = unpack("C4", $addr);
+ $addr = "$i[0].$i[1].$i[2].$i[3]";
+ }
+ return getaddrinfo($addr, $_[1], $_[2] || &AF_UNSPEC, &SOCK_STREAM);
+ }
+ my $addr;
+ if ($_[0] =~ /^\d+$/) {
+ $addr = pack("N", $_[0]+0);
+ } elsif ($_[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
+ $addr = pack("c4", $1, $2, $3, $4);
+ } else {
+ $addr=(gethostbyname($_[0]))[4];
+ return -1 unless (defined($addr));
+ }
+ return (&AF_INET, &SOCK_STREAM, 0, pack_sockaddr_in($_[1], $addr), undef);
+}
+
+$nextfh="sircblah000";
+sub newfh {
+ return ++$nextfh;
+}
+
+sub connect {
+ $_[0]=&newfh;
+ local($fh, $host, $port)=@_;
+ my @res = resolve($host, $port);
+ &tell("*\cbE\cb* Hostname `$host' not found"), return -1 if scalar(@res) < 5;
+ $family = -1;
+ my $bindfailed;
+ while (scalar(@res) >= 5) {
+ ($family, my ($socktype, $proto, $addr), undef, @res) = @res;
+ &print("*\cbE\cb* Out of file descriptors: $!"), return -2
+ unless socket($fh, $family, $socktype, $proto);
+
+ $bindfailed = undef;
+ if ($set{"LOCALHOST"}) {
+ # once again, DCC only does ipv4
+ $bindaddr = (&resolve($set{"LOCALHOST"}, 0, &AF_INET))[3];
+ $bindfailed = 1 unless bind($fh, $bindaddr);
+ }
+
+ $trysock=$fh;
+ $SIG{'QUIT'}='sigquit';
+ $SIG{'QUIT'}='IGNORE', last if connect($fh, $addr);
+ $SIG{'QUIT'}='IGNORE';
+ $family = -1;
+ }
+ &print("*\cbE\cb* Can't connect to host: $!"), return -3 if $family == -1;
+ # Tried to just check for $family != &AF_INET where needed, but
+ # that segfaulted perl (!), guess it's a bug in Socket6.pm, but I won't try
+ # to debug that. (malte)
+ $ipv6 = 1 if ($sock6 && $family == &AF_INET6);
+ &tell("*\cbE\cb* Warning: can't bind to sirc host: ".$set{'LOCALHOST'})
+ if $bindfailed;
+
+ if ($ipv6 != 1)
+ {
+ $bindaddr=getsockname($fh) unless $bindaddr;
+ }
+ select($fh); $|=1; select(STDOUT);
+ return 1;
+}
+
+sub connectSSL {
+ eval "use IO::Socket::SSL;";
+
+ if($@){
+ &tell("Can't load SSL socket library, perl does not support SSL!");
+ &tell("To use SSL you must install the IO::Socket::SSL perl library");
+ &tell("Try as root: perl -MCPAN -e 'install IO::Socket::SSL'");
+ &tell("Giving up connect");
+ return 0;
+ }
+ local($fh, $host, $port)=@_;
+ &tell("*** Doing SSL server connect...");
+ $fh = new IO::Socket::SSL("$host:$port");
+ if(defined $fh){
+ $_[0] = $fh;
+ select($fh); $|=1; select(STDOUT);
+ return 1;
+ }
+ else {
+ warn "*** I encountered a problem: ($!) ",
+ &IO::Socket::SSL::errstr();
+ warn "*** Invalid hostname or port?\n";
+ return -1;
+ }
+}
+
+sub sel_nbconnecthandler {
+ local($fh) = $_[0];
+ &remwsel($fh);
+ $!="";
+ my $res = unpack("i", getsockopt("$fh", SOL_SOCKET(), SO_ERROR()) || die "Failed to get sockopt: $!");
+ select($fh); $|=1; select(STDOUT);
+ &{$nbconnectlist{$fh}{"callback"}}($fh, $res);
+ $nbconnectlist{$fh} = undef;
+}
+
+#
+# Non blocking connect
+# arguments are: filehandle(returned), host, port, callback function.
+#
+
+sub connectnb {
+ if($hasPOSIX == 0){
+ my $cb = $_[3];
+ $_[3] = undef;
+ my $ret = &connect(@_);
+ if($ret == 1){
+ &$cb($_[0], 0);
+ }
+ else {
+ &$cb($_[0], -1);
+ }
+ return $ret;
+
+ }
+ $_[0]=&newfh;
+ local($fh, $host, $port, $callback)=@_;
+ my @res = resolve($host, $port);
+ &tell("*\cbE\cb* Hostname `$host' not found"), return -1 if scalar(@res) < 5;
+
+ while (scalar(@res) >= 5) {
+ ($family, my ($socktype, $proto, $addr), undef, @res) = @res;
+ &print("*\cbE\cb* Out of file descriptors: $!"), return -2
+ unless socket($fh, $family, $socktype, $proto);
+
+ fcntl($fh, F_SETFL(), O_NONBLOCK());
+ &addwsel($fh, "nbconnecthandler", 0);
+ if(connect($fh, $addr)){
+ &$callback($fh, 0);
+ }
+ else {
+ if($! == EINPROGRESS()){
+ $nbconnectlist{$fh}{"callback"} = $callback;
+ }
+ else {
+ &print("*\cbI\cb* got other error $!");
+ return -1;
+ }
+ }
+ }
+ return 1;
+}
+
+sub listen {
+ $_[0]=&newfh;
+ local($fh, $port)=@_;
+ local($thisend);
+
+ &tell("\cbE\cb* first set your ipv4 hostname with /set LOCALHOST <hostname>"), return 0
+ unless (length $bindaddr);
+
+
+# XXX: don't use ipv6 for the time being as ipv6 and dcc don't mix
+# if ($ipv6) {
+ # XXX: substr() hack to avoid problems on some Linux systems
+# (undef, my $addr) = unpack_sockaddr_in6(substr($bindaddr, 0, 24));
+# $thisend = pack_sockaddr_in6($port, $addr);
+# } else {
+ (undef, my $addr) = unpack_sockaddr_in($bindaddr);
+ $thisend = pack_sockaddr_in($port, $addr);
+# }
+ &tell("*\cbE\cb* Out of file descriptors"), return 0
+ unless socket($fh, &AF_INET, &SOCK_STREAM, 0);
+ &tell("*\cbE\cb* Can't bind local socket!"), close $fh, return 0
+ unless bind($fh, $thisend);
+ &tell("*\cbE\cb* Can't listen to socket!"), close $fh, return
+ unless listen($fh, 5);
+ $ipv6=0;
+ return getsockname($fh);
+}
+
+sub accept {
+ $_[0]=&newfh;
+ return (accept($_[0], $_[1]), close($_[1]))[0];
+}
+
+sub bindtoserver {
+ @channels=(); $talkchannel='';
+ %mode=(); $umode=''; %limit=(); %haveops=(); %chankey=(); $away='';
+ $listmin=0; $listmax=100000; $listpat='';
+ @waituh=(); @douh=(); @erruh=(); $invited='';
+ &dostatus;
+ &tell("*** Connecting to $server, port $port...");
+ if($SSL == 1){
+ sleep 10, &bindtoserver if &connectSSL($S, $server, $port) < 0;
+ } else {
+ sleep 10, &bindtoserver if &connect($S, $server, $port) < 0;
+ }
+ $connected=1;
+ $server1=$server;
+ $port1=$port;
+ $pass1=$pass;
+ &sl("PASS $pass") if $pass;
+ &sl("USER $username blah blah :".$set{'IRCNAME'});
+ &sl("NICK $nick");
+ @channels=(); $talkchannel=''; %mode=(); $umode=''; %limit=();
+ %haveops=(); %chankey=();
+}
+
+sub gl {
+ if ($buffer{$_[0]} =~ /^([^\n\r]*)\r?\n\r?/) {
+ $buffer{$_[0]}=$';
+ $_=$1."\n";
+ return 1;
+ }
+ local($buf)='';
+ # &tell("About to sysread: $_[0]");
+ if (sysread($_[0], $buf, 4096)) {
+ $buffer{$_[0]}.=$buf;
+ if ($buffer{$_[0]} =~ /^([^\n\r]*)\r?\n\r?/) {
+ $buffer{$_[0]}=$';
+ $_=$1."\n";
+ return 1;
+ }
+ return '';
+ }
+ $_='';
+ return 1;
+}
+
+sub sl {
+ $logging && print LOG "<<".$_[0]."\n";
+ if(!print $S $_[0]."\n"){
+ &print("*\cbE\cb* Error writing to server: $!");
+ &tell("*\cbE\cb* Connection to server lost");
+ close($S);
+ delete $buffer{$S};
+ $connected=0;
+ &dohooks("disconnect");
+ &bindtoserver;
+ }
+ elsif (time-$floodtimer < 1){
+ select(undef, undef, undef, 0.5);
+ }
+ $floodtimer=time;
+}
+
+sub dostatus {
+ return unless $ssfe;
+ local($t, $s)=($talkchannel, " [sirc] ");
+ my($i);
+ for($i=0; $i<=$#channels; $i++){
+ $s = " [sirc] ";
+ $t = $channels[$i];
+ $t =~ tr/A-Z/a-z/;
+ $s.="*" if $umode =~ /o/;
+ $s.="\@" if $t && $haveops{$t};
+ $s.=$nick;
+ $s.=" (+$umode)" if $umode;
+ $s.=" [query: ${query}]" if $query;
+ $s.=" (away)" if $away;
+ if ($talkchannel ne '') {
+ $s.=" on $t (+$mode{$t})";
+ $s.=" <key: $chankey{$t}>" if $chankey{$t};
+ $s.=" <limit: $limit{$t}>" if $limit{$t};
+ }
+ &dohooks("status", $s);
+# $laststatus=$s, print "~${t}~`#ssfe#s$s\n" if $laststatus ne $s;
+ $laststatus=$s;
+ $logging && print LOG "** ~${t}~`#ssfe#s$s\n";
+ print "~${t}~`#ssfe#s$s\n";
+ }
+}
+
+$bold="\c[[1m";
+$underline="\c[[4m";
+$reverse="\c[[7m";
+$normal="\c[[m";
+$cls="\c[[H\c[[2J";
+
+sub enhance {
+ local($what)=@_;
+ $what =~ tr/\c@-\c^/@-^/;
+ return "\cv${what}\cv";
+}
+
+sub print {
+ local($skip, $what)=(0, @_);
+ &dohooks("print", $what);
+ return if $skip;
+ $what =~ s/\s+$//;
+ # thanks to Toy (wacren@obspm.fr) for this translation
+ $what =~ tr/\x80-\xff/\x00-\x1f !cLxY|$_ca<\-\-R_o+23\'mp.,1o>123?AAAAAAACEEEEIIIIDNOOOOO*0UUUUYPBaaaaaaaceeeeiiiidnooooo:0uuuuypy/
+ if $set{"EIGHT_BIT"} ne 'on';
+ $logging && print LOG "-> " . $what."\n";
+ if ($raw_mode) {
+ print $what, "\n" || &exit;
+ } elsif ($ansi) {
+ # this is buggy if you combine effects
+ $what =~ s/([\ca\cc-\ch\cj-\cu\cw-\c^])/&enhance($1)/eg;
+ while ($what =~ /\cb/) {
+ ($what =~ s/\cb([^\cb]*)\cb/$bold$1$normal/) ||
+ $what =~ s/\cb/$bold/g;
+ }
+ while ($what =~ /\c_/) {
+ ($what =~ s/\c_([^\c_]*)\c_/$underline$1$normal/) ||
+ $what =~ s/\c_/$underline/g;
+ }
+ while ($what =~ /\cv/) {
+ ($what =~ s/\cv([^\cv]*)\cv/$reverse$1$normal/) ||
+ $what =~ s/\cv/$reverse/g;
+ }
+ print $what, $normal, "\n" || &exit;
+ } else {
+ $what =~ tr/\ca-\ch\cj-\c_//d;
+ print $what, "\n" || &exit;
+ }
+}
+
+sub tell {
+ $silent || &print;
+}
+
+sub dohooks {
+ $hooktype=shift;
+ local(@hl);
+ eval "\@hl=\@${hooktype}_hooks;";
+ foreach $h (@hl) {
+ eval { &$h(@_); };
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in $hooktype hook &$h: $@")
+ if $@ ne '';
+ }
+}
+
+sub dcerror {
+ local($fh, $n)=($_[0], $dcnick{$_[0]});
+ &dohooks("chat_disconnect", $n);
+ &tell("*\cbE\cb* DCC chat with $n lost");
+ &tell("~!dcc~Closing DCC CHAT with who: $n");
+ close($fh);
+ $n =~ tr/A-Z/a-z/;
+ delete $dcnick{$fh};
+ delete $dcvol{$n};
+ delete $dcfh{$n};
+ delete $buffer{$fh};
+}
+
+sub dgsclose {
+ local($sfh, $rfh, $type, $err)=@_;
+ &dohooks("dcc_disconnect", $dnick{$sfh}, $dfile{$rfh}, $dtransferred{$sfh},
+ time-$dstarttime{$rfh}, $rfh);
+ &tell("*\cbD\cb* DCC $type with $dnick{$sfh} ($dfile{$rfh}) terminated; $dtransferred{$sfh} bytes transferred in ".(time-$dstarttime{$rfh}). " seconds");
+ &tell("~!dcc~DCC $type terminated who: $dnick{$sfh} file: $dfile{$rfh} reason: $err");
+ close($sfh);
+ close($rfh);
+ delete $dgrfh{$sfh};
+ delete $dsrfh{$sfh};
+ delete $dfile{$rfh};
+ delete $dstarttime{$rfh};
+ delete $dtransferred{$sfh};
+ delete $dsoffset{$sfh};
+ delete $dsport{$sfh};
+ delete $dsresumedb{$sfh};
+ delete $dgxferadd{$sfh};
+ delete $dnick{$sfh};
+}
+
+sub msg {
+ local($towho, $what)=@_;
+ print "`#ssfe#t/m $towho \n" if $ssfe && !&eq($towho, $talkchannel);
+ if ($towho =~ s/^=//) {
+ local($n, $fh)=($towho);
+ $n =~ tr/A-Z/a-z/;
+ $fh=$dcfh{$n};
+ if ($fh) {
+ (print $fh $what."\n") || &dcerror($fh);
+ $dcvol{$n}+=length($what);
+ &dohooks("send_dcc_chat", $towho, $what);
+ &tell("~=${towho}~|\cb$towho\cb| $what"); #KSIRC MOD
+ } else {
+ &tell("*\cbE\cb* No active DCC chat with $towho");
+ }
+ } elsif ($connected>1) {
+ $what=substr($what, 0, 485);
+ &dohooks("send_text", $towho, $what);
+ if (&eq($towho, $talkchannel) && !$printchan) {
+ &tell("~${towho}~<${nick}> $what"); # KSIRC MOD
+ } elsif ($towho =~ /^[\&\#\+]/) {
+ &tell("~${towho}~<$nick> $what"); #KSIRC MOD
+ } else {
+ &tell("~${towho}~>${nick}< $what"); #KSIRC MOD
+ }
+ &sl("PRIVMSG $towho :$what");
+ } else {
+ &tell("*** You're not connected to a server");
+ }
+}
+
+sub say {
+ if ($query)
+ {
+ &msg($query, @_);
+ }
+ elsif ($talkchannel) {
+ &msg($talkchannel, @_);
+ } else {
+ &tell("*\cbE\cb* Not on a channel");
+ }
+}
+
+sub notice {
+ local($towho, $what)=@_;
+ $what=substr($what, 0, 485);
+ &dohooks("send_notice", $towho, $what);
+ &tell("~${towho}~-> -~n${towho}~n- $what");
+ &sl("NOTICE $towho :$what");
+}
+
+sub describe {
+ local($towho, $what)=@_;
+ $what=substr($what, 0, 480);
+ &dohooks("send_action", $towho, $what);
+ if (&eq($towho, $talkchannel) && !$printchan) {
+ &tell("~${towho}~* $nick $what"); # KSIRC MOD
+ } elsif ($towho =~ /^[\#\&\+]/) {
+ &tell("~${towho}~* $nick $what"); # KSIRC MOD
+ } else {
+ &tell("~${towho}~* $nick $what"); #KSIRC MOD
+# &tell("~${towho}~*-> \cb${towho}\cb: $nick $what"); #KSIRC MOD
+ }
+ &sl("PRIVMSG $towho :\caACTION".($what eq "" ? "" : " ").$what."\ca");
+}
+
+sub me {
+ if ($talkchannel) {
+ &describe($talkchannel, @_);
+ } else {
+ &tell("*\cbE\cb* Not on a channel");
+ }
+}
+
+sub yetonearg {
+ ($newarg, $args)=split(/ +/, $args, 2);
+ $args =~ s/^://;
+}
+
+sub getarg {
+ ($newarg, $args)=split(/ +/, $args, 2);
+}
+
+@weekdays=("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
+@months=("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
+ "Nov", "Dec");
+
+sub date {
+ local($sec, $min, $hour, $mday, $mon, $year, $wday)=localtime($_[0]);
+ return sprintf("$weekdays[$wday] $months[$mon] $mday %.2d:%.2d:%.2d %d",
+ $hour, $min, $sec, $year+1900);
+}
+
+sub reply {
+ return if $set{"CTCP"} eq 'noreply';
+ if ($lastrep<time-10) {
+ $lastrep=time;
+ $nreps=1;
+ } else {
+ return if $nreps++>=2 && $set{"CTCP"} eq 'noflood';
+ }
+ &sl("NOTICE $who :\ca$_[0]\ca");
+}
+
+sub ctcp {
+ local($towho, $to, $what)=$_[0];
+ ($what, $args)=split(/ +/, $_[1], 2);
+ $what =~ tr/a-z/A-Z/;
+ &dohooks("ctcp", $towho, $what, $args);
+ return if $skip;
+ local($a)=$args;
+ $a && ($a=' '.$a);
+ $to = (&eq($towho, $nick) ? "you" : $towho);
+
+ &tell("~$to~*** $who$puh1 did a CTCP $what$a to $to")
+ unless $what =~ /^(ACTION|PING|DCC|VERSION)$/;
+ if ($what eq 'ACTION') {
+ &dohooks("action", $towho, $args);
+ if (&eq($towho, $nick)) {
+ &tell("~$who~* \cb${who}\cb$puh1 $args"); # KSIRC MOD
+ } elsif (&eq($towho, $talkchannel) && !$printchan) {
+ &tell("~$towho~* $who $args"); #KSIRC MOD
+ } else {
+ &tell("~$towho~* $who$puh2 $args"); #KSIRC MOD
+ }
+ } elsif ($what eq 'TIME') {
+ &reply("TIME ".&date(time));
+ } elsif ($what eq 'CLIENTINFO') {
+ &reply("CLIENTINFO ACTION, CLIENTINFO, DCC, ECHO, ERRMSG, FINGER, PING, TIME, USERINFO, VERSION");
+ } elsif ($what eq 'FINGER') {
+ &reply("FINGER ".$set{"FINGER"});
+ } elsif ($what eq 'USERINFO') {
+ &reply("USERINFO ".$set{"USERINFO"});
+ } elsif ($what eq 'VERSION') {
+ local($u)=$add_ons;
+ $u =~ s/^\+//;
+ $u =~ s/\+/ + /g;
+ $u=" -- using $u" if $u;
+ if($to eq 'you'){
+ &tell("~$who~*** $who$puh1 did a CTCP $what$a to $to")
+ }
+ else {
+ &tell("~$to~*** $who$puh1 did a CTCP $what$a to $to")
+ }
+ &reply("VERSION sirc $version, a \cbperl\cb client$u");
+ } elsif ($what eq 'PING') {
+ &reply("PING $args");
+ &tell("*** $who$puh1 did a CTCP PING to $to"); #KSIRC
+ } elsif ($what eq 'ECHO' || $what eq 'ERRMSG') {
+ &reply("$what $args");
+ } elsif ($what eq 'DCC') {
+ &getarg;
+ if ($newarg eq 'CHAT' || $newarg eq 'SEND' && !$restrict) {
+ local($dfile, $dhost, $dport, $dsize)=split(/ +/, $args, 4);
+ $dfile=$1 if $dfile =~ m|/([^/]*)$|;
+ $dfile =~ s/^\./_/;
+ if ($dhost==2130706433 || !$dport>1024 || $dhost !~ /^\d+$/ ||
+ $dport !~ /^\d+$/) {
+ &tell("*\cbE\cb* DCC $newarg ($dfile) from $who$puh1 rejected");
+ } elsif ($newarg eq 'CHAT' && grep (&eq($who, $dcwait{$_}),
+ keys(%dcwait))) {
+ &tell("*\cbD\cb* DCC chat already requested from $who, connecting...");
+ my ($wfh)=(grep(&eq($dcwait{$_}, $who), keys(%dcwait)));
+ my ($n, $fh)=$who;
+ delete $dcwait{$wfh};
+ close($wfh);
+ my $w = $who;
+ my $cb = sub {
+ my ($lfh, $lres) = @_;
+ if($lres != 0){
+ &tell("*\cbD\cb* DCC CHAT with $w failed: " . strerror($lres));
+ &tell("~!dcc~DCC CHAT failed who: $who reason: " . strerror($lres));
+ close($lfh);
+ return;
+ }
+ $dcnick{$lfh}=$w;
+ &tell("*\cbD\cb* DCC CHAT with $w established");
+ &tell("~!dcc~DCC CHAT established who: $w");
+ $n =~ tr/A-Z/a-z/;
+ $dcvol{$n}=0;
+ $dcfh{$n}=$lfh;
+ print "`#ssfe#t/m =$w \n" if $ssfe;
+ };
+ if(&connectnb($fh, $dhost, $dport, $cb) < 1) {
+ return;
+ }
+ } elsif ($newarg eq 'CHAT' && grep(&eq($who, $_), keys(%dcfh))) {
+ &tell("*\cbD\cb* DCC chat from $who$puh1 ignored (already established)");
+ } else {
+ #&tell("*\cbD\cb* DCC $newarg ($dfile) from $who$puh1 ".
+ # ($dsize ? "(size: $dsize) " : "")."[$dhost, $dport]");
+ my $ip = inet_ntoa(pack("N", $dhost));
+ if ($newarg eq 'CHAT') {
+ &tell("~!dcc~DCC CHAT OFFERED who: $who$puh1 ip: $ip port: $dport");
+ $dcoffered{$who}="$dhost $dport";
+ &dohooks("dcc_request", "CHAT", $dhost, $dport);
+ } else {
+ my $index = 1; # KSIRC MOD - Make the file name unique
+ UNIQ: {
+ foreach $i (keys(%dgoffered)) {
+ my($h, $p, $f) = split(/ /, $i);
+ if (&eq($f, $dfile)) {
+ $dfile =~ s/(.*)\.\d+$/$1/;
+ $dfile .= ".$index";
+ $index++;
+ redo UNIQ;
+ }
+ }
+ }
+ &tell("~!dcc~INBOUND DCC SEND who: $who$puh1 file: $dfile size: $dsize ip: $ip port: $dport");
+
+ $dgoffered{"$dhost $dport $dfile"}=$who;
+ &dohooks("dcc_request", "SEND", $dhost, $dport, $dfile, $dsize);
+ }
+ }
+ } else {
+ &tell("*** $who$puh1 did a CTCP ${what}$a to $to");
+ }
+ }
+}
+
+sub doset {
+ local($var, $val)=@_;
+ $var =~ tr/a-z/A-Z/;
+ $val="" unless defined($val);
+ if ($var eq 'PRINTUH') {
+ $set{$var}="all" if $val =~ /^(on|all)$/i;
+ $set{$var}="some" if $val =~ /^some$/i;
+ $set{$var}="none" if $val =~ /^(off|none)$/i;
+ } elsif ($var eq 'PRINTCHAN') {
+ $set{$var}="on", $printchan=1 if $val =~ /^on$/i;
+ $set{$var}="off", $printchan=0 if $val =~ /^off$/i;
+ } elsif ($var eq 'CTCP') {
+ $val =~ tr/A-Z/a-z/;
+ $set{$var}=$val if $val =~ /^(none|all)$/;
+ $set{$var}="noreply" if $val =~ /^(noreply|off)$/;
+ $set{$var}="noflood" if $val =~ /^(noflood|on)$/;
+ } elsif ($var eq 'SENDAHEAD') {
+ $set{$var}=$val if $val =~ /^\d+$/ && $val<=65536;
+ } elsif ($var eq 'USERINFO') {
+ $set{$var}=$val;
+ } elsif ($var eq 'FINGER') {
+ $set{$var}=$val;
+ } elsif ($var eq 'IRCNAME') {
+ $set{$var}=$val;
+ } elsif ($var eq 'EIGHT_BIT') {
+ $val =~ tr/A-Z/a-z/;
+ $set{$var}=$val if $val =~ /^(on|off)$/;
+ } elsif ($var eq 'LOCALHOST') {
+ &restrict || return;
+ # IPV6: DCC is always ipv4 :(
+ local($ad) = (&resolve($val, 0, &AF_INET))[3];
+ $set{$var}=$val, $bindaddr=$ad if $ad;
+ } elsif ($var eq 'LOADPATH') {
+ @loadpath=split(/:/, $val);
+ foreach (@loadpath) {
+ &tilde($_);
+ }
+ $set{$var}=join(":", @loadpath);
+ } elsif ($var eq 'CTRL_T') {
+ $set{$var}=$val;
+ print "`#ssfe#T$val\n" if $ssfe;
+ } elsif ($var eq 'LOGFILE') {
+ &restrict || return;
+ &tilde($val);
+ $logfile=$set{$var}=$val;
+ } elsif ($var eq 'LOG') {
+ &restrict || return;
+ if ($val =~ /^on$/i) {
+ $logging && close LOG;
+ if (open(LOG,
+ ($logfile =~ /\.gz$/ ? "| gzip >> $logfile" : ">> $logfile"))) {
+ $logging=1;
+ $set{$var}="on";
+ select(LOG); $|=1; select(STDOUT);
+ print LOG "*\cbL\cb* IRC log started on ".&date(time)."\n";
+ } else {
+ $logging='';
+ $set{$var}="off";
+ &tell("*\cbE\cb* Can't write to logfile $logfile");
+ }
+ } elsif ($val =~ /^off$/i) {
+ print LOG "*\cbL\cb* Log ended on ".&date(time)."\n", close LOG
+ if $logging;
+ $logging='';
+ $set{$var}="off";
+ }
+ } elsif (defined($sets{$var})) {
+ local($f)=$sets{$var};
+ eval { &$f($val); };
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in SET $var hook: $@") if $@ ne '';
+ }
+}
+
+sub ctcpreply {
+ local($ctcp, $rest)=split(/ +/, $_[1], 2);
+ $ctcp =~ tr/a-z/A-Z/;
+ &dohooks("ctcp_reply", $_[0], $ctcp, $rest);
+ $rest=(time-$rest)." seconds" if $ctcp eq 'PING';
+ if (&eq($_[0], $nick)) {
+ &tell("*** CTCP $ctcp reply from $who$puh1: $rest");
+ } else {
+ &tell("*** CTCP $ctcp reply to $_[0] from $who$puh2: $rest");
+ }
+}
+
+sub load {
+ local($f)=@_;
+ &tilde($f);
+ if ($f !~ /\//) {
+ foreach (@loadpath) {
+ $f="$_/$f", last if -f "$_/$f";
+ $f="$_/${f}.pl", last if $f !~ /\.pl$/ && -f "$_/${f}.pl";
+ }
+ } else {
+ $f.=".pl" if -f "${f}.pl" && !-f $f;
+ }
+ if ($f =~ /\// && -f $f) {
+ do $f;
+ $@ =~ s/\n$//, &tell("*\cbE\cb* Load error in $f: $@") if $@ ne '';
+ } else {
+ &tell("*\cbE\cb* $f: File not found");
+ }
+}
+
+sub restrict {
+ &tell("*\cbE\cb* Command not available"), return 0 if $restrict;
+ 1;
+}
+
+sub dosplat {
+ $args =~ s/^\s*\*($|\s)/${talkchannel}${1}/ if $talkchannel;
+}
+
+sub expand {
+ if ($_[0] eq '$') {
+ return '$';
+ } elsif ($_[0] =~ /^(\d+)$/) {
+ return (split(/ +/, $args))[$1];
+ } elsif ($_[0] =~ /^(\d+)-$/) {
+ return (split(/ +/, $args, 1+$1))[$1];
+ } else {
+ return eval "\$$_[0]";
+ }
+}
+
+$recdepth=0;
+$maxrecursion=20;
+
+sub docommand {
+ local($line)=@_;
+ local($recdepth)=$recdepth+1;
+ &print("*\cbE\cb* Max recursion exceeded!"), return
+ if $recdepth > $maxrecursion;
+ local($noalias)=($line =~ s/^\///);
+ local($silent)=1 if $line =~ s/^\^//;
+ local($cmd, $args)=split(/ +/, $line, 2);
+ $cmd =~ tr/a-z/A-Z/;
+ if (!$noalias && defined($aliases{$cmd})) {
+ $line=$aliases{$cmd};
+ $line.=($args ne '' ? " ".$args : "")
+ unless ($line =~ s/\$(\$|\d+-?|\w+)/&expand($1)/eg);
+ $line =~ s/^\///;
+ $noalias=1 if $line =~ s/^\///;
+ $silent=1 if $line =~ s/^\^//;
+ ($cmd, $args)=split(/ +/, $line, 2);
+ $cmd =~ tr/a-z/A-Z/;
+ }
+ if (!$noalias && defined($cmds{$cmd})) {
+ eval $cmds{$cmd};
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in command $cmd: $@") if $@ ne '';
+ } elsif ($cmd eq 'ALIAS') {
+ &getarg;
+ if ($newarg =~ /^-/) {
+ local($a)=$';
+ if ($a eq '') {
+ %aliases=();
+ &tell("*** All aliases removed");
+ } else {
+ $a =~ tr/a-z/A-Z/;
+ delete $aliases{$a};
+ &tell("*** Alias $a removed");
+ }
+ } elsif ($newarg ne '') {
+ $newarg =~ tr/a-z/A-Z/;
+ if ($args ne '') {
+ $aliases{$newarg}=$args;
+ &tell("*** $newarg aliased to $args");
+ } else {
+ if (defined($aliases{$newarg})) {
+ &tell("*** $newarg is aliased to: $aliases{$newarg}");
+ } else {
+ &tell("*** $newarg: no such alias");
+ }
+ }
+ } else {
+ foreach $a (sort(keys(%aliases))) {
+ &tell("*** $a is aliased to $aliases{$a}");
+ }
+ }
+ } elsif ($cmd eq 'SET') {
+ &getarg;
+ local($s)=$newarg;
+ $s =~ tr/a-z/A-Z/;
+ if ($s =~ s/^-//) {
+ &tell("*** No such variable $s"), return unless defined($set{$s});
+ &doset($s, "");
+ &tell("*** $s is ".($set{$s} ne '' ? "set to $set{$s}" : "unset"));
+ } elsif ($s ne '') {
+ &tell("*** No such variable $s"), return unless defined($set{$s});
+ &doset($s, $args) if $args ne '';
+ &tell("*** $s is ".($set{$s} ne '' ? "set to $set{$s}" : "unset"));
+ } else {
+ foreach $s (sort(keys (%set))) {
+ &tell("*** $s is ".($set{$s} ne '' ? "set to $set{$s}" : "unset"));
+ }
+ }
+ } elsif ($cmd eq 'NOTIFY' || $cmd eq 'N') {
+ if ($args eq '-') {
+ &tell("*** Notify list cleared");
+ my($value);
+ while(($_, $value) = each %notify){ # Remove all nicks
+ &tell("*\cb(\cb* Signoff by $_ detected!"); # KSIRC MOD
+ }
+ %notify=();
+ } elsif ($args eq '') {
+ local($l)='';
+ foreach (grep($notify{$_}, keys %notify)) {
+ &tell("*** Currently present: $l"), $l='' if length($l)>450;
+ &tell("*\cb)\cb* Signon by $_ detected!"); # KSIRC MOD
+ $l.=$_." ";
+ }
+ $l && &tell("*** Currently present: $l");
+ $l='';
+ foreach (grep(!$notify{$_}, keys %notify)) {
+ &tell("*** Currently absent: $l"), $l='' if length($l)>450;
+ &tell("*\cb(\cb* Signoff by $_ detected!"); # KSIRC MOD
+ $l.=$_." ";
+ }
+ $l && &tell("*** Currently absent: $l");
+ } else {
+ local($w, $n);
+ foreach $w (split(/ +/, $args)) {
+ if ($w =~ s/^-//) {
+ ($n)=(grep(&eq($_, $w), keys(%notify)), '');
+ $n ne '' && delete $notify{$n};
+ &tell("*** $w removed from notify list");
+ &tell("*\cb(\cb* Signoff by $w detected!"); # KSIRC MOD
+ } else {
+ $notify{$w}='0';
+ &tell("*** $w added to notify list");
+ $newisons=1;
+ }
+ }
+ }
+ } elsif ($cmd eq 'IGNORE' || $cmd eq 'IG') {
+ &getarg;
+ if ($newarg eq '-') {
+ @ignore=();
+ &tell("*** Ignore list cleared");
+ } elsif ($newarg eq '') {
+ local($p);
+ &tell("*** You're ignoring:");
+ foreach (@ignore) {
+ $p=$_;
+ $p =~ s/\\//g;
+ $p =~ s/\.\*/*/g;
+ &tell("*** $p");
+ }
+ } else {
+ local($d, $p)=('');
+ $d=1 if $newarg =~ s/^-//;
+ if ($newarg =~ /\!.*\@/) {
+ } elsif ($newarg !~ /[\@\!]/) {
+ $newarg.="!*";
+ } elsif ($newarg =~ /\@/) {
+ $newarg="*!".$newarg;
+ } else {
+ $newarg.="\@*";
+ }
+ $p=$newarg;
+ $newarg =~ s/([^\\])\./$1\\./g;
+ $newarg =~ s/\*/\.\*/g;
+ $newarg =~ s/([^\.\*\\\w])/\\$1/g;
+ if ($d) {
+ &tell("*** Removing $p from the ignore list");
+ @ignore=grep(!&eq($_, $newarg), @ignore);
+ } else {
+ &tell("*** Ignoring $p ... what a relief!");
+ push(@ignore, $newarg);
+ }
+ }
+ } elsif ($cmd eq 'ECHO') {
+ &print($args);
+ } elsif ($cmd eq 'CLEAR' || $cmd eq 'CL') {
+ print $cls if $ansi;
+ print "`#ssfe#l\n" if $ssfe;
+ } elsif ($cmd eq 'EVAL') {
+ &restrict || return;
+ eval ($args);
+ $@ =~ s/\n$//, &tell("*\cbE\cb* eval error: $@") if $@ ne '';
+ } elsif ($cmd eq 'HELP') {
+ &tell("*\cbH\cb* Help not available"), return unless @help;
+ $args='main' if $args =~ /^\s*$/;
+ $args =~ s/ *$//;
+ local($found)='';
+ foreach (@help) {
+ if (/^\@/) {
+ last if $found;
+ if (&eq($_, "\@$args")) {
+ $found=1;
+ &tell("*\cbH\cb* Help on $args") if $args ne 'main';
+ }
+ } else {
+ &tell("*\cbH\cb* $_") if $found;
+ }
+ }
+ &tell("*\cbH\cb* Unknown help topic; try /help") unless $found;
+ } elsif ($cmd eq 'LOAD') {
+ &restrict || return;
+ &getarg;
+ &tell("*\cbE\cb* Yeah, but what?"), return if $newarg eq '';
+ &load($newarg);
+ } elsif ($cmd eq 'VERSION') {
+ &tell("*** \cbsirc\cb version $version, written in \cbperl\cb by \cborabidoo\cb");
+ $_=$add_ons;
+ s/^\+//;
+ s/\+/, /g;
+ &tell("*** add-ons: $_") if $_;
+ $connected==2 && &sl("VERSION $args");
+ } elsif ($cmd eq 'CD') {
+ &restrict || return;
+ &getarg;
+ if ($newarg ne '') {
+ &tilde($newarg);
+ chdir($newarg) || &tell("*\cbE\cb* Can't chdir to $newarg");
+ }
+ local($cwd); chop($cwd=`pwd`);
+ &tell("*** Current directory is $cwd");
+ } elsif ($cmd eq 'SYSTEM') {
+ &restrict || return;
+ system($args);
+ } elsif ($cmd eq 'BYE' || $cmd eq 'QUIT' || $cmd eq 'EXIT' ||
+ $cmd eq 'SIGNOFF') {
+ $args || ($args="using sirc version $version$add_ons");
+ &dohooks("quit");
+ &sl("QUIT :$args") if $connected;
+ &exit;
+ } elsif ($cmd eq 'SERVER') {
+ $args=$1 if $args =~ /^\s*(.*)\s*$/;
+ $args="$server0:$port0:$pass0" if $args eq '0';
+ $args="$server1:$port1:$pass1" if $args eq '1';
+ if ($args eq '') {
+ &tell($connected ? "*** Your current server is $server" :
+ "*** You're not connected to a server");
+ } else {
+ ($server, $port, $pass)=split(/[\s:]+/, $args);
+ $server=$', $nick=$1 if $server =~ /^([^\@]+)\@/;
+ $port || ($port=$port0);
+ &sl("QUIT :changing servers"), close $S, delete $buffer{$S} if $connected;
+ $connected=0;
+ }
+ } elsif ($cmd eq 'MSG' || $cmd eq 'M') {
+ &dosplat;
+ if ($args) {
+ ($newarg, $args)=split(/ /, $args, 2);
+ &msg($newarg, $args);
+ } else {
+ &tell("*\cbE\cb* You must specify a nick or channel!");
+ }
+ } elsif ($cmd eq 'QUERY' || $cmd eq 'Q') {
+ if ($args) {
+ $args =~ s/\s+$//;
+ $query=$args;
+ &tell("*** Starting conversation with $query");
+ &dostatus;
+ } elsif ($query) {
+ &tell("*** Ending conversation with $query");
+ $query='';
+ &dostatus;
+ } else {
+ &tell("*** You aren't querying anyone :p");
+ }
+ } elsif ($cmd eq 'DCC') {
+ &getarg;
+ if ($newarg =~ /^chat$/i) {
+ &getarg;
+ local($n)=grep(&eq($newarg, $_), keys(%dcoffered));
+ if ($n) {
+ local($dcadr, $dcport)=split(/ +/, $dcoffered{$n});
+ local($fh);
+ delete $dcoffered{$n};
+ my $w = $n;
+ my $cb = sub {
+ my ($lfh, $lres) = @_;
+ if($lres != 0){
+ &tell("*\cbD\cb* DCC CHAT with $w failed: " . strerror($lres));
+ &tell("~!dcc~DCC CHAT failed who: $w reason: " . strerror($lres));
+ close($lfh);
+ return;
+ }
+ $dcnick{$lfh}=$w;
+ &tell("*\cbD\cb* DCC CHAT with $w established");
+ &tell("~!dcc~DCC CHAT established who: $w");
+ print "`#ssfe#t/m =$w \n" if $ssfe;
+ my $n = $w;
+ $n =~ tr/A-Z/a-z/;
+ $dcvol{$n}=0;
+ $dcfh{$n}=$fh;
+ };
+ if(&connectnb($fh, $dcadr, $dcport, $cb) < 1){
+ return;
+ }
+ } elsif (grep (&eq($newarg, $dcwait{$_}), keys(%dcwait))) {
+ &tell("*\cbE\cb* DCC CHAT request to $newarg already sent");
+ } elsif (grep(&eq($newarg, $dcnick{$_}), keys(%dcnick))) {
+ &tell("*\cbE\cb* DCC CHAT with $newarg already established");
+ } elsif ($newarg) {
+ &tell("*** You're not connected to a server"), return if $connected<2;
+ &tell("*** Don't be antisocial!"), return if &eq($newarg, $nick);
+ local($mynumber, $myport, $fh);
+ my $sockaddr = &listen($fh) or return;
+ if ($ipv6) {
+ # XXX: substr is used in order to avoid dying on Linux with older
+ # glibc that lacks the scope field from sockaddr_in6 but the kernel
+ # has it and returns it from getsockname()
+ ($myport, undef) = unpack_sockaddr_in6(substr($sockaddr, 0, 24));
+ $mynumber = '0';
+ } else {
+ ($myport, $mynumber) = unpack_sockaddr_in(&listen($fh)) or return;
+ $mynumber = unpack("N", $mynumber);
+ }
+ $dcwait{$fh}=$newarg;
+ &sl("PRIVMSG $newarg :\caDCC CHAT chat $mynumber $myport\ca");
+ &dohooks("send_ctcp", $newarg, "DCC CHAT chat $mynumber $myport");
+ &tell("*\cbD\cb* Sent DCC CHAT request to $newarg");
+ &tell("~!dcc~DCC CHAT SEND who: $newarg");
+ } else {
+ &tell("*** I need a nick");
+ }
+ } elsif ($newarg =~ /^rchat$/i) {
+ &getarg;
+ local($n)=$newarg;
+ &getarg;
+ if ($newarg) {
+ local($fh)=grep(&eq($dcnick{$_}, $n), keys(%dcnick));
+ if( ! $fh){
+ &tell("*\cbE\cb* No DCC CHAT established with $n");
+ &tell("~!dcc~No DCC CHAT established who: $n");
+ return;
+ }
+ &tell("*\cbE\cb* DCC CHAT already established with $newarg"), return
+ if grep(&eq($dcnick{$_}, $newarg), keys(%dcnick));
+ &tell("*\cbD\cb* DCC CHAT with $n renamed to $newarg");
+ &tell("~!dcc~DCC CHAT renamed who: $n to: $newarg");
+ $dcnick{$fh}=$newarg;
+ $n =~ tr/A-Z/a-z/;
+ $newarg =~ tr/A-Z/a-z/;
+ $dcfh{$newarg}=$dcfh{$n};
+ $dcvol{$newarg}=$dcvol{$n};
+ delete $dcfh{$n};
+ delete $dcvol{$n};
+ } else {
+ &tell("*** I need *two* nicks");
+ }
+ } elsif ($newarg =~ /^close$/i) {
+ &getarg;
+ if ($newarg =~ /^chat$/i) {
+ &getarg;
+ local($n)=$newarg;
+ $newarg =~ tr/A-Z/a-z/;
+ local($fh)=$dcfh{$newarg};
+ local($nn)=(grep(&eq($_, $newarg), keys(%dcoffered)));
+ if ($nn) {
+ &tell("*\cbD\cb* Forgetting offered DCC CHAT from $nn");
+ &tell("~!dcc~Closing DCC CHAT who: $nn");
+ delete $dcoffered{$nn};
+ if($no_reject == 0){
+ $who = $nn;
+ &reply("DCC REJECT CHAT chat");
+ }
+ $no_reject = 0;
+ } elsif ($fh) {
+ &dohooks("chat_disconnect", $n);
+ &tell("*\cbD\cb* Closing DCC CHAT connection with $n");
+ &tell("~!dcc~Closing DCC CHAT who: $n");
+ close($fh);
+ delete $dcnick{$fh};
+ delete $dcvol{$newarg};
+ delete $dcfh{$newarg};
+ delete $buffer{$fh};
+ if($no_reject == 0){
+ $who = $n;
+ &reply("DCC REJECT CHAT chat");
+ }
+ $no_reject = 0;
+
+ } elsif (($fh)=grep(&eq($dcwait{$_}, $n), keys (%dcwait)), $fh) {
+ close($fh);
+ delete $dcwait{$fh};
+ &tell("*\cbD\cb* Closing listening DCC CHAT with $n");
+ &tell("~!dcc~Closing DCC CHAT who: $n");
+ if($no_reject == 0){
+ $who = $n;
+ &reply("DCC REJECT CHAT chat");
+ }
+ $no_reject = 0;
+ } else {
+ if($n){
+ &tell("*\cbE\cb* No DCC CHAT connection with $n");
+ &tell("~!dcc~No DCC CHAT connection who: $n");
+ }
+ }
+ } elsif ($newarg =~ /^get$/i) {
+ &getarg;
+ my $arg = $newarg;
+ local($found)='';
+ foreach $i (keys(%dgoffered)) {
+ if (&eq($dgoffered{$i}, $newarg) && (!$args ||
+ &eq($args, (split(/ +/, $i))[2]))) {
+ &tell("*\cbE\cb* Forgetting pending DCC GET from $newarg");
+ my($host, $port, $file) = split(/ /, $i);
+ &tell("~!dcc~Closing DCC GET connection with who: $newarg file: $file"); # KSIRC MOD
+ delete $dgoffered{$i};
+ $found=1;
+ if($no_reject == 0){
+ $who = $newarg;
+ &reply("DCC REJECT GET $file");
+ }
+ $no_reject = 0;
+ }
+ }
+ foreach $sfh (grep(&eq($newarg, $dnick{$_}), keys(%dnick))) {
+ if (!$found && $dgrfh{$sfh}) {
+ local($fh)=$dgrfh{$sfh};
+ my($file)=$dfile{$fh};
+ next if $args && ($args ne $dfile{$fh});
+ &dohooks("dcc_disconnect", $dnick{$sfh}, $dfile{$fh},
+ $dtransferred{$sfh}, time-$dstarttime{$fh}, $fh);
+
+ &tell("*\cbE\cb* Closing DCC GET connection with: $newarg ($file)"); # KSIRC MOD
+ &tell("~!dcc~Closing DCC GET connection with who: $newarg file: $file"); # KSIRC MOD
+ $found=1;
+ close $sfh;
+ close $fh;
+ delete $dgrfh{$sfh};
+ delete $dfile{$fh};
+ delete $dstarttime{$fh};
+ delete $dtransferred{$sfh};
+ delete $dgxferadd{$sfh};
+ delete $dnick{$sfh};
+ if($no_reject == 0){
+ $who = $newarg;
+ &reply("DCC REJECT GET $file");
+ }
+ $no_reject = 0;
+ }
+ }
+ if( ! $found){
+ &tell("*\cbE\cb* No DCC GET connection with $newarg for $arg");
+ &tell("~!dcc~No DCC GET connection who: $newarg file: $arg");
+ }
+ } elsif ($newarg =~ /^send$/i) {
+ &getarg;
+ local($n, $found, $fh)=($newarg, '');
+ &getarg;
+ my $arg = $newarg;
+ $newarg =~ s/(\W)/\\$1/g;
+ foreach $sfh (keys(%dswait), keys(%dsrfh)) {
+ next unless &eq($dnick{$sfh}, $n);
+ $fh=$dswait{$sfh} || $dsrfh{$sfh} || next;
+ if ($newarg eq '' || $dfile{$fh} =~ /^${newarg}$/ ||
+ $dfile{$fh} =~ /\/${newarg}$/) {
+ #&tell("*\cbD\cb* DCC SEND connection with $n closed");
+ #my($file)=$dfile{$fh};
+ #&tell("~!dcc~Closing DCC SEND connection with who: $n file: $file"); # KSIRC MOD
+ #&dohooks("dcc_disconnect", $dnick{$sfh}, $dfile{$fh},
+ # $dtransferred{$sfh}, time-$dstarttime{$fh}, $fh);
+ #close($sfh);
+ #close($fh);
+ #delete $dswait{$sfh};
+ #delete $dsrfh{$sfh};
+ #delete $dfile{$fh};
+ #delete $dstarttime{$fh};
+ #delete $dtransferred{$sfh};
+ #delete $dsoffset{$sfh};
+ #delete $dsport{$sfh};
+ #delete $dsresumedb{$sfh};
+ #delete $dgxferadd{$sfh};
+ #delete $dnick{$sfh};
+ if($no_reject == 0){
+ $who = $n;
+ &reply("DCC REJECT SEND $dfile{$fh}");
+ }
+ $no_reject = 0;
+
+ if($dstarttime{$fh} == undef) {
+ $dstarttime{$fh} = time;
+ }
+ &dgsclose($sfh, $fh, "SEND", "CLOSE");
+
+ $found=1;
+ }
+ }
+ if(!$found){
+ &tell("*\cbE\cb* No DCC SEND connection with $n for $arg");
+ &tell("~!dcc~No DCC SEND connection with who: $n file: $arg");
+ }
+ } else {
+ &tell("*\cbE\cb* Unknown DCC type");
+ }
+ } elsif ($newarg =~ /^rename$/i) {
+ local($found, $n);
+ &getarg;
+ $n=$newarg;
+ &getarg;
+ $args=$newarg, $newarg='' if $args eq '';
+ &tell("*\cbE\cb* I need a filename :p"), return if $args eq '';
+ &tilde($args);
+ foreach $i (keys(%dgoffered)) {
+ if (&eq($dgoffered{$i}, $n) && (!$newarg ||
+ &eq($newarg, (split(/ +/, $i))[2]))) {
+ local($m, $p, $f)=split(/ +/, $i);
+ delete $dgoffered{$i};
+ $dgoffered{"$m $p $args"}=$n;
+ &tell("*\cbD\cb* Renaming \"$f\" (offered by $n) to \"$args\"");
+ $found=1;
+ last;
+ }
+ }
+ &tell("*\cbE\cb* No such file offered by $n") unless $found;
+ } elsif ($newarg =~ /^get$/i) {
+ &getarg;
+ local($n)=grep((&eq($newarg, $dgoffered{$_}) && (!$args ||
+ &eq($args, (split(/ +/, $_))[2]))),
+ keys(%dgoffered));
+ if ($n) {
+ my($dgadr, $dgport, $file)=split(/ +/, $n);
+ my($fh, $sfh);
+ my $offset = 0;
+ $n=(delete $dgoffered{$n});
+ $fh=&newfh;
+ if($dgresume{$dgport} && $dgresume{$dgport}{"GotReply"}){
+ &print("*\cbE\cb* Can't write to file $file"), return unless open($fh, ">> $file");
+ seek($fh, $dgresume{$dgport}{"pos"}, SEEK_SET);
+ $offset = $dgresume{$dgport}{"pos"};
+ delete $dgresume{$dgport};
+ }
+ else {
+ &print("*\cbE\cb* Can't write to file $file"), return unless open($fh, "> $file");
+ }
+ my $who = $n;
+ my $cb = sub {
+ my ($lfh, $lres) = @_;
+ if($lres != 0){
+ &tell("*\cbD\cb* DCC GET connection with $who ($file) failed: " . strerror($lres));
+ &tell("~!dcc~DCC GET failed who: $who file: $file reason: " . strerror($lres));
+ close($lfh);
+ return;
+ }
+ $dgrfh{$lfh}=$fh;
+ $dnick{$lfh}=$who;
+ $dfile{$fh}=$file;
+ $dstarttime{$fh}=time;
+ $dtransferred{$lfh}=0;
+ $dgxferadd{$lfh}=$offset;
+ &tell("*\cbD\cb* DCC GET connection with $who established");
+ &tell("~!dcc~DCC GET established who: $who file: $file");
+ &dohooks("dcc_get", $who, $file, $fh);
+ };
+ if(&connectnb($sfh, $dgadr, $dgport, $cb) < 1){
+ return;
+ }
+ } else {
+ if ($newarg) {
+ &tell("*\cbE\cb* No pending DCC GET from $newarg");
+ } else {
+ &tell("*\cbE\cb* Uhm, who from?");
+ }
+ }
+ } elsif ($newarg =~ /^list$/i || $newarg eq '') {
+ &tell("*\cbD\cb* List of DCC connections:");
+ foreach $n (keys(%dcfh)) {
+ &tell("*\cbD\cb* Established DCC CHAT with $n ($dcvol{$n} bytes)");
+ }
+ foreach $n (keys(%dcoffered)) {
+ my ($pip, $port) = split(/ /, $dcoffered{$n});
+ my $ip = inet_ntoa(pack("N", $pip));
+ &tell("*\cbD\cb* DCC CHAT offered by $n ($ip:$port)");
+ }
+ foreach $f (keys(%dcwait)) {
+ &tell("*\cbD\cb* DCC CHAT offered to $dcwait{$f}");
+ }
+ foreach $i (keys(%dgoffered)) {
+ my ($pip, $port, $file) = split(/ /, $i);
+ my $ip = inet_ntoa(pack("N", $pip));
+ &tell("*\cbD\cb* DCC GET \"$file\" ($ip:$port) offered by $dgoffered{$i}");
+ }
+ foreach $s (keys(%dgrfh)) {
+ local($f)=$dgrfh{$s};
+ &tell("*\cbD\cb* DCC GET \"$dfile{$f}\" established with $dnick{$s}, $dtransferred{$s} bytes read in ".(time-$dstarttime{$f})." seconds.");
+ }
+ foreach $s (keys(%dswait)) {
+ local($f)=$dswait{$s};
+ &tell("*\cbD\cb* DCC SEND \"$dfile{$f}\" offered to $dnick{$s}");
+ }
+ foreach $s (keys(%dsrfh)) {
+ local($f)=$dsrfh{$s};
+ &tell("*\cbD\cb* DCC SEND \"$dfile{$f}\" established with $dnick{$s}, $dtransferred{$s} bytes sent in ".(time-$dstarttime{$f})." seconds.");
+ }
+ } elsif ($newarg =~ /^send$/i) {
+ &tell("*** You're not connected to a server"), return if $connected<2;
+ &restrict || return;
+ local(($n),($f)) = $args =~ /^(.+?) (.+)/;
+ local($tf, $mynumber, $sz, $fh, $myport, $lfh)=($f);
+ &tilde($f);
+ while (my($fh, $ni) = each %dnick ) {
+ if(&eq($n, $ni)){
+ my $lfh = $dswait{$fh};
+ if(&eq($dfile{$lfh}, $f)){
+ &tell("*\cbE\cb* DCC Send already pending of $f to $n");
+ return;
+ }
+ if($dsrfh{$fh}){
+ &tell("*\cbE\cb* DCC Send already in progress $f to $n");
+ return;
+
+ }
+ }
+ }
+ $fh=&newfh;
+ &tell("*\cbE\cb* Can't open file $f"), return unless open($fh, "<$f");
+ my $sockaddr = &listen($lfh) or (close $fh, return);
+ if ($ipv6) {
+ # XXX: substr is used in order to avoid dying on Linux with older
+ # glibc that lacks the scope field from sockaddr_in6 but the kernel
+ # has it and returns it from getsockname()
+ ($myport, undef) = unpack_sockaddr_in6(substr($sockaddr, 0, 24));
+ $mynumber = 0;
+ } else {
+ ($myport, $mynumber) = unpack_sockaddr_in($sockaddr);
+ $mynumber = unpack("N", $mynumber);
+ }
+ $dswait{$lfh}=$fh;
+ $tf=$1 if $f =~ m|/([^/]*)$|;
+ $sz=(-s $f);
+ $tf =~ s/ /_/g; # we have to convert spaces in the filename to underscores
+ &sl("PRIVMSG $n :\caDCC SEND $tf $mynumber $myport $sz\ca");
+ &dohooks("send_ctcp", $n, "DCC SEND $tf $mynumber $myport $sz");
+ &dohooks("dcc_send", $n, $f, $sz, $fh);
+ #&tell("*\cbD\cb* Sent DCC SEND request to $n ($f,$sz)");
+ &tell("~!dcc~Sent DCC SEND request to who: $n file: $f size: $sz");
+ $dfile{$fh}=$f;
+ $dswait{$lfh}=$fh;
+ $dnick{$lfh}=$n;
+ $dsport{$lfh}=$myport;
+ $dsoffset{$lfh}=0;
+ } else {
+ &tell("*** I can \"only\" do DCC CHAT, RCHAT, GET, SEND, CLOSE, RENAME and LIST, *sheesh*");
+ }
+ } elsif ($cmd eq 'QUOTE') { #KSIRC MOD
+ $args ne '' && &sl($args); #Allow this even if not connected to talk to proxies
+ } elsif ($connected<2) {
+ &tell("*** You're not connected to a server");
+ } elsif ($cmd eq 'AWAY') {
+ &sl($args ? "AWAY :$args" : "AWAY");
+ my $oldchannel = $talkchannel;
+ if ( $publicAway == 1 ) {
+ foreach $talkchannel (@channels) {
+ &me($args ? "is away: $args" : "is back");
+ }
+ }
+ $talkchannel = $oldchannel;
+ } elsif ($cmd eq 'NEXT') {
+ if ($#channels>0) {
+ $talkchannel=shift(@channels);
+ push(@channels, $talkchannel);
+ !$ssfe && &tell("*** Talking to $talkchannel now");
+ &dostatus;
+ }
+ } elsif ($cmd eq 'SAY' || $cmd eq '') {
+ &say($args);
+ } elsif ($cmd eq 'NOTICE' || $cmd eq 'NO') {
+ &dosplat;
+ if ($args) {
+ ($newarg, $args)=split(/ /, $args, 2);
+ &notice($newarg, $args);
+ } else {
+ &tell("*\cbE\cb* You must specify a nick or channel!");
+ }
+ } elsif ($cmd eq 'DESCRIBE' || $cmd eq 'DE') {
+ &dosplat;
+ if ($args) {
+ ($newarg, $args)=split(/ /, $args, 2);
+ &describe($newarg, $args);
+ } else {
+ &tell("*\cbE\cb* You must specify a nick or channel!");
+ }
+ } elsif ($cmd eq 'KICK' || $cmd eq 'K') {
+ &dosplat;
+ &getarg;
+ local($c)=$talkchannel;
+ if ($newarg =~ /^[\#\&\+]/) {
+ $c=$newarg;
+ &getarg;
+ }
+ if ($newarg) {
+ $args || ($args=$nick);
+ &sl("KICK $c $newarg :$args");
+ } else {
+ &tell("*\cbE\cb* You must specify a nick!");
+ }
+ } elsif ($cmd eq 'DISCONNECT' || $cmd eq 'DIS') {
+ &tell("*** Disconnecting from $server");
+ close($S);
+ delete $buffer{$S};
+ $connected=0;
+ &dohooks("disconnect");
+ &bindtoserver;
+
+ } elsif ($cmd eq 'INVITE' || $cmd eq 'INV' || $cmd eq 'I') {
+ local(@ns)=split(/ +/, $args);
+ local($l, $c)=(pop(@ns), $talkchannel);
+ if ($l =~ /^[\#\&\+]/) {
+ $c=$l;
+ } else {
+ $l && push(@ns, $l);
+ }
+ foreach (@ns) {
+ &sl("INVITE $_ $c");
+ }
+ } elsif ($cmd eq 'CTCP') {
+ &dosplat;
+ if ($args) {
+ &getarg;
+ local($towho)=$newarg;
+ &getarg;
+ $newarg =~ tr/a-z/A-Z/;
+ $args=" ".$args if $args ne '';
+ &sl("PRIVMSG $towho :\ca$newarg$args\ca");
+ &dohooks("send_ctcp", $towho, $newarg.$args);
+ &tell("*** Sending a CTCP $newarg$args to $towho");
+ } else {
+ &tell("*\cbE\cb* You must specify a nick or channel!");
+ }
+ } elsif ($cmd eq 'PING' || $cmd eq 'P') {
+ &dosplat;
+ if ($args) {
+ &getarg;
+ local($t)=time;
+ &sl("PRIVMSG $newarg :\caPING $t\ca");
+ &dohooks("send_ctcp", $newarg, "PING $t");
+ &tell("*** Sending a CTCP PING to $newarg");
+ } else {
+ &tell("*\cbE\cb* You must specify a nick or channel!");
+ }
+ } elsif ($cmd eq 'ME') {
+ if ($talkchannel) {
+ &describe($talkchannel, $args);
+ } else {
+ &tell("*\cbE\cb* Not on a channel");
+ }
+ } elsif ($cmd eq 'TOPIC' || $cmd eq 'T') {
+ &dosplat;
+ local($c)=$talkchannel;
+ if ($args =~ /^[\#\&\+]/) {
+ &getarg;
+ $c=$newarg;
+ }
+ if ($args) {
+ &sl("TOPIC $c :$args");
+ } else {
+ &sl("TOPIC $c");
+ }
+ } elsif ($cmd eq 'LEAVE' || $cmd eq 'PART' || $cmd eq 'HOP') {
+ &dosplat;
+ $args=$talkchannel if $args eq '';
+ &sl("PART $args");
+ } elsif ($cmd eq 'LL') {
+ if ($talkchannel) {
+ &sl("WHO $talkchannel");
+ } else {
+ &tell("*\cbE\cb* Not on a channel");
+ }
+ } elsif ($cmd eq 'O' || $cmd eq 'OP') {
+ local($c, $n, $l)=($talkchannel, 0, '');
+ &getarg, $c=$newarg if ($args =~ /^[\#\&\+]/);
+ local(@ppl)=split(/ +/, $args);
+ foreach (@ppl) {
+ if ($n<4) {
+ $l .= " ".$_;
+ $n++;
+ } else {
+ &sl("MODE $c +oooo $l");
+ $l=$_;
+ $n=1;
+ }
+ }
+ $l && &sl("MODE $c +oooo $l");
+ } elsif ($cmd eq 'D' || $cmd eq 'DEOP') {
+ local($c, $n, $l)=($talkchannel, 0, '');
+ &getarg, $c=$newarg if ($args =~ /^[\#\&\+]/);
+ local(@ppl)=split(/ +/, $args);
+ foreach (@ppl) {
+ if ($n<4) {
+ $l .= " ".$_;
+ $n++;
+ } else {
+ &sl("MODE $c -oooo $l");
+ $l=$_;
+ $n=1;
+ }
+ }
+ $l && &sl("MODE $c -oooo $l");
+ } elsif ($cmd eq 'W' || $cmd eq 'WHOIS') {
+ &sl($args eq '' ? "WHOIS $nick" : "WHOIS $args");
+ } elsif ($cmd eq 'WI') {
+ &getarg;
+ $newarg=$nick if $newarg eq '';
+ &sl("WHOIS $newarg $newarg");
+ } elsif ($cmd eq 'WHO') {
+ &dosplat;
+ if ($args =~ /^[\s\*]*$/) {
+ &tell("*** Uhm, better not");
+ } else {
+ &sl("WHO $args");
+ }
+ } elsif ($cmd eq 'JOIN' || $cmd eq 'J') {
+ $args=$invited if $args eq '';
+ if ($args !~ /^[\#\&\+]/) {
+ $query = $args;
+ }
+ elsif (grep(&eq($_, $args), @channels)) {
+# &tell("*** Talking to $args now"); # KSIRC MOD
+ $talkchannel=$args;
+ $query = "";
+ &dostatus;
+ } else {
+ &sl("JOIN $args");
+ }
+ } elsif ($cmd eq 'UMODE') {
+ &sl("MODE $nick $args");
+ } elsif ($cmd eq 'MO') {
+ if ($talkchannel) {
+ &sl("MODE $talkchannel $args");
+ } else {
+ &tell("*\cbE\cb* You're not on any channel anyway");
+ }
+ } elsif ($cmd eq 'LIST') {
+ &dosplat;
+ $listmin=0;
+ $listmax=100000;
+ $listpat='';
+ if ($args =~ /\*/ || $args =~ /-m[ia][nx]\s/i) {
+ while (&getarg, $newarg ne '') {
+ if ($newarg =~ /^-min$/i) {
+ &getarg;
+ $listmin=$newarg if $newarg>0;
+ } elsif ($newarg =~ /^-max$/i) {
+ &getarg;
+ $listmax=$newarg if $newarg>0;
+ } else {
+ $newarg =~ s/([^\\])\./$1\\./g;
+ $newarg =~ s/\*/\.\*/g;
+ $newarg =~ s/([^\.\*\\\w])/\\$1/g;
+ $listpat=$newarg;
+ }
+ }
+ &sl("LIST");
+ } else {
+ &sl($line);
+ }
+ } elsif ($cmd eq 'RPING') {
+ &getarg;
+ &sl("RPING $newarg ".time);
+ } elsif ($cmd eq 'KILL') {
+ &getarg;
+ if ($newarg) {
+ $args || ($args=$nick);
+ &sl("KILL $newarg :$args");
+ } else {
+ &tell("*\cbE\cb* You must specify a nick!");
+ }
+ } elsif ($cmd eq 'MODE' || $cmd eq 'NAMES') {
+ &dosplat;
+ &sl("$cmd $args");
+ } elsif ($cmd eq 'OPER') {
+ &getarg;
+ $newarg=$nick unless $newarg;
+ &getuserpass("Oper password? ", "Passwd: "), $args=$_ unless $args;
+ &sl("OPER $newarg $args");
+ } elsif ($cmd eq 'CONNECT') {
+ &getarg;
+ local($srv)=$newarg;
+ &getarg;
+ if ($args) {
+ &sl("CONNECT $srv $newarg $args");
+ } else {
+ &sl("CONNECT $srv 6667 $newarg");
+ }
+ } elsif ($cmd eq 'SQUIT') {
+ &getarg;
+ &sl("SQUIT $newarg :$args");
+ } elsif ($cmd eq 'WHOWAS' || $cmd eq 'ADMIN' || $cmd eq 'STATS' ||
+ $cmd eq 'INFO' || $cmd eq 'LUSERS' || $cmd eq 'SQUIT' ||
+ $cmd eq 'REHASH' || $cmd eq 'DIE' || $cmd eq 'LINKS' ||
+ $cmd eq 'NOTE' || $cmd eq 'WALLOPS' || $cmd eq 'NICK' ||
+ $cmd eq 'MOTD' || $cmd eq 'TIME' || $cmd eq 'TRACE' ||
+ $cmd eq 'USERS' || $cmd eq 'SILENCE' || $cmd eq 'MAP' ||
+ $cmd eq 'UPING') {
+ &sl($line);
+ } else {
+ # Unknown command sucks. People want to use extensions like /nickserv, which works
+ # on some servers (Simon)
+ &sl($line);
+# &tell("*\cbE\cb* Unknown command: $cmd");
+ }
+}
+
+sub douserline {
+ local($skip, $line)=(0, @_);
+ if ($line =~ /^\@ssfe\@/) {
+ $ssfe=$raw_mode=1;
+ $add_ons.="+ssfe";
+ &dostatus;
+ } else {
+ &dohooks("command", $line);
+ return if $skip;
+ if ($line =~ s/^\///) {
+ &docommand($line);
+ } elsif ($query ne '') {
+ &msg($query, $line);
+ } else {
+ &say($line);
+ }
+ }
+}
+
+$ssfe_getline="`#ssfe#p";
+sub getuserline {
+ local($skip)='';
+ &dohooks("input", $_[0], $_[1]);
+ return if $skip;
+ print $_[0];
+ print "\n" if $raw_mode;
+ print $ssfe_getline.$_[1]."\n" if $ssfe;
+ while (($_=<STDIN>) ne '') {
+ if (/^\@ssfe\@/) {
+ $ssfe || ($add_ons.="+ssfe");
+ $ssfe=$raw_mode=1;
+ &dostatus;
+ } else {
+ &exit if $_ eq '';
+ chop;
+ return;
+ }
+ }
+ &exit;
+}
+
+sub getuserpass {
+ local($ssfe_getline)="`#ssfe#P";
+ &getuserline;
+}
+
+%cmds=();
+sub addcmd {
+ local($cmd)=$_[0];
+ $cmd =~ tr/a-z/A-Z/;
+ $cmds{$cmd}="&cmd_".$_[0].";";
+}
+
+sub addhelp {
+ local($cmd, $txt)=@_;
+ $cmd =~ tr/A-Z/a-z/;
+ foreach (reverse(split(/\n/, $txt))) {
+ s/\$v/$version/g;
+ s/\$d/$date/g;
+ unshift (@help, $_);
+ }
+ unshift(@help, "\@".$cmd);
+}
+
+sub addset {
+ local($var)=$_[0];
+ $var =~ tr/a-z/A-Z/;
+ $sets{$var}="set_".$_[0];
+}
+
+sub addsel {
+ $buf_fds{$_[0]}="sel_".$_[1] if $_[2];
+ $sel_fds{$_[0]}="sel_".$_[1] unless $_[2];
+}
+
+sub remsel {
+ delete $buf_fds{$_[0]};
+ delete $sel_fds{$_[0]};
+}
+
+sub addwsel {
+ $sel_w_fds{$_[0]}="sel_".$_[1];
+}
+
+sub remwsel {
+ delete $sel_w_fds{$_[0]};
+}
+
+@hooks=("action", "ctcp", "ctcp_reply", "dcc_chat", "dcc_request", "input",
+ "invite", "join", "kick", "leave", "mode", "msg", "nick", "notice",
+ "server_notice", "notify_signoff", "notify_signon", "public",
+ "raw_irc", "send_action", "send_dcc_chat", "send_text", "send_notice",
+ "signoff", "topic", "disconnect", "status", "print", "command",
+ "chat_disconnect", "dcc_disconnect", "send_ctcp",
+ "dcc_send", "dcc_send_status", "dcc_get", "dcc_get_status", "quit",
+ "pong"); # ksirc additions
+
+sub addhook {
+ local($type, $name)=@_;
+ $type =~ tr/A-Z/a-z/;
+ $name="hook_".$name;
+ if ($type =~ /^\d\d\d$/ || grep(($_ eq $type), @hooks)) {
+ ($type =~ /^\d\d\d$/) && ($type="num_".$type);
+ eval "*ugly_hack_hooks=*${type}_hooks;";
+ unless (grep(($_ eq $name), @ugly_hack_hooks)) {
+ push(@ugly_hack_hooks, $name);
+ }
+ } else {
+ &tell("*\cbE\cb* $type: no such hook");
+ }
+}
+
+sub remhook {
+ local($type, $name)=@_;
+ $type =~ tr/A-Z/a-z/;
+ $name="hook_".$name;
+ if ($type =~ /^\d\d\d$/ || grep(($_ eq $type), @hooks)) {
+ ($type =~ /^\d\d\d$/) && ($type="num_".$type);
+ eval "*ugly_hack_hooks=*${type}_hooks;";
+ @ugly_hack_hooks=grep(($_ ne $name), @ugly_hack_hooks);
+ } else {
+ &tell("*\cbE\cb* $type: no such hook");
+ }
+}
+
+sub userhost {
+ push (@waituh, $_[0]);
+ push (@douh, $_[1]);
+ push (@erruh, $_[2]);
+ &sl("USERHOST $_[0]");
+}
+
+sub deltimer {
+ local($ref)=$_[0];
+ local($i);
+ if ($#trefs>=0 && $ref!=0) {
+ # delete the timer if it exists
+ for ($i=0; $i<=$#trefs; $i++) {
+ if ($trefs[$i]==$ref) {
+ splice(@trefs,$i,1);
+ splice(@timers,$i,1);
+ splice(@timeactions,$i,1);
+ last;
+ }
+ }
+ }
+}
+
+sub timer {
+ local(@r, @t, @a)=();
+ local($t)=$_[0]+time;
+ local($ref)=$_[2] || 0;
+ &deltimer($ref) if $ref;
+ while ($#timers>=0 && $timers[0]<=$t) {
+ push (@r, shift(@trefs));
+ push (@t, shift(@timers));
+ push (@a, shift(@timeactions));
+ }
+ @trefs=(@r, $ref, @trefs);
+ @timers=(@t, $t, @timers);
+ @timeactions=(@a, $_[1], @timeactions);
+}
+
+sub disappeared {
+ local($n)=(grep(&eq($_, $_[0]), keys(%notify)));
+ if ($n ne '' && $notify{$n}>0) {
+ local($silent)=0;
+ &dohooks("notify_signoff", $_[0]);
+ &tell("*\cb(\cb* Signoff by $_[0] detected");
+ $notify{$n}=0;
+ }
+}
+
+sub appeared {
+ local($t, $n)=(time, grep(&eq($_, $_[0]), keys(%notify)));
+ if ($n ne '') {
+ if ($notify{$n}==0) {
+ local($silent)=0;
+ &dohooks("notify_signon", $_[0]);
+ &tell("*\cb)\cb* Signon by $_[0] detected!");
+ }
+ else {
+# &tell("*\cb(\cb* Signoff by $_[0] detected!");
+ }
+ $notify{$n}=$t;
+ }
+}
+
+$lastsendison=0;
+sub send_isons {
+ local($l)='';
+ foreach (keys %notify) {
+ &sl("ISON : $l"), $l='' if (length($l)>500);
+ $l.=$_." ";
+ }
+ &sl("ISON :$l") if $l;
+ $lastsendison=time;
+ $newisons='';
+ $checkisons=1;
+}
+
+sub signoffs {
+ foreach (keys %notify) {
+ if ($notify{$_}>0 && $notify{$_}<$lastsendison) {
+ $notify{$_}=0;
+ local($silent)=0;
+ &dohooks("notify_signoff", $_);
+ &tell("*\cb(\cb* Signoff by $_ detected");
+ }
+ }
+ $checkisons='';
+}
+
+sub modestripper {
+ local($chnl, $what)=@_;
+ $chnl =~ tr/A-Z/a-z/;
+ local($how, $modes, @args)=('+', split(/ +/, $what));
+ foreach $m (split(//, $modes)) {
+ if ($m =~ /[\-\+]/) {
+ $how=$m;
+ } elsif ($m =~ /[vb]/) {
+ shift(@args);
+ } elsif ($m eq 'k') {
+ $how eq '+' ? ($chankey{$chnl}=$args[0]) : delete $chankey{$chnl};
+ shift(@args);
+ } elsif ($m eq 'l') {
+ $how eq '+' ? ($limit{$chnl}=shift(@args)) : delete $limit{$chnl};
+ } elsif ($m eq 'o') {
+ $haveops{$chnl}=($how eq '+') if (&eq(shift(@args), $nick));
+ } else {
+ $mode{$chnl} =~ s/$m//g;
+ $mode{$chnl}.=$m if $how eq '+';
+ }
+ }
+}
+
+sub umodechange {
+ local($what)=@_;
+ local($how)='+';
+ foreach $m (split(//, $what)) {
+ if ($m =~ /[\-\+]/) {
+ $how=$m;
+ } else {
+ $umode =~ s/$m//g;
+ $umode.=$m if ($how eq '+' && $m !~ /\s/);
+ }
+ }
+}
+
+sub ignored {
+ foreach (@ignore) {
+ return 1 if $_[0] =~ /^${_}$/;
+ }
+ return '';
+}
+
+sub dorcfile {
+ return if !open(RCFILE, "<$_[0]");
+ while (<RCFILE>) {
+ chop;
+ s/^\///;
+ next if /^\#/;
+ &docommand($_) if $_;
+ $silent=$skip='';
+ }
+ close RCFILE;
+}
+
+sub loadrc {
+ $rcloaded=1;
+ $sysrc && &dorcfile($sysrc);
+ $rcfile && &dorcfile($rcfile);
+}
+
+sub selline {
+ $leftover=0;
+ $rin=$rout="\0" x 32;
+ $win=$wout="\0" x 32;
+ foreach ($S, 'STDIN', keys(%dcnick), keys(%buf_fds)) {
+ $leftover=1, return $_ if $buffer{$_} =~ /\n/;
+ }
+ foreach ('STDIN', keys(%dcnick), keys(%dcwait), keys(%dgrfh), keys(%dswait),
+ keys(%dsrfh), keys(%sel_fds), keys(%buf_fds)) {
+ vec($rin, fileno($_), 1)=1;
+ }
+ foreach (keys(%sel_w_fds)){
+ vec($win, fileno($_), 1)=1;
+ }
+ vec($rin, fileno($S), 1)=1 if $connected;
+ if ($#timers<0 || $timers[0]>time+30) {
+ select($rout=$rin, $wout=$win, undef, 30);
+ } elsif ($timers[0]<=time) {
+ select($rout=$rin, $wout=$win, undef, 0);
+ } else {
+ select($rout=$rin, $wout=$win, undef, $timers[0]-time);
+ }
+}
+
+sub getnick {
+ if ($ENV{'BACKUPNICK'} && !($nick eq $ENV{'BACKUPNICK'})) {
+ $nick=$ENV{'BACKUPNICK'};
+ } else {
+ &getuserline("Pick a nick: ", "Nick: ");
+ $nick=$_;
+ }
+ &sl("NICK $nick");
+ &dostatus;
+}
+
+sub donumeric {
+ local($from)=($who eq $myserver ? '' : " (from ${who})");
+ if ($cmd eq '401') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cb?\cb* Cannot find $newarg on irc$from");
+ } elsif ($cmd eq '402') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cb?\cb* $newarg: no such server$from");
+ } elsif ($cmd eq '403') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cb?\cb* $newarg: no such channel$from");
+ } elsif ($cmd eq '406') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cb?\cb* $newarg: there was no such nickname$from");
+ } elsif ($cmd eq '421') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cb?\cb* $newarg: unknown command$from");
+ } elsif ($cmd =~ /^4[012]/) {
+ $args =~ s/^[^:]*://;
+ &tell("*** $args$from");
+ } elsif ($cmd eq '431') {
+ &tell("*** Was expecting a nickname somewhere...");
+ &getnick if $connected<2;
+ } elsif ($cmd eq '432') {
+ if ($connected==2) {
+ &tell("*\cbN\cb* Invalid nickname, you're still \"$nick\"");
+ } else {
+ &tell("*\cbN\cb* Invalid nickname!");
+ &getnick;
+ }
+ } elsif ($cmd eq '433') {
+ if ($connected==2) {
+ &tell("*\cbN\cb* Nick already taken, you're still \"$nick\"");
+ } else {
+ &tell("*\cbN\cb* Nick already taken!");
+ &getnick;
+ }
+ } elsif ($cmd eq '441') {
+ local($g, $w, $c)=split(/ +/, $args);
+ &tell("*\cbE\cb* $w is not on channel $c$from");
+ } elsif ($cmd eq '442') {
+ local($w, $c)=split(/ +/, $args);
+# &tell("*\cbE\cb* You're not on channel $c$from"); # KSIRC MOD
+ } elsif ($cmd eq '443') {
+ local($w, $o, $c)=split(/ +/, $args);
+ &tell("*\cbE\cb* $o is already on channel $c$from");
+ } elsif ($cmd eq '465') {
+ &tell("*\cbE\cb* You are banned from this server$from");
+ } elsif ($cmd eq '461') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cbE\cb* The command $newarg needs more arguments than that$from");
+ } elsif ($cmd =~ /^47[1345]$/) {
+ &yetonearg;
+ &yetonearg;
+ local($r);
+ if ($cmd eq '471') {
+ $r="channel is full";
+ } elsif ($cmd eq '473') {
+ $r="channel is invite-only";
+ } elsif ($cmd eq '474') {
+ $r="banned from channel";
+ } else {
+ $r="bad channel key";
+ }
+ &tell("*\cbE\cb* Can't join $newarg: ${r}$from");
+ } elsif ($cmd eq '301') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*** $newarg is away: $args");
+ } elsif ($cmd eq '302') {
+ &yetonearg;
+ &yetonearg;
+ local($n, $do, $err)=(shift(@waituh), shift(@douh), shift(@erruh));
+ if ($newarg =~ /^([^\s\*=]+)[\*]?=([\-+])/) {
+ $who=$1;
+ local($adr)=$';
+ if ($adr =~ /\@/) {
+ $user=$`;
+ $host=$';
+ } else {
+ $user=$host='';
+ }
+ if (&eq($who, $n)) {
+ eval $do;
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in userhost: $@") if $@ ne '';
+ } else {
+ &tell("*\cbE\cb* userhost returned for unexpected nick $who");
+ }
+ } else {
+ if (defined($err)) {
+ eval $err;
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in userhost: $@") if $@ ne '';
+ } else {
+ &tell("*\cb?\cb* Cannot find $n on irc");
+ }
+ }
+ } elsif ($cmd eq '303') {
+ &yetonearg;
+ local($n);
+ foreach $n (split(/ +/, $args)) {
+ &appeared($n);
+ }
+ } elsif ($cmd eq '305') {
+ &tell("*** You are no longer marked as away");
+ $away='';
+ &dostatus;
+ } elsif ($cmd eq '306') {
+ &tell("*** You are marked as being away");
+ $away=1;
+ &dostatus;
+ } elsif ($cmd eq '311') {
+ local($g, $n, $u, $m, $g, $r)=split(/ +/, $args, 6);
+ $r =~ s/^://;
+ &tell("*** $n is $u\@$m ($r)");
+ } elsif ($cmd eq '312') {
+ &yetonearg;
+ &yetonearg;
+ &yetonearg;
+ local($s)=$newarg;
+ &tell("*** on IRC via server $s ($args)");
+ } elsif ($cmd eq '313') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*** $newarg $args");
+ } elsif ($cmd eq '314') {
+ local($g, $n, $u, $m, $g, $r)=split(/ +/, $args, 6);
+ $r =~ s/^://;
+ &tell("*** $n was $u\@$m ($r)");
+ } elsif ($cmd eq '317') {
+ &yetonearg;
+ &yetonearg;
+ local($n)=$newarg;
+ &yetonearg;
+ if ($newarg>=3600) {
+ &tell("*** $n has been idle for ".int($newarg/3600)." hours, ".
+ int(($newarg%3600)/60)." minutes and ".
+ ($newarg%60)." seconds");
+ } elsif ($newarg>=60) {
+ &tell("*** $n has been idle for ".int($newarg/60)." minutes and ".
+ ($newarg%60)." seconds");
+ } else {
+ &tell("*** $n has been idle for $newarg seconds");
+ }
+ } elsif ($cmd eq '319') {
+ local($g, $g, $c)=split(/ +/, $args, 3);
+ $c =~ s/^://;
+ &tell("*** on channels: $c");
+ } elsif ($cmd eq '322') {
+ local($g, $c, $n, $r)=split(/ +/, $args, 4);
+ $r =~ s/^://;
+ $n>=$listmin && $n <=$listmax && (!$listpat || $c =~ /^${listpat}$/i)
+ && &tell(sprintf("*** %-10s %-5s %s", $c, $n, $r));
+ } elsif ($cmd eq '323') {
+ $listmin=0;
+ $listmax=100000;
+ $listpat='';
+ } elsif ($cmd eq '324') {
+ local($g, $c, $m)=split(/ +/, $args, 3);
+ $m =~ s/^://;
+ $m =~ s/ $//;
+ $c =~ tr/A-Z/a-z/;
+ if (grep(&eq($_, $c), @channels)) {
+ if (defined($mode{$c})) {
+ &tell("*\cb+\cb* Mode for channel $c is \"$m\"");
+ } else {
+ $mode{$c}='';
+ }
+ &modestripper($c, $m);
+ &dostatus;
+ } else {
+ &tell("*\cb+\cb* Mode for channel $c is \"$m\"");
+ }
+ } elsif ($cmd eq '329') {
+ &yetonearg;
+ &yetonearg;
+ local($c)=$newarg;
+ &yetonearg;
+ local($t)=($newarg ? ("created " . &date($newarg)) : "0 TS");
+ &tell("*** $c : $t");
+ } elsif ($cmd eq '331') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cbT\cb* No topic is set on channel $newarg");
+ } elsif ($cmd eq '332') {
+ &yetonearg;
+ &yetonearg;
+ &tell("*\cbT\cb* Topic for $newarg: $args");
+ } elsif ($cmd eq '333') {
+ local($g, $c, $n, $t)=split(/ +/, $args, 4);
+ local($d)=&date($t);
+ &tell("*\cbT\cb* Topic for $c set by $n on $d");
+ } elsif ($cmd eq '318' || $cmd eq '315' || $cmd eq '369' ||
+ $cmd eq '321' || $cmd eq '376' || # KSIRC MOD
+ $cmd eq '365' || $cmd eq '368' || $cmd eq '374' ||
+ $cmd eq '219' || $cmd eq '007') {
+ #nothing!
+ } elsif ($cmd eq '341') {
+ local($g, $n, $c)=split(/ +/, $args, 3);
+ &tell("*\cbI\cb* Inviting $n to channel $c");
+ } elsif ($cmd eq '352') {
+ local($g, $c, $u, $m, $s, $n, $st, $g, $i)=split(/ +/, $args, 9);
+ &tell(sprintf("%-10s %-9s %4s %s\@%s (%s)", $c, $n, $st, $u, $m, $i));
+ } elsif ($cmd eq '353') {
+ local($g, $m, $c, $r)=split(/ +/, $args, 4);
+ local($n)=$nick;
+ $n =~ s/(\W)/\\$1/g;
+ $r =~ s/^://;
+ if($DSIRC_NAMES eq ''){ #KSIRC MOD
+ &tell("*I* Users on $c: $r"); # KSIRC MOD
+ $DSIRC_NAMES = $c; # KSIRC MOD
+ } # KSIRC MOD
+ else { # KSIRC MOD
+ &tell("*\cbI\cb* Users on $c: $r"); # KSIRC MOD
+ } # KSIRC MOD
+ $c =~ tr/A-Z/a-z/;
+ $haveops{$c}=1 if ($r =~ /\@${n}( |$)/i);
+ &dostatus if &eq($c, $talkchannel);
+ } elsif ($cmd eq '366'){ # KSIRC MOD
+ #&tell("*I* Users on $DSIRC_NAMES:"); # KSIRC MOD
+ $DSIRC_NAMES = ''; # KSIRC MOD
+ } elsif ($cmd eq '221') {
+ &yetonearg;
+ &tell("*\cb+\cb* Your user mode is \"$args\"");
+ } elsif ($cmd eq '200') {
+ local($b, $l, $v, $n, $s)=split(/ +/, $args);
+ $s =~ s/^://;
+ &tell("*** $l $who ($v) ==> $n $s");
+ } elsif ($cmd eq '205') {
+ local($b, $u, $h, $n)=split(/ +/, $args);
+ $n =~ s/^://;
+ &tell("*** $u [$h] ==> $n");
+ } elsif ($cmd =~ /^20/) {
+ local($b, $t, $n, $r)=split(/ +/, $args, 4);
+ &tell("*** $t [$n] ==> $r");
+ } elsif ($cmd eq '375' || $cmd eq '372' || $cmd =~ /^25/) {
+ &yetonearg;
+ &tell("*** $args");
+ } elsif ($cmd eq '379' ) { # RPL_FORWARD (Simon)
+ &yetonearg;
+ local( $from_channel, $to_channel ) = split( / +/, $args );
+ &tell("~$from_channel~*\cb<\cb* You have left channel $from_channel");
+ } else {
+ &yetonearg;
+ #$args =~ s/ :/ /;
+ &tell("*** $args$from");
+ }
+}
+
+# main prog
+
+print "`#ssfe#i\n" unless (-t STDOUT);
+&tell("*** Welcome to \cbsirc\cb version $version; type /help for help");
+
+&load($sysinit) if $sysinit ne '' && -f $sysinit;
+&load($initfile) if !$restrict && $initfile ne '' && -f $initfile;
+
+while (1) {
+ &bindtoserver, undef $ready if $ready;
+ $silent=$skip='';
+ if ($connected==2) {
+ $time=time;
+ &loadrc unless $rcloaded;
+ &send_isons
+ if $time>=$lastsendison+90 || ($newisons && $time>=$lastsendison+10);
+ &signoffs if $checkisons && ($time>=$lastsendison+30);
+ }
+ $fh=&selline;
+ foreach $rfh (keys (%buf_fds)) {
+ if (vec($rout, fileno($rfh), 1) || ($leftover && $fh eq $rfh)) {
+ &gl($rfh) || next;
+ local($line, $h)=($_, $buf_fds{$rfh});
+ delete $buf_fds{$rfh}, delete $buffer{$rfh}, close($rfh) if $_ eq '';
+ eval { &$h($line); };
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in buffered fd hook &$h: $@")
+ if $@ ne '';
+ }
+ }
+ foreach $rfh (keys (%sel_fds)) {
+ if (vec($rout, fileno($rfh), 1)) {
+ local($h)=$sel_fds{$rfh};
+ eval { &$h($rfh); }; #KSIRC MOD
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in unbuffered fd hook &$h: $@")
+ if $@ ne '';
+ }
+ }
+ foreach $rfh (keys (%sel_w_fds)) {
+ if (vec($wout, fileno($rfh), 1)) {
+ local($h)=$sel_w_fds{$rfh};
+ eval { &$h($rfh); }; #KSIRC MOD
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in unbuffered fd hook &$h: $@")
+ if $@ ne '';
+ }
+ }
+ foreach $rfh (keys (%dcnick)) {
+ if (vec($rout, fileno($rfh), 1) || ($leftover && $fh eq $rfh)) {
+ &gl($rfh) || next;
+ &dcerror($rfh), next if $_ eq '';
+ chop;
+ local($who, $what)=($dcnick{$rfh}, $_);
+ $dcvol{$dcnick{$rfh}}+=length($what);
+ print "`#ssfe#t/m =$who \n" if $ssfe;
+ print "`#ssfe#o=${who}= $what\n" if $ssfe;
+ &dohooks("dcc_chat", $who, $what);
+ &tell("~=${who}~=\cb${who}\cb= $what"); # KSIRC MOD
+ $silent='';
+ }
+ }
+ foreach $rfh (keys (%dcwait)) {
+ if (vec($rout, fileno($rfh), 1)) {
+ local($n, $fh);
+ my $paddr;
+ if ($paddr = &accept($fh, $rfh)) {
+ select($fh); $|=1; select(STDOUT);
+ my($port,$iaddr) = sockaddr_in($paddr);
+ my $ip = inet_ntoa($iaddr);
+ $n=$dcwait{$rfh};
+ $dcnick{$fh}=$n;
+ $n =~ tr/A-Z/a-z/;
+ $dcvol{$n}=0;
+ $dcfh{$n}=$fh;
+ &tell("*\cbD\cb* DCC CHAT connection with $n established");
+ &tell("~!dcc~DCC CHAT inbound established who: $n ip: $ip");
+ print "`#ssfe#t/m =$n \n" if $ssfe;
+ }
+ delete $dcwait{$rfh};
+ }
+ }
+ foreach $sfh (keys (%dswait)) {
+ local($rfh, $fh)=$dswait{$sfh};
+ if (vec($rout, fileno($sfh), 1)) {
+ my $paddr;
+ if ($paddr = &accept($fh, $sfh)) {
+ my($port,$iaddr) = sockaddr_in($paddr);
+ my $ip = inet_ntoa($iaddr);
+ select($fh); $|=1; select(STDOUT);
+ $dsrfh{$fh}=$rfh;
+ $dstarttime{$rfh}=time;
+ $dtransferred{$fh}=0;
+ $dnick{$fh}=$dnick{$sfh};
+ $dsoffset{$fh}=$dsoffset{$sfh};
+ &tell("*\cbD\cb* DCC SEND connection with $dnick{$sfh}/$ip ($dfile{$rfh}) established");
+ &tell("~!dcc~DCC SEND established who: $dnick{$sfh} file: $dfile{$rfh} ip: $ip");
+ }
+ delete $dnick{$sfh};
+ delete $dswait{$sfh};
+ delete $dsoffset{$sfh};
+ delete $dsport{$sfh};
+ }
+ }
+ foreach $sfh (keys (%dgrfh)) {
+ local($rfh)=$dgrfh{$sfh};
+ if (vec($rout, fileno($sfh), 1)) {
+ local($a, $buf)=(0, '');
+ $a=sysread($sfh, $buf, 4096);
+ if ($a) {
+ $dtransferred{$sfh}+=$a;
+ &dohooks("dcc_get_status", $dfile{$rfh}, $dtransferred{$sfh}, $rfh);
+ # &tell("*\cbD\cb* DCC GET read: $dfile{$rfh} bytes: $dtransferred{$sfh}"); # KSIRC MOD FOR 971217
+ my $b = $dtransferred{$sfh}+$dgxferadd{$sfh};
+ &tell("~!dcc~DCC GET read: $dfile{$rfh} who: $dnick{$sfh} bytes: $b"); # KSIRC MOD FOR 971217
+ print $rfh $buf;
+ print $sfh pack("N", $b); # used to be just $dtransfered but most seem to want xfet + offset
+ } else {
+ &dgsclose($sfh, $rfh, "GET", "OK");
+ }
+ }
+ }
+ foreach $sfh (keys (%dsrfh)) {
+ local($rfh)=$dsrfh{$sfh};
+ if (vec($rout, fileno($sfh), 1) || !$dtransferred{$sfh}) {
+ local($ack, $csa, $buf, $b, $l, $w)=(0, '', '');
+ if ($dtransferred{$sfh}) {
+ &dgsclose($sfh, $rfh, "SEND", "Protocol Error"), next if sysread($sfh, $b, 4)!=4;
+ $ack=unpack("N", $b);
+ }
+ if($ack > ($dtransferred{$sfh} + $dsoffset{$sfh})){
+ my $v = $dtransferred{$sfh} + $dsoffset{$sfh};
+ &tell("*\cbD\cb* DCC transfer protocol failure! $ack $dtransferred{$sfh} $dsoffset{$sfh} $v");
+ &dgsclose($sfh, $rfh, "SEND", "Protocol Out of Sync");
+ next;
+ }
+ #
+ # When you do a dcc resume the ack value returned from the
+ # remote client is not well defined. Two different values
+ # are used, the current number of bytes transfered, or
+ # the current location in the file. We try to detech
+ # which type of ack we got and we adjust our math
+ # according so we keep up nice packet sizes.
+ # xchat can't seem to take > 4k packets after a resume
+ # and it causes the backoff to ack a little funny, but
+ # it's not our fault!
+ #
+ if($dsoffset{$sfh} && ($ack != 0) && ($dsresumedb{$sfh} == undef)) {
+ if($ack > $dsoffset{$sfh}){
+ $dsresumedb{$sfh} = 1;
+ }
+ else {
+ $dsresumedb{$sfh} = 2;
+ }
+ #&print("*** Resume style is: $dsresumedb{$sfh}");
+
+ }
+ if($dsoffset{$sfh} && ($dsresumedb{$sfh} == 1)){
+ $csa=$set{"SENDAHEAD"}-($dtransferred{$sfh}+$dsoffset{$sfh})+$ack;
+ }
+ else {
+ $csa=$set{"SENDAHEAD"}-$dtransferred{$sfh}+$ack;
+ }
+ #&print("*** CSA is: $csa ack: $ack dt: $dtransferred{$sfh} $dsoffset{$sfh}");
+ next if $csa<0;
+ $l=read($rfh, $buf, 512+$csa);
+ $w=syswrite($sfh, $buf, $l) if $l;
+ &dohooks("dcc_send_status", $dfile{$rfh}, $dtransferred{$sfh}, $rfh);
+ # &tell("*\cbD\cb* DCC SEND write: $dfile{$rfh} bytes: $dtransferred{$sfh}"); # KSIRC MOD FOR 971218
+ my $sz = $dtransferred{$sfh}+$dsoffset{$sfh};
+ &tell("~!dcc~DCC SEND write: $dfile{$rfh} who: $dnick{$sfh} bytes: $sz"); # KSIRC MOD FOR 971218
+ next if $l==0 && $ack<$dtransferred{$sfh};
+ $dtransferred{$sfh}+=$w;
+ &dgsclose($sfh, $rfh, "SEND", "OK"), next if ($w<$l || $l==0);
+ }
+ }
+ while ($#timers>=0 && $timers[0]<=time) {
+ shift (@timers);
+ shift (@trefs);
+ eval shift (@timeactions);
+ $@ =~ s/\n$//, &tell("*\cbE\cb* error in timer: $@") if $@ ne '';
+ }
+ if (vec($rout, fileno(STDIN), 1) || ($leftover && $fh eq 'STDIN')) {
+ &gl('STDIN') || next;
+ &exit if $_ eq '';
+ chop;
+ $logging && print LOG "<- " . $_ . "\n";
+ &douserline($_) if $_ ne '';
+ }
+ if ($connected && (($leftover && $fh eq $S) || vec($rout, fileno($S), 1))) {
+ &gl($S) || next;
+ if ($_ eq '') {
+ &tell("*\cbE\cb* Connection to server lost");
+ close($S);
+ delete $buffer{$S};
+ $connected=0;
+ &dohooks("disconnect");
+ &bindtoserver;
+ next;
+ }
+ chop;
+ $logging && print LOG ">> " . $_ . "\n";
+ $serverline=$_;
+ $_=$server." ".$_ unless /^:/;
+ ($who, $cmd, $args)=split(/ /, $_, 3);
+ $cmd =~ tr/a-z/A-Z/;
+ $who =~ s/^://;
+ $args =~ s/^://;
+ $user=$host=$puh1=$puh2='';
+ if ($who =~ /^([^!@ ]+)!([^@ ]+)@([^ ]+)$/) {
+ ($who, $user, $host) = ($1, $2, $3);
+ $puh1="!$user\@$host" if $set{"PRINTUH"} ne 'none';
+ $puh2=$puh1 if $set{"PRINTUH"} eq 'all';
+ }
+ &dohooks("raw_irc", $cmd, $args);
+ next if $skip;
+ next if (($cmd eq 'PRIVMSG' || $cmd eq 'NOTICE') &&
+ &ignored("$who!$user\@$host"));
+ if ($cmd eq '001') {
+ $connected=2;
+ $myserver=$who;
+ ($nick)=split(/ /, $args, 2);
+ }
+ if ($cmd =~ /^\d\d\d$/) {
+ &dohooks("num_".$cmd, $args);
+ next if $skip;
+ &donumeric;
+ } elsif ($cmd eq 'PING') {
+ &sl("PONG $args");
+ } elsif ($cmd eq 'PRIVMSG') {
+ &yetonearg;
+ if ($args =~ /^\001([^\001]*)\001$/ && $set{'CTCP'} ne 'none') {
+ &ctcp($newarg, $1);
+ } elsif (!$printchan && &eq($newarg, $talkchannel)) {
+ &dohooks("public", $newarg, $args);
+ &tell("~${newarg}~<${who}> $args"); # MOD FOR KSIRC
+ } elsif ($newarg =~ /^[\#\&\+]/) {
+ &dohooks("public", $newarg, $args);
+ &tell("~${newarg}~<${who}> $args"); # MOD FOR KSIRC
+ } elsif (&eq ($newarg, $nick)) {
+ print "`#ssfe#t/m $who \n" if $ssfe;
+ print "`#ssfe#o[$who$puh1] $args\n" if $ssfe;
+ &dohooks("msg", $args);
+ &tell("~${who}~[\cb${who}\cb${puh1}] $args"); # MOD FOR KSIRC
+ } else {
+ &tell("~${who}~[\cb${who}\cb${puh1}\cb] $args"); # MOD FOR KSIRC
+ }
+ } elsif ($cmd eq 'NOTICE') {
+ &yetonearg;
+ if ($args =~ /^\001([^\001]*)\001$/) {
+ &ctcpreply($newarg, $1);
+ } elsif ($newarg =~ /^[\#\&\+]/) {
+ &dohooks("notice", $newarg, $args);
+ &tell("~${newarg}~-${who}- $args"); # MOD FOR KSIRC
+ } elsif ($who =~ /\./) {
+ &dohooks("server_notice", $args);
+ $args="*** ".$args unless ($args =~ /^\*/);
+ &tell($args);
+ } elsif (&eq($newarg, $nick)) {
+ &dohooks("notice", $newarg, $args);
+ &tell("~${who}~-\cb${who}\cb${puh1}- $args"); # MOD FOR KSIRC
+ } else {
+ &dohooks("notice", $newarg, $args);
+ &tell("~${who}~-\cb$who$puh1\cb- $args"); # MOD FOR KSIRC
+ }
+ $newarg =~ s/\cg.*//; # ircnet kludge
+ } elsif ($cmd eq 'KICK') {
+ &yetonearg;
+ local($channel)=$newarg;
+ &yetonearg;
+ $args=$who unless $args;
+ if (&eq($nick, $newarg)) {
+ &tell("~${channel}~*\cb<\cb* You have been kicked off channel $channel by $who$puh2 ($args)"); # MOD FOR KSIRC
+ @channels=grep(!&eq($_, $channel), @channels);
+ if (@channels) {
+ $talkchannel=$channels[$#channels];
+ } else {
+ $talkchannel='';
+ }
+ $channel =~ tr/A-Z/a-z/;
+ &dohooks("kick", $newarg, $channel, $args);
+ delete $mode{$channel};
+ delete $limit{$channel};
+ delete $haveops{$channel};
+ delete $chankey{$channel};
+ $talkchannel && !$ssfe && &tell("*** Talking to $talkchannel now");
+ &dostatus;
+ } else {
+ &dohooks("kick", $newarg, $channel, $args);
+ &tell("~${channel}~*\cb<\cb* $newarg has been kicked off channel $channel by $who$puh2 ($args)"); # MOD FOR KSIRC
+ }
+ } elsif ($cmd eq 'PART') {
+ &yetonearg;
+ if (&eq($who, $nick)) {
+ #&tell("~!all~*\cb<\cb* You have left channel $newarg"); # MOD FOR KSIRC
+ @channels=grep(!&eq($_, $newarg), @channels);
+ if (@channels) {
+ $talkchannel=$channels[$#channels];
+ } else {
+ $talkchannel='';
+ }
+ $newarg =~ tr/A-Z/a-z/;
+ delete $mode{$newarg};
+ delete $limit{$newarg};
+ delete $haveops{$newarg};
+ delete $chankey{$newarg};
+ &dohooks("leave", $newarg);
+ $talkchannel && !$ssfe && &tell("*** Talking to $talkchannel now");
+ &dostatus;
+ } else {
+ &dohooks("leave", $newarg);
+ &tell("~${newarg}~*\cb<\cb* $who$puh2 has left channel $newarg"); # MOD FOR KSIRC
+ }
+ } elsif ($cmd eq 'JOIN') {
+ &yetonearg;
+ if (&eq($nick, $who)) {
+ $newarg =~ tr/A-Z/a-z/;
+ push(@channels, $newarg);
+ $talkchannel=$newarg;
+ &dohooks("join", $newarg);
+ &dostatus;
+ &tell("~${newarg}~*\cb>\cb* You have joined channel $newarg"); # MOD FOR KSIRC
+ &sl("MODE $newarg");
+ } else {
+ &dohooks("join", $newarg);
+ &tell("~${newarg}~*\cb>\cb* $who ($user\@$host) has joined channel $newarg"); # MOD FOR KSIRC
+ }
+ &appeared($who);
+ } elsif ($cmd eq 'NICK') {
+ &yetonearg;
+ if (&eq($nick, $who)) {
+ $oldnick = $nick;
+ $nick=$newarg;
+ &dohooks("nick", $newarg);
+ $who=$newarg;
+ &dostatus;
+ &tell("~!all~*\cbN\cb* $oldnick is now known as $newarg");
+ } else {
+ &dohooks("nick", $newarg);
+ &tell("~!all~*\cbN\cb* $who$puh2 is now known as $newarg"); # MOD FOR KSIRC
+ }
+ } elsif ($cmd eq 'MODE') {
+ &yetonearg;
+ $args =~ s/ $//;
+ if ($newarg =~ /^[\#\&\+]/) {
+ &modestripper($newarg, $args);
+ &dohooks("mode", $newarg, $args);
+ &dostatus;
+ &tell("~${newarg}~*\cb+\cb* Mode change \"$args\" on channel $newarg by $who$puh2"); # MOD FOR KSIRC
+ } else {
+ local($towho)=$newarg;
+ &yetonearg;
+ &umodechange($newarg), &dostatus if &eq($towho, $nick);
+ &dohooks("mode", $towho, $newarg);
+ &tell("*\cb+\cb* Mode change \"$newarg\" for user $towho by $who"); # MOD FOR KSIRC
+ }
+ } elsif ($cmd eq 'KILL') {
+ &yetonearg;
+ local($n)=$newarg;
+ $args || ($args=$who);
+ &tell("~${newarg}~*\cb<\cb* $n got killed by $who$puh1 ($args)"); # MOD FOR KSIRC
+ } elsif ($cmd eq 'INVITE') {
+ &yetonearg;
+ &yetonearg;
+ &dohooks("invite", $newarg);
+ $invited=$newarg;
+ &tell("~!default~*\cbI\cb* $who$puh1 invites you to channel $newarg"); # MOD FOR KSIRC
+ } elsif ($cmd eq 'TOPIC') {
+ &yetonearg;
+ &dohooks("topic", $newarg, $args);
+ &tell("~${newarg}~*\cbT\cb* $who$puh2 has changed the topic on channel $newarg to \"$args\""); # MOD FOR KSIRC
+ } elsif ($cmd eq 'SILENCE') {
+ &tell("*** Silence $args");
+ } elsif ($cmd eq 'PONG') {
+ &dohooks("pong", $args);
+ } elsif ($cmd eq 'QUIT') {
+ &dohooks("signoff", $args);
+ &tell("~!all~*\cb<\cb* Signoff: $who$puh2 ($args)"); # MOD FOR KSIRC
+ &disappeared($who);
+ } elsif ($cmd eq 'WALLOPS') {
+ &tell("!$who$puh2! ".$args);
+ } elsif ($cmd eq 'RPONG') {
+ local($n, $t, $ms, $ts)=split(/ +/, $args);
+ $ts =~ s/^://;
+ &tell("*** RPONG: $who - $t: $ms ms, ".time-$ts." sec");
+ } else {
+ &tell("*** The server says: $serverline");
+ }
+ }
+}
+
diff --git a/ksirc/eventsrc b/ksirc/eventsrc
new file mode 100644
index 00000000..56031051
--- /dev/null
+++ b/ksirc/eventsrc
@@ -0,0 +1,364 @@
+[!Global!]
+IconName=ksirc
+Comment=KSirc
+Comment[af]=Ksirc
+Comment[bn]=কে-à¦à¦¸-আর-আই-সি
+Comment[hi]=के-à¤à¤¸à¤†à¤ˆà¤†à¤°à¤¸à¥€
+Comment[sv]=Ksirc
+
+[ChannelChanged]
+Name=Channel event
+Name[af]=Kanaal gebeurtenis
+Name[ar]=حدث القناة
+Name[be]=ÐŸÐ°Ð´Ð·ÐµÑ Ð½Ð° канале
+Name[bg]=Има Ñъбитие в канала
+Name[bn]=চà§à¦¯à¦¾à¦¨à§‡à¦² ঘটনা
+Name[bs]=Događaj na kanalu
+Name[ca]=Esdeveniment del canal
+Name[cs]=Událost v kanálu
+Name[cy]=Digwyddiad sianel
+Name[da]=Kanalbegivenhed
+Name[de]=Kanalereignis
+Name[el]=Γεγονός καναλιοÏ
+Name[eo]=Kanala evento
+Name[es]=Evento de canal
+Name[et]=Kanali sündmus
+Name[eu]=Kanal gertaera
+Name[fa]=رویداد کانال
+Name[fi]=Kanavatapahtuma
+Name[fr]=Événement de canal
+Name[gl]=Evento de canle
+Name[he]=×ירוע של הערוץ
+Name[hi]=चैनल घटना
+Name[hr]=Događaj na kanalu
+Name[hu]=Csatornaesemény
+Name[is]=Atburður á rás
+Name[it]=Canale evento
+Name[ja]=ãƒãƒ£ãƒãƒ«ã‚¤ãƒ™ãƒ³ãƒˆ
+Name[ka]=áƒáƒ áƒ®áƒ˜áƒ¡ მáƒáƒ•áƒšáƒ”ნáƒ
+Name[kk]=Ðрнадағы оқиға
+Name[km]=ព្រឹážáŸ’ážáž·áž€áž¶ážšážŽáŸâ€‹áž–្រឹážáŸ’ážáž·áž€áž¶ážšážŽáŸ
+Name[lt]=Įvykis kanale
+Name[mk]=ÐаÑтан на каналот
+Name[mn]=Сувгийн үйл Ñвдал
+Name[mt]=Avveniment tal-kanal
+Name[nb]=Kanalhendelse
+Name[nds]=Kanaalbegeefnis
+Name[ne]=चà¥à¤¯à¤¾à¤¨à¤² घटना
+Name[nl]=Kanaalgebeurtenis
+Name[nn]=Kanalhending
+Name[nso]=Tiragalo ya kanale
+Name[pa]=ਚੈਨਲ ਘਟਨਾ
+Name[pl]=Zdarzenie na kanale
+Name[pt]=Evento do canal
+Name[pt_BR]=Evento do Canal
+Name[ru]=Событие в канале
+Name[se]=Kanáladáhpáhus
+Name[sk]=Udalosť na kanály
+Name[sl]=Dogodek kanala
+Name[sr]=Догађај на каналу
+Name[sr@Latn]=Događaj na kanalu
+Name[sv]=Kanalhändelse
+Name[ta]=தட நிகழà¯à®µà¯
+Name[tg]=ҲодиÑаи канал
+Name[th]=เหตุà¸à¸²à¸£à¸“์ของช่องสนทนา
+Name[tr]=Kanal olayı
+Name[uk]=ÐŸÐ¾Ð´Ñ–Ñ Ð² каналі
+Name[ven]=Vhutambo ha Channel
+Name[xh]=Itshanele yesiganeko
+Name[zh_CN]=通é“事件
+Name[zh_HK]=é »é“事件
+Name[zh_TW]=é »é“事件
+Name[zu]=Uhlelo lwe-Shaneli
+Comment=IRC channel event
+Comment[af]=Irc kanaal gebeurtenis
+Comment[ar]=IRC حدث قناة
+Comment[be]=ÐŸÐ°Ð´Ð·ÐµÑ Ð½Ð° канале IRC
+Comment[bg]=Има Ñъбитие в канала
+Comment[bn]=আই-আর-সি চà§à¦¯à¦¾à¦¨à§‡à¦² ঘটনা
+Comment[bs]=Događaj na IRC kanalu
+Comment[ca]=Esdeveniment del canal d'IRC
+Comment[cs]=Událost IRC kanálu
+Comment[cy]=Digwyddiad sianel IRC
+Comment[da]=IRC-kanalbegivenhed
+Comment[de]=IRC Kanalereignis
+Comment[el]=Γεγονός ÎºÎ±Î½Î±Î»Î¹Î¿Ï IRC
+Comment[eo]=IRC-kanalo
+Comment[es]=Evento de canal IRC
+Comment[et]=IRC kanali sündmus
+Comment[eu]=IRC kanal gertaera
+Comment[fa]=رویداد کانال IRC
+Comment[fi]=IRC-kanavatapahtuma
+Comment[fr]=Événement de canal IRC
+Comment[gl]=Evento na canle de IRC
+Comment[he]=×ירוע של ערוץ IRC
+Comment[hi]=IRC चैनल घटना
+Comment[hr]=Događaj IRC kanala
+Comment[hu]=IRC csatornaesemény
+Comment[is]=IRC rásar-atburður
+Comment[it]=Evento canale IRC
+Comment[ja]=IRC ãƒãƒ£ãƒ³ãƒãƒ«ã‚¤ãƒ™ãƒ³ãƒˆ
+Comment[ka]=IRC áƒáƒ áƒ®áƒ˜áƒ¡ მáƒáƒ•áƒšáƒ”ნáƒ
+Comment[kk]=IRC арнаÑындағы оқиға
+Comment[km]=ព្រឹážáŸ’ážáž·áž€áž¶ážšážŽáŸâ€‹áž†áž¶áž“ែល IRC
+Comment[lt]=IRC kanalo įvykis
+Comment[mk]=ÐаÑтан на IRC-канал
+Comment[mn]=IRC Ñувагийн үйл Ñвдал
+Comment[ms]=acara saluaran IRC
+Comment[mt]=Avveniment ta' kanal tal-IRC
+Comment[nb]=IRC-kanalhendelse
+Comment[nds]=IRC-Kanaalbegeefnis
+Comment[ne]=आइआरसी चà¥à¤¯à¤¾à¤¨à¤² घटना
+Comment[nl]=IRC-kanaalgebeurtenis
+Comment[nn]=IRC-kanalhending
+Comment[nso]=Tiragalo ya kanale ya IRC
+Comment[pa]=IRC ਚੈਨਲ ਘਟਨਾ
+Comment[pl]=Zdarzenie na kanale IRC
+Comment[pt]=Evento no canal de IRC
+Comment[pt_BR]=Evento no Canal IRC
+Comment[ru]=Событие на канале IRC
+Comment[se]=IRC-kanáldáhpáhus
+Comment[sk]=IRC udalosť na kanály
+Comment[sl]=Dogodek kanala IRC
+Comment[sr]=Догађај IRC канала
+Comment[sr@Latn]=Događaj IRC kanala
+Comment[sv]=Händelse i IRC-kanal
+Comment[ta]=IRC தட நிகழà¯à®µà¯
+Comment[tg]=рӯйдодҳои канали IRC
+Comment[th]=เหตุà¸à¸²à¸£à¸“์ในห้อง IRC
+Comment[tr]=IRC kanalı olayı
+Comment[uk]=ÐŸÐ¾Ð´Ñ–Ñ Ð² каналі IRC
+Comment[ven]=Vhutambo ha channel ya IRC
+Comment[xh]=Itshanele ye IRC yesiganeko
+Comment[zh_CN]=IRC 通é“事件
+Comment[zh_HK]=IRC é »é“事件
+Comment[zh_TW]=IRC é »é“事件
+Comment[zu]=Uhlelo lweshaneli IRC
+default_presentation=1
+default_sound=KDE_Pop.ogg
+
+[ChannelPersonal]
+Name=Personal message in channel
+Name[af]=Persoonlike boodskap in kanaal
+Name[ar]=رسالة شخصية ÙÙŠ القناة
+Name[be]=Прыватнае паведамленне ў канале
+Name[bg]=ÐÑкой Ñпомена пÑевдонима ви
+Name[bn]=চà§à¦¯à¦¾à¦¨à§‡à¦²à§‡ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত বারà§à¦¤à¦¾
+Name[bs]=LiÄna poruka na kanalu
+Name[ca]=Missatge personal en el canal
+Name[cs]=Osobní zpráva v kanálu
+Name[cy]=Neges personol yn y sianel
+Name[da]=Personlig besked i kanal
+Name[de]=Persönliche Nachricht im Kanal
+Name[el]=ΠÏοσωπικό μήνυμα στο κανάλι
+Name[eo]=Persona mesaÄo en kanalo
+Name[es]=Mensaje personal en canal
+Name[et]=Erasõnum kanalis
+Name[eu]=Mezu pertsonala kanalan
+Name[fa]=پیامهای شخصی در کانال
+Name[fi]=Henkilökohtainen viesti kanavalla
+Name[fr]=Message personnel dans le canal
+Name[gl]=Mensaxe personal na canle
+Name[he]=הודעה ×ישית בערוץ
+Name[hi]=चैनल में निजी संदेश
+Name[hr]=Osobna poruka u kanalu
+Name[hu]=Személyes üzenet a csatornán
+Name[is]=Persónulegt skeyti á rás
+Name[it]=Messaggio personale nel canale
+Name[ja]=ãƒãƒ£ãƒãƒ«å†…ã®å€‹äººãƒ¡ãƒƒã‚»ãƒ¼ã‚¸
+Name[ka]=áƒáƒ áƒ®áƒ¨áƒ˜ პირáƒáƒ“ი შეტყáƒáƒ‘ინებáƒ
+Name[kk]=Ðрнада жеке хабарлама
+Name[km]=សារ​ផ្ទាល់​ážáŸ’លួន​នៅ​ក្នុង​ឆានែល
+Name[lt]=Asmeninė žinutė kanale
+Name[mk]=Лична порака на каналот
+Name[mn]=Суваг дахь хувийн илгÑÑвÑÑ€
+Name[ms]=Mesej peribadi di saluran
+Name[mt]=Messaġġ personali fil-kanal
+Name[nb]=Personlig melding i kanalen
+Name[nds]=Persöönliche Naricht in den Klöön-Kanaal
+Name[ne]=चà¥à¤¯à¤¾à¤¨à¤²à¤®à¤¾ वà¥à¤¯à¤•à¥à¤¤à¤¿à¤—त सनà¥à¤¦à¥‡à¤¶
+Name[nl]=Persoonlijk bericht in kanaal
+Name[nn]=Personleg melding i kanalen
+Name[nso]=Molaetsa wa botho kanaleng
+Name[pa]=ਚੈਨਲ ਵਿੱਚ ਨਿੱਜੀ ਸà©à¨¨à©‡à¨¹à¨¾
+Name[pl]=Wiadomość osobista na kanale
+Name[pt]=Mensagem pessoal no canal
+Name[pt_BR]=Mensagem Pessoal no canal
+Name[ru]=Получено личное Ñообщение по каналу
+Name[se]=Persuvnnalaš diehtu kanálas
+Name[sk]=Osobná správa na kanály
+Name[sl]=Osebno sporoÄilo na kanalu
+Name[sr]=Лична порука на каналу
+Name[sr@Latn]=LiÄna poruka na kanalu
+Name[sv]=Personligt meddelande i kanal
+Name[ta]=தடதà¯à®¤à®¿à®²à¯ சொநà¯à®¤ செயà¯à®¤à®¿
+Name[tg]=Паёми шахÑÓ£ дар канал
+Name[th]=ข้อความส่วนตัวในช่องสนทนา
+Name[tr]=Kanal kişisel mesajı
+Name[uk]=ПерÑональне Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð² каналі
+Name[ven]=Mulaedza wa vhune kha channel
+Name[xh]=Umyalezo ongobuqu okwi tshanele
+Name[zh_CN]=通é“中的个人消æ¯
+Name[zh_HK]=é »é“中的個人訊æ¯
+Name[zh_TW]=é »é“中的個人訊æ¯
+Name[zu]=Umlayezo wakho useshanelini
+Comment=Someone mentioned your nick on IRC
+Comment[af]=Iemand genoem jou by op Irc
+Comment[ar]=شخص ما ذكر اسمك على الايرسي
+Comment[be]=Ðехта напіÑаў вашую мÑнушку Ñž IRC
+Comment[bg]=ÐÑкой Ñпомена пÑевдонима ви
+Comment[bn]=কেউ à¦à¦•à¦œà¦¨ আই-আর-সিতে আপনার ডাকনাম উলà§à¦²à§‡à¦– করল
+Comment[bs]=Neko je spomenuo vaš nick na IRCu
+Comment[ca]=Algú a mencionat el vostre sobrenom a l'IRC
+Comment[cs]=Někdo zmínil vaši přezdívku na IRC
+Comment[cy]=Mae rhywun wedi sôn am eich ffugenw ar IRC
+Comment[da]=Nogen nævnte dit alias på IRC
+Comment[de]=Jemand hat Ihren Spitznamen im IRC erwähnt
+Comment[el]=Κάποιος ανέφεÏε το ψευδώνυμό σας στο IRC
+Comment[eo]=Iu diris vian nomon en IRC-Babilejo
+Comment[es]=Alguien mencionó su apodo en IRC
+Comment[et]=Keegi mainis sinu hüüdnime IRCs
+Comment[eu]=Norbaitek zure goitizena idatzi du IRC-an
+Comment[fa]=شخصی لقب شما را در IRC ذکر کرد
+Comment[fi]=Joku mainitsi lempinimesi IRC:ssä
+Comment[fr]=Quelqu'un a mentionné votre pseudo sur IRC
+Comment[gl]=Alguén mencionou o teu alcume no IRC
+Comment[he]=מישהו הזכיר ×ת הכינוי שלך ב-IRC
+Comment[hi]=संदेश मे किसी ने आपका निक उलà¥à¤²à¥‡à¤– किया
+Comment[hr]=Netko je spomenuo vaš nickname na IRC-u
+Comment[hu]=Valaki említette az IRC-n az Ön becenevét
+Comment[is]=Einhver minntist á þig á Irkinu
+Comment[it]=Qualcuno ha menzionato il tuo nick su IRC
+Comment[ja]=誰ã‹ãŒ IRC ã§ã‚ãªãŸã®ãƒ‹ãƒƒã‚¯ãƒãƒ¼ãƒ ã«è¨€åŠã—ã¾ã—ãŸ
+Comment[ka]=ვიღáƒáƒªáƒáƒ› áƒáƒ®áƒ¡áƒ”ნრთქვენი მეტსáƒáƒ®áƒ”ლი IRC-ზე
+Comment[kk]=IRC арнаÑында біреу Сізді атады
+Comment[km]=មាន​គáŸâ€‹áž“ិយាយ​អំពី​សម្មážáž·áž“ាម​របស់​អ្នក​នៅ​លើ IRC
+Comment[lt]=Kažkas paminėjo Jūsų slapyvardį IRC
+Comment[mk]=Ðекој го Ñпоменува вашиот прекар на IRC
+Comment[mn]=IRC-д Ñ…Ñн нÑгÑн нь таны никийг нÑрлÑв
+Comment[ms]=Seseorang melibatkan nama samaran anda di dalam IRC
+Comment[mt]=Xi ħadd semma ismek fuq l-IRC
+Comment[nb]=Noen nevnte ditt kallenavn på IRC
+Comment[nds]=Een hett Dien Ökelnaam bi't Klönen nöömt
+Comment[ne]=कसैले तपाईà¤à¤•à¥‹ आइआरसी मा उपनाम उलà¥à¤²à¥‡à¤– गरà¥à¤¯à¥‹
+Comment[nl]=Iemand noemde uw bijnaam op IRC
+Comment[nn]=Nokon nemnde kallenamnet ditt på IRC
+Comment[nso]=Yo mongwe o boletse leina la gago la metlae go IRC
+Comment[pl]=Ktoś wspomniał Twój przydomek
+Comment[pt]=Alguém mencionou o seu nome no IRC
+Comment[pt_BR]=Alguém mencionou seu apelido no IRC
+Comment[ru]=Кто-то упомÑнул ваше Ð¸Ð¼Ñ Ð² IRC
+Comment[se]=Giinu namuhii du gohÄÄodannama IRC:as
+Comment[sk]=Niekto zmenil vašu prezývku na IRC
+Comment[sl]=Nekdo je omenil vaš vzdevek na IRC-u
+Comment[sr]=Ðеко је Ñпоменуо ваш надимак на IRC-у
+Comment[sr@Latn]=Neko je spomenuo vaš nadimak na IRC-u
+Comment[sv]=Någon nämnde ditt smeknamn på IRC
+Comment[ta]=யாரோ à®’à®°à¯à®µà®°à¯ உஙà¯à®•à®³à¯ பà¯à®©à¯ˆà®ªà¯à®ªà¯†à®¯à®°à¯ˆ IRC யில௠கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿà¯à®³à¯à®³à®¾à®°à¯
+Comment[tg]=КаÑе ники шуморо дар IRC ёд овард
+Comment[th]=มีบางคนพาดพิงถึงคุณบน IRC
+Comment[tr]=IRC'de takma adınızdan söz eden birisi
+Comment[uk]=ХтоÑÑŒ згадав ваше прізвиÑько в IRC
+Comment[ven]=Munwe o bula tshikhethekanyi kha IRC yanu
+Comment[xh]=Omnye umntu uchaze igama lakho lesiteketiso kwi-IRC
+Comment[zh_CN]=有人在 IRC 中æ到了您的昵称
+Comment[zh_HK]=æŸäººåœ¨ IRC æ到您的暱稱
+Comment[zh_TW]=æŸäººåœ¨ IRC æ到您的暱稱
+Comment[zu]=kukhona osho igama lakho lokudlala kwi IRC
+default_presentation=1
+default_sound=KDE_Beep.ogg
+
+[BeepReceived]
+Name=Beep received
+Name[be]=Ðтрыманы Ñігнал
+Name[bg]=Звуков Ñигнал
+Name[bn]=বিপ গà§à¦°à¦¹à¦£ করল
+Name[bs]=Primljen beep
+Name[ca]=S'ha rebut un bip
+Name[cs]=Obdrženo pípnutí
+Name[da]=Lydsignal modtaget
+Name[de]=Signalton empfangen
+Name[el]=ΠαÏαλαβή ηχητικής ειδοποίησης
+Name[eo]=Hupo ricevita
+Name[es]=Pitido recibido
+Name[et]=Saabus piiks
+Name[eu]=Bip-a jaso da
+Name[fa]=بوق دریاÙت شد
+Name[fr]=Bip reçu
+Name[ga]=Fuarthas bíp
+Name[gl]=Recibiuse unha badalada
+Name[he]=התקבל ביפ
+Name[hu]=Csipogás érkezett
+Name[is]=Hljóðmerki móttekið
+Name[it]=Ricevuto un bip
+Name[ja]=呼ã³å‡ºã—ã‚’å—ã‘ã¾ã—ãŸ
+Name[ka]=შეტყáƒáƒ‘ინებრმáƒáƒ•áƒ˜áƒ“áƒ
+Name[kk]=Қоңырау Ñоғылды
+Name[km]=បាន​ទទួល​សំឡáŸáž„​ប៊ីប
+Name[lt]=Gautas skambutis
+Name[nb]=Tut mottat
+Name[nds]=Signaaltoon kregen
+Name[ne]=बीप पà¥à¤°à¤¾à¤ªà¥à¤¤ भयो
+Name[nl]=Geluidsignaal ontvangen
+Name[nn]=Pip motteke
+Name[pl]=Otrzymano brzęczyk
+Name[pt]=Apito recebido
+Name[pt_BR]=Beep recebido
+Name[ru]=Получен Ñигнал
+Name[sk]=Prijaté pípnutie
+Name[sl]=Prejet pisk
+Name[sr]=Примљен је бип
+Name[sr@Latn]=Primljen je bip
+Name[sv]=Ljudsignal mottagen
+Name[tr]=Zil alındı
+Name[uk]=Отримано гудок
+Name[zh_CN]=收到了呼å«
+Name[zh_HK]=收到響è²
+Name[zh_TW]=收到嗶è²
+Comment=A beep has been received from the server
+Comment[be]=Ðтрыманы Ñігнал ад Ñервера
+Comment[bg]=ПриÑтигна звуков Ñигнал от Ñървъра
+Comment[bn]=সারà§à¦­à¦¾à¦° থেকে à¦à¦•à¦Ÿà¦¿ বিপ গà§à¦°à¦¹à¦£ করা হয়েছে
+Comment[bs]=Primljen je beep sa servera
+Comment[ca]=S'ha rebut un bip des del servidor
+Comment[cs]=Bylo obdrženo pípnutí ze serveru
+Comment[da]=Et lydsignal er modtaget fra serveren.
+Comment[de]=Von diesem Server wurde ein Signalton empfangen.
+Comment[el]=Μια ηχητική ειδοποίηση παÏαλήφθηκε από τον εξυπηÏετητή
+Comment[es]=Se ha recibido un pitido del servidor
+Comment[et]=Serverilt saabus piiks
+Comment[eu]=Bip bat jaso da zerbitzaritik
+Comment[fa]=یک بوق از کارساز دریاÙت شد
+Comment[fr]=Un bip a été reçu du serveur
+Comment[gl]=Recibiuse unha badalada dende o servidor
+Comment[he]=התקבל ביפ מהשרת
+Comment[hu]=Csipogás érkezett a kiszolgálóról
+Comment[is]=Hljóðmerki hefur verið móttekið frá þjóninum
+Comment[it]=È stato ricevuto un bip dal server
+Comment[ja]=サーãƒã‹ã‚‰å‘¼ã³å‡ºã—ã‚’å—ã‘ã¾ã—ãŸ
+Comment[ka]=სერვერიდáƒáƒœ შეტყáƒáƒ‘ინებრმáƒáƒ•áƒ˜áƒ“áƒ
+Comment[kk]=Серверден қоңырау келді
+Comment[km]=បាន​ទទួល​សំឡáŸáž„​ប៊ីប​មួយ​ពី​ម៉ាស៊ីន​បម្រើ
+Comment[lt]=IÅ¡ serverio gautas skambutis
+Comment[nb]=Et tut er mottatt fra tjeneren
+Comment[nds]=Signaaltoon vun den Server kregen
+Comment[ne]=सरà¥à¤­à¤°à¤¬à¤¾à¤Ÿ बीप पà¥à¤°à¤¾à¤ªà¥à¤¤ भयो
+Comment[nl]=Geluidssignaal van de server ontvangen
+Comment[nn]=Eit pip vart motteke frå tenaren
+Comment[pl]=Otrzymano brzęczyk z serwera
+Comment[pt]=Foi recebido um apito do servidor
+Comment[pt_BR]=Um beep foi recebido do servidor
+Comment[ru]=Получен звуковой Ñигнал Ñ Ñервера
+Comment[sk]=Prijalo sa pípnutie zo servera
+Comment[sl]=Od strežnika ste prejeli pisk
+Comment[sr]=Звучни Ñигнал је примљен Ñа Ñервера
+Comment[sr@Latn]=ZvuÄni signal je primljen sa servera
+Comment[sv]=En ljudsignal har tagits emot från servern
+Comment[tr]=Sunucudan bir bip alındı
+Comment[uk]=Отримано гудок з Ñервера
+Comment[zh_CN]=收到了æœåŠ¡å™¨çš„呼å«
+Comment[zh_HK]=從伺æœå™¨æ”¶åˆ°éŸ¿è²
+Comment[zh_TW]=從伺æœå™¨ä¸Šæ”¶åˆ°å—¶è²
+default_presentation=1
+default_sound=KDE_Beep.ogg
+
diff --git a/ksirc/filters.pl b/ksirc/filters.pl
new file mode 100644
index 00000000..f7359714
--- /dev/null
+++ b/ksirc/filters.pl
@@ -0,0 +1,171 @@
+#
+# Structure format is:
+# $var[filter_number]{field}
+#
+# Defined fields: (* is required)
+# SEARCH(*): search filter
+# FROM(*): intput to subtitution regex
+# TO(*): resultant to substitution regex
+# DESC: description of filter rule
+#
+
+$#KSIRC_FILTER = 0;
+
+print "*** Loading filter parser...\n";
+
+$ksirc_dump = 0;
+
+sub hook_ksircfilter {
+ my($i) = 0;
+ for(; $i <= $#KSIRC_FILTER; $i++){
+ eval{
+ if($_[0] =~ m/$KSIRC_FILTER[$i]{'SEARCH'}/){
+ $_[0] =~ s/$KSIRC_FILTER[$i]{'FROM'}/$KSIRC_FILTER[$i]{'TO'}/eeg;
+ }
+ };
+ if ( $@ ){
+ (my $error = $@ ) =~ s/before HERE.*//;
+ my $desc = $KSIRC_FILTER[$i]{'DESC'};
+ splice(@KSIRC_FILTER, $i--, 1);
+ &tell("*\cbE\cb* Filter $desc disabled due to error: $error");
+ }
+ }
+}
+
+print "*** Filter Parser Loaded\n";
+
+addhook("print", "ksircfilter");
+
+sub cmd_ksircprintrule {
+ my($i) = 0;
+ for(; $i <= $#KSIRC_FILTER; $i++){
+ print STDOUT "*** Rule $i " . $KSIRC_FILTER[$i]{DESC} . ": if ". $KSIRC_FILTER[$i]{SEARCH} . " then ". $KSIRC_FILTER[$i]{FROM} . " -> " . $KSIRC_FILTER[$i]{TO} . "\n";
+ }
+}
+
+addcmd("ksircprintrule");
+&docommand("^alias prule ksircprintrule");
+
+#
+# Addrule command takes 4 or arguments seperated by " key==value !!! key2==value2 ||| etc"
+# 1. Name of rule
+# 2. Pattern to search for
+# 3. Substitution to take
+# 4. Sub to make
+
+sub cmd_ksircappendrule {
+ my($rule, %PARSED);
+ foreach $rule (split(/ !!! /, $args)){
+ my($key,$value) = split(/==/, $rule);
+ $PARSED{$key} = $value;
+ }
+ if($PARSED{'DESC'} && $PARSED{'SEARCH'} && $PARSED{'FROM'} && $PARSED{'TO'}){
+ my($i) = $#KSIRC_FILTER + 1;
+ my($key, $value);
+ while(($key, $value) = each %PARSED){
+ $KSIRC_FILTER[$i]{$key} = $value;
+ }
+# &tell("*** Added rule: " . $KSIRC_FILTER[$i]{'DESC'} . "\n");
+ }
+ else{
+ print "*E* Parse Error in Rule, format is: name !!! search !!! from !!! to\n";
+ }
+}
+
+addcmd("ksircappendrule");
+&docommand("^alias arule ksircappendrule");
+
+sub cmd_ksircclearrule {
+ @KSIRC_FILTER = ();
+# &tell("*** ALL FILTER RULES ERASED - DEFAULTS ADDED\n");
+}
+
+&addcmd("ksircclearrule");
+&docommand("^alias crule ksircclearrule");
+&docommand("^crule");
+
+sub cmd_ksircdelrule {
+ if($args =~ /^\d+$/){
+ splice(@KSIRC_FILTER, $args, 1);
+ print STDOUT "*** Deleted rule: $args\n";
+ }
+ else {
+ print STDOUT "*E* Syntax is ksircdelrule <rule number>\n";
+ }
+}
+
+&addcmd("ksircdelrule");
+&docommand("^alias drule ksircdelrule");
+
+sub hook_pong_lag {
+ if($_[0] =~ /.*:LAG ([0-9.]+)/){
+ my($_l) = $1;
+ my($_t) = kgettimeofday();
+ $_t -= $_l;
+ #print "*** Diff: $_t\n";
+ print "~!lag~*L* " . $_t . "\n";
+ }
+}
+
+&addhook("pong", "pong_lag");
+
+sub cmd_lag {
+ my($_t) = kgettimeofday();
+ # &docommand("^ctcp $nick LAG $_t");
+ &docommand("^quote PING :LAG $_t");
+ my $c;
+ foreach $c (@channels){
+ if($WHO_IGNORE{uc("$c")} != 1){
+ &docommand("^extnames $c");
+ }
+ }
+}
+
+
+eval {
+require 'sys/syscall.ph';
+};
+
+if(! defined(&SYS_gettimeofday)){
+ if(open(SYSCALL, "/usr/include/sys/syscall.h")){
+ my(@line) = grep(/define\s+SYS_gettimeofday/, <SYSCALL>);
+ close SYSCALL;
+ print "*E* Strange syscall.h, SYS_gettimeofday defined more than once!\n" if $#line > 1;
+ my($line) = "@line";
+ if($line =~ /SYS_gettimeofday\s+(\d+)/){
+ eval "sub SYS_gettimeofday () {$1;}";
+ print "*** Set time of day to: $1\n";
+ }
+ }
+
+ if(! defined(&SYS_gettimeofday)){
+ eval 'sub SYS_gettimeofday () {78;}';
+ print "*E* Unable to find SYS_gettimeofday, using LINUX default!\n";
+ }
+}
+
+
+sub kgettimeofday {
+ local($failed) = 0;
+ local($TIMEVAL_T) = "LL";
+ local($start) = pack($TIMEVAL_T, ());
+ eval{
+ (syscall( &SYS_gettimeofday, $start, 0) != -1) or $failed = 1;
+ };
+ if(!$failed){
+ my(@start) = unpack($TIMEVAL_T, $start);
+ $start[1] /= 1000000;
+ return $start[0] + $start[1];
+ }
+ else {
+ return time();
+ }
+}
+
+&addcmd("lag");
+
+sub hook_ksirc_notify_connected {
+ &print('~!all~`#ssfe#R reconnected');
+}
+
+&addhook("376", "ksirc_notify_connected"); # join on the "end of MOTD"
diff --git a/ksirc/getdate.c b/ksirc/getdate.c
new file mode 100644
index 00000000..a0ccb561
--- /dev/null
+++ b/ksirc/getdate.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <time.h>
+
+int main() {
+ printf("#define COMPILE_DATE %d\n", (int) time(NULL));
+ return 0;
+}
diff --git a/ksirc/icons/Makefile.am b/ksirc/icons/Makefile.am
new file mode 100644
index 00000000..6cebb136
--- /dev/null
+++ b/ksirc/icons/Makefile.am
@@ -0,0 +1,5 @@
+# Directory where to install them
+ksircicondir = $(kde_datadir)/ksirc/icons
+ksircicon_ICON = AUTO
+
+KDE_ICON = ksirc
diff --git a/ksirc/icons/X.png b/ksirc/icons/X.png
new file mode 100644
index 00000000..382679c1
--- /dev/null
+++ b/ksirc/icons/X.png
Binary files differ
diff --git a/ksirc/icons/cr22-action-info.png b/ksirc/icons/cr22-action-info.png
new file mode 100644
index 00000000..3626ba7e
--- /dev/null
+++ b/ksirc/icons/cr22-action-info.png
Binary files differ
diff --git a/ksirc/icons/cr22-action-ksirc_dock.png b/ksirc/icons/cr22-action-ksirc_dock.png
new file mode 100644
index 00000000..34704755
--- /dev/null
+++ b/ksirc/icons/cr22-action-ksirc_dock.png
Binary files differ
diff --git a/ksirc/icons/ctcpping.png b/ksirc/icons/ctcpping.png
new file mode 100644
index 00000000..23ace0f1
--- /dev/null
+++ b/ksirc/icons/ctcpping.png
Binary files differ
diff --git a/ksirc/icons/error.png b/ksirc/icons/error.png
new file mode 100644
index 00000000..a2b60e4d
--- /dev/null
+++ b/ksirc/icons/error.png
Binary files differ
diff --git a/ksirc/icons/hi16-app-ksirc.png b/ksirc/icons/hi16-app-ksirc.png
new file mode 100644
index 00000000..b29cb89a
--- /dev/null
+++ b/ksirc/icons/hi16-app-ksirc.png
Binary files differ
diff --git a/ksirc/icons/hi22-app-ksirc.png b/ksirc/icons/hi22-app-ksirc.png
new file mode 100644
index 00000000..637db592
--- /dev/null
+++ b/ksirc/icons/hi22-app-ksirc.png
Binary files differ
diff --git a/ksirc/icons/hi32-app-ksirc.png b/ksirc/icons/hi32-app-ksirc.png
new file mode 100644
index 00000000..05068df6
--- /dev/null
+++ b/ksirc/icons/hi32-app-ksirc.png
Binary files differ
diff --git a/ksirc/icons/hi48-app-ksirc.png b/ksirc/icons/hi48-app-ksirc.png
new file mode 100644
index 00000000..025b2e2f
--- /dev/null
+++ b/ksirc/icons/hi48-app-ksirc.png
Binary files differ
diff --git a/ksirc/icons/hi64-app-ksirc.png b/ksirc/icons/hi64-app-ksirc.png
new file mode 100644
index 00000000..3f88f7f4
--- /dev/null
+++ b/ksirc/icons/hi64-app-ksirc.png
Binary files differ
diff --git a/ksirc/img/Makefile.am b/ksirc/img/Makefile.am
new file mode 100644
index 00000000..fdd16a3e
--- /dev/null
+++ b/ksirc/img/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = emoticons
+
+# List of files to install
+emo_DATA = server.xpm channel.xpm channels.xpm \
+ ksirc_a.xpm ksirc_b.xpm \
+ arrow.png greenpin.png madsmiley.png smiley.png sadsmiley.png \
+ blueball.png star.png bluepin.png info.png info1.png \
+ mini-run.png ksirc.png sdi.png mdi.png \
+ dcc.png kick.png mode.png quit.png \
+ X.png dccget.png minus.png notice.png servinfo.png \
+ action.png dccsend.png ominus.png topic.png \
+ bminus.png elipsis.png oplus.png \
+ bplus.png error.png part.png \
+ ctcpping.png join.png plus.png
+
+# Directory where to install them
+emodir = $(kde_datadir)/ksirc/pics
+
diff --git a/ksirc/img/X.png b/ksirc/img/X.png
new file mode 100644
index 00000000..acc082dd
--- /dev/null
+++ b/ksirc/img/X.png
Binary files differ
diff --git a/ksirc/img/action.png b/ksirc/img/action.png
new file mode 100644
index 00000000..5b5463cb
--- /dev/null
+++ b/ksirc/img/action.png
Binary files differ
diff --git a/ksirc/img/arrow.png b/ksirc/img/arrow.png
new file mode 100644
index 00000000..a24c7cc7
--- /dev/null
+++ b/ksirc/img/arrow.png
Binary files differ
diff --git a/ksirc/img/blueball.png b/ksirc/img/blueball.png
new file mode 100644
index 00000000..308ef21f
--- /dev/null
+++ b/ksirc/img/blueball.png
Binary files differ
diff --git a/ksirc/img/bluepin.png b/ksirc/img/bluepin.png
new file mode 100644
index 00000000..4117235b
--- /dev/null
+++ b/ksirc/img/bluepin.png
Binary files differ
diff --git a/ksirc/img/bminus.png b/ksirc/img/bminus.png
new file mode 100644
index 00000000..b1baa0e0
--- /dev/null
+++ b/ksirc/img/bminus.png
Binary files differ
diff --git a/ksirc/img/bplus.png b/ksirc/img/bplus.png
new file mode 100644
index 00000000..169cc218
--- /dev/null
+++ b/ksirc/img/bplus.png
Binary files differ
diff --git a/ksirc/img/channel.xpm b/ksirc/img/channel.xpm
new file mode 100644
index 00000000..fdd11fe2
--- /dev/null
+++ b/ksirc/img/channel.xpm
@@ -0,0 +1,36 @@
+/* XPM */
+static char * people_xpm[] = {
+"24 24 9 1",
+" c None",
+". c #000000",
+"+ c #0000FF",
+"@ c #00C300",
+"# c #0000C0",
+"$ c #00C000",
+"% c #008000",
+"& c #FF0000",
+"* c #C00000",
+" .... .... ",
+" .++++. .@@@@. ",
+" .+++++#. .@$$$$%. ",
+" .+.++.#. .@.$$.%. ",
+" .+.++.#. .@.$$.%. ",
+" .+++++#. .... .@$$$$%. ",
+" .####. .&&&&. .%%%%. ",
+" .... .&&&&&*. .... ",
+" .++++..&.&&.*..@@@@. ",
+" .+++++#.&.&&.*.@$$$$%. ",
+" .+++++#.&&&&&*.@$$$$%. ",
+" .+++++#..****..@$$$$%. ",
+" .+++++#. .... .@$$$$%. ",
+" .+++++#..&&&&..@$$$$%. ",
+" .+++++#.&&&&&*.@$$$$%. ",
+" .+++++#.&&&&&*.@$$$$%. ",
+" .+++++#.&&&&&*.@$$$$%. ",
+" .+++++#.&&&&&*.@$$$$%. ",
+" .+++++#.&&&&&*.@$$$$%. ",
+" .+++++#.&&&&&*.@$$$$%. ",
+" .######.&&&&&*.%%%%%%. ",
+" .......&&&&&*....... ",
+" .******. ",
+" ........ "};
diff --git a/ksirc/img/channels.xpm b/ksirc/img/channels.xpm
new file mode 100644
index 00000000..cf0c4020
--- /dev/null
+++ b/ksirc/img/channels.xpm
@@ -0,0 +1,60 @@
+/* XPM */
+static char *channels[]={
+"22 22 35 1",
+". c None",
+"E c #3b200a",
+"D c #402611",
+"y c #523418",
+"w c #572c07",
+"d c #585858",
+"B c #592d08",
+"t c #5e513e",
+"x c #6bb0af",
+"g c #6e6c6e",
+"G c #6f6d6f",
+"e c #706e70",
+"s c #714d2b",
+"j c #757375",
+"m c #75b4b4",
+"k c #777477",
+"i c #777577",
+"r c #7e6f58",
+"l c #88bdbc",
+"C c #92c1c0",
+"F c #939393",
+"c c #949394",
+"b c #949494",
+"a c #969696",
+"o c #9e9e9e",
+"n c #a0a0a0",
+"h c #bebbf4",
+"# c #c3c3c3",
+"f c #c7c3ff",
+"A c #d16810",
+"z c #d17c31",
+"v c #e18a3c",
+"u c #f1c38c",
+"p c #f4bbf4",
+"q c #ffc3ff",
+"......................",
+"......................",
+"......................",
+"......................",
+".#abbbbbc#............",
+".addddddde............",
+".bdfffffdg............",
+".bdfffffdg............",
+".bdfffffdg............",
+".bdhhhhhdg............",
+".bdddddddg............",
+".#ijjjjjk#............",
+"....lm................",
+"....lm......#noooooo#.",
+"....lm......bdddddddg.",
+"....lm......bdpppqpdg.",
+"....rs......bdqqqqqdg.",
+"...tuvwxxxxxbdqqqqqdg.",
+"...yzABCCCCCbdqqqqqdg.",
+"....DE......FdddddddG.",
+"............#egggggG#.",
+"......................"};
diff --git a/ksirc/img/ctcpping.png b/ksirc/img/ctcpping.png
new file mode 100644
index 00000000..0164dffa
--- /dev/null
+++ b/ksirc/img/ctcpping.png
Binary files differ
diff --git a/ksirc/img/dcc.png b/ksirc/img/dcc.png
new file mode 100644
index 00000000..038bdca2
--- /dev/null
+++ b/ksirc/img/dcc.png
Binary files differ
diff --git a/ksirc/img/dccget.png b/ksirc/img/dccget.png
new file mode 100644
index 00000000..27539e0b
--- /dev/null
+++ b/ksirc/img/dccget.png
Binary files differ
diff --git a/ksirc/img/dccsend.png b/ksirc/img/dccsend.png
new file mode 100644
index 00000000..dbc183b6
--- /dev/null
+++ b/ksirc/img/dccsend.png
Binary files differ
diff --git a/ksirc/img/elipsis.png b/ksirc/img/elipsis.png
new file mode 100644
index 00000000..09d0e8af
--- /dev/null
+++ b/ksirc/img/elipsis.png
Binary files differ
diff --git a/ksirc/img/emoticons/Makefile.am b/ksirc/img/emoticons/Makefile.am
new file mode 100644
index 00000000..5e68be4a
--- /dev/null
+++ b/ksirc/img/emoticons/Makefile.am
@@ -0,0 +1,5 @@
+
+emodir = $(kde_datadir)/ksirc/pics/emoticons
+emo_DATA = biggrin.png clown.png cry.png devil.png frown.png \
+ heart.png loveit.png puh.png puh2.png redface.png sadley.png \
+ slime.png smile.png wink.png yummie.png
diff --git a/ksirc/img/emoticons/biggrin.png b/ksirc/img/emoticons/biggrin.png
new file mode 100644
index 00000000..b560b7ba
--- /dev/null
+++ b/ksirc/img/emoticons/biggrin.png
Binary files differ
diff --git a/ksirc/img/emoticons/clown.png b/ksirc/img/emoticons/clown.png
new file mode 100644
index 00000000..c6d78469
--- /dev/null
+++ b/ksirc/img/emoticons/clown.png
Binary files differ
diff --git a/ksirc/img/emoticons/cry.png b/ksirc/img/emoticons/cry.png
new file mode 100644
index 00000000..c2bf24da
--- /dev/null
+++ b/ksirc/img/emoticons/cry.png
Binary files differ
diff --git a/ksirc/img/emoticons/devil.png b/ksirc/img/emoticons/devil.png
new file mode 100644
index 00000000..2024b36c
--- /dev/null
+++ b/ksirc/img/emoticons/devil.png
Binary files differ
diff --git a/ksirc/img/emoticons/frown.png b/ksirc/img/emoticons/frown.png
new file mode 100644
index 00000000..1086d6b7
--- /dev/null
+++ b/ksirc/img/emoticons/frown.png
Binary files differ
diff --git a/ksirc/img/emoticons/heart.png b/ksirc/img/emoticons/heart.png
new file mode 100644
index 00000000..8f453cb6
--- /dev/null
+++ b/ksirc/img/emoticons/heart.png
Binary files differ
diff --git a/ksirc/img/emoticons/loveit.png b/ksirc/img/emoticons/loveit.png
new file mode 100644
index 00000000..e99f0921
--- /dev/null
+++ b/ksirc/img/emoticons/loveit.png
Binary files differ
diff --git a/ksirc/img/emoticons/puh.png b/ksirc/img/emoticons/puh.png
new file mode 100644
index 00000000..54a9dba1
--- /dev/null
+++ b/ksirc/img/emoticons/puh.png
Binary files differ
diff --git a/ksirc/img/emoticons/puh2.png b/ksirc/img/emoticons/puh2.png
new file mode 100644
index 00000000..4fade60e
--- /dev/null
+++ b/ksirc/img/emoticons/puh2.png
Binary files differ
diff --git a/ksirc/img/emoticons/redface.png b/ksirc/img/emoticons/redface.png
new file mode 100644
index 00000000..8d1872e7
--- /dev/null
+++ b/ksirc/img/emoticons/redface.png
Binary files differ
diff --git a/ksirc/img/emoticons/sadley.png b/ksirc/img/emoticons/sadley.png
new file mode 100644
index 00000000..6fd82d98
--- /dev/null
+++ b/ksirc/img/emoticons/sadley.png
Binary files differ
diff --git a/ksirc/img/emoticons/slime.png b/ksirc/img/emoticons/slime.png
new file mode 100644
index 00000000..1b515eb5
--- /dev/null
+++ b/ksirc/img/emoticons/slime.png
Binary files differ
diff --git a/ksirc/img/emoticons/smile.png b/ksirc/img/emoticons/smile.png
new file mode 100644
index 00000000..bd4ee806
--- /dev/null
+++ b/ksirc/img/emoticons/smile.png
Binary files differ
diff --git a/ksirc/img/emoticons/wink.png b/ksirc/img/emoticons/wink.png
new file mode 100644
index 00000000..727c9bdc
--- /dev/null
+++ b/ksirc/img/emoticons/wink.png
Binary files differ
diff --git a/ksirc/img/emoticons/yummie.png b/ksirc/img/emoticons/yummie.png
new file mode 100644
index 00000000..4cad21a3
--- /dev/null
+++ b/ksirc/img/emoticons/yummie.png
Binary files differ
diff --git a/ksirc/img/error.png b/ksirc/img/error.png
new file mode 100644
index 00000000..3809edbf
--- /dev/null
+++ b/ksirc/img/error.png
Binary files differ
diff --git a/ksirc/img/greenpin.png b/ksirc/img/greenpin.png
new file mode 100644
index 00000000..ac8a7622
--- /dev/null
+++ b/ksirc/img/greenpin.png
Binary files differ
diff --git a/ksirc/img/info.png b/ksirc/img/info.png
new file mode 100644
index 00000000..b0da7ff5
--- /dev/null
+++ b/ksirc/img/info.png
Binary files differ
diff --git a/ksirc/img/info1.png b/ksirc/img/info1.png
new file mode 100644
index 00000000..41c0d7f0
--- /dev/null
+++ b/ksirc/img/info1.png
Binary files differ
diff --git a/ksirc/img/join.png b/ksirc/img/join.png
new file mode 100644
index 00000000..d80b36a6
--- /dev/null
+++ b/ksirc/img/join.png
Binary files differ
diff --git a/ksirc/img/kick.png b/ksirc/img/kick.png
new file mode 100644
index 00000000..ef8501f5
--- /dev/null
+++ b/ksirc/img/kick.png
Binary files differ
diff --git a/ksirc/img/ksirc.png b/ksirc/img/ksirc.png
new file mode 100644
index 00000000..0a9a902e
--- /dev/null
+++ b/ksirc/img/ksirc.png
Binary files differ
diff --git a/ksirc/img/ksirc_a.xpm b/ksirc/img/ksirc_a.xpm
new file mode 100644
index 00000000..79286a2d
--- /dev/null
+++ b/ksirc/img/ksirc_a.xpm
@@ -0,0 +1,46 @@
+/* XPM */
+static char * ksirc2_xpm[] = {
+"32 32 11 1",
+" c None",
+". c #303030",
+"+ c #00FF00",
+"@ c #008200",
+"# c #0000FF",
+"$ c #00C300",
+"% c #0000C7",
+"& c #000086",
+"* c #000000",
+"= c #FFFF00",
+"- c #C7C300",
+" ....... ",
+" ..++++++@.. ",
+" .++++++++###. ",
+" .#++++++$@####. ",
+" .##+++++++$@####. ",
+" .###@++++++$@#####. ",
+" .$###+++$$+@#####+. ",
+" .#$###@+$@#$######$#. ",
+" .$@####@+##########@. ",
+" .%######@$@########%. ",
+" .%%########@######%%. ",
+" .%%%#######+$$###%%%. ",
+" .&%%%#####$+++$%%%%&. ",
+" .&$%%%%%##@$++$#%%%&. ",
+" .&$@%%%%%%&$$@%%%&. ",
+" .&&@%%%%%%@$@%%%&&. ",
+" .&&%%%%%%$@%%%&&. ",
+" *****&&&%%@@%%&&&***** ",
+" **=====**&&&&&&&&**=====** ",
+" *=========*&&&&&&*=========* ",
+" *===========*....*===========* ",
+" *=========*=* *==*=====*==* ",
+"*-========**==* *==**=====**==*",
+"*-========**==* *==*=======*==*",
+"*-============* *=============*",
+"*-============* *=============*",
+"*-=======*====* *===*=====.===*",
+" *-======***** *-==*===.===* ",
+" *-======* *-===*..===-* ",
+" *--====-* *--=====--* ",
+" **-----* **-----** ",
+" ***** ***** "};
diff --git a/ksirc/img/ksirc_b.xpm b/ksirc/img/ksirc_b.xpm
new file mode 100644
index 00000000..1741d641
--- /dev/null
+++ b/ksirc/img/ksirc_b.xpm
@@ -0,0 +1,48 @@
+/* XPM */
+static char * ksirc_xpm[] = {
+"32 32 13 1",
+" c None",
+". c #303030",
+"+ c #00FF00",
+"@ c #008200",
+"# c #0000FF",
+"$ c #00C300",
+"% c #0000C7",
+"& c #000086",
+"* c #000000",
+"= c #DFDFDF",
+"- c #A6A2A6",
+"; c #C7C3FF",
+"> c #FFC3FF",
+" ....... ",
+" ..++++++@.. ",
+" .++++++++###. ",
+" .#++++++$@####. ",
+" .##+++++++$@####. ",
+" .###@++++++$@#####. ",
+" .$###+++$$+@#####+. ",
+" .#$###@+$@#$######$#. ",
+" .$@####@+##########@. ",
+" .%######@$@########%. ",
+" .%%########@######%%. ",
+" .%%%#######+$$###%%%. ",
+" .&%%%#####$+++$%%%%&. ",
+" .&$%%%%%##@$++$#%%%&. ",
+" .&$@%%%%%%&$$@%%%&. ",
+" .&&@%%%%%%@$@%%%&&. ",
+" .&&%%%%%%$@%%%&&. ",
+" .&&&&%%@@%&&&&. ",
+" .&&&&&&&&&&&. ",
+" ..&&&&&&&.. ",
+" ********* ....... ********* ",
+" *========-* *========-* ",
+" *=*******-* *=*******-* ",
+" *=*;;;;;*-* *=*>>>>>*-* ",
+" *=*;;;;;*-* *=*>>>>>*-* ",
+" *=*;;;;;*-* *=*>>>>>*-* ",
+" *=*******-* *=*******-* ",
+" *---------* *---------* ",
+" *********** *********** ",
+"*==========-* *==========-* ",
+"*-----------* *-----------* ",
+" *********** *********** "};
diff --git a/ksirc/img/ksirc_dock.png b/ksirc/img/ksirc_dock.png
new file mode 100644
index 00000000..bcc6ec8f
--- /dev/null
+++ b/ksirc/img/ksirc_dock.png
Binary files differ
diff --git a/ksirc/img/ksirc_dock.xpm b/ksirc/img/ksirc_dock.xpm
new file mode 100644
index 00000000..802b8927
--- /dev/null
+++ b/ksirc/img/ksirc_dock.xpm
@@ -0,0 +1,192 @@
+/* XPM */
+static char * ksirc_dock_xpm[] = {
+"22 22 167 2",
+" c None",
+". c #DD3232",
+"+ c #E03333",
+"@ c #C01111",
+"# c #810000",
+"$ c #E03535",
+"% c #FEA8A8",
+"& c #FE7C7C",
+"* c #EE5050",
+"= c #B01313",
+"- c #E03D3D",
+"; c #FF7C7C",
+"> c #FF7E7E",
+", c #F97878",
+"' c #C03636",
+") c #C42525",
+"! c #F25959",
+"~ c #F97171",
+"{ c #EB7070",
+"] c #A33131",
+"^ c #AC1F1F",
+"/ c #B82B2B",
+"( c #982626",
+"_ c #560E0E",
+": c #2E2F2F",
+"< c #1F2020",
+"[ c #1B1C1C",
+"} c #080808",
+"| c #2C2C2C",
+"1 c #737373",
+"2 c #505050",
+"3 c #515151",
+"4 c #292929",
+"5 c #030305",
+"6 c #121B6B",
+"7 c #232430",
+"8 c #525252",
+"9 c #5F5F5F",
+"0 c #696969",
+"a c #555553",
+"b c #0E1128",
+"c c #142081",
+"d c #162391",
+"e c #14228F",
+"f c #16228F",
+"g c #131F89",
+"h c #09156F",
+"i c #1D299A",
+"j c #5058BF",
+"k c #5E66CA",
+"l c #152084",
+"m c #1F2134",
+"n c #575757",
+"o c #676767",
+"p c #717171",
+"q c #5C5C5B",
+"r c #0E0F1F",
+"s c #0C1358",
+"t c #0D1565",
+"u c #0C1564",
+"v c #0E1665",
+"w c #0C1460",
+"x c #060D4C",
+"y c #18249B",
+"z c #4D54BC",
+"A c #3E46AA",
+"B c #0D177A",
+"C c #000859",
+"D c #242633",
+"E c #606060",
+"F c #6F6F6F",
+"G c #797979",
+"H c #0C0C0C",
+"I c #02117B",
+"J c #1D29A1",
+"K c #232D9F",
+"L c #030F7B",
+"M c #000952",
+"N c #2E2E2F",
+"O c #666665",
+"P c #747474",
+"Q c #7E7E7E",
+"R c #626262",
+"S c #0D0D0D",
+"T c #192599",
+"U c #0C166F",
+"V c #01107E",
+"W c #111E97",
+"X c #0A1A98",
+"Y c #000F77",
+"Z c #343434",
+"` c #787878",
+" . c #818181",
+".. c #0B0B0B",
+"+. c #11209C",
+"@. c #0E1877",
+"#. c #010634",
+"$. c #000E70",
+"%. c #0C1A8E",
+"&. c #1724A6",
+"*. c #091A9A",
+"=. c #353433",
+"-. c #6B6B69",
+";. c #838382",
+">. c #61605F",
+",. c #0A0A09",
+"'. c #1728AE",
+"). c #1726A2",
+"!. c #09136C",
+"~. c #010635",
+"{. c #000B56",
+"]. c #020F75",
+"^. c #19259A",
+"/. c #404BCC",
+"(. c #3846C8",
+"_. c #222A84",
+":. c #2E325D",
+"<. c #585C79",
+"[. c #666A83",
+"}. c #6E728A",
+"|. c #4E5372",
+"1. c #12195B",
+"2. c #1F2EAE",
+"3. c #2B39C2",
+"4. c #1C2797",
+"5. c #060F5E",
+"6. c #000A58",
+"7. c #020E6F",
+"8. c #242E95",
+"9. c #6B74C8",
+"0. c #8089E1",
+"a. c #737EE1",
+"b. c #6D78DF",
+"c. c #6874DD",
+"d. c #6470DD",
+"e. c #5865DD",
+"f. c #4753D3",
+"g. c #323DB3",
+"h. c #131C78",
+"i. c #010846",
+"j. c #000842",
+"k. c #010A58",
+"l. c #0D1369",
+"m. c #1E2478",
+"n. c #293484",
+"o. c #313B8C",
+"p. c #323D90",
+"q. c #313C91",
+"r. c #212D89",
+"s. c #0F176E",
+"t. c #050B51",
+"u. c #121739",
+"v. c #24294F",
+"w. c #252B55",
+"x. c #292F58",
+"y. c #1D2143",
+"z. c #020416",
+"A. c #1E1E1D",
+"B. c #4A4A49",
+"C. c #585858",
+"D. c #5D5D5D",
+"E. c #353534",
+"F. c #030303",
+"G. c #1D1D1D",
+"H. c #262626",
+"I. c #242424",
+"J. c #0E0E0E",
+" ",
+" . + @ # ",
+" $ % & * = ",
+" - ; > , ' ",
+" ) ! ~ { ] ",
+" ^ / ( _ ",
+" ",
+" : < [ } ",
+" | 1 2 3 4 5 ",
+" 6 7 8 9 0 a b c d e f g h ",
+" i j k l m n o p q r s t u v w x ",
+" y z A B C D E F G 9 H ",
+" I J K L M N O P Q R S T U ",
+" V W X Y Z 0 ` .R .. +.@.#. ",
+" $.%.&.*. =.-.G ;.>.,. '.).!.~. ",
+" {.].^./.(._.:.<.[.}.|.1.2.3.4.5. ",
+" 6.7.8.9.0.a.b.c.d.e.f.g.h.i. ",
+" j.k.l.m.n.o.p.q.r.s.t. ",
+" u.v.w.x.y.z. ",
+" A.B.C.D.E.F. ",
+" G.H.I.J. ",
+" "};
diff --git a/ksirc/img/madsmiley.png b/ksirc/img/madsmiley.png
new file mode 100644
index 00000000..a8836f3e
--- /dev/null
+++ b/ksirc/img/madsmiley.png
Binary files differ
diff --git a/ksirc/img/mdi.png b/ksirc/img/mdi.png
new file mode 100644
index 00000000..9c053670
--- /dev/null
+++ b/ksirc/img/mdi.png
Binary files differ
diff --git a/ksirc/img/mini-run.png b/ksirc/img/mini-run.png
new file mode 100644
index 00000000..f9047029
--- /dev/null
+++ b/ksirc/img/mini-run.png
Binary files differ
diff --git a/ksirc/img/minus.png b/ksirc/img/minus.png
new file mode 100644
index 00000000..d451898d
--- /dev/null
+++ b/ksirc/img/minus.png
Binary files differ
diff --git a/ksirc/img/misc1.png b/ksirc/img/misc1.png
new file mode 100644
index 00000000..e5db7943
--- /dev/null
+++ b/ksirc/img/misc1.png
Binary files differ
diff --git a/ksirc/img/misc2.png b/ksirc/img/misc2.png
new file mode 100644
index 00000000..9037026d
--- /dev/null
+++ b/ksirc/img/misc2.png
Binary files differ
diff --git a/ksirc/img/misc3.png b/ksirc/img/misc3.png
new file mode 100644
index 00000000..a3085c8d
--- /dev/null
+++ b/ksirc/img/misc3.png
Binary files differ
diff --git a/ksirc/img/misc4.png b/ksirc/img/misc4.png
new file mode 100644
index 00000000..59dca5a9
--- /dev/null
+++ b/ksirc/img/misc4.png
Binary files differ
diff --git a/ksirc/img/misc5.png b/ksirc/img/misc5.png
new file mode 100644
index 00000000..4f4207d3
--- /dev/null
+++ b/ksirc/img/misc5.png
Binary files differ
diff --git a/ksirc/img/misc6.png b/ksirc/img/misc6.png
new file mode 100644
index 00000000..38cbd349
--- /dev/null
+++ b/ksirc/img/misc6.png
Binary files differ
diff --git a/ksirc/img/misc7.png b/ksirc/img/misc7.png
new file mode 100644
index 00000000..ba68e214
--- /dev/null
+++ b/ksirc/img/misc7.png
Binary files differ
diff --git a/ksirc/img/misc8.png b/ksirc/img/misc8.png
new file mode 100644
index 00000000..7ec56e20
--- /dev/null
+++ b/ksirc/img/misc8.png
Binary files differ
diff --git a/ksirc/img/misc9.png b/ksirc/img/misc9.png
new file mode 100644
index 00000000..d6776689
--- /dev/null
+++ b/ksirc/img/misc9.png
Binary files differ
diff --git a/ksirc/img/miscA.png b/ksirc/img/miscA.png
new file mode 100644
index 00000000..289040b5
--- /dev/null
+++ b/ksirc/img/miscA.png
Binary files differ
diff --git a/ksirc/img/mode.png b/ksirc/img/mode.png
new file mode 100644
index 00000000..bde2461f
--- /dev/null
+++ b/ksirc/img/mode.png
Binary files differ
diff --git a/ksirc/img/notice.png b/ksirc/img/notice.png
new file mode 100644
index 00000000..07f27e2d
--- /dev/null
+++ b/ksirc/img/notice.png
Binary files differ
diff --git a/ksirc/img/ominus.png b/ksirc/img/ominus.png
new file mode 100644
index 00000000..a69be335
--- /dev/null
+++ b/ksirc/img/ominus.png
Binary files differ
diff --git a/ksirc/img/oplus.png b/ksirc/img/oplus.png
new file mode 100644
index 00000000..25e248ff
--- /dev/null
+++ b/ksirc/img/oplus.png
Binary files differ
diff --git a/ksirc/img/part.png b/ksirc/img/part.png
new file mode 100644
index 00000000..dd1fe2bc
--- /dev/null
+++ b/ksirc/img/part.png
Binary files differ
diff --git a/ksirc/img/plus.png b/ksirc/img/plus.png
new file mode 100644
index 00000000..211bdc6f
--- /dev/null
+++ b/ksirc/img/plus.png
Binary files differ
diff --git a/ksirc/img/ppl.png b/ksirc/img/ppl.png
new file mode 100644
index 00000000..f5585b07
--- /dev/null
+++ b/ksirc/img/ppl.png
Binary files differ
diff --git a/ksirc/img/quit.png b/ksirc/img/quit.png
new file mode 100644
index 00000000..4aa8a09a
--- /dev/null
+++ b/ksirc/img/quit.png
Binary files differ
diff --git a/ksirc/img/sadsmiley.png b/ksirc/img/sadsmiley.png
new file mode 100644
index 00000000..11bd7d4c
--- /dev/null
+++ b/ksirc/img/sadsmiley.png
Binary files differ
diff --git a/ksirc/img/sdi.png b/ksirc/img/sdi.png
new file mode 100644
index 00000000..aa39c8c5
--- /dev/null
+++ b/ksirc/img/sdi.png
Binary files differ
diff --git a/ksirc/img/server.xpm b/ksirc/img/server.xpm
new file mode 100644
index 00000000..89bd5ac9
--- /dev/null
+++ b/ksirc/img/server.xpm
@@ -0,0 +1,320 @@
+/* XPM */
+static char *server[]={
+"22 22 295 2",
+"Qt c None",
+".m c #06a66a",
+"#6 c #078c5c",
+"#N c #079161",
+"bk c #079e54",
+"bM c #08905e",
+".N c #089161",
+"bN c #089261",
+".1 c #089262",
+"bB c #08955e",
+"#M c #08955f",
+".y c #089561",
+".M c #08965f",
+"#L c #089759",
+"bA c #08975e",
+"#f c #08975f",
+"bm c #08995a",
+"bz c #08995c",
+".x c #089a5b",
+".L c #089b59",
+".0 c #089c58",
+"#v c #089c59",
+"bl c #089d57",
+"#e c #089d58",
+"a8 c #08a050",
+"b2 c #0a8b56",
+"#K c #0a9a4d",
+"bO c #0b8a61",
+".z c #0b9161",
+".K c #0ba14c",
+".w c #0bae5e",
+"b1 c #0c8864",
+"#u c #0ca34b",
+"a7 c #0ca44a",
+"#d c #0ea349",
+".Z c #0ea34a",
+"#5 c #118c70",
+"a6 c #12a545",
+"bH c #147a84",
+"b3 c #147f64",
+".2 c #148c58",
+"#g c #148c59",
+"#w c #168b58",
+".O c #188c58",
+"aQ c #19a742",
+".v c #1abe52",
+"#O c #1b8a56",
+"#7 c #1d7f55",
+"bL c #1daaaa",
+"bj c #1dac81",
+"cg c #1e7e98",
+"cs c #1e86b9",
+".l c #1ec9ae",
+"a5 c #1fa952",
+"by c #20b5a2",
+"#4 c #219390",
+"b0 c #22a9d7",
+"ce c #258c9f",
+".J c #25a741",
+"bt c #26858f",
+"#J c #269d53",
+"cf c #277562",
+"#t c #29a940",
+".Y c #2da940",
+".k c #2dd2c2",
+"bd c #2e8089",
+"#3 c #2e9f90",
+"#c c #2fa940",
+"aP c #2faa3f",
+"bK c #32c5fc",
+"bG c #389098",
+"#1 c #39a43c",
+"az c #3cab3c",
+"bw c #3ccefb",
+"#8 c #3d7360",
+"#2 c #3dbaa0",
+".n c #3eaa80",
+"aO c #3eac3e",
+"bx c #3fd1fc",
+"cJ c #403f3f",
+"a. c #446b74",
+"cI c #454545",
+"#h c #458653",
+"aN c #45ab3b",
+"bX c #464646",
+".3 c #478753",
+"#x c #488553",
+"#I c #49a738",
+"bh c #4ad7ff",
+"cH c #4b4b4b",
+"bi c #4bd1ed",
+"#P c #4d8352",
+"cF c #4f4e4e",
+"ar c #4f4f4f",
+"ay c #4fb03c",
+"#R c #506763",
+"bs c #509da4",
+"a1 c #515151",
+".I c #52b03a",
+"a4 c #52c9c5",
+"cB c #535453",
+"aM c #53ad70",
+".j c #54dbeb",
+"aq c #555555",
+"ap c #565656",
+"bc c #57989f",
+".X c #57b038",
+".u c #57d074",
+"ca c #585858",
+"co c #595959",
+"ax c #59b23a",
+"#s c #59b83d",
+"aI c #5a5a5a",
+"au c #5aa64a",
+"cb c #5b5b5b",
+"ag c #5bac47",
+"#i c #5d7454",
+"at c #5db695",
+"#0 c #5eac70",
+"#b c #5eb941",
+"a2 c #5ed3f5",
+"ao c #5f5f5f",
+"av c #5fb038",
+"aw c #5fb538",
+"cE c #606160",
+"a3 c #60dcfe",
+"aK c #61d1ed",
+"an c #646464",
+"bF c #64a8af",
+"#Z c #65a846",
+".i c #65dfd0",
+"cA c #666665",
+"#Q c #667653",
+".W c #66ad33",
+".t c #66c552",
+"#y c #677a53",
+"cG c #686767",
+"#9 c #687659",
+"ct c #696969",
+"#H c #69c03d",
+"aL c #69cace",
+"af c #6ab936",
+"ah c #6cc4ad",
+"am c #6d6d6d",
+"bu c #6d9ca0",
+"bI c #6d9ea2",
+"bV c #6e9fa3",
+"be c #6f989d",
+"al c #707070",
+".H c #70c33f",
+"ak c #717171",
+"c# c #727272",
+"cp c #747474",
+"ae c #75bb34",
+"bU c #77a1a5",
+"bD c #77abb0",
+".A c #77b99c",
+".h c #78cec1",
+"aY c #79969a",
+"ab c #79bd31",
+"#r c #79cc48",
+"aa c #79cc52",
+"bZ c #79ccf3",
+"#Y c #7abf2e",
+"bE c #7bb5bb",
+"ad c #7bbd32",
+"ac c #7cbe31",
+".s c #7ccd7d",
+".C c #7cd5ed",
+"cy c #7d7d7d",
+"## c #7fb64d",
+"cd c #7fbfe0",
+"#a c #80ca72",
+"bY c #828282",
+"aJ c #848383",
+"ch c #848384",
+"c. c #848484",
+".o c #84bfa9",
+"br c #85bbc0",
+"#X c #85c22c",
+"aj c #868686",
+"cr c #86b8cb",
+".q c #86dee6",
+"bT c #87a9ac",
+".P c #87b091",
+".r c #87dec2",
+"b9 c #898989",
+".V c #89c431",
+"bJ c #89d1ef",
+"#. c #8ab755",
+"cq c #8ab9d0",
+"aX c #8ba5a7",
+"a# c #8c9a9e",
+"#W c #8dc42a",
+"#q c #8dc980",
+"b6 c #8e8e8e",
+"bS c #8eadb0",
+"bb c #8ebabe",
+"#U c #8ec929",
+"b8 c #8f8f8f",
+"#V c #8fc529",
+"bR c #90acae",
+"b5 c #939394",
+"#T c #93e270",
+"cK c #959493",
+"cx c #959595",
+".Q c #95d5e5",
+"#G c #95e077",
+"bv c #96d5ed",
+".G c #96d973",
+"b7 c #979797",
+"bC c #97afb1",
+"a0 c #999999",
+"b4 c #9a9a9a",
+".6 c #9aeaf1",
+"aZ c #9babad",
+"bf c #9c9c9c",
+"bg c #9ce1f2",
+"bP c #9d9d9d",
+"bW c #9db0b2",
+".9 c #9dc7a4",
+"as c #9e9e9e",
+"bp c #9ec3c7",
+"cC c #9f9f9f",
+".4 c #9fab98",
+"#j c #9faba6",
+"aA c #a0a0a0",
+".U c #a0cf27",
+"bn c #a1a1a1",
+"aW c #a1b9bb",
+"#D c #a1cb19",
+"a9 c #a3a2a2",
+"ck c #a3a3a3",
+"#C c #a3cd18",
+"aS c #a4a4a4",
+"bq c #a4cccf",
+"#A c #a4e6b9",
+"bo c #a5bcbf",
+".T c #a7c719",
+"#E c #a7d954",
+".F c #a8e27d",
+".D c #a9efcf",
+"cm c #acacac",
+"cz c #adadad",
+"bQ c #adbaba",
+"#F c #ade977",
+"aH c #aeaeae",
+"#z c #aeb1a1",
+"aV c #aec6c9",
+"cc c #afaead",
+"b. c #afc7c9",
+".g c #afd3d3",
+"#p c #afe1c2",
+".f c #b0d2d0",
+"cD c #b2b2b2",
+"ba c #b4d1d4",
+".p c #b4e4f0",
+"cv c #b5b5b5",
+"aU c #b5cdce",
+".8 c #b5da82",
+"b# c #b6d0d3",
+"#B c #b6e137",
+"cj c #b7b7b7",
+"#o c #b7e4be",
+"cw c #b8b8b8",
+"cn c #b9b9b9",
+".5 c #b9e0e9",
+".R c #bbf2b0",
+"cl c #bcbcbc",
+"cu c #bfbfbf",
+".B c #c1d8e0",
+".e c #c1ded3",
+"#n c #c1e22b",
+".E c #c1f263",
+"aR c #c3c2c1",
+"ci c #c5c5c6",
+".S c #c5e157",
+"#l c #c5f6a6",
+".7 c #c6e35a",
+".d c #c7e3e3",
+"#k c #c8edea",
+"aG c #cacaca",
+".c c #cbe3ec",
+"#S c #ccd2d4",
+"aT c #cddbdc",
+".b c #cde5ec",
+".a c #cfe5ea",
+"#m c #d2e91d",
+".# c #d3dfdb",
+"ai c #d6d5d4",
+"aF c #d6d6d6",
+"aB c #dcdcdc",
+"aE c #dedede",
+"aD c #e7e7e7",
+"aC c #ececec",
+"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt",
+"QtQtQtQtQtQtQtQt.#.a.b.c.d.eQtQtQtQtQtQtQtQt",
+"QtQtQtQtQtQt.f.g.h.i.j.k.l.m.n.oQtQtQtQtQtQt",
+"QtQtQtQtQt.p.q.r.s.t.u.v.w.x.y.z.AQtQtQtQtQt",
+"QtQtQt.B.C.D.E.F.G.H.I.J.K.L.M.N.O.PQtQtQtQt",
+"QtQtQt.Q.R.S.T.U.V.W.X.Y.Z.0.M.1.2.3.4QtQtQt",
+"QtQt.5.6.7.8.9#.###a#b#c#d#e#f.1#g#h#i#jQtQt",
+"QtQt#k#l#m#n#o#p#q#r#s#t#u#v.M.1#w#x#y#zQtQt",
+"Qt#A#A#B#C#D#E#F#G#H#I#J#K#L#M#N#O#P#Q#R#SQt",
+"Qt#A#T#U#V#W#X#Y#Z#0#1#2#3#4#5#6#7#8#9a.a#Qt",
+"Qt#AaaabacadaeafagahaiajakalamanaoapaqarasQt",
+"Qt#AatauavawaxayazaiaAaBaCaCaDaEaFaGaHaIaJQt",
+"Qt.caKaLaMaNaOaPaQaRaSaTaUaVaWaXaYaZa0a1aJQt",
+"Qt.ca2a3a4a5a6a7a8aRa9b.b#babbbcbdbebfa1aJQt",
+"QtQtbgbhbibjbkblbmaRbnbobpbqbrbsbtbubfa1aJQt",
+"QtQtbvbwbxbybzbAbBaRaAbCbDbEbFbGbHbIbfa1aJQt",
+"QtQtQtbJbKbLbMbNbOaRbPbQbRbSbTbUbVbWa0bXbYQt",
+"QtQtQtQtbZb0b1b2b3aRb4b5b6b7b4b8b9c.c#cacbcc",
+"QtQtQtQtQtcdcecfcgchcicjckclcicmasbfcnb8cocp",
+"QtQtQtQtQtQtcqcrcsctcucjcvcwcncxc#cyczcAcBcp",
+"QtQtQtQtQtQtQtQtQtaocCcxcxcxcxckcDczb4cEcFcc",
+"QtQtQtQtQtQtQtQtQtcGcHcIcIcIcIcIcIcIcIcJcKQt"};
diff --git a/ksirc/img/servinfo.png b/ksirc/img/servinfo.png
new file mode 100644
index 00000000..65ca0284
--- /dev/null
+++ b/ksirc/img/servinfo.png
Binary files differ
diff --git a/ksirc/img/smiley.png b/ksirc/img/smiley.png
new file mode 100644
index 00000000..d57f7844
--- /dev/null
+++ b/ksirc/img/smiley.png
Binary files differ
diff --git a/ksirc/img/star.png b/ksirc/img/star.png
new file mode 100644
index 00000000..c0086462
--- /dev/null
+++ b/ksirc/img/star.png
Binary files differ
diff --git a/ksirc/img/start.xpm b/ksirc/img/start.xpm
new file mode 100644
index 00000000..7c54b4f4
--- /dev/null
+++ b/ksirc/img/start.xpm
@@ -0,0 +1,29 @@
+/* XPM */
+static char * start_xpm[] = {
+"22 22 4 1",
+" c None",
+". c #000000000000",
+"X c #FFFFFFFFFFFF",
+"o c #820782078207",
+" ",
+" ",
+" ",
+" ",
+" ",
+" . . ",
+" . .. ",
+" . .X. ",
+" . .XX........ ",
+" . .XX XXXXXXX. ",
+" ..XX . ",
+" . .X . ",
+" . o.X ........ ",
+" . o.X.ooooooo ",
+" . o..o ",
+" . o.o ",
+" oo ",
+" o ",
+" ",
+" ",
+" ",
+" "};
diff --git a/ksirc/img/stop.xpm b/ksirc/img/stop.xpm
new file mode 100644
index 00000000..571cf656
--- /dev/null
+++ b/ksirc/img/stop.xpm
@@ -0,0 +1,120 @@
+/* XPM */
+static char *stop[]={
+"17 17 100 2",
+"Qt c None",
+".U c #1a1414",
+".1 c #1e1414",
+".I c #291414",
+"#E c #2f1414",
+".x c #341414",
+".n c #3b1414",
+"#w c #411414",
+".f c #541a16",
+".e c #5c1d18",
+".d c #5c1f1a",
+".c c #612621",
+".8 c #642722",
+".T c #671414",
+".a c #672f2a",
+"#v c #6a1414",
+".# c #6a3936",
+"#H c #6b1414",
+".b c #703b36",
+"#D c #761414",
+".0 c #7a1414",
+".7 c #7d1414",
+".H c #8e1414",
+".w c #901414",
+"#G c #911414",
+"#u c #961414",
+".m c #a15c54",
+".Z c #a61414",
+".G c #a71414",
+"#o c #ae7269",
+"#C c #b41414",
+".6 c #b51414",
+"#F c #b51616",
+"#B c #b71414",
+"#i c #b81515",
+"#A c #ba1414",
+".v c #bb4744",
+"#n c #bc1414",
+"#z c #be2727",
+".Y c #c0231c",
+"#x c #c0231f",
+".S c #c12c24",
+"#t c #c13228",
+"#p c #c15350",
+"#y c #c2271f",
+".5 c #c23333",
+"#s c #c55047",
+"#d c #c55252",
+"#k c #c56058",
+".u c #c56460",
+"#c c #c65451",
+"#m c #c75950",
+"#r c #c85148",
+".R c #ca544e",
+"#q c #ca5953",
+"#f c #ca655d",
+".t c #ca7169",
+"#b c #cb635c",
+".4 c #cb655e",
+"#. c #cb6661",
+"#h c #ce6f67",
+".F c #d16e66",
+".s c #d27e78",
+".O c #d46b66",
+".Q c #d46c67",
+"#l c #d47d77",
+".E c #d4817c",
+".W c #d77570",
+".l c #d7a29c",
+".y c #d97570",
+".r c #d98680",
+"#j c #d9a8a2",
+".K c #da7d7a",
+".3 c #da7f7b",
+".q c #da807c",
+".M c #db746f",
+".p c #db7975",
+".P c #dc7875",
+"#g c #dc7a78",
+"## c #dc7b77",
+".C c #dc7d78",
+".A c #dd7772",
+"#a c #dd7978",
+".X c #de7a78",
+".D c #de7e7a",
+".L c #df7e7d",
+".z c #df7f7b",
+".B c #df8580",
+".k c #e6b9b5",
+"#e c #e7b8b4",
+".j c #eabeb9",
+".9 c #eabfbb",
+".2 c #f1c8c6",
+".i c #f3d7d5",
+".V c #f3d8d7",
+".h c #f3dada",
+".g c #f6e7e7",
+".J c #f6eceb",
+".N c #fef3f3",
+".o c #ffffff",
+"QtQtQtQt.#.a.b.c.d.e.fQtQtQtQtQtQt",
+"QtQtQt.#.g.h.i.j.k.l.m.nQtQtQtQtQt",
+"QtQt.#.o.p.q.r.s.t.u.v.w.xQtQtQtQt",
+"Qt.#.o.y.z.A.B.C.D.E.F.G.H.IQtQtQt",
+".#.J.K.L.M.N.O.P.Q.N.R.S.G.T.UQtQt",
+".#.V.W.X.N.N.N.Q.N.N.N.Y.Z.0.1QtQt",
+".#.2.Q.3.Q.N.N.N.N.N.4.5.6.7.1QtQt",
+".8.9#.###a.Q.N.N.N#b#c#d.6.7.1QtQt",
+".d#e#f#g.Q.N.N.N.N.N#h#i.Z.7.1QtQt",
+".e#j#k#l.N.N.N#m.N.N.N#n.Z.0.1QtQt",
+".f#o#p#q#r.N#m#s#t.N.6.Z#u#v.UQtQt",
+"Qt#w.w.G#x#y#z#A#B#C.Z#u#D#EQtQtQt",
+"QtQt.x.H.G.6#F.6.Z.Z#G#D#EQtQtQtQt",
+"QtQtQt.x#H.0.7.7.7.0#v#EQtQtQtQtQt",
+"QtQtQtQt.U.1.1.1.1.1.UQtQtQtQtQtQt",
+"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt",
+"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt"};
diff --git a/ksirc/img/tile.xpm b/ksirc/img/tile.xpm
new file mode 100644
index 00000000..ada13ff9
--- /dev/null
+++ b/ksirc/img/tile.xpm
Binary files differ
diff --git a/ksirc/img/topic.png b/ksirc/img/topic.png
new file mode 100644
index 00000000..3984ca18
--- /dev/null
+++ b/ksirc/img/topic.png
Binary files differ
diff --git a/ksirc/ioBroadcast.cpp b/ksirc/ioBroadcast.cpp
new file mode 100644
index 00000000..9bac4e30
--- /dev/null
+++ b/ksirc/ioBroadcast.cpp
@@ -0,0 +1,101 @@
+/**********************************************************************
+
+ The IO Broadcaster
+
+ $$Id$$
+
+ The IO broadcaster bassed on the ksircmessage receiver takes a
+ message and send it all ksircmessage receivers, except of course it
+ self.
+
+ It does the same with control_messages.
+
+ Implementation:
+
+ Make a QDictIterator, iterate over the windows sedning to each
+ broadcaster that's not itself.
+
+ *** NOTE! don't have 2 broadcasters or else they'll broadcast forever!
+
+**********************************************************************/
+
+#include "ioBroadcast.h"
+#include "ksircprocess.h"
+
+
+KSircIOBroadcast::~KSircIOBroadcast()
+{
+}
+
+void KSircIOBroadcast::sirc_receive(QCString str, bool)
+{
+
+ QDictIterator<KSircMessageReceiver> it(proc->getWindowList());
+
+ KSircMessageReceiver *dflt = (proc->getWindowList())["!default"];
+ if(dflt->getBroadcast() == TRUE)
+ dflt->sirc_receive(str, true);
+
+ it.toFirst();
+
+ while(it.current()){
+ if((it.current()->getBroadcast() == TRUE) && (it.current() != dflt))
+ it.current()->sirc_receive(str, true);
+ ++it;
+ }
+
+}
+
+void KSircIOBroadcast::control_message(int command, QString str)
+{
+
+ QDictIterator<KSircMessageReceiver> it(proc->getWindowList());
+
+ it.toFirst();
+
+ while(it.current()){
+ if(it.current() != this)
+ it.current()->control_message(command, str);
+ ++it;
+ }
+}
+
+
+filterRuleList *KSircIOBroadcast::defaultRules()
+{
+ filterRule *fr;
+ filterRuleList *frl = new filterRuleList();
+ frl->setAutoDelete(TRUE);
+ fr = new filterRule();
+ fr->desc = "Inverse to KSIRC inverse";
+ fr->search = ".*";
+ fr->from = "(?g)\\x16";
+ fr->to = "~r";
+ frl->append(fr);
+ fr = new filterRule();
+ fr->desc = "Underline to KSIRC underline";
+ fr->search = ".*";
+ fr->from = "(?g)\\x1f";
+ fr->to = "~u";
+ frl->append(fr);
+ fr = new filterRule();
+ fr->desc = "Bold to KSIRC bold";
+ fr->search = ".*";
+ fr->from = "(?g)\\x02";
+ fr->to = "~b";
+ frl->append(fr);
+ fr = new filterRule();
+ fr->desc = "Beep to KSIRC beep";
+ fr->search = ".*";
+ fr->from = "(?g)\\x07";
+ fr->to = "~g";
+ frl->append(fr);
+ fr = new filterRule();
+ fr->desc = "Ordinary to KSIRC ordinary";
+ fr->search = ".*";
+ fr->from = "(?g)\\x0f";
+ fr->to = "~c";
+ frl->append(fr);
+ return frl;
+
+}
diff --git a/ksirc/ioBroadcast.h b/ksirc/ioBroadcast.h
new file mode 100644
index 00000000..5be56390
--- /dev/null
+++ b/ksirc/ioBroadcast.h
@@ -0,0 +1,25 @@
+#ifndef KIOBROADCAST_H
+#define KIOBROADCAST_H
+
+#include "messageReceiver.h"
+
+class KSircIOBroadcast : public KSircMessageReceiver
+{
+public:
+ KSircIOBroadcast(KSircProcess *_proc) : KSircMessageReceiver(_proc)
+ {
+ proc = _proc;
+ setBroadcast(FALSE);
+ }
+ virtual ~KSircIOBroadcast();
+
+ virtual void sirc_receive(QCString str, bool broadcast);
+ virtual void control_message(int, QString);
+
+ virtual filterRuleList *defaultRules();
+
+private:
+ KSircProcess *proc;
+};
+
+#endif
diff --git a/ksirc/ioDCC.cpp b/ksirc/ioDCC.cpp
new file mode 100644
index 00000000..7c576904
--- /dev/null
+++ b/ksirc/ioDCC.cpp
@@ -0,0 +1,643 @@
+/**********************************************************************
+
+ The IO DCC Window
+
+ $$Id$$
+
+ Display DCC progress, etc. This in the future should be expanded.
+
+**********************************************************************/
+
+#include "ioDCC.h"
+#include "ksircprocess.h"
+#include "displayMgr.h"
+#include "control_message.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpassivepopup.h>
+
+#include <qregexp.h>
+
+extern DisplayMgr *displayMgr;
+
+KSircIODCC::KSircIODCC(KSircProcess *_proc) :
+ QObject(),
+ KSircMessageReceiver(_proc)
+{
+ proc = _proc;
+ setBroadcast(FALSE);
+ mgr = new dccTopLevel(0x0, "dccTopLevel Manager");
+ displayMgr->newTopLevel(mgr, FALSE);
+ displayMgr->setCaption(mgr, proc->serverName() + i18n(" DCC Controller"));
+
+ connect(mgr->mgr(), SIGNAL(dccConnectClicked(dccItem *)), this, SLOT(dccConnectClicked(dccItem *)));
+ connect(mgr->mgr(), SIGNAL(dccResumeClicked(dccItem *)), this, SLOT(dccResumeClicked(dccItem *)));
+ connect(mgr->mgr(), SIGNAL(dccRenameClicked(dccItem *)), this, SLOT(dccRenameClicked(dccItem *)));
+ connect(mgr->mgr(), SIGNAL(dccAbortClicked(dccItem *)), this, SLOT(dccAbortClicked(dccItem *)));
+ connect(mgr->mgr(), SIGNAL(outputLine(QCString)), this, SIGNAL(outputLine(QCString)));
+}
+
+
+KSircIODCC::~KSircIODCC()
+{
+ // displayMgr->removeTopLevel(mgr);
+ if(mgr)
+ delete (dccTopLevel *) mgr;
+}
+
+void KSircIODCC::sirc_receive(QCString str, bool )
+{
+ if(!mgr)
+ return;
+ // Parse the string to find out what type it is.
+ // Note the order here.
+ // Most people tend to receive files, so let's
+ // parse the byte xfered messages first since there's lot's of them.
+ // The we get lots of send bytexfer messages so parse them second.
+ // Then we look at the one time start/stop messages. They only arrive
+ // once in a long long time (compared to the byte messages) so if it takes
+ // a few extra clock cycles to find them, who cares?
+ if(str.find("DCC GET read:", 0) != -1){ /*fold01*/
+ QRegExp rx("read: (.+) who: (.+) bytes: (.*)");
+ if(rx.search(str)){
+ QString key = QString("%1/%2").arg(rx.cap(1)).arg(rx.cap(2));
+ uint bytesXfer = rx.cap(3).toUInt();
+
+ //
+ // Only update the display for 1% intervals.
+ // LastSize + 1%Size must be less than the total xfered bytes.
+ //
+ if(DCCGetItems[key]){
+ DCCGetItems[key]->setReceivedBytes(bytesXfer/1024);
+ }
+ }
+ }
+ else if(str.find("DCC SEND write:", 0) != -1){ /*fold01*/
+ QRegExp rx("write: (.+) who: (.+) bytes: (.*)");
+ if(rx.search(str)){
+ QString key = QString("%1/%2").arg(rx.cap(1)).arg(rx.cap(2));
+ uint bytesXfer = rx.cap(3).toUInt();
+
+ if(DCCSendItems[key]){
+ DCCSendItems[key]->setReceivedBytes(bytesXfer/1024);
+ }
+ }
+ }
+ else if(str.find("INBOUND DCC SEND", 0) != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+) file: (.+) size: (.*) ip: (.+) port: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString size = rx.cap(3);
+ QString ip = rx.cap(4);
+ //QSTring port = rx.cap(5);
+
+ int fileSize = size.toInt(); // Bytes per step
+ fileSize /= 1024;
+
+ // setup dcc dialog
+ displayMgr->show(mgr);
+ dccItem *it = mgr->mgr()->newGetItem(filename, who, dccItem::dccGotOffer, fileSize);
+ connect(it, SIGNAL(itemRenamed(dccItem *, QString, QString)),
+ this, SLOT(dccRenameDone(dccItem *, QString, QString)));
+ it->setWhoPostfix("(" + ip + ")");
+
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCGetItems[key]){
+ /*
+ * don't add duplicates, this cuases real headaches
+ * for both us and the user.
+ */
+ QString renamed;
+ dccItem *old = DCCGetItems.take(key);
+ int i;
+ for(i = 0; i <= (int) DCCGetItems.count()+1; i++){
+ renamed = QString("%1 (finished %2)/%3").arg(filename).arg(i+1).arg(old->who());
+ if( DCCGetItems[renamed] == 0x0)
+ break;
+ }
+ old->changeFilename(QString("%1 (finished %2)").arg(filename).arg(i+1));
+ DCCGetItems.insert(renamed, it);
+ }
+
+ DCCGetItems.insert(key, it);
+ }
+ else {
+ kdDebug(5008) << "DCC SEND was unable to parse: " << str << endl;
+ }
+ }
+ else if(str.find("Sent DCC SEND", 0) != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+) file: (.+) size: (.*)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString size = rx.cap(3);
+ int fileSize = size.toInt(); // Bytes per step
+ fileSize /= 1024;
+
+ // setup dcc dialog
+ displayMgr->show(mgr);
+ dccItem *it = mgr->mgr()->newSendItem(filename, who, dccItem::dccSentOffer, fileSize);
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCSendItems[key]){
+ /*
+ * don't add duplicates, this cuases real headaches
+ * for both us and the user.
+ * We can get these on repeated sends or old files,
+ * just renamed them, their finished anyways
+ */
+ QString renamed;
+ dccItem *old = DCCSendItems.take(key);
+ int i;
+ for(i = 0; i <= (int) DCCSendItems.count()+1; i++){
+ renamed = QString("%1 (sent %2)/%3").arg(filename).arg(i+1).arg(old->who());
+ if( DCCSendItems[renamed] == 0x0)
+ break;
+ }
+ old->changeFilename(QString("%1 (sent %2)").arg(filename).arg(i+1));
+ DCCSendItems.insert(renamed, it);
+ }
+ DCCSendItems.insert(key, it);
+ }
+ else {
+ kdDebug(5008) << "DCC SENT was unable to parse: " << str << endl;
+ }
+ }
+ else if(str.find("DCC CHAT OFFERED", 0) != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+) ip: (.+) port: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString ip = rx.cap(2);
+ QString port = rx.cap(3);
+ // setup dcc dialog
+ displayMgr->show(mgr);
+ dccItem *it = mgr->mgr()->newChatItem(who, dccItem::dccGotOffer);
+ connect(it, SIGNAL(itemRenamed(dccItem *, QString, QString)),
+ this, SLOT(dccRenameDone(dccItem *, QString, QString)));
+ it->setWhoPostfix("(" + ip + ")");
+ DCCChatItems.insert(who, it);
+ }
+ else {
+ kdDebug(5008) << "DCC CHAT SEND was unable to parse: " << str << endl;
+ }
+ }
+ else if(str.find("DCC CHAT SEND", 0) != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+
+ // setup dcc dialog
+ displayMgr->show(mgr);
+ dccItem *it = mgr->mgr()->newChatItem(who, dccItem::dccSentOffer);
+ connect(it, SIGNAL(itemRenamed(dccItem *, QString, QString)),
+ this, SLOT(dccRenameDone(dccItem *, QString, QString)));
+ DCCChatItems.insert(who, it);
+ }
+ else {
+ kdDebug(5008) << "DCC CHAT SEND was unable to parse: " << str << endl;
+ }
+ }
+ else if(str.find("DCC SEND terminated") != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+) file: (.+) reason: (.*)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString error = rx.cap(3);
+ enum dccItem::dccStatus status = dccItem::dccDone;
+
+ if(error == "CLOSE"){
+ status = dccItem::dccCancel;
+ }
+ if(error != "OK"){
+ status = dccItem::dccError;
+ KPassivePopup::message(i18n("DCC SEND with %1 for %2 failed because of %3").arg(who).arg(filename).arg(error), mgr->mgr());
+ }
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCSendItems[key]){
+ kdDebug(5008) << "SendPercent: " << DCCSendItems[key]->getPercent() << endl;
+ if((status == dccItem::dccDone) && (DCCSendItems[key]->getPercent() < 100))
+ status = dccItem::dccError;
+ DCCSendItems[key]->changeStatus(status);
+ }
+ }
+ }
+ else if(str.find ("DCC GET terminated") != -1){ /*fold01*/
+ kdDebug(5008) << "Term: " << str << endl;
+ QRegExp rx("who: (.+) file: (.+) reason: (.*)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString error = rx.cap(3);
+ enum dccItem::dccStatus status = dccItem::dccDone;
+
+ if(error != "OK"){
+ status = dccItem::dccError;
+ KPassivePopup::message(i18n("DCC GET with %1 for %2 failed because of %3").arg(who).arg(filename).arg(error), mgr->mgr());
+ }
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCGetItems[key]){
+ kdDebug(5008) << "GetPercent: " << DCCGetItems[key]->getPercent() << endl;
+ if((status == dccItem::dccDone) && (DCCGetItems[key]->getPercent() < 100))
+ status = dccItem::dccError;
+ DCCGetItems[key]->changeStatus(status);
+ }
+ }
+ else {
+ kdDebug(5008) << "DCC Get term failed to parse: " << str << endl;
+ }
+ }
+ else if(str.find("DCC GET resumed") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCGetItems[key]){
+ dccItem *it = DCCGetItems[key];
+ kdDebug(5008) << "Got DCC GET resumed message..." << it->file() << endl;
+ if(it->status() == dccItem::dccWaitOnResume)
+ dccConnectClicked(it);
+ it->changeStatus(dccItem::dccResumed);
+ }
+ }
+ }
+ else if(str.find("DCC SEND resumed") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCSendItems[key]){
+ DCCSendItems[key]->changeStatus(dccItem::dccResumed);
+ }
+ }
+ }
+ else if(str.find("DCC GET established") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCGetItems[key]){
+ DCCGetItems[key]->changeStatus(dccItem::dccRecving);
+ }
+ }
+ }
+ else if(str.find("DCC SEND established") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+) ip: (\\S+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString ip = rx.cap(3);
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCSendItems[key]){
+ DCCSendItems[key]->setWhoPostfix("(" + ip + ")");
+ DCCSendItems[key]->changeStatus(dccItem::dccSending);
+ }
+ }
+ }
+ else if(str.find("DCC CHAT established") != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ if(DCCChatItems[who]){
+ DCCChatItems[who]->changeStatus(dccItem::dccOpen);
+ proc->new_toplevel(KSircChannel(proc->serverName(), QString("=") + who.lower()));
+ }
+ }
+ }
+ else if(str.find("DCC CHAT inbound established") != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+) ip: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString ip = rx.cap(2);
+ if(DCCChatItems[who]){
+ DCCChatItems[who]->setWhoPostfix("(" + ip + ")");
+ DCCChatItems[who]->changeStatus(dccItem::dccOpen);
+ proc->new_toplevel(KSircChannel(proc->serverName(), QString("=") + who.lower()));
+ }
+ }
+ }
+ else if(str.find("DCC GET failed") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+) reason: (.*)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString error = rx.cap(3);
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCGetItems[key]){
+ DCCGetItems[key]->changeStatus(dccItem::dccError);
+ }
+ KPassivePopup::message(i18n("DCC Get with %1 for %2 failed because of %3").arg(who).arg(filename).arg(error), mgr->mgr());
+ }
+ }
+ else if(str.find("DCC CHAT failed") != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+) reason: (.*)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString error = rx.cap(2);
+ if(DCCChatItems[who]){
+ DCCChatItems[who]->changeStatus(dccItem::dccError);
+ }
+ KPassivePopup::message(i18n("DCC Chat with %1 failed because of %2").arg(who).arg(error), mgr->mgr());
+ }
+ }
+ else if(str.find("DCC CHAT renamed") != -1){ /*FOLD01*/
+ QRegExp rx("who: (.+) to: (.+)");
+ if(rx.search(str)){
+ QString oldwho = rx.cap(1);
+ QString newwho = rx.cap(2);
+
+ QString oldwin = "=" + oldwho;
+ if(proc->getWindowList().find(oldwin)){
+ proc->getWindowList().find(oldwin)->control_message(CHANGE_CHANNEL,QString("=" +newwho).lower());
+ }
+ }
+ }
+ else if(str.find("Closing DCC GET") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+ QString key = QString("%1/%2").arg(filename).arg(who);
+ if(DCCGetItems[key]){
+ DCCGetItems[key]->changeStatus(dccItem::dccCancel);
+ }
+ }
+ }
+// else if(str.find("Closing DCC SEND") != -1){ /*FOLD01*/
+// QRegExp rx("who: (.+) file: (.+)");
+// if(rx.search(str)){
+// QString who = rx.cap(1);
+// QString filename = rx.cap(2);
+// QString key = QString("%1/%2").arg(filename).arg(who);
+// if(DCCSendItems[key]){
+// DCCSendItems[key]->changeStatus(dccItem::dccCancel);
+// }
+// }
+// }
+ else if(str.find("Closing DCC CHAT") != -1){ /*fold01*/
+ QRegExp rx("who: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ if(DCCChatItems[who]){
+ DCCChatItems[who]->changeStatus(dccItem::dccDone);
+ }
+ }
+ }
+ else if(str.find("No DCC SEND") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+
+ //QString key = QString("%1/%2").arg(filename).arg(who);
+
+ QPtrList<dccItem> toDel;
+ QDict<dccItem> new_list;
+ QDictIterator<dccItem> it( DCCSendItems );
+ for(;it.current(); ++it){
+ if((it.current()->who() == who) &&
+ (it.current()->file() == filename)
+ ){
+ toDel.append(it.current());
+ }
+ else {
+ new_list.insert(it.currentKey(), it.current());
+ }
+ }
+ DCCSendItems = new_list;
+ toDel.setAutoDelete(true);
+ toDel.clear();
+ }
+ }
+ else if(str.find("No DCC GET") != -1){ /*fold01*/
+ QRegExp rx("who: (.+) file: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+ QString filename = rx.cap(2);
+
+ QPtrList<dccItem> toDel;
+ QDict<dccItem> new_list;
+ QDictIterator<dccItem> it( DCCGetItems );
+ for(;it.current(); ++it){
+ if((it.current()->who() == who) &&
+ (it.current()->file() == filename)
+ ){
+ toDel.append(it.current());
+ }
+ else {
+ new_list.insert(it.currentKey(), it.current());
+ }
+ }
+ DCCGetItems = new_list;
+ toDel.setAutoDelete(true);
+ toDel.clear();
+ }
+ }
+ else if(str.find("No DCC CHAT") != -1){ /*fold01*/
+ QRegExp rx("who: (.+)");
+ if(rx.search(str)){
+ QString who = rx.cap(1);
+
+ QPtrList<dccItem> toDel;
+ QDict<dccItem> new_list;
+ QDictIterator<dccItem> it( DCCChatItems );
+ for(;it.current(); ++it){
+ if(it.current()->who() == who){
+ toDel.append(it.current());
+ }
+ else {
+ new_list.insert(it.currentKey(), it.current());
+ }
+ }
+ DCCChatItems = new_list;
+ toDel.setAutoDelete(true);
+ toDel.clear();
+ }
+ }
+ else{ /*FOLD01*/
+ proc->getWindowList()["!default"]->sirc_receive(str);
+ }
+
+}
+
+void KSircIODCC::control_message(int, QString)
+{
+}
+
+void KSircIODCC::cancelTransfer(QString filename)
+{
+ //if(DlgList[filename]){
+ //emit outputLine(DCCStatus[filename]->cancelMessage.ascii());
+ //delete DlgList[filename];
+ //DlgList.remove(filename);
+ //delete DCCStatus[filename];
+ //DCCStatus.remove(filename);
+ //}
+}
+
+void KSircIODCC::getFile()
+{
+ /*
+ QString text = pending->fileListing()->text(pending->fileListing()->currentItem());
+ int pos = text.find(" ", 0);
+ QString nick = text.mid(0, pos);
+ pos = text.find(" ", pos+1) + 1;
+ QString filename = text.mid(pos, text.length() - pos);
+ //if(DlgList[filename]->isVisible() == FALSE)
+ // DlgList[filename]->show();
+ QString command = "/dcc get " + nick + " " + filename + "\n";
+ emit outputLine(command.ascii());
+ for(uint i = 0; i < pending->fileListing()->count(); i++)
+ if(QString(pending->fileListing()->text(i)) == (nick + " offered " + filename))
+ pending->fileListing()->removeItem(i);
+
+ if(pending->fileListing()->count() == 0)
+ pending->hide();
+ */
+}
+
+void KSircIODCC::forgetFile()
+{
+ /*
+ QString text = pending->fileListing()->text(pending->fileListing()->currentItem());
+ int pos = text.find(" ", 0);
+ QString nick = text.mid(0, pos);
+ pos = text.find(" ", pos+1) + 1;
+ QString filename = text.mid(pos, text.length() - pos);
+ QString command = "/dcc close get " + nick + " " + filename + "\n";
+ emit outputLine(command.ascii());
+ for(uint i = 0; i < pending->fileListing()->count(); i++)
+ if(QString(pending->fileListing()->text(i)) == (nick + " offered " + filename))
+ pending->fileListing()->removeItem(i);
+
+ if(pending->fileListing()->count() == 0)
+ pending->hide();
+ */
+
+}
+
+filterRuleList *KSircIODCC::defaultRules()
+{
+
+// filterRule *fr;
+ filterRuleList *frl = new filterRuleList();
+ frl->setAutoDelete(TRUE);
+ /*
+ fr = new filterRule();
+ fr->desc = "Capture DCC IO Messages";
+ fr->search = "^\\*D\\*";
+ fr->from = "^";
+ fr->to = "~!dcc~";
+ frl->append(fr);
+ */
+ return frl;
+
+}
+
+void KSircIODCC::dccConnectClicked(dccItem *it)
+{
+ QString str;
+ kdDebug(5008) << "Got connect click on " << it->who() << " " << it->type() << endl;
+ switch(it->type()){
+ case dccItem::dccGet:
+ str = "/dcc get " + it->who() + " " + it->file() + "\n";
+ emit outputLine(str.ascii());
+ break;
+ case dccItem::dccChat:
+ str = "/dcc chat " + it->who() + "\n";
+ emit outputLine(str.ascii());
+ break;
+ default:
+ break;
+ }
+
+}
+void KSircIODCC::dccResumeClicked(dccItem *it)
+{
+ QString str;
+ kdDebug(5008) << "Got resume click on " << it->who() << " " << it->type() << endl;
+ switch(it->type()){
+ case dccItem::dccGet:
+ it->changeStatus(dccItem::dccWaitOnResume);
+ str = "/resume " + it->who() + " " + it->file() + "\n";
+ emit outputLine(str.ascii());
+ break;
+ default:
+ break;
+ }
+
+}
+void KSircIODCC::dccRenameClicked(dccItem *it)
+{
+ it->doRename();
+}
+void KSircIODCC::dccAbortClicked(dccItem *it)
+{
+ QString str;
+ switch(it->status()){
+ case dccItem::dccDone:
+ case dccItem::dccCancel:
+ case dccItem::dccError:
+ switch(it->type()) {
+ case dccItem::dccGet:
+ DCCGetItems.remove(QString("%1/%2").arg(it->file()).arg(it->who()));
+ break;
+ case dccItem::dccSend:
+ DCCSendItems.remove(QString("%1/%2").arg(it->file()).arg(it->who()));
+ break;
+ case dccItem::dccChat:
+ DCCChatItems.remove(it->who());
+ break;
+ }
+ delete it;
+ break;
+ default:
+ switch(it->type()) {
+ case dccItem::dccGet:
+ str = "/dcc close get " + it->who() + " " + it->file() + "\n";
+ emit outputLine(str.ascii());
+ break;
+ case dccItem::dccSend:
+ str = "/dcc close send " + it->who() + " " + it->file() + "\n";
+ emit outputLine(str.ascii());
+ break;
+ case dccItem::dccChat:
+ str = "/dcc close chat " + it->who() + "\n";
+ emit outputLine(str.ascii());
+ break;
+ }
+ }
+}
+
+void KSircIODCC::dccRenameDone(dccItem *it, QString oldWho, QString oldFile)
+{
+ if(it->type() == dccItem::dccGet){
+ QString str = QString("/dcc rename %1 %2 %3\n").arg(oldWho).arg(oldFile).arg(it->file());
+ QString key = QString("%1/%2").arg(oldFile).arg(oldWho);
+ if(DCCGetItems[key]){
+ DCCGetItems.take(key);
+ QString newkey = QString("%1/%2").arg(it->file()).arg(it->who());
+ DCCGetItems.insert(newkey, it);
+ }
+ emit outputLine(str.ascii());
+ }
+ else if(it->type() == dccItem::dccChat){
+ if(DCCChatItems[oldWho]){
+ DCCChatItems.take(oldWho);
+ DCCChatItems.insert(it->who(), it);
+ }
+ QString str = QString("/dcc rchat %1 %2\n").arg(oldWho).arg(it->who());
+ emit outputLine(str.ascii());
+
+ }
+}
+
+void KSircIODCC::showMgr()
+{
+ displayMgr->show(mgr);
+}
+
+#include "ioDCC.moc"
diff --git a/ksirc/ioDCC.h b/ksirc/ioDCC.h
new file mode 100644
index 00000000..76a93941
--- /dev/null
+++ b/ksirc/ioDCC.h
@@ -0,0 +1,65 @@
+#ifndef KIODCCC_H
+#define KIODCCC_H
+
+#include <qdict.h>
+#include <qobject.h>
+#include <qguardedptr.h>
+
+#include "dccManager.h"
+#include "dccToplevel.h"
+#include "messageReceiver.h"
+
+class KSProgress;
+
+struct DCCInfo {
+ QString nick;
+ QString cancelMessage;
+ int LastSize;
+ int PercentSize;
+ bool inProgress;
+};
+
+class KSircIODCC : public QObject,
+ public KSircMessageReceiver
+{
+ Q_OBJECT
+public:
+ KSircIODCC(KSircProcess *_proc);
+ virtual ~KSircIODCC();
+
+ virtual void sirc_receive(QCString, bool broadcast);
+ virtual void control_message(int, QString);
+ virtual filterRuleList *defaultRules();
+
+ virtual void showMgr();
+
+protected slots:
+ void cancelTransfer(QString);
+ void getFile();
+ void forgetFile();
+
+ void dccConnectClicked(dccItem *);
+ void dccResumeClicked(dccItem *);
+ void dccRenameClicked(dccItem *);
+ void dccAbortClicked(dccItem *);
+
+ void dccRenameDone(dccItem *, QString, QString);
+
+signals:
+ void outputLine(QCString);
+
+private:
+// QDict<QProgressDialog> DlgList;
+ //QDict<KSProgress> DlgList;
+ //QDict<DCCInfo> DCCStatus;
+ QDict<dccItem> DCCGetItems;
+ QDict<dccItem> DCCSendItems;
+ QDict<dccItem> DCCChatItems;
+
+ //dccDialog *pending;
+ QGuardedPtr<dccTopLevel> mgr;
+
+ KSircProcess *proc;
+};
+
+#endif
diff --git a/ksirc/ioDiscard.cpp b/ksirc/ioDiscard.cpp
new file mode 100644
index 00000000..7ce4173e
--- /dev/null
+++ b/ksirc/ioDiscard.cpp
@@ -0,0 +1,23 @@
+/**********************************************************************
+
+ The IO Discarder
+
+ $$Id$$
+
+ Simple rule, junk EVERYTHING!!!
+
+**********************************************************************/
+
+#include "ioDiscard.h"
+
+KSircIODiscard::~KSircIODiscard()
+{
+}
+
+void KSircIODiscard::sirc_receive(QCString, bool)
+{
+}
+
+void KSircIODiscard::control_message(int, QString)
+{
+}
diff --git a/ksirc/ioDiscard.h b/ksirc/ioDiscard.h
new file mode 100644
index 00000000..e15c62da
--- /dev/null
+++ b/ksirc/ioDiscard.h
@@ -0,0 +1,20 @@
+#ifndef KIODISCARD_H
+#define KIODISCARD_H
+
+#include "messageReceiver.h"
+
+class KSircIODiscard : public KSircMessageReceiver
+{
+public:
+ KSircIODiscard(KSircProcess *_proc) : KSircMessageReceiver(_proc)
+ {
+ }
+ virtual ~KSircIODiscard();
+
+ virtual void sirc_receive(QCString, bool broadcast);
+ virtual void control_message(int, QString);
+
+private:
+};
+
+#endif
diff --git a/ksirc/ioLAG.cpp b/ksirc/ioLAG.cpp
new file mode 100644
index 00000000..50f3f082
--- /dev/null
+++ b/ksirc/ioLAG.cpp
@@ -0,0 +1,61 @@
+/**********************************************************************
+
+ The IO LAG Controller
+
+ $$Id$$
+
+**********************************************************************/
+
+#include "ioLAG.h"
+#include "control_message.h"
+#include "ksircprocess.h"
+
+#include <kdebug.h>
+
+KSircIOLAG::KSircIOLAG(KSircProcess *_proc)
+ : QObject(),
+ KSircMessageReceiver(_proc)
+{
+ proc = _proc;
+ setBroadcast(FALSE);
+ startTimer(30000);
+// startTimer(5000);
+//(proc->getWindowList())["!all"]->control_message(SET_LAG, "99");
+}
+
+
+KSircIOLAG::~KSircIOLAG()
+{
+ killTimers();
+}
+
+void KSircIOLAG::sirc_receive(QCString str, bool)
+{
+
+ if(str.contains("*L*")){
+ int s1, s2;
+ s1 = str.find("*L* ") + 4;
+ s2 = str.length();
+ if(s1 < 0 || s2 < 0){
+ kdDebug(5008) << "Lag mesage broken: " << str << endl;
+ return;
+ }
+ QString lag = str.mid(s1, s2 - s1);
+ // cerr << "Lag: " << str << endl;
+ // cerr << "Setting lag to: " << lag << endl;
+ (proc->getWindowList())["!all"]->control_message(SET_LAG, lag);
+ }
+
+}
+
+void KSircIOLAG::control_message(int, QString)
+{
+}
+
+void KSircIOLAG::timerEvent ( QTimerEvent * )
+{
+ QCString cmd = "/lag\n";
+ emit outputLine(cmd);
+}
+
+#include "ioLAG.moc"
diff --git a/ksirc/ioLAG.h b/ksirc/ioLAG.h
new file mode 100644
index 00000000..1c3bc00d
--- /dev/null
+++ b/ksirc/ioLAG.h
@@ -0,0 +1,31 @@
+#ifndef KIOLAG_H
+#define KIOLAG_H
+
+#include <qobject.h>
+
+#include "messageReceiver.h"
+
+class KSircIOLAG : public QObject,
+ public KSircMessageReceiver
+{
+ Q_OBJECT
+public:
+ KSircIOLAG(KSircProcess *_proc);
+ virtual ~KSircIOLAG();
+
+ virtual void sirc_receive(QCString, bool broadcast);
+ virtual void control_message(int, QString);
+
+protected slots:
+
+protected:
+ virtual void timerEvent ( QTimerEvent * );
+
+signals:
+ void outputLine(QCString);
+
+private:
+ KSircProcess *proc;
+};
+
+#endif
diff --git a/ksirc/ioNotify.cpp b/ksirc/ioNotify.cpp
new file mode 100644
index 00000000..14c6e9e8
--- /dev/null
+++ b/ksirc/ioNotify.cpp
@@ -0,0 +1,75 @@
+/**********************************************************************
+
+ IO Notify Messanger
+
+ $$Id$$
+
+**********************************************************************/
+
+#include "ioNotify.h"
+#include "ksircprocess.h"
+
+#include <kdebug.h>
+
+KSircIONotify::KSircIONotify(KSircProcess *_proc)
+ : QObject(),
+ KSircMessageReceiver(_proc)
+{
+ proc = _proc;
+ setBroadcast(FALSE);
+}
+
+
+KSircIONotify::~KSircIONotify()
+{
+}
+
+void KSircIONotify::sirc_receive(QCString str, bool)
+{
+ if(str.contains("*)*")){
+ int s1, s2;
+ s1 = str.find("Signon by") + 10;
+ s2 = str.find(" ", s1);
+ if(s1 < 0 || s2 < 0){
+ kdDebug(5008) << "Nick Notify mesage broken: " << str << endl;
+ return;
+ }
+ QString nick = str.mid(s1, s2 - s1);
+ emit notify_online(nick);
+ }
+ else if(str.contains("*(*")){
+ int s1, s2;
+ s1 = str.find("Signoff by") + 11;
+ s2 = str.find(" ", s1);
+ if(s1 < 0 || s2 < 0){
+ kdDebug(5008) << "Nick Notify mesage broken: " << str << endl;
+ return;
+ }
+ QString nick = str.mid(s1, s2 - s1);
+ emit notify_offline(nick);
+ }
+ else{
+ proc->getWindowList()["!default"]->sirc_receive(str);
+ kdDebug(5008) << "Nick Notifer got " << str << endl;
+ }
+}
+
+void KSircIONotify::control_message(int, QString)
+{
+}
+
+
+filterRuleList *KSircIONotify::defaultRules()
+{
+ filterRule *fr;
+ filterRuleList *frl = new filterRuleList();
+ frl->setAutoDelete(TRUE);
+ fr = new filterRule();
+ fr->desc = "Send Nick Notifies to notifier parser";
+ fr->search = "^\\*\\S?[\\(\\)]\\S?\\* ";
+ fr->from = "^";
+ fr->to = "~!notify~";
+ frl->append(fr);
+ return frl;
+}
+#include "ioNotify.moc"
diff --git a/ksirc/ioNotify.h b/ksirc/ioNotify.h
new file mode 100644
index 00000000..e95edabe
--- /dev/null
+++ b/ksirc/ioNotify.h
@@ -0,0 +1,31 @@
+#ifndef KIONOTIFY_H
+#define KIONOTIFY_H
+
+#include <qobject.h>
+
+#include "messageReceiver.h"
+
+class KSircIONotify : public QObject,
+ public KSircMessageReceiver
+{
+ Q_OBJECT
+public:
+ KSircIONotify(KSircProcess *_proc);
+ virtual ~KSircIONotify();
+
+ virtual void sirc_receive(QCString, bool broadcast);
+ virtual void control_message(int, QString);
+
+ virtual filterRuleList *defaultRules();
+
+signals:
+ virtual void notify_online(QString);
+ virtual void notify_offline(QString);
+
+protected slots:
+
+private:
+ KSircProcess *proc;
+};
+
+#endif
diff --git a/ksirc/iocontroller.cpp b/ksirc/iocontroller.cpp
new file mode 100644
index 00000000..61b0b49c
--- /dev/null
+++ b/ksirc/iocontroller.cpp
@@ -0,0 +1,426 @@
+/***********************************************************************
+
+ IO Controller Object
+
+ $$Id$$
+
+ Main io controller. Reads and writes strings to sirc. Input
+ received in the following 2 formats:
+
+ 1. ~window name~<message>
+ 2. <message>
+
+ each is handled diffrently. The window name is extracted from #1 and
+ if the window exists the message portion is sent to it. If the
+ window doesn't exist, or case 2 is found the window is sent to the
+ control window "!default". !default is NOT a constant window but
+ rather follows focus arround. This is the easiest way to solve the
+ problem of output to commands that don't have a fixed destination
+ window. (/whois, /help, etc )
+
+ Implementation:
+
+ Friends with KSircProcess allows easy access to TopList. Makes sence
+ and means that IOController has access to TopList, etc. The two work
+ closely together.
+
+ Variables:
+ holder: used to hold partital lines between writes.
+ *proc: the acutally sirc client process.
+ *ksircproc: the companion ksircprocess GUI controller
+ stdout_notif: access to SocketNotifier, why is this global to the
+ class?
+ counter: existance counter.
+
+ Functions:
+ public:
+ KSircIOController(KProcess*, KSircProcess*):
+ - Object constructor takes two arguements the KProcess
+ that holds a running copy of sirc.
+ - KSircProcess is saved for access latter to TopList.
+ - The receivedStdout signal from KProcess is connected to
+ stdout_read and the processExited is connected to the sircDied
+ slot.
+
+ ~KSircIOController: does nothing at this time.
+
+ public slots:
+ stdout_read(KProcess *, _buffer, buflen):
+ - Called by kprocess when data arrives.
+ - This function does all the parsing and sending of messages
+ to each window.
+
+ stderr_read(KProcess*, _buffer, buflen):
+ - Should be called for stderr data, not connected, does
+ nothing.
+
+ stdin_write(QString):
+ - Slot that get's connected to by KSircProcess to each
+ window. QString shold be written un touched! Let the
+ writter figure out what ever he wants to do.
+
+ sircDied:
+ - Should restart sirc or something....
+ - Becarefull not to get it die->start->die->... etc
+
+***********************************************************************/
+
+#include <config.h>
+
+#include "ksopts.h"
+#include "control_message.h"
+#include "iocontroller.h"
+#include "ksircprocess.h"
+#include "messageReceiver.h"
+#include "ksopts.h"
+
+#include <qlistbox.h>
+#include <qtextcodec.h>
+#include <kcharsets.h>
+#include <kglobal.h>
+#include <qpopupmenu.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kfiledialog.h>
+
+int KSircIOController::counter = 0;
+
+KSircIOController::KSircIOController(KProcess *_proc, KSircProcess *_ksircproc)
+ : QObject()
+{
+
+ counter++;
+
+ proc = _proc; // save proc
+ ksircproc = _ksircproc; // save ksircproce
+
+ send_buf = 0x0;
+ m_debugLB = 0;
+
+ // Connect the data arrived
+ // to sirc receive for adding
+ // the main text window
+ connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)),
+ this, SLOT(stdout_read(KProcess*, char*, int)));
+
+ // Connect the stderr data
+ // to sirc receive for adding
+ // the main text window
+ connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)),
+ this, SLOT(stderr_read(KProcess*, char*, int)));
+
+ connect(proc, SIGNAL(processExited(KProcess *)),
+ this, SLOT(sircDied(KProcess *)));
+ // Notify on sirc dying
+ connect(proc, SIGNAL(wroteStdin(KProcess*)),
+ this, SLOT(procCTS(KProcess*)));
+ proc_CTS = TRUE;
+#if 0
+ showDebugTraffic(true);
+#endif
+}
+
+void my_print(const char *c){
+ while(*c != 0x0){
+ if(*c & 0x80)
+ fprintf(stderr, "<%02X>", 0xff & *c);
+ else
+ fprintf(stderr, "%c", *c);
+ c++;
+ }
+ fprintf(stderr, "\n");
+}
+
+void KSircIOController::stdout_read(KProcess *, char *_buffer, int buflen)
+{
+
+ /*
+
+ Main reader reads from sirc and ships it out to the right
+ (hopefully) window.
+
+ Problem trying to solve:
+
+ _buffer holds upto 1024 (it seems) block of data. We need to
+ take it, split into lines figure out where each line should go,
+ and ship it there.
+
+ We watch for broken end of lines, ie partial lines and reattach
+ them to the front on the next read.
+
+ We also stop all processing in the windows while writting the
+ lines.
+
+ Implementation:
+
+ Variables:
+ _buffer original buffer, holds just, icky thing, NOT NULL terminated!
+ buf: new clean just the right size buf that is null terminated.
+ pos, pos2, pos3 used to cut the string up into peices, etc.
+ name: destination window.
+ line: line to ship out.
+
+ Steps:
+ 1. read and copy buffer, make sure it's valid.
+ 2. If we're holding a broken line, append it.
+ 3. Check for a broken line, and save the end if it is.
+ 4. Stop updates in all windows.
+ 5. Step through the data and send the lines out to the right
+ window.
+ 6. Cleanup and continue.
+
+ */
+
+ int pos,pos2,pos3;
+ QCString name, line;
+
+ assert(_buffer != 0);
+ assert(buflen > 0);
+
+ QCString buffer(_buffer, buflen+1);
+ //fprintf(stderr, "first print: \n");
+ //my_print(buffer);
+ //kdDebug(5008) << "<-- read: " << buffer << endl;
+ name = "!default";
+
+
+ if(holder.length() > 0){
+ buffer.prepend(holder);
+ holder.truncate(0);
+ }
+
+ if(buffer[buffer.length()-1] != '\n'){
+ pos = buffer.findRev('\n');
+ if(pos != -1){
+ holder = buffer.right(buffer.length()-(pos+1));
+ buffer.truncate(pos+1);
+ }
+ else {
+ /* there is _NO_ linefeeds in this line at all, means we're
+ * only part of a string, buffer it all!!
+ * (lines are linefeed delimeted)
+ */
+ holder = buffer;
+ return;
+ }
+ }
+
+ pos = pos2 = 0;
+
+ KSircMessageReceiver * rec = ksircproc->TopList["!all"];
+
+ if (0 == rec)
+ {
+ return;
+ }
+
+ rec->control_message(STOP_UPDATES, "");
+ if(m_debugLB)
+ m_debugLB->setUpdatesEnabled(false);
+
+ do{
+ pos2 = buffer.find('\n', pos);
+
+ if(pos2 == -1)
+ pos2 = buffer.length();
+
+ line = buffer.mid(pos, pos2 - pos);
+ if(m_debugLB){
+ QString s = QString::fromUtf8(line);
+ m_debugLB->insertItem(s);
+ }
+
+ //kdDebug(5008) << "Line: " << line << endl;
+
+ if((line.length() > 0) && (line[0] == '~')){
+ pos3 = line.find('~', 1);
+ if(pos3 > 1){
+ name = line.mid(1,pos3-1).lower();
+ name = name.lower();
+ line.remove(0, pos3+1);
+ }
+ }
+ QString enc = KGlobal::charsets()->encodingForName( ksopts->channel["global"]["global"].encoding );
+ QTextCodec *qtc = KGlobal::charsets()->codecForName( enc );
+ QString qsname = qtc->toUnicode(name);
+ /*
+ char *b = qstrdup(line);
+ kdDebug(5008) << "----------------------------------------" << endl;
+ kdDebug(5008) << "Line: " << b << endl;
+ fprintf(stderr, "My_print: " ); my_print(b);
+ fprintf(stderr, "fprintf: %s\n", (const char *)b);
+ kdDebug(5008) << "Codec: " << qtc->name() << " (" << ksopts->channel["global"]["global"].encoding << ")" << " Name: " << name << " qsname: " << qsname << endl;
+ kdDebug(5008) << "Line(de): " << qtc->toUnicode(b) << endl;
+ kdDebug(5008) << "----------------------------------------" << endl;
+ */
+
+ if(!(ksircproc->TopList[qsname])){
+ // Ignore ssfe control messages with `
+ // we left channel, don't open a window for a control message
+ bool noticeCreate = true;
+ if(ksopts->autoCreateWinForNotice == false && (line[0] == '-' || line[0] == '*'))
+ noticeCreate = false;
+ if(ksopts->autoCreateWin == TRUE && line[0] != '`' && line[1] != '#' && line[1] != '&' && noticeCreate) {
+ //kdDebug(5008) << "Creating window for: " << qsname << " because of: " << line.data() << endl;
+ ksircproc->new_toplevel(KSircChannel(ksircproc->serverName(), qsname));
+ }
+ if (!ksircproc->TopList[qsname]) {
+ qsname = "!default";
+ if(line[0] == '`')
+ qsname = "!discard";
+ }
+ assert(ksircproc->TopList[qsname]);
+ }
+
+ ksircproc->TopList[qsname]->sirc_receive(line);
+
+
+ pos = pos2+1;
+ } while((uint) pos < buffer.length());
+
+ ksircproc->TopList["!all"]->control_message(RESUME_UPDATES, "");
+ if(m_debugLB){
+ m_debugLB->triggerUpdate(true);
+ m_debugLB->setContentsPos( 0, m_debugLB->contentsHeight()-m_debugLB->visibleHeight());
+ m_debugLB->setUpdatesEnabled(true);
+ m_debugLB->triggerUpdate(false);
+ }
+
+
+}
+
+KSircIOController::~KSircIOController()
+{
+ delete m_debugLB;
+}
+
+void KSircIOController::stderr_read(KProcess *p, char *b, int l)
+{
+ stdout_read(p, b, l);
+}
+
+void KSircIOController::stdin_write(QCString s)
+{
+ if (!proc->isRunning())
+ {
+ kdDebug(5008) << "writing to a dead process! (" << s << ")\n";
+ return;
+ }
+
+ //kdDebug(5008) << "--> wrote: " << s;
+ buffer += s;
+ //fprintf(stderr, "Buffer output: ");
+ //my_print(buffer);
+
+ if(proc_CTS == TRUE){
+ int len = buffer.length();
+ if(send_buf != 0x0){
+ qWarning("KProcess barfed in all clear signal again");
+ delete[] send_buf;
+ }
+ send_buf = new char[len];
+ memcpy(send_buf, buffer.data(), len);
+ if(proc->writeStdin(send_buf, len) == FALSE){
+ kdDebug(5008) << "Failed to write but CTS HIGH! Setting low!: " << s << endl;
+ }
+ else{
+ if(m_debugLB){
+ QString s = QString::fromUtf8(buffer);
+ m_debugLB->insertItem(s);
+ m_debugLB->setContentsPos( 0, m_debugLB->contentsHeight());
+ }
+ buffer.truncate(0);
+ }
+ proc_CTS = FALSE;
+ }
+
+ if(buffer.length() > 5000){
+ kdDebug(5008) << "IOController: KProcess barfing again!\n";
+ }
+ // write(sirc_stdin, s, s.length());
+
+}
+
+void KSircIOController::sircDied(KProcess *process)
+{
+ if ( process->exitStatus() == 0 )
+ return;
+ kdDebug(5008) << "IOController: KProcess died!\n";
+ ksircproc->TopList["!all"]->sirc_receive("*E* DSIRC IS DEAD");
+ ksircproc->TopList["!all"]->sirc_receive("*E* KSIRC WINDOW HALTED");
+ ksircproc->TopList["!all"]->sirc_receive( QCString( "*E* Tried to run: " ) + KGlobal::dirs()->findExe("dsirc").ascii() + QCString( "\n" ) );
+ ksircproc->TopList["!all"]->sirc_receive("*E* DID YOU READ THE INSTALL INTRUCTIONS?");
+}
+
+void KSircIOController::procCTS ( KProcess *)
+{
+ proc_CTS = true;
+ delete[] send_buf;
+ send_buf = 0x0;
+ if(!buffer.isEmpty()){
+ QCString str = "";
+ stdin_write(str);
+ }
+}
+
+void KSircIOController::showContextMenuOnDebugWindow(QListBoxItem *, const QPoint &pos)
+{
+ if (!m_debugLB)
+ return;
+
+ QPopupMenu popup(m_debugLB);
+ popup.insertItem("Save Contents to File...", 1);
+ if (popup.exec( pos ) != 1)
+ return;
+
+ QString path = KFileDialog::getSaveFileName();
+ if (path.isEmpty())
+ return;
+
+ QFile file(path);
+ if (!file.open(IO_WriteOnly))
+ return;
+
+ QTextStream stream(&file);
+
+ for (uint i = 0; i < m_debugLB->count(); ++i)
+ stream << m_debugLB->text(i) << endl;
+}
+
+void KSircIOController::showDebugTraffic(bool show)
+{
+ kdDebug(5008) << "Got show request: " << show << endl;
+ if(m_debugLB == 0 && show == true){
+ m_debugLB = new QListBox(0x0, QCString(this->name()) + "_debugWindow");
+ m_debugLB->resize(600, 300);
+ m_debugLB->show();
+ connect(m_debugLB,SIGNAL(contextMenuRequested(QListBoxItem *,const QPoint &)),
+ this,SLOT(showContextMenuOnDebugWindow(QListBoxItem *,const QPoint &)));
+ }
+ else if(m_debugLB != 0 && show == false){
+ delete m_debugLB;
+ m_debugLB = 0x0;
+ }
+
+}
+
+bool KSircIOController::isDebugTraffic()
+{
+ if(m_debugLB != 0)
+ return true;
+ else
+ return false;
+}
+
+void KSircIOController::appendDebug(QString s)
+{
+ if(m_debugLB){
+ m_debugLB->insertItem(s);
+ m_debugLB->setContentsPos( 0, m_debugLB->contentsHeight()-m_debugLB->visibleHeight());
+ }
+}
+
+#include "iocontroller.moc"
diff --git a/ksirc/iocontroller.h b/ksirc/iocontroller.h
new file mode 100644
index 00000000..76c97e18
--- /dev/null
+++ b/ksirc/iocontroller.h
@@ -0,0 +1,54 @@
+#ifndef IOCONTROL_H
+#define IOCONTROL_H
+
+#include <qobject.h>
+
+class KProcess;
+class KSircProcess;
+class QListBox;
+class QListBoxItem;
+
+class KSircIOController : public QObject
+{
+
+ Q_OBJECT
+ friend class KSircProcess;
+public:
+ KSircIOController(KProcess *, KSircProcess *);
+ virtual ~KSircIOController();
+
+ void showDebugTraffic(bool show);
+ bool isDebugTraffic();
+
+public slots:
+ virtual void stdout_read(KProcess *proc, char *_buffer, int buflen);
+ virtual void stderr_read(KProcess *proc, char *_buffer, int buflen);
+
+ virtual void stdin_write(QCString);
+
+ virtual void sircDied(KProcess *);
+
+ virtual void appendDebug(QString);
+
+
+protected slots:
+ virtual void procCTS(KProcess *);
+
+private slots:
+ void showContextMenuOnDebugWindow( QListBoxItem *, const QPoint &pos );
+
+private:
+ QCString holder;
+ bool proc_CTS;
+ KProcess *proc;
+ KSircProcess *ksircproc;
+ char *send_buf;
+
+ QCString buffer;
+
+ static int counter;
+
+ QListBox *m_debugLB;
+};
+
+#endif
diff --git a/ksirc/ksirc.cpp b/ksirc/ksirc.cpp
new file mode 100644
index 00000000..eddb450a
--- /dev/null
+++ b/ksirc/ksirc.cpp
@@ -0,0 +1,151 @@
+/*************************************************************************
+
+ Main KSirc start
+
+ $$Id$$
+
+ Main start file that defines 3 global vars, etc
+
+*************************************************************************/
+
+/*
+ * Needed items
+ * 4. Send a /quit and/or kill dsirc on exit
+ * */
+
+#include <stdlib.h>
+
+#include <qsessionmanager.h>
+
+#include <kuniqueapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+//#include "cdate.h"
+#include "ksopts.h"
+#include "servercontroller.h"
+#include "version.h"
+
+static const char description[] =
+ I18N_NOOP("KDE IRC client");
+
+//QDict<KSircTopLevel> TopList;
+//QDict<KSircMessageReceiver> TopList;
+
+class KCmdLineOptions options[] =
+{
+ { "nick <nickname>", I18N_NOOP( "Nickname to use" ), 0 } ,
+ { "server <server>", I18N_NOOP( "Server to connect to on startup" ), 0 },
+ { "channel <#channel>", I18N_NOOP( "Channel to connect to on startup" ), 0 },
+ { "o", 0, 0 },
+ { "noautoconnect", I18N_NOOP( "Do not autoconnect on startup" ), 0 },
+ KCmdLineLastOption
+};
+
+class KSircSessionManaged : public KSessionManaged
+{
+public:
+ KSircSessionManaged() {}
+
+ virtual bool commitData( QSessionManager &sm )
+ {
+ servercontroller *controller = servercontroller::self();
+ if ( !controller || !sm.allowsInteraction() ) return true;
+
+ // if the controller is hidden KMWSessionManaged won't send the fake close event.
+ // we want it in any way however.
+ if ( controller->isHidden() ) {
+ QCloseEvent e;
+ QApplication::sendEvent( controller, &e );
+ }
+
+ return true;
+ }
+};
+
+extern "C" KDE_EXPORT int kdemain( int argc, char ** argv )
+{
+ KAboutData aboutData( "ksirc", I18N_NOOP("KSirc"),
+ KSIRC_VERSION, description, KAboutData::License_Artistic,
+ I18N_NOOP("(c) 1997-2002, The KSirc Developers"));
+ aboutData.addAuthor("Andrew Stanley-Jones",I18N_NOOP("Original Author"), "asj-ksirc@cban.com");
+ aboutData.addAuthor("Waldo Bastian",0, "bastian@kde.org");
+ aboutData.addAuthor("Carsten Pfeiffer",0, "pfeiffer@kde.org");
+ aboutData.addAuthor("Malte Starostik",0, "malte@kde.org");
+ aboutData.addAuthor("Daniel Molkentin",0, "molkentin@kde.org");
+ aboutData.addAuthor("Simon Hausmann",0, "hausmann@kde.org");
+ aboutData.addAuthor("Alyssa Mejawohld", I18N_NOOP("Icons Author"), "amejawohld@bellsouth.net");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KUniqueApplication::addCmdLineOptions();
+
+ if (!KUniqueApplication::start()) {
+ exit(0);
+ }
+
+ // Start the KDE application
+ KUniqueApplication app;
+
+ KSircSessionManaged sm;
+
+ // Options
+ KSOptions opts;
+ opts.load();
+
+ servercontroller *sc = new servercontroller(0, "servercontroller");
+ app.setMainWidget(sc);
+
+ if (KMainWindow::canBeRestored(1))
+ {
+ sc->restore(1, false );
+ }
+ else
+ { // no Session management -> care about docking, geometry, etc.
+
+ if( !opts.geometry.isEmpty() )
+ sc->setGeometry( opts.geometry );
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ QCString nickName = args->getOption( "nick" );
+ QCString server = args->getOption( "server" );
+ QCString channel = args->getOption( "channel" );
+
+ if ( !nickName.isEmpty() )
+ ksopts->server["global"].nick = nickName;
+
+ if ( !server.isEmpty() ) {
+ QString ser = QString::fromLocal8Bit( server );
+ QString port = "6667";
+ if(ser.contains(":")){
+ port = ser.section(":", 1, 1);
+ ser = ser.section(":", 0, 0);
+ }
+ KSircServer kss(ser, port, "", "", false);
+ sc->new_ksircprocess( kss );
+ if ( !channel.isEmpty() ) {
+ QStringList channels = QStringList::split( ',', QString::fromLocal8Bit( channel ) );
+ QStringList::ConstIterator it = channels.begin();
+ QStringList::ConstIterator end = channels.end();
+ for ( ; it != end; ++it ) {
+ sc->new_toplevel( KSircChannel(ser, *it), true );
+ }
+ }
+ }
+ else {
+ if(args->isSet("autoconnect") == TRUE){
+ sc->start_autoconnect();
+ }
+ }
+
+ args->clear();
+ }
+
+ return app.exec();
+}
+
+/* vim: et sw=4
+ */
diff --git a/ksirc/ksirc.desktop b/ksirc/ksirc.desktop
new file mode 100644
index 00000000..1289552e
--- /dev/null
+++ b/ksirc/ksirc.desktop
@@ -0,0 +1,87 @@
+[Desktop Entry]
+GenericName=IRC Client
+GenericName[af]=Irc Kliënt
+GenericName[ar]=عميل IRC
+GenericName[be]=Кліент IRC
+GenericName[bg]=Клиент за IRC
+GenericName[bn]=আই-আর-সি কà§à¦²à¦¾à§Ÿà§‡à¦¨à§à¦Ÿ
+GenericName[br]=Kliant IRC
+GenericName[ca]=Client IRC
+GenericName[cs]=IRC klient
+GenericName[cy]=Dibynnydd IRC
+GenericName[da]=IRC-klient
+GenericName[de]=IRC Programm
+GenericName[el]=Πελάτης IRC
+GenericName[eo]=IRC-kliento
+GenericName[es]=Cliente de IRC
+GenericName[et]=IRC klient
+GenericName[eu]=IRC bezeroa
+GenericName[fa]=کارخواه IRC
+GenericName[fi]=IRC-asiakasohjelma
+GenericName[fr]=Client IRC
+GenericName[ga]=Cliant IRC
+GenericName[gl]=Cliente de IRC
+GenericName[he]=לקוח IRC
+GenericName[hi]=आईआरसी कà¥à¤²à¤¾à¤à¤‚ट
+GenericName[hr]=IRC klijent
+GenericName[hu]=IRC-kliens
+GenericName[is]=IRC forrit
+GenericName[it]=Client IRC
+GenericName[ja]=IRC クライアント
+GenericName[ka]=IRC კლიენტი
+GenericName[kk]=IRC клиенті
+GenericName[km]=កម្មវិធី IRC
+GenericName[lt]=IRC klientas
+GenericName[lv]=IRC Klients
+GenericName[mk]=Клиент за IRC
+GenericName[mn]=IRC Ñ…ÑÑ€ÑглÑгч
+GenericName[ms]=Klien IRC
+GenericName[mt]=Klijent IRC
+GenericName[nb]=IRC-klient
+GenericName[nds]=IRC-Klöönprogramm
+GenericName[ne]=आइआरसी कà¥à¤²à¤¾à¤‡à¤¨à¥à¤Ÿ
+GenericName[nl]=IRC-client
+GenericName[nn]=IRC-klient
+GenericName[nso]=Moreki wa IRC
+GenericName[pa]=IRC ਕਲਾਂਇਟ
+GenericName[pl]=Klient IRC
+GenericName[pt]=Cliente de IRC
+GenericName[pt_BR]=Cliente IRC
+GenericName[ro]=Un client IRC
+GenericName[ru]=Клиент IRC
+GenericName[se]=IRC-klienta
+GenericName[sk]=IRC klient
+GenericName[sl]=Odjemalec za IRC
+GenericName[sr]=IRC клијент
+GenericName[sr@Latn]=IRC klijent
+GenericName[sv]=IRC-klient
+GenericName[ta]=IRC நிரலà¯
+GenericName[tg]=Мизоҷи IRC
+GenericName[th]=ไคลเอนต์ IRC
+GenericName[tr]=IRC Programı
+GenericName[uk]=Клієнт IRC
+GenericName[uz]=IRC klienti
+GenericName[uz@cyrillic]=IRC клиенти
+GenericName[ven]=Mushumisani wa IRC
+GenericName[wa]=Cliyint IRC
+GenericName[xh]=Umxhasi we IRC
+GenericName[zh_CN]=IRC 客户程åº
+GenericName[zh_HK]=IRC 客戶端程å¼
+GenericName[zh_TW]=IRC 客戶端程å¼
+GenericName[zu]=Umthengi we IRC
+SwallowExec=
+Name=KSirc
+Name[af]=Ksirc
+Name[bn]=কে-à¦à¦¸-আর-আই-সি
+Name[eo]=IRC-kliento
+Name[hi]=के-à¤à¤¸à¤†à¤ˆà¤†à¤°à¤¸à¥€
+Name[sv]=Ksirc
+MimeType=
+Exec=ksirc %i %m
+Icon=ksirc
+Path=
+Type=Application
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Network;IRCClient;
diff --git a/ksirc/ksirc.pl b/ksirc/ksirc.pl
new file mode 100644
index 00000000..a1768f63
--- /dev/null
+++ b/ksirc/ksirc.pl
@@ -0,0 +1,781 @@
+#
+# $$Id$$
+#
+
+&addhelp("server",
+"\cbAdded by KSirc.pl\cb
+Usage: server server [port] [password]
+Connects to a new server opening it in a new window.
+If server name is prefixed with a + then an ssl connection
+is used. Port and password are optional.");
+
+&addhelp("Ban",
+"\cbAdded by KSirc.pl\cb
+Usage: BAN <nickname>
+bans the specified user on the current channel. Only channel operators
+can use this command. Bans the user in the form *!*user\@hostmask.
+hostmask is xxx.xxx.xxx.* if the hostname is in dotted quad form, otherwise
+it is *.domain.com
+See Also: UNBAN, CLRBAN, BANLIST");
+
+&addhelp("UnBan",
+"\cbAdded by KSirc.pl\cb
+Usage: UNBAN <nickname>
+Unbans the specified user on the given channel. Only channel operators
+can use this command.
+See Also: BAN, CLRBAN, BANLIST");
+
+&addhelp("ClrBan",
+"\cbAdded by KSirc.pl\cb
+Usage: CLRBAN [<#channel>]
+Removes ALL bans from the given channel. Only channel operators can use
+this command. The channel defaults to your current one.
+See Also: MODE [-b], BAN, UNBAN, CLRBAN, BANLIST");
+
+&addhelp("BanList",
+"\cbAdded by KSirc.pl\cb
+Usage: BANLIST [<#channel>]
+Shows all bans on the given channel. The channel defaults to your current one.
+See Also: BAN, UNBAN, CLRBAN");
+
+&addhelp("FC",
+"\cbAdded by KSirc.pl\cb
+Usage: FC [<#channel>] <Filter> <command>
+Does /names on the given channel. Uses the current channel if none
+specified. Does a userhost on each person received. if their name
+(in form nick!user\@host) matches your filter (in perl regex form)
+then command is executed, in command $1 is expanded to the nick of
+the matchee.
+Examples:
+ /fc #dragonrealm *!*\@*.com msg $1 you are on a host that ends in .com
+ /fc *!*\@((\\d+)\\.){3}\\.(\\d+) say $1 has a numeric host.");
+
+&addhelp("Pig",
+"\cbAdded by KSirc.pl\cb
+Usage: PIG <message>
+Translates your message into piglatin and says it on the current channel.");
+
+&addhelp("WallOP",
+"\cbAdded by KSirc.pl\cb
+Usage: WALLOP [<#channel>] <message>
+Sends a message to all of the channel operators on the given channel.
+Defaults the the current channel.");
+
+&addhelp("Amarok",
+"\cbAdded by KSirc.pl\cb
+Usage: AMAROK
+Sends a message to the current channel saying what are you playing in amarok.");
+
+sub cmd_wallop {
+ &getarg;
+ unless ($newarg =~ /^#/) {
+ $args = $newarg." ".$args;
+ $newarg = $talkchannel;
+ }
+ &notice("\@$newarg","[KSirc-Wall/$newarg]: $args");
+}
+&addcmd("wallop");
+
+
+sub modeb {
+ ($which) = @_;
+ $user =~ s/^~//;
+ if (length($user) > 8) {
+ $user = substr($user,0, 7);
+ $user .= "*";
+ }
+ @quad = split(/\./, $host);
+ if ($host =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
+ pop @quad;
+ $toban = join('.', @quad);
+ $toban .= ".*";
+ } else {
+ $toban = "*".$quad[@quad-2].".".$quad[@quad-1];
+ }
+ &docommand("mode $talkchannel ${which}b *!*$user*\@$toban");
+}
+
+sub cmd_ban {
+ &getarg;
+ if ($newarg) {
+ &userhost($newarg, "&modeb(\"+\");");
+ } else {
+ &tell("*\cbE\cb* Usage: /ban <nick>.");
+ }
+}
+&addcmd("ban");
+
+sub cmd_unban {
+ &getarg;
+ if ($newarg) {
+ &userhost($newarg, "&modeb(\"-\");");
+ } else {
+ &tell("*\cbE\cb* Usage: /unban <nick>.");
+ }
+}
+&addcmd("unban");
+
+sub cmd_banlist {
+ &getarg;
+ $newarg = $talkchannel unless $newarg;
+ &docommand("mode $newarg b");
+ &addhook("367", "banlist");
+ &addhook("368","rmbanlist");
+}
+&addcmd("banlist");
+
+sub hook_banlist {
+ $silent = 1;
+ my (undef, $channel, $mask, $banner, $time) = split(/ +/, $_[0]);
+ &print("~!default~*** \cb$mask\cb banned from \cb$channel\cb by \cb$banner\cb on \cb" . localtime($time). "\cb");
+}
+
+sub hook_rmbanlist {
+ &remhook("367","banlist");
+ &remhook("368","rmbanlist");
+}
+
+sub cmd_k {
+ &getarg;
+ $args = "You have been kicked by a KSirc user." unless $args;
+ if ($newarg) {
+ &docommand("kick $talkchannel $newarg $args");
+ } else {
+ &tell("*\cbE\cb* Usage: /k <nick> [reason]");
+ }
+}
+&addcmd("k");
+
+sub cmd_kb {
+ &getarg;
+ if ($newarg) {
+ &docommand("ban $newarg");
+ &docommand("k $newarg $args");
+ } else {
+ &tell("*\cbE\cb* Usage: /kb <nick> [reason]");
+ }
+}
+&addcmd("kb");
+
+sub cmd_clrban {
+ &getarg;
+ $newarg = $talkchannel unless $newarg;
+ &addhook("367", "tban");
+ &addhook("368","rm367");
+ &docommand("mode $newarg b");
+}
+&addcmd("clrban");
+
+sub hook_tban {
+ $silent = 1;
+ my ($shit, $channel, $mask, $banner, $time) = split(/ +/, $_[0]);
+ push @bans, $mask;
+ if (@bans == 6) {
+ &print("mode $channel -bbbbbb @bans");
+ @bans = ();
+ }
+}
+
+sub hook_rm367 {
+ @bans = ();
+ &remhook("367","tban");
+ &remhook("368","rm367");
+}
+
+sub hook_disconnectd {
+ &docommand("server 1");
+}
+&addhook("disconnect","disconnectd");
+
+#sub hook_kickd {
+# &docommand("join $_[1]") if $_[0] eq $nick;
+#}
+#&addhook("kick","kickd");
+
+sub cmd_fcmd {
+ ($names,$mask,$command) = split(/ /, $args,3);
+ $mask =~ s/\!/\!/;
+ $mask =~ s/\@/\@/;
+ $mask =~ s/\./\\./g;
+ $mask =~ s/\*/.*/g;
+ &addhook("353","filtercommand");
+ &addhook("366","removefiltercommand");
+ &tell("\t\cb~4Matching /$mask/i on $names...");
+ &docommand("names $names");
+}
+&addcmd("fcmd");
+
+sub hook_filtercommand {
+ ($shit, $_[0]) = split(/:/, $_[0]);
+ my @names = split(/ /, $_[0]);
+ for (@names) {
+ $_ =~ s/^\@//;
+ &userhost($_, "&dofilter");
+ }
+ $silent=1;
+}
+
+sub dofilter {
+ $s = "$who\!$user\@$host";
+ #&tell("$s =~ /$mask/");
+ if ($s =~ /$mask/i) {
+ $d = $command;
+ $d =~ s/\$1/$who/;
+ &docommand($d);
+ }
+}
+
+sub hook_removefiltercommand {
+ &remhook("353","filtercommand");
+ &remhook("366","removefiltercommand");
+ &tell("*\cbI\cb* Filter on $names, /$mask/i, Done.");
+}
+
+sub cmd_fc {
+ my ($mask, $cmd) = split(/ /, $args, 2);
+ &docommand("fcmd $talkchannel $mask $cmd");
+}
+&addcmd("fc");
+
+sub cmd_pig {
+ $_[0] =~ s/^pig //i;
+ &say(&topiglatin($_[0]));
+}
+&addcmd("pig");
+
+sub topiglatin {
+@words = split(/ /, $_[0]);
+for (@words) {
+ if ($_ =~ /^([bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ])([aeiouAEIOU])/) {
+ $_ .= substr($_,0,1)."ay";
+ $_ = substr($_,1);
+ } elsif ($_ =~ /^([bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ])([bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ])/) {
+ $_ .= $1.$2."ay";
+ $_ = substr($_,2);
+ } elsif ($_ =~ /^[aeiouAEIOU]/) {
+ $_ .= "way";
+ } else {
+ print "shouldn't print me\n";
+ }
+}
+return "@words";
+}
+
+&addhelp("follow",
+"\cbAdded by KSirc.pl\cb
+Usage: follow <nick>
+Highlight <nick> in colour when ever they say anything");
+
+&addhelp("unfollow",
+"\cbAdded by KSirc.pl\cb
+Usage: unfollow <nick>
+Stop highlighting the nick");
+
+&addhelp("showfollows",
+"\cbAdded by KSirc.pl\cb
+Usage: showfollows
+Shows who you are currently following");
+
+#### Start follow script from caracas
+
+&addcmd ('follow');
+&addcmd ('unfollow');
+&addcmd ('showfollows');
+
+
+@follow_colors = ( '~1', '~2', '~3', '~4', '~5', '~6', '~7', '~8', '~9', '~10', '~11', '~12', '~13', '~14', '~15' );
+undef %following;
+
+
+sub cmd_follow
+{
+ my ($fnick) = shift;
+ my ($color);
+
+ $fnick =~ s/^follow\s+//;
+ $fnick =~ tr/A-Z/a-z/;
+ if (defined ($following{$fnick}))
+ {
+ &tell ("*\cbI\cb* Already following " . $following{$fnick});
+ }
+ else
+ {
+ $color = $follow_colors [int (rand scalar (@follow_colors))];
+ &docommand ("^ksircappendrule DESC==Follow $fnick !!! " .
+ "SEARCH==<\\S*$fnick\\S*> !!! FROM==<\\S*($fnick)\\S*> !!! TO==\"<$color\$1~c>\"");
+ $following{$fnick} = "${color}${fnick}~c";
+ &tell ("*\cbI\cb* Following ${color}$fnick~c ...");
+ }
+}
+
+
+sub cmd_unfollow
+{
+ my ($fnick) = shift;
+ my ($filter);
+
+ $fnick =~ s/^unfollow\s+//;
+ $fnick =~ tr/A-Z/a-z/;
+ for ($filter = 0; $filter <= $#KSIRC_FILTER; $filter++)
+ {
+ if ($KSIRC_FILTER [$filter]{'DESC'} =~ /Follow $fnick/i)
+ {
+ &docommand ("^ksircdelrule $filter");
+ delete ($following{$fnick});
+ &tell ("*\cbI\cb* $fnick no longer followed");
+ return;
+ }
+ }
+ &tell ("*\cbI\cb* Wasn't following $fnick");
+}
+
+
+sub cmd_showfollows
+{
+ my ($fnick);
+
+ if (scalar (keys %following) > 0)
+ {
+ foreach $fnick (sort keys %following)
+ {
+ &tell ("*\cbI\cb* Following " . $following {$fnick});
+ }
+ }
+ else
+ {
+ &tell ("\*cbI\cb* Not currently following anyone");
+ }
+}
+
+#### End follow
+
+sub cmd_refresh
+{
+ &tell("*** Refresh nick list");
+ &docommand("^extnames_forget $dest_chan");
+ &docommand("extnames $dest_chan");
+}
+&addcmd("refresh");
+
+sub hook_url_who_list {
+ my @info = split(/\s+/, $_[0]);
+ &print("*I* URL: http://$info[3]:<port>/");
+ $silent = 1;
+}
+
+sub hook_url_end_who {
+ &remhook("352", "url_who_list");
+ &remhook("315", "url_end_who");
+ $args = "";
+}
+
+&addhelp("url",
+"\cbAdded by KSirc.pl\cb
+Usage: URL
+Prints out your url");
+
+
+sub cmd_url
+{
+ &addhook("352", "url_who_list");
+ &addhook("315", "url_end_who");
+ &sl("who :$nick");
+}
+&addcmd("url");
+
+%WHO_IGNORE = "";
+
+sub cmd_extnames
+{
+ &dosplat;
+ &getarg;
+ $newarg =~ tr/A-Z/a-z/;
+ return if $WHO_IGNORE{$newarg} == 1;
+ if($who_active == 0){
+ &addhook("352", "ksirc_who_list");
+ &addhook("315", "ksirc_who_end");
+ }
+ &sl("who :$newarg");
+ $who_active++;
+ $WHO_INFO{$newarg} = "";
+ $WHO_TIME{$newarg} = 0;
+ $WHO_COUNT{$newarg} = 0;
+}
+&addcmd("extnames");
+
+sub hook_ksirc_who_end {
+ $who_active--;
+ if($who_active == 0){
+ &remhook("352", "ksirc_who_list");
+ &remhook("315", "ksirc_who_end");
+ }
+ my @info = split(/\s+/, $_[0]);
+ # 0: our nick
+ # 1: channel
+ # 2 Onwards: misc info
+ $info[1] =~ tr/A-Z/a-z/;
+ chop($WHO_INFO{$info[1]}); # Remove trailing space
+ my $c = ($WHO_TIME{$info[1]} == 0) ? "C" : "!";
+ if(length($WHO_INFO{$info[1]}) > 0){
+ &print("~$info[1]~*$c* Users on $info[1]: $WHO_INFO{$info[1]}");
+ $WHO_COUNT{$info[1]}++;
+ }
+ &print("~$info[1]~*c* Done Parsing Who");
+
+
+ # print "*I* Parsing: extnames done, $info[1], count: " . $WHO_COUNT{$info[1]} . "\n";
+ if($WHO_COUNT{$info[1]} > 25){
+ if($WHO_IGNORE{$info[1]} != 1){
+ $WHO_IGNORE{$info[1]} = 1;
+ &print('*$*' . " Extended nick list info turned off for $info[1], too many people in channel\n");
+ &print("*I* Extended nick list info turned off for $info[1], too many people in channel\n");
+ }
+ }
+ else {
+ $WHO_IGNORE{$info[1]} = 0;
+ }
+
+ delete($WHO_COUNT{$info[1]});
+ delete($WHO_INFO{$info[1]});
+ delete($WHO_TIME{$info[1]});
+ $args = "";
+}
+
+sub hook_ksirc_who_list {
+ my @info = split(/\s+/, $_[0]);
+ # 0: our nick
+ # 1: channel
+ # 2: ident
+ # 3: one server
+ # 4: another server
+ # 5: nick
+ # 6: status
+ # 7: rest is useless
+ $silent = 1;
+ my $who_nick = $info[5];
+ # print "*I* Parsing: $_[0], info6: $info[6]\n";
+ if($info[6] =~ /G/){
+ $who_nick = "#" . $who_nick;
+ }
+ if($info[6] =~ /\+/){
+ $who_nick = "+" . $who_nick;
+ }
+ if($info[6] =~ /\@/){
+ $who_nick = "@" . $who_nick;
+ }
+ if($info[6] =~ /\*/){
+ $who_nick = "*" . $who_nick;
+ }
+ $info[1] =~ tr/A-Z/a-z/;
+ $WHO_COUNT{$info[1]}++;
+
+ $WHO_INFO{$info[1]} .= $who_nick . " ";
+ if(length($WHO_INFO{$info[1]}) > 350){
+ my $c = ($WHO_TIME{$info[1]} == 0) ? "C" : "!";
+ &print("~$info[1]~*$c* Users on $info[1]: $WHO_INFO{$info[1]}");
+ $WHO_INFO{$info[1]} = "";
+ $WHO_TIME{$info[1]}++;
+ }
+}
+
+sub cmd_extnames_forget
+{
+ &dosplat;
+ &getarg;
+ $newarg =~ tr/A-Z/a-z/;
+ $WHO_IGNORE{$newarg} = 0;
+}
+
+&addcmd("extnames_forget");
+
+sub hook_nicks_on_join {
+ my $channel = shift;
+ if(&eq($who, $nick)){
+ &docommand("^extnames_forget $channel");
+ }
+ &docommand("^extnames $channel");
+}
+
+addhook("join", "nicks_on_join");
+
+
+&tell("*** \0032,4\cbLoaded KSirc.pl\003");
+&tell("*** \00313,3\cbWith: Super Willy Enhancements, LotR's exec\003");
+sub cmd_exec {
+
+ my $how, $to;
+
+ &getarg;
+ $how = "x";
+ if (&eq($newarg, "-OUT")) { $how = 'c'; }
+ if (&eq($newarg, "-MSG")) { $how = 'm'; &getarg; $to = $newarg; }
+ if (&eq($newarg, "-NOTICE")) { $how = 'n'; &getarg; $to = $newarg; }
+ if ($how eq "x") { $args = $newarg . " " . $args; }
+ open (CMD, "$args|");
+ while (<CMD>) {
+ chomp;
+ if ($how eq 'c') {
+ &say(" $_");
+ } elsif ($how eq 'm') {
+ &msg($to, $_);
+ } elsif ($how eq 'n') {
+ &notice($to, $_);
+ } else {
+ print "$_\n";
+ }
+ }
+ close CMD;
+}
+
+&addcmd("exec");
+&addhelp("exec", "Usage: EXEC <shell commands>\n" .
+ "EXEC -OUT <shell commands]\n" .
+ "EXEC -MSG <nickname> <shell commands>]\n" .
+ "EXEC -NOTICE <nickname> <shell commands>]\n" );
+
+$k_highlight = 1;
+
+if(open(FH, "<$HOME/.ksirc_highlight")){
+ chomp($k_highlight = <FH>);
+ close(FH);
+}
+
+sub hook_fixcolours {
+ if($k_highlight == 1){
+ $_[1] =~ s/(^|\s)\*([^*]+?)\*($|\s)/$1\002$2\002$3/g;
+ $_[1] =~ s/(^|\s)_([^_]+?)_($|\s)/$1\037$2\037$3/g;
+ $_[1] =~ s/(^|\s)#([^#]+?)#($|\s)/$1\026$2\026$3/g;
+ }
+}
+
+&addhook("send_text", "fixcolours");
+
+sub cmd_dishighlight {
+
+ print "*I* Highlight parsing: ";
+ if($k_highlight == 0) {
+ $k_highlight = 1;
+ print "Enabled\n";
+ }
+ else {
+ $k_highlight = 0;
+ print "Disabled\n";
+ }
+
+ if(open(FH, ">$ENV{HOME}/.ksirc_highlight")){
+ print FH "$k_highlight\n";
+ close(FH);
+ }
+ else {
+ print "*E* Can't save highlight state $!\n";
+ }
+
+}
+
+&addcmd("dishighlight");
+&addhelp("dishighlight", "Usage: dishighlight\n" .
+ "Toggles the convertion of *bold* into \cbbold\cb\n" .
+ "and _underline_ into \c_underline\c_ and #reverse#\n" .
+ "into \cvreverse\cv. It saves the state into\n" .
+ "~/.ksirc_highlight for convenience");
+
+sub cmd_help {
+ &tell("*\cbH\cb* Help not available"), return unless @help;
+ my $found ='';
+
+ &getarg;
+ if($newarg =~ /^\s*$/){
+ my $line = '';
+ my %once;
+ foreach (@help) {
+ if (/^\@/) {
+ if (&eq($_, "\@main")) {
+ $found=1;
+ &tell("*\cbH\cb* Help on $newarg") if $newarg ne 'main'; # KSIRC MOD
+ }
+ else {
+ $found=0;
+ }
+ }
+ else {
+ &tell("*\cbH\cb* $_") if $found;
+ }
+ }
+ foreach (@help) {
+ if(/^\@/){
+ if(!&eq($_, "\@main")){
+ $found = 0;
+ my $cmd = /\@(\S+)/;
+ next if $once{$1};
+ $once{$1} = 1;
+ $line .= "$1 " . " "x(15-length("$1 ")); # KSIRC MOD
+ if(length($line) > 50){
+ &tell("*\cbH\cb* $line");
+ $line = "";
+ }
+ }
+ }
+ }
+ &tell("*\cbH\cb* $line");
+ $found=1;
+ }
+ else{
+ $newarg =~ s/ *$//;
+ foreach (@help) {
+ if (/^\@/) {
+ last if $found;
+ if (&eq($_, "\@$newarg")) {
+ $found=1;
+ &tell("*\cbH\cb* Help on $newarg") if $newarg ne 'main';
+ }
+ } else {
+ &tell("*\cbH\cb* $_") if $found;
+ }
+ }
+ } # KSIRC MOD
+ &tell("*\cbH\cb* Unknown help topic; try /help") unless $found;
+}
+
+&addcmd("help");
+
+
+# New DCC resume/get features
+
+
+my %A_RESUME_WAIT = ();
+
+sub hook_ctcp_resume_reply {
+ my $towho = shift;
+ my $what = shift;
+ my $args = shift;
+
+ if($what eq 'DCC'){
+ my ($which, $file, $port, $pos) = split(/ +/, $args);
+ &tell("Got which: $which");
+ if($which eq 'ACCEPT'){
+ # &print("Got resume from $who port $port file: $file pos: $pos args: $args");
+ if($A_RESUME_WAIT{$port}){
+ &print("*\cbI\cb* DCC Resume with $who accepted");
+ &tell("~!dcc~DCC GET resumed who: $who file: " . $dgresume{$port}{"file"});
+ &tell("~!dcc~DCC GET read: " . $dgresume{$port}{"file"} . " bytes: " . $dgresume{$port}{"pos"}); # KSIRC MOD FOR 971217
+ $dgresume{$port}{"GotReply"} = 1;
+ delete $A_RESUME_WAIT{$port};
+ $skip = 1;
+
+ if($A_AUTOSTART{$port}){
+ &docommand($A_AUTOSTART{$port});
+ delete $A_AUTOSTART{$port};
+ }
+ }
+ }
+ elsif($which eq 'RESUME'){
+ my($lfh, $myport);
+ while(($lfh, $myport) = each %dsport){
+ if($port == $myport){
+ $skip = 1;
+ my $size = (-s $dfile{$dswait{$lfh}});
+ if($pos < $size){
+ seek($dswait{$lfh}, $pos, SEEK_SET);
+ $dsoffset{$lfh} = $pos;
+ &docommand("ctcp $who DCC ACCEPT $file $port $pos");
+ &tell("~!dcc~DCC SEND resumed who: $who file: " . $dfile{$dswait{$lfh}});
+ &tell("~!dcc~DCC SEND write: " . $dfile{$dswait{$lfh}} . " bytes: " . $pos); # KSIRC MOD FOR 971217
+ }
+ else {
+ &tell("*\cbE\cb* Got DCC resume with invalid size from $who for " . $dfile{$dswait{$lfh}});
+ }
+ }
+ }
+ }
+ }
+}
+
+&addhook("ctcp", "ctcp_resume_reply");
+
+sub hook_ctcp_reject_reply {
+ my $towho = shift;
+ my $what = shift;
+ my $args = shift;
+
+ if($what eq 'DCC'){
+ my ($which, $type, $file) = split(/ +/, $args);
+ if($which eq 'REJECT'){
+ &tell("Got reject");
+ if($type eq 'CHAT'){
+ $no_reject = 1;
+ &tell("*\cbI\cb* DCC CHAT with $who rejected");
+ &docommand("/dcc close chat $who");
+ $skip = 1;
+ }
+ elsif($type eq 'GET'){
+ $no_reject = 1;
+ &tell("*\cbI\cb* DCC GET rejected by $who for $file");
+ &docommand("/dcc close get $who $file");
+ $skip = 1;
+ }
+ elsif($type eq 'SEND'){
+ $no_reject = 1;
+ &tell("*\cbI\cb* DCC SEND rejected by $who file $file");
+ &docommand("/dcc close send $who $file");
+ $skip = 1;
+ }
+ }
+ }
+}
+
+&addhook("ctcp_reply", "ctcp_reject_reply");
+
+sub cmd_resume {
+ &getarg;
+ my $who = $newarg;
+ &getarg;
+ my $file = $newarg;
+
+ foreach $i (keys(%dgoffered)) {
+ my($h, $p, $f) = split(/ /, $i);
+ if (&eq($f, $file) && &eq($dgoffered{$i}, $who)) {
+ if(my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat($file)){
+ &print("*\cbI\cb* Doing resume for $f with $who ($p)");
+ &docommand("ctcp $who DCC RESUME $f $p $size");
+ $dgresume{$p}{"pos"} = $size;
+ $dgresume{$p}{"file"} = $f;
+ $dgresume{$p}{"who"} = $who;
+ $A_RESUME_WAIT{$p} = 1;
+ }
+ else {
+ &print("*\cbE\cb* Error getting file ($file) size: $!");
+ }
+ }
+ }
+}
+
+&addcmd("resume");
+
+
+sub cmd_amarok
+{
+ $dcop=`dcop amarok`;
+ if(! ($dcop =~ /player/) ) {
+ &print("Error: Amarok is *not* running");
+ return;
+ }
+
+ $dcop=`dcop amarok player isPlaying`;
+ if(! ($dcop =~ /true/) ) {
+ &print("Amarok is not playing anything");
+ return
+ }
+
+ $output='is playing "$dcop" with Amarok';
+ $dcop= `dcop amarok player nowPlaying` ;
+$dcop =~ s/^\s+//;
+$dcop =~ s/\s+$//;
+ $output=~ s/(\$\w+)/$1/eeg;
+ &me( $output );
+}
+&addcmd("amarok");
+
+
+
diff --git a/ksirc/ksircchannel.h b/ksirc/ksircchannel.h
new file mode 100644
index 00000000..1913b530
--- /dev/null
+++ b/ksirc/ksircchannel.h
@@ -0,0 +1,35 @@
+#ifndef KSIRCCHANNEL_H
+#define KSIRCCHANNEL_H
+
+#include <qstring.h>
+
+class KSircChannel
+{
+
+public:
+ KSircChannel( const QString server,
+ const QString channel,
+ const QString key = QString::null,
+ const QString encoding = QString::null
+ ) :
+ m_server(server), m_channel(channel),
+ m_key(key), m_encoding(encoding) {}
+
+ const QString server() const { return m_server; }
+ const QString channel() const { return m_channel; }
+ const QString key() const { return m_key; }
+ const QString encoding() const { return m_encoding; }
+
+ void setChannel(QString channel) { m_channel = channel; }
+ void setKey(QString key) { m_key = key; }
+ void setEncoding(QString encoding) { m_encoding = encoding; }
+
+private:
+ const QString m_server; /* channels can never change server */
+ QString m_channel;
+ QString m_key;
+ QString m_encoding;
+
+};
+
+#endif
diff --git a/ksirc/ksircprocess.cpp b/ksirc/ksircprocess.cpp
new file mode 100644
index 00000000..1fff6807
--- /dev/null
+++ b/ksirc/ksircprocess.cpp
@@ -0,0 +1,663 @@
+/*************************************************************************
+
+ KSircProcess, sirc controller
+
+ $$Id$$
+
+ KSircProcess cerate and controls toplevel widgets and sirc process'.
+ Each sirc process has 1 and only 1 KSircProcess to control it. KSirc
+ process passes all IO to IOController which is it's friend.
+
+ Interface:
+
+ public:
+ KSircProcess(*server=0L, *parent=0, *name=0)
+ server: is the name of the server to connect to. It must be
+ provided or else start sirc will barf. :(
+ parent: parent window, this _should_ be null
+ name: name, passed to QObject...
+
+ ~KSirProcess:
+ kill the sirc process, and iocontrollller, emit delete_toplevel
+
+ getWindowList:
+ returns the TopList, see bellow.
+
+ Signals:
+ made_toplevel(server, window)
+ made a new toplevel window for the "server" we are connected to
+ with "window" as the title.
+
+ dalete_toplevel(server, window)
+ delete toplevel with server and called window. If we emit null
+ as the window name it means to destroy all info about the
+ server and ksircprocess.
+
+ changeChannel(server, old_name, new_name)
+ toplevel with old_name has been changed to new_name and all
+ future refrences will use new_name.
+
+ public slots:
+ new_toplevel(window):
+ create a new window with name window. This MAY only change the
+ name of an existing window that's now idle.
+
+ close_topevel(KsircTopLevel*, window):
+ deletes all refrences to window and if needed finds a new
+ default toplevel.
+
+ default_window(KSricTopLevel*):
+ KSircTopLevel is requesting change to !default. Be carefull
+ with this one.
+
+ recvChangeChannel(old, new):
+ window old is changing to new. emit ChangeChannel with server
+ name added. Without server name we can uniqely id the window. :(
+
+ Implementation:
+
+ Bassic process is to create a new KSircProcess and it takes care of
+ the rest. It emits signals for each new window and every time a
+ window is delete so you can update external display (like
+ servercontroller uses).
+
+ Startup:
+
+ 1. Creates a case insensitive TopList. This is a list of ALL
+ KSircReceivers under control of this server, and includes such
+ items as "!all" and "!default". All !name are control windows.
+
+ 2. Forks off a KProcess for sirc and passes it over to IOController
+ which grabs and control's it's IO.
+
+ 3. It then opens a "!default" window. This will receive all
+ initial input and such. It WILL change it's name on the first
+ join.
+
+ 4. The IO broadcast object is created and setup.
+
+ 5. everything is put into run mode.
+
+
+ Operation, see code bellow for inline comments.
+
+*************************************************************************/
+
+
+
+#include "baserules.h"
+#include "ksopts.h"
+#include "control_message.h"
+#include "displayMgr.h"
+#include "ioBroadcast.h"
+#include "ioDCC.h"
+#include "ioDiscard.h"
+#include "ioLAG.h"
+#include "ioNotify.h"
+#include "iocontroller.h"
+#include "ksircprocess.h"
+#include "objFinder.h"
+#include "servercontroller.h"
+#include "toplevel.h"
+#include "version.h"
+#include "KSProgress/ksprogress.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <qtimer.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+
+
+extern DisplayMgr *displayMgr;
+
+KSircProcess::KSircProcess( QString &server_id, KSircServer &kss, QObject * parent, const char * name )
+ : QObject(parent, name), m_kss(kss), m_serverid(server_id)
+{
+
+ proc = new KProcess();
+
+#ifndef NDEBUG
+ if(getuid() != 0)
+ proc->setRunPrivileged(true); /* make ksirc run under gdb as a user */
+#endif
+
+ //server = qstrdup(kss.server());
+
+ QDict<KSircMessageReceiver> nTopList(17, FALSE);
+ TopList = nTopList;
+ // TopList.setAutoDelete(TRUE)
+
+ auto_create_really = FALSE;
+
+ // Create the ksopts server structure
+ ksopts->serverSetup(kss);
+
+ // Setup the environment for KSirc
+ QString qsNick, qsRealname, qsUserID, qsAltNick;
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("StartUp");
+ qsNick = ksopts->serv(kss).nick;
+ qsAltNick = ksopts->serv(kss).altNick;
+ qsRealname = ksopts->serv(kss).realName;
+ qsUserID = ksopts->serv(kss).userID;
+ kdDebug(5008) << "qsNick: " << qsNick << " qsAltNick: " << qsAltNick << " qsRealname: " << qsRealname << "qsUserID: " << qsUserID << endl;
+
+ m_nick = qsNick;
+
+ if((qsNick.isEmpty() == FALSE)){
+ proc->setEnvironment("SIRCNICK", qsNick);
+ }
+ if((qsAltNick.isEmpty() == FALSE)){
+ proc->setEnvironment("BACKUPNICK", qsAltNick);
+ }
+ if((qsRealname.isEmpty() == FALSE)){
+ proc->setEnvironment("SIRCNAME", qsRealname);
+ }
+ if((qsUserID.isEmpty() == FALSE)){
+ proc->setEnvironment("SIRCUSER", qsUserID);
+ kdDebug(5008) << "Set SIRCUSER to: " << qsUserID << endl;
+ }
+
+ proc->setEnvironment("SIRCLIB", KGlobal::dirs()->findResourceDir("appdata", "ksirc.pl"));
+ proc->setEnvironment("SIRCWAIT", "1");
+
+ QString env = locate("appdata", "ksircrc");
+ if (!env.isEmpty())
+ proc->setEnvironment("SIRCRC", env);
+ env = locate("appdata", "ksircrc.pl");
+ if (!env.isEmpty())
+ proc->setEnvironment("SIRCRCPL", env);
+
+ // Setup the proc now, so iocontroller can use it. It's latter
+ // though. started bellow though.
+
+ proc->setName(QCString(name) + "_kprocess");
+ objFinder::insert(proc);
+// insertChild(proc);
+
+ // pass the server string using an environment variable, because it might contain
+ // a password that could be spyed out, as the commandline option is readable to others.
+ // Fixes 47157.
+ proc->setEnvironment( "SIRCSERVER", "[" + kss.server() + "]:" + kss.port() + ":" + kss.password());
+
+ QString sslopt;
+ if(kss.usessl())
+ sslopt = "-S";
+ *proc << "perl" << KGlobal::dirs()->findExe("dsirc") << "-8" << "-r" << sslopt;
+
+ // Finally start the iocontroller.
+
+ iocontrol = new KSircIOController(proc, this);
+ iocontrol->setName(QCString(name) + "_iocontrol");
+
+ // Create toplevel before iocontroller so it has somewhere to write stuff.
+
+ running_window = TRUE; // True so we do create the default
+ default_follow_focus = TRUE;
+ KSircChannel ci(kss.server(), "!no_channel");
+ new_toplevel(ci, true); //
+ TopList.replace("!default", TopList[ci.channel()]);
+
+ running_window = FALSE; // set false so next changes the first name
+
+ // Write default commands, and open default windows.
+
+ TopList.insert("!all", new KSircIOBroadcast(this));
+ TopList.insert("!discard", new KSircIODiscard(this));
+
+ KSircIODCC *dcc = new KSircIODCC(this);
+ TopList.insert("!dcc", dcc);
+ dcc = static_cast<KSircIODCC *>( TopList["!dcc"] ); // g++ bug
+ connect(dcc, SIGNAL(outputLine(QCString)),
+ iocontrol, SLOT(stdin_write(QCString)));
+
+ KSircIOLAG *lag = new KSircIOLAG(this);
+ TopList.insert("!lag", lag);
+ lag = static_cast<KSircIOLAG*>( TopList["!lag"] ); // g++ bug!
+ connect(lag, SIGNAL(outputLine(QCString)),
+ iocontrol, SLOT(stdin_write(QCString)));
+
+ KSircIONotify *notify = new KSircIONotify(this);
+ TopList.insert("!notify", notify);
+ notify = static_cast<KSircIONotify *>( TopList["!notify"] ); // g++ bug
+ connect(notify, SIGNAL(notify_online(QString)),
+ this, SLOT(notify_forw_online(QString)));
+ connect(notify, SIGNAL(notify_offline(QString)),
+ this, SLOT(notify_forw_offline(QString)));
+
+ TopList.insert("!base_rules", new KSMBaseRules(this));
+
+ // Now that all windows are up, start sirc.
+
+ proc->start(KProcess::NotifyOnExit, KProcess::All);
+ // Intial commands to load ASAP.
+ // turn on sirc ssfe mode
+ QCString command = "/eval $ssfe=1\n";
+ iocontrol->stdin_write(command);
+
+ command = "/eval $version .= \"+KSIRC/" + QCString(KSIRC_VERSION) + "\"\n";
+ iocontrol->stdin_write(command);
+ command = "/load " + locate("appdata", "filters.pl").local8Bit() + "\n";
+ iocontrol->stdin_write(command);
+ command = "/load " + locate("appdata", "ksirc.pl").local8Bit() + "\n";
+ iocontrol->stdin_write(command);
+ /*
+ command = "/load " + locate("appdata", "puke.pl") + "\n";
+ iocontrol->stdin_write(command);
+ command = "/load " + locate("appdata", "dcc_status.pm") + "\n";
+ iocontrol->stdin_write(command);
+ */
+ command = "/eval $ready = 1\n";
+ iocontrol->stdin_write(command);
+
+
+ // Load all the filter rules. Must be after /load filtes.pl so all
+ // the functions are available
+
+ filters_update();
+
+ // We do this after filters_update() since filters_update loads the
+ // require notify filters, etc.
+
+ command = "/notify ";
+ command += ksopts->serv(kss).notifyList.join(" ").latin1();
+ command += "\n";
+ kdDebug(5008) << "Notify: " << command << endl;
+ iocontrol->stdin_write(command);
+
+}
+
+KSircProcess::~KSircProcess()
+{
+ cleanup();
+}
+
+QPtrList<KSircMessageReceiver> KSircProcess::messageReceivers() const
+{
+ QPtrList<KSircMessageReceiver> res;
+ res.setAutoDelete( false );
+ QDictIterator<KSircMessageReceiver> it( TopList );
+ for (; it.current(); ++it )
+ if ( it.currentKey() != "!default" &&
+ it.currentKey() != "!no_channel" )
+ res.append( it.current() );
+ return res;
+}
+
+const QDict<KSircMessageReceiver> &KSircProcess::mrList() const
+{
+ return TopList;
+}
+
+void KSircProcess::cleanup()
+{
+ if(TopList["!default"]){
+ TopList.remove("!default"); // remove default so we don't delete it twice.
+ }
+
+ TopList.setAutoDelete(true);
+ TopList.clear();
+
+ emit ProcMessage(m_serverid, ProcCommand::procClose, QString());
+
+ // Do closing down commands, this should release all puke widgets
+#if 0
+ dsirc does this on SIGTERM (malte)
+ QString quit_cmd = "/eval &dohooks(\"quit\");\n";
+ proc->writeStdin(quit_cmd.ascii(), quit_cmd.length());
+ sleep(1);
+#endif
+ if(proc->isRunning()){
+ proc->kill(SIGTERM);
+ }
+
+ delete proc; // Delete process, seems to kill sirc, good.
+ delete iocontrol; // Take out io controller
+// delete []server;
+
+ proc = 0L;
+ iocontrol = 0L;
+// server = 0L;
+}
+
+void KSircProcess::new_toplevel(const KSircChannel &channelInfo, bool safe)
+{
+ static time_t last_window_open = 0;
+ static int number_open = 0;
+ static bool flood_dlg = FALSE;
+
+ if(running_window == FALSE){ // If we're not fully running, reusing
+ // !default window for next chan.
+ running_window = TRUE;
+ // insert and remove is done as a side effect of the control_message call
+ // TopList.insert(str, TopList["!no_channel"]);
+ // TopList.remove("!no_channel"); // We're no longer !no_channel
+ TopList["!no_channel"]->control_message(CHANGE_CHANNEL, channelInfo.server() + "!!!" + channelInfo.channel() + "!!!" + channelInfo.key());
+ }
+ else if(TopList.find(channelInfo.channel()) == 0x0){ // If the window doesn't exist, continue
+ // If AutoCreate windows is on, let's make sure we're not being flooded.
+ if(ksopts->autoCreateWin == TRUE && safe == false){
+ time_t current_time = time(NULL);
+ if((channelInfo.channel()[0] != '#' || channelInfo.channel()[0] != '&') &&
+ ((current_time - last_window_open) < 5)){
+ if(number_open > 4 && flood_dlg == FALSE){
+ flood_dlg = TRUE;
+ int res = KMessageBox::warningYesNo(0,
+ i18n("5 Channel windows were opened "
+ "in less than 5 seconds. Someone "
+ "may be trying to flood your X server "
+ "with windows.\n"
+ "Shall I turn off AutoCreate windows?"),
+ i18n("Flood Warning"), i18n("Turn Off"), i18n("Keep Enabled"));
+ switch(res) {
+ case KMessageBox::Yes:
+ emit ProcMessage(serverID(), ProcCommand::turnOffAutoCreate, QString());
+ }
+ last_window_open = current_time;
+ number_open = 0;
+ }
+ else{
+ // Joining channels can't be a flood, can it?
+ if(channelInfo.channel()[0] != '#' || channelInfo.channel()[0] != '&')
+ if(!safe)
+ number_open++;
+ }
+ flood_dlg = FALSE;
+ }
+ else{
+ last_window_open = current_time;
+ }
+ }
+
+ // Create a new toplevel, and add it to the toplist.
+ // TopList is a list of KSircReceivers so we still need wm.
+ KSircTopLevel *wm = new KSircTopLevel(this, channelInfo, (serverID() +"_" + channelInfo.channel()).ascii() );
+ TopList.insert(channelInfo.channel(), wm);
+
+ // Connect needed signals. For a message window we never want it
+ // becomming the default so we ignore focusIn events into it.
+ connect(wm, SIGNAL(outputLine(QCString)),
+ iocontrol, SLOT(stdin_write(QCString)));
+ connect(wm, SIGNAL(open_toplevel(const KSircChannel &)),
+ this,SLOT(new_toplevel (const KSircChannel &)));
+ connect(wm, SIGNAL(closing(KSircTopLevel *, QString)),
+ this,SLOT(close_toplevel(KSircTopLevel *, QString)));
+ connect(wm, SIGNAL(currentWindow(KSircTopLevel *)),
+ this,SLOT(default_window(KSircTopLevel *)));
+ connect(wm, SIGNAL(changeChannel(const QString &, const QString &)),
+ this,SLOT(recvChangeChannel(const QString &, const QString &)));
+ connect(wm, SIGNAL(destroyed(QObject *)),
+ this,SLOT(clean_toplevel(QObject *)));
+ connect( wm, SIGNAL( requestQuit( const QCString& ) ),
+ SLOT( request_quit( const QCString& ) ) );
+
+ default_window(wm); // Set it to the default window.
+ emit ProcMessage(serverID(), ProcCommand::addTopLevel, channelInfo.channel());
+
+ displayMgr->newTopLevel(wm, TRUE);
+ displayMgr->setCaption(wm, channelInfo.channel());
+// displayMgr->show(wm);
+ wm->lineEdit()->setFocus(); // Give focus back to the linee, someone takes it away on new create
+ }
+ else {
+ QWidget *w = dynamic_cast<QWidget *>(TopList.find(channelInfo.channel()));
+ if(w)
+ displayMgr->raise(w);
+ }
+}
+
+void KSircProcess::close_toplevel(KSircTopLevel *wm, QString name)
+{
+ if(auto_create_really == TRUE)
+ turn_on_autocreate();
+
+ kdDebug(5008) << "KSP: get close_toplevel: " << name << endl;
+
+ // the removeTopLevel below also deletes the mditoplevel (in case
+ // we are using mdi) , which deletes its children, which deletes
+ // 'wm' , so watch out not to delete twice! (Simon)
+ QGuardedPtr<KSircTopLevel> guardedwm = wm;
+ // Do this now or we get junk left on the screen
+ displayMgr->removeTopLevel(wm);
+
+ while(TopList.remove(name)); // In case multiple copies exist remove them all
+
+ bool isDefault = (wm == TopList["!default"]);
+
+ // Ok, now if we just deleted the default we have a problem, we need
+ // a new default. BUT don't make the default "!all" or !message.
+ // So let's go grab a default, and make sure it's not "!" control
+ // object.
+
+ QDictIterator<KSircMessageReceiver> it(TopList);
+ for(;it.current() && it.currentKey().startsWith("!"); ++it);
+
+ if (!it.current())
+ {
+ // No top-level windows left.
+ QCString command = "/quit\n"; // "/signoff" ?
+ iocontrol->stdin_write(command); // kill sirc
+ kdDebug(5008) << "KSP closing: " << m_kss.server() << endl;
+ delete guardedwm;
+ delete this; // Delete ourself, WARNING MUST RETURN SINCE WE NO
+ // LONGER EXIST!!!!
+ return; // ^^^^^^^^^^^^^^^
+ }
+
+ if (isDefault)
+ TopList.replace("!default", it.current());
+
+ // Let's let em know she's deleted!
+ if(ksopts->autoCreateWin == TRUE){
+ emit ProcMessage(serverID(), ProcCommand::turnOffAutoCreate, QString());
+ QTimer::singleShot(5000, this, SLOT(turn_on_autocreate()));
+ auto_create_really = TRUE;
+ }
+ else{
+ auto_create_really = FALSE;
+ }
+
+ delete guardedwm;
+ emit ProcMessage(serverID(), ProcCommand::deleteTopLevel, name);
+}
+
+void KSircProcess::clean_toplevel(QObject *clean){
+ if(!clean){
+ qWarning("Passed null to cleaner!!");
+ return;
+ }
+ bool cont = FALSE;
+ do{
+ cont = FALSE;
+ QDictIterator<KSircMessageReceiver> it(TopList);
+ while(it.current() != 0x0){
+ if((QObject *)it.current() == clean){
+ QString key = it.currentKey();
+ while(TopList[key] != 0x0){
+ TopList.remove(key);
+ }
+ cont = TRUE;
+ break;
+ }
+ ++it;
+ }
+ } while(cont == TRUE);
+}
+
+void KSircProcess::request_quit( const QCString& command )
+{
+ iocontrol->stdin_write( command );
+ // Since removing the toplevels will delete the one that emitted this
+ // signal as well, we need to defer this a little (malte)
+ QTimer::singleShot( 0, this, SLOT( do_quit() ) );
+}
+
+void KSircProcess::do_quit()
+{
+ for ( QDictIterator< KSircMessageReceiver > it( TopList ); it.current(); ++it )
+ {
+ if ( it.currentKey() == "!default" ) continue;
+ if ( KSircTopLevel* topLevel = dynamic_cast< KSircTopLevel* >( it.current() ) )
+ {
+ QGuardedPtr< KSircTopLevel > guardedTL = topLevel;
+ displayMgr->removeTopLevel( topLevel );
+ delete guardedTL;
+ }
+ else delete it.current();
+ }
+ // cleanup() would otherwise delete them a second time
+ TopList.clear();
+ delete this;
+}
+
+void KSircProcess::default_window(KSircTopLevel *w)
+{
+
+ //
+ // If we want to track the default as it goes around, change the
+ // window on focus changes.
+ //
+
+ if(w && (default_follow_focus == TRUE))
+ TopList.replace("!default", w);
+
+}
+
+void KSircProcess::recvChangeChannel(const QString &old_chan, const QString &new_chan)
+{
+ //
+ // Channel changed name, add our own name and off we go.
+ // ServerController needs our name so it can have a uniq handle for
+ // the window name.
+ //
+
+ if(TopList[old_chan]) {
+ kdDebug(5008) << "In change channel, found it" << endl;
+ TopList.insert(new_chan, TopList.take(old_chan));
+ }
+ else {
+ kdDebug(5008) << "In change channel, didn;t find it" << endl;
+ }
+ emit ProcMessage(serverID(), ProcCommand::changeChannel,
+ old_chan + " " + new_chan);
+}
+
+void KSircProcess::filters_update()
+{
+ QString command, next_part, key, data;
+ command = "/crule\n";
+ iocontrol->stdin_write(command.ascii());
+ QDictIterator<KSircMessageReceiver> it(TopList);
+ KSircMessageReceiver *cur, *br;
+ filterRuleList *frl;
+ filterRule *fr;
+ cur = TopList["!base_rules"];
+ br = cur;
+ while(cur){
+ frl = cur->defaultRules();
+ for ( fr=frl->first(); fr != 0; fr=frl->next() ){
+ command.truncate(0);
+ command += "/ksircappendrule DESC==";
+ command += fr->desc;
+ command += " !!! SEARCH==";
+ command += fr->search;
+ command += " !!! FROM==";
+ command += fr->from;
+ command += " !!! TO==\"";
+ command += fr->to;
+ command += "\"\n";
+ iocontrol->stdin_write(command.local8Bit());
+ }
+ delete frl;
+ ++it;
+ cur = it.current();
+ if(cur == br){
+ ++it;
+ cur = it.current();
+ }
+ }
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("FilterRules");
+ int max = kConfig->readNumEntry("Rules", 0);
+ for(int number = 1; number <= max; number++){
+ command.truncate(0);
+ key.sprintf("name-%d", number);
+ next_part.sprintf("/ksircappendrule DESC==%s !!! ", kConfig->readEntry(key).ascii());
+ command += next_part;
+ key.sprintf("search-%d", number);
+ next_part.sprintf("SEARCH==%s !!! ", kConfig->readEntry(key).ascii());
+ command += next_part;
+ key.sprintf("from-%d", number);
+ next_part.sprintf("FROM==%s !!! ", kConfig->readEntry(key).ascii());
+ command += next_part;
+ key.sprintf("to-%d", number);
+ next_part.sprintf("TO==\"%s\"\n", kConfig->readEntry(key).ascii());
+ command += next_part;
+ iocontrol->stdin_write(command.ascii());
+ }
+}
+
+
+void KSircProcess::notify_forw_online(QString nick)
+{
+ emit ProcMessage(serverID(), ProcCommand::nickOnline, nick);
+}
+
+void KSircProcess::notify_forw_offline(QString nick)
+{
+ emit ProcMessage(serverID(), ProcCommand::nickOffline, nick);
+}
+
+void KSircProcess::ServMessage(QString dst_server, int command, QString args)
+{
+ if(dst_server.isEmpty() || (dst_server == serverID())){
+ switch(command){
+ case ServCommand::updateFilters:
+ filters_update();
+ break;
+ default:
+ kdDebug(5008) << "Unkown command: " << command << " to " << command << " args " << args << endl;
+ break;
+ }
+ }
+}
+
+void KSircProcess::turn_on_autocreate()
+{
+ emit ProcMessage(serverID(), ProcCommand::turnOnAutoCreate, QString());
+ auto_create_really = FALSE;
+}
+
+void KSircProcess::setNick(const QString nick)
+{
+ QString new_nick = nick;
+ while (!new_nick.isEmpty() &&
+ (new_nick[0].latin1() == '@' || new_nick[0].latin1() == '*'))
+ new_nick.remove(0, 1);
+ if(new_nick != m_nick){
+ m_nick = new_nick;
+ /*
+ * redo the filter rules since they use
+ * our nick
+ */
+ kdDebug(5008) << "Redo filters" << endl;
+ filters_update();
+ }
+
+}
+
+const QString KSircProcess::getNick() const
+{
+ return m_nick;
+}
+
+#include "ksircprocess.moc"
+
+// vim: ts=4 sw=4 et
diff --git a/ksirc/ksircprocess.h b/ksirc/ksircprocess.h
new file mode 100644
index 00000000..9a4cf7c3
--- /dev/null
+++ b/ksirc/ksircprocess.h
@@ -0,0 +1,92 @@
+#ifndef KSIRCPROCESS
+#define KSIRCPROCESS
+
+class KSircProcess;
+class KSircTopLevel;
+
+#include <qdict.h>
+#include <qobject.h>
+
+#include "iocontroller.h"
+#include "ksircserver.h"
+#include "ksircchannel.h"
+
+class KProcess;
+class KSircIOController;
+class KSircMessageReceiver;
+class KSircIOController;
+
+class KSircProcess : public QObject
+{
+ Q_OBJECT
+ friend class KSircIOController;
+public:
+ KSircProcess(QString &server_id, KSircServer &kss, QObject * parent=0, const char * name=0);
+ virtual ~KSircProcess();
+
+ QDict<KSircMessageReceiver> &getWindowList()
+ {
+ return TopList;
+ }
+
+ QPtrList<KSircMessageReceiver> messageReceivers() const;
+ const QDict<KSircMessageReceiver> &mrList() const;
+
+ QString serverName() const { return m_kss.server(); }
+ QString serverPort() const { return m_kss.port(); }
+ QString serverID() const { return m_serverid; }
+
+ KSircIOController *getIOController() { return iocontrol; }
+
+ const QString getNick() const;
+ void setNick(const QString nick);
+
+
+signals:
+ void ProcMessage(QString, int, QString);
+
+public slots:
+ virtual void ServMessage(QString server, int command, QString args);
+ virtual void close_toplevel(KSircTopLevel *, QString);
+ virtual void default_window(KSircTopLevel *);
+ virtual void recvChangeChannel(const QString &, const QString &);
+ virtual void new_toplevel(const KSircChannel &, bool safe = false);
+
+ virtual void filters_update();
+
+ virtual void notify_forw_online(QString);
+ virtual void notify_forw_offline(QString);
+
+protected slots:
+ virtual void clean_toplevel(QObject *clean);
+ virtual void request_quit( const QCString& command );
+ virtual void do_quit();
+
+ virtual void turn_on_autocreate();
+
+
+private:
+ void base_filters();
+ void cleanup();
+
+ KSircIOController *iocontrol;
+ KProcess *proc;
+
+ QDict<KSircMessageReceiver> TopList;
+
+ bool running_window;
+ bool default_follow_focus;
+ bool auto_create_really;
+
+ KSircServer m_kss;
+ const QString m_serverid;
+
+ /*
+ * m_nick is our nick as reported by the lower levels
+ */
+ QString m_nick;
+
+// char *server;
+};
+
+#endif
diff --git a/ksirc/ksircrc b/ksirc/ksircrc
new file mode 100644
index 00000000..548160e5
--- /dev/null
+++ b/ksirc/ksircrc
@@ -0,0 +1,62 @@
+[Colours]
+Background=234,234,234
+chan=57,36,162
+error=255,0,0
+info=0,0,255
+kcolour=true
+mcolour=false
+nickbcolour=-1
+nickfcolour=1
+text=0,0,0
+uscolour=6
+
+[ColourSchemes]
+Names=boren,wheels,danimo
+
+[ColourSchemes-boren]
+Background=0,0,0
+SelForeground=0,0,0
+SelBackground=255,255,255
+Channel=0,192,0
+Error=255,0,0
+Info=0,0,255
+NickBackground=invalid
+NickForeground=255,128,0
+OwnNick=255,0,0
+Text=0,192,192
+Link=201,97,205
+
+[ColourSchemes-wheels]
+Background=45,53,59
+SelForeground=45,53,59
+SelBackground=129,154,170
+Channel=72,46,204
+Error=255,0,0
+Info=0,0,255
+NickBackground=invalid
+NickForeground=165,155,161
+OwnNick=128,0,128
+Text=129,154,170
+Link=0,0,255
+
+[ColourSchemes-danimo]
+Background=0,0,0
+SelBackground=255,255,255
+SelForeground=0,0,0
+Channel=49,222,238
+Error=255,0,0
+Info=49,222,238
+NickBackground=invalid
+NickForeground=255,255,255
+OwnNick=243,255,7
+Text=255,255,255
+Link=49,222,238
+
+[General]
+AutoCreateWin=true
+AutoRejoin=true
+BeepNotify=true
+ColourPicker=true
+DisplayTopic=true
+NickCompletion=true
+WindowLength=200
diff --git a/ksirc/ksircserver.h b/ksirc/ksircserver.h
new file mode 100644
index 00000000..ec63e1f6
--- /dev/null
+++ b/ksirc/ksircserver.h
@@ -0,0 +1,34 @@
+#ifndef KSIRCSERVER_H
+#define KSIRCSERVER_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+class KSircServer
+{
+
+public:
+ KSircServer( const QString &server,
+ const QString &port,
+ const QString &script = QString::null,
+ const QString &password = QString::null,
+ bool ssl = false ) :
+ m_server(server), m_port(port), m_script(script),
+ m_password(password), m_ssl(ssl) {}
+
+ const QString server() const { return m_server; }
+ const QString port() const { return m_port; }
+ const QString script() const { return m_script; }
+ const QString password() const { return m_password; }
+ bool usessl() const { return m_ssl; }
+
+private:
+ const QString m_server;
+ const QString m_port;
+ const QString m_script;
+ const QString m_password;
+ const bool m_ssl;
+
+};
+
+#endif
diff --git a/ksirc/ksopts.cpp b/ksirc/ksopts.cpp
new file mode 100644
index 00000000..11b25ad8
--- /dev/null
+++ b/ksirc/ksopts.cpp
@@ -0,0 +1,542 @@
+
+#include <kapplication.h>
+#include <kconfig.h>
+
+#if KDE_IS_VERSION(3,1,92)
+#include <kuser.h>
+#else
+#include <unistd.h>
+#include <pwd.h>
+#endif
+
+#include <kdebug.h>
+
+#include "ksopts.h"
+
+
+KSOptions *KSOptions::s_options = 0;
+bool KSOChannel::applyGlobally = false;
+
+KSOGeneral::KSOGeneral()
+{
+ displayMode = MDI;
+ autoCreateWin = true;
+ autoCreateWinForNotice = false;
+ nickCompletion = true;
+ displayTopic = true;
+ oneLineEntry = true;
+ runDocked = false;
+// timeStamp = true;
+// beepNotify = true;
+ colorPicker = true;
+ autoRejoin = false;
+ windowLength = 200;
+// logging = false;
+// beepOnMsg = false;
+ publicAway = true;
+ // topicShow = true;
+ useColourNickList = false;
+ dockPopups = true;
+ autoSaveHistory = true;
+
+}
+
+QPixmap KSOGeneral::backgroundPixmap()
+{
+ if ( m_backgroundPixmap.isNull() && !backgroundFile.isEmpty() )
+ m_backgroundPixmap = QPixmap( backgroundFile );
+ return m_backgroundPixmap;
+}
+
+KSOStartup::KSOStartup()
+{
+}
+
+KSOServer::KSOServer()
+{
+#if KDE_IS_VERSION(3,1,92)
+ KUser user;
+ nick = user.loginName();
+ userID = user.loginName();
+ realName = user.fullName();
+#else
+ struct passwd *pw = getpwuid( getuid() );
+ if ( pw )
+ {
+ nick = QString::fromLocal8Bit( pw->pw_name );
+ userID = QString::fromLocal8Bit( pw->pw_name );
+ realName = QString::fromLocal8Bit( pw->pw_gecos ).section( ',', 0, 0 );
+ }
+#endif
+}
+
+
+KSOColors::KSOColors()
+{
+ textColor = Qt::black;
+ linkColor = Qt::blue;
+ infoColor = Qt::blue;
+ channelColor = Qt::green;
+ errorColor = Qt::red;
+
+ ksircColors = true;
+ mircColors = false;
+ nickColourization = false;
+ ownNickBold = false;
+ ownNickUl = true;
+ ownNickRev = false;
+
+ msg1Regex = false;
+ msg2Regex = false;
+
+ backgroundColor = kapp->palette().color( QPalette::Active, QColorGroup::Mid );
+ selBackgroundColor = kapp->palette().color( QPalette::Active, QColorGroup::Highlight );
+ selForegroundColor = kapp->palette().color( QPalette::Active, QColorGroup::HighlightedText );
+
+ ircColors[0] = Qt::white;
+ ircColors[1] = Qt::black;
+ ircColors[2] = Qt::darkBlue;
+ ircColors[3] = Qt::darkGreen;
+ ircColors[4] = Qt::red;
+ ircColors[5] = QColor ( 165, 42, 42 );
+ ircColors[6] = Qt::darkMagenta;
+ ircColors[7] = QColor( 255, 0x7b, 00 );
+ ircColors[8] = Qt::yellow;
+ ircColors[9] = Qt::green;
+ ircColors[10] = Qt::darkCyan;
+ ircColors[11] = Qt::cyan;
+ ircColors[12] = Qt::blue;
+ ircColors[13] = QColor( 255, 0, 255 );
+ ircColors[14] = Qt::gray;
+ ircColors[15] = Qt::lightGray;
+
+ uint i;
+ for(i = 0; i < numColors; i++){
+ nickHighlight[i] = true;
+ }
+
+ colourTheme = "Custom";
+}
+
+KSORMBMenu::KSORMBMenu()
+{
+}
+
+KSOServChan::KSOServChan()
+{
+}
+
+KSOChannel::KSOChannel()
+{
+ timeStamp = false;
+ beepNotify = false;
+ beepOnMsg = false;
+ logging = false;
+ topicShow = true;
+ filterJoinPart = false;
+ applyGlobally = false;
+ encoding = "Default";
+}
+
+void KSOptions::load( int sections )
+{
+ KConfig *conf = kapp->config();
+ conf->setGroup( "ServerController" );
+ geometry = conf->readRectEntry( "Size" );
+
+ // Using the fields itself as default values as they are already
+ // set to the defaults.
+ if ( sections & General )
+ {
+ conf->setGroup( "General" );
+ int mode = conf->readNumEntry( "DisplayMode", static_cast<int>(displayMode) );
+ if (mode == 0)
+ displayMode = SDI;
+ else
+ displayMode = MDI;
+
+ autoCreateWin = conf->readBoolEntry( "AutoCreateWin", autoCreateWin );
+ autoCreateWinForNotice = conf->readBoolEntry( "AutoCreateWinForNotice", autoCreateWinForNotice );
+ nickCompletion = conf->readBoolEntry( "NickCompletion", nickCompletion );
+ displayTopic = conf->readBoolEntry( "DisplayTopic", displayTopic );
+ oneLineEntry = conf->readBoolEntry( "OneLineEntry", oneLineEntry );
+ runDocked = conf->readBoolEntry( "runDocked", runDocked );
+// timeStamp = conf->readBoolEntry( "TimeStamp", timeStamp );
+// beepNotify = conf->readBoolEntry( "BeepNotify", beepNotify );
+ colorPicker = conf->readBoolEntry( "ColourPicker", colorPicker );
+ autoRejoin = conf->readBoolEntry( "AutoRejoin", autoRejoin );
+ windowLength = conf->readNumEntry( "WindowLength", windowLength );
+ backgroundFile = conf->readPathEntry( "BackgroundFile", backgroundFile );
+// logging = conf->readBoolEntry( "Logging", logging );
+// beepOnMsg = conf->readBoolEntry( "BeepOnMessage", false );
+ publicAway = conf->readBoolEntry( "PublicAway", publicAway );
+ // topicShow = conf->readBoolEntry("TopicShow", topicShow);
+ useColourNickList = conf->readBoolEntry("ColourNickList", useColourNickList);
+ dockPopups = conf->readBoolEntry("dockPopups", dockPopups);
+ autoSaveHistory = conf->readBoolEntry("autoSaveHistory", autoSaveHistory);
+ }
+
+ if ( sections & Startup )
+ {
+ conf->setGroup( "StartUp" );
+ }
+
+
+ if ( sections & Colors )
+ {
+ if ( !conf->hasGroup( "ColorScheme" ) && conf->hasGroup( "Colours" ) )
+ {
+ conf->setGroup( "Colours" );
+ textColor = conf->readColorEntry( "text", &textColor );
+ infoColor = conf->readColorEntry( "info", &infoColor );
+ channelColor = conf->readColorEntry( "chan", &channelColor );
+ errorColor = conf->readColorEntry( "error", &errorColor );
+ int c = conf->readNumEntry( "uscolour", -1 );
+ if ( c >= 0 && c < 16 )
+ ownNickColor = ircColors[c];
+ c = conf->readNumEntry( "nickfcolour", -1 );
+ if ( c >= 0 && c < 16 )
+ nickForeground = ircColors[c];
+ c = conf->readNumEntry( "nickbcolour", -1 );
+ if ( c >= 0 && c < 16 )
+ nickBackground = ircColors[c];
+ backgroundColor = conf->readColorEntry( "Background", &backgroundColor );
+ }
+ else
+ {
+ conf->setGroup( "ColorScheme" );
+ textColor = conf->readColorEntry( "Text", &textColor );
+ linkColor = conf->readColorEntry( "Link", &linkColor );
+ infoColor = conf->readColorEntry( "Info", &infoColor );
+ channelColor = conf->readColorEntry( "Channel", &channelColor );
+ errorColor = conf->readColorEntry( "Error", &errorColor );
+ ownNickColor = conf->readColorEntry( "OwnNick", &ownNickColor );
+ ownNickBold = conf->readBoolEntry( "OwnNickBold", ownNickBold );
+ ownNickUl = conf->readBoolEntry( "OwnNickUnderline", ownNickUl );
+ ownNickRev = conf->readBoolEntry( "OwnNickReverse", ownNickRev );
+ msgContainNick = conf->readColorEntry( "msgContainNick", &ownNickColor ); // default to the ownNick colour
+ msg1Contain = conf->readColorEntry( "msg1Contain", &msg1Contain );
+ msg1String = conf->readEntry( "msg1String", msg1String );
+ msg1Regex = conf->readBoolEntry( "msg1Regex", msg1Regex );
+ msg2Contain = conf->readColorEntry( "msg2Contain", &msg2Contain );
+ msg2String = conf->readEntry( "msg2String", msg2String );
+ msg2Regex = conf->readBoolEntry( "msg2Regex", msg2Regex );
+ nickForeground = conf->readColorEntry( "NickForeground", &nickForeground );
+ nickBackground = conf->readColorEntry( "NickBackground", &nickBackground );
+ backgroundColor = conf->readColorEntry( "Background", &backgroundColor );
+ selBackgroundColor = conf->readColorEntry( "SelBackground", &selBackgroundColor );
+ selForegroundColor = conf->readColorEntry( "SelForeground", &selForegroundColor );
+ ksircColors = conf->readBoolEntry( "ksircColors", ksircColors );
+ mircColors = conf->readBoolEntry( "mircColors", mircColors );
+ nickColourization = conf->readBoolEntry( "nickColourization", mircColors );
+ colourTheme = conf->readEntry("ColourTheme", colourTheme );
+ for ( int i = 0; i < 16; ++i ) {
+ ircColors[i] =
+ conf->readColorEntry(QString::fromLatin1( "IRC-%1" ).arg( i ),
+ &ircColors[i] );
+ nickHighlight[i] =
+ conf->readBoolEntry(QString::fromLatin1( "nickHighlight-%1" ).arg( i ),
+ &nickHighlight[i] );
+ }
+ }
+ conf->setGroup( "GlobalOptions" );
+ QFont df = kapp->font(0);
+ defaultFont = conf->readFontEntry( "MainFont", &df);
+ QApplication::setFont( defaultFont, true, "KSirc::TextView" );
+ }
+ if ( sections & Channels )
+ {
+ conf->setGroup( "Channel" );
+
+ /*
+ * do global first
+ */
+ if(channel.contains("global") == FALSE){
+ KSOChannel global;
+ ChannelOpMap coMap;
+ channel.insert(QString("global"), coMap);
+ channel["global"].insert("global", global);
+ channel["global"]["global"].server = "global";
+ channel["global"]["global"].channel = "global";
+ channel["global"]["global"].timeStamp = conf->readBoolEntry("globalglobalTimeStamp", false);
+ channel["global"]["global"].beepNotify = conf->readBoolEntry("globalglobalBeepNotify", false);
+ channel["global"]["global"].beepOnMsg = conf->readBoolEntry("globalglobalBeepOnMsg", false);
+ channel["global"]["global"].logging = conf->readBoolEntry("globalglobalLogging", false);
+ channel["global"]["global"].topicShow = conf->readBoolEntry("globalglobalTopicShow", true);
+ channel["global"]["global"].filterJoinPart = conf->readBoolEntry("globalglobalFilterJoinPart", false);
+ channel["global"]["global"].applyGlobally = conf->readBoolEntry("globalglobalApplyGlobally", false);
+ channel["global"]["global"].encoding = conf->readEntry("globalglobalEncoding", "Default");
+ }
+
+ QDateTime now(QDateTime::currentDateTime());
+ QStringList servers = conf->readListEntry("Servers");
+ QStringList::ConstIterator ser = servers.begin();
+ for( ; ser != servers.end(); ser++){
+ ChannelOpMap coMap;
+ channel.insert(*ser, coMap);
+ QStringList channels = conf->readListEntry(*ser);
+ QStringList::ConstIterator chan = channels.begin();
+ for( ; chan != channels.end(); chan++){
+ QDateTime lastUsed = conf->readDateTimeEntry(*ser + *chan + "lastUsed", &now);
+ if((lastUsed.daysTo(now) < 30 )||
+ (*chan == "global" && *ser == "global"))
+ {
+ KSOChannel ksoc;
+ ksoc = channel["global"]["global"];
+ ksoc.server = *ser;
+ ksoc.channel = *chan;
+ ksoc.timeStamp = conf->readBoolEntry(*ser + *chan + "TimeStamp", ksoc.timeStamp);
+ ksoc.beepNotify = conf->readBoolEntry(*ser + *chan + "BeepNotify", ksoc.beepNotify);
+ ksoc.beepOnMsg = conf->readBoolEntry(*ser + *chan + "BeepOnMsg", ksoc.beepOnMsg);
+ ksoc.logging = conf->readBoolEntry(*ser + *chan + "Logging", ksoc.logging);
+ ksoc.topicShow = conf->readBoolEntry(*ser + *chan + "TopicShow", ksoc.topicShow);
+ ksoc.encoding = conf->readEntry(*ser + *chan + "Encoding", ksoc.encoding);
+ ksoc.filterJoinPart = conf->readBoolEntry(*ser + *chan + "FilterJoinPart", ksoc.filterJoinPart);
+ ksoc.lastUsed = lastUsed;
+ channel[*ser].insert(*chan, ksoc);
+ }
+ else { /* expire junk */
+ conf->deleteEntry(*ser + *chan + "TimeStamp");
+ conf->deleteEntry(*ser + *chan + "BeepNotify");
+ conf->deleteEntry(*ser + *chan + "BeepOnMsg");
+ conf->deleteEntry(*ser + *chan + "Logging");
+ conf->deleteEntry(*ser + *chan + "TopicShow");
+ conf->deleteEntry(*ser + *chan + "Encoding");
+ conf->deleteEntry(*ser + *chan + "FilterJoinPart");
+ conf->deleteEntry(*ser + *chan + "lastUsed");
+ }
+ }
+ }
+ }
+ if ( sections & Servers )
+ {
+ conf->setGroup( "Server" );
+
+ /*
+ * do global first
+ */
+ if(server.contains("global") == FALSE){
+ KSOServer global;
+ server.insert(QString("global"), global);
+ server["global"].server = "global";
+ server["global"].globalCopy = false;
+
+ conf->setGroup( "StartUp" );
+ server["global"].nick = conf->readEntry("Nick");
+ server["global"].altNick = conf->readEntry("altNick");
+ server["global"].realName = conf->readEntry("RealName");
+ server["global"].userID = conf->readEntry("userID");
+ server["global"].notifyList = conf->readListEntry("NotifyList");
+
+ conf->setGroup( "Server" );
+ }
+
+ kdDebug(5008) << "Load: in Server" << endl;
+
+ QStringList servers = conf->readListEntry("Servers");
+
+ QStringList::ConstIterator ser = servers.begin();
+ for( ; ser != servers.end(); ser++){
+ KSOServer ksos;
+ ksos = server["global"];
+ ksos.server = *ser;
+ ksos.globalCopy = false;
+ ksos.nick = conf->readEntry(*ser + "nick");
+ ksos.altNick = conf->readEntry(*ser + "altNick");
+ ksos.realName = conf->readEntry(*ser + "realName");
+ ksos.userID = conf->readEntry(*ser + "userID");
+ ksos.notifyList = conf->readListEntry(*ser + "notifyList");
+ kdDebug(5008) << *ser << ": nick: " << ksos.nick << " altNick: " << ksos.altNick << endl;
+ server.insert(*ser, ksos);
+ }
+ }
+ kdDebug(5008) << "Done full load" << endl;
+}
+
+void KSOptions::save( int sections )
+{
+ KConfig *conf = kapp->config();
+
+ if ( sections & General )
+ {
+ conf->setGroup( "General" );
+ conf->writeEntry( "DisplayMode", static_cast<int>(displayMode) );
+ conf->writeEntry( "AutoCreateWin", autoCreateWin );
+ conf->writeEntry( "AutoCreateWinForNotice", autoCreateWinForNotice );
+ conf->writeEntry( "NickCompletion", nickCompletion );
+ conf->writeEntry( "DisplayTopic", displayTopic );
+ conf->writeEntry( "OneLineEntry", oneLineEntry );
+ conf->writeEntry( "runDocked", runDocked );
+// conf->writeEntry( "TimeStamp", timeStamp );
+// conf->writeEntry( "BeepNotify", beepNotify );
+ conf->writeEntry( "ColourPicker", colorPicker );
+ conf->writeEntry( "AutoRejoin", autoRejoin );
+ conf->writeEntry( "WindowLength", windowLength );
+ conf->writePathEntry( "BackgroundFile", backgroundFile );
+// conf->writeEntry( "Logging", logging );
+// conf->writeEntry( "BeepOnMessage", beepOnMsg );
+ conf->writeEntry( "PublicAway", publicAway );
+ conf->writeEntry( "ColourNickList", useColourNickList );
+ conf->writeEntry( "dockPopups", dockPopups );
+ conf->writeEntry( "autoSaveHistory", autoSaveHistory );
+ }
+
+ if ( sections & Startup )
+ {
+ conf->setGroup( "StartUp" );
+ /*
+ conf->writeEntry( "Nick", nick );
+ conf->writeEntry( "AlternativeNick", altNick );
+ conf->writeEntry( "RealName", realName );
+ conf->writeEntry( "userID", userID );
+ conf->writeEntry( "NotifyList", notifyList );
+ */
+ }
+
+ if ( sections & Colors )
+ {
+ conf->setGroup( "ColorScheme" );
+ conf->writeEntry( "Text", textColor );
+ conf->writeEntry( "Link", linkColor );
+ conf->writeEntry( "Info", infoColor );
+ conf->writeEntry( "Channel", channelColor );
+ conf->writeEntry( "Error", errorColor );
+ conf->writeEntry( "OwnNick", ownNickColor );
+ conf->writeEntry( "OwnNickBold", ownNickBold );
+ conf->writeEntry( "OwnNickUnderline", ownNickUl );
+ conf->writeEntry( "OwnNickReverse", ownNickRev );
+ conf->writeEntry( "msgContainNick", msgContainNick );
+ conf->writeEntry( "msg1Contain", msg1Contain );
+ conf->writeEntry( "msg1String", msg1String );
+ conf->writeEntry( "msg1Regex", msg1Regex );
+ conf->writeEntry( "msg2Contain", msg2Contain );
+ conf->writeEntry( "msg2String", msg2String );
+ conf->writeEntry( "msg2Regex", msg2Regex );
+ conf->writeEntry( "NickForeground", nickForeground );
+ conf->writeEntry( "NickBackground", nickBackground );
+ conf->writeEntry( "Background", backgroundColor );
+ conf->writeEntry( "SelBackground", selBackgroundColor );
+ conf->writeEntry( "SelForeground", selForegroundColor );
+ conf->writeEntry( "ksircColors", (bool) ksircColors );
+ conf->writeEntry( "mircColors", mircColors );
+ conf->writeEntry( "nickColourization", nickColourization );
+ conf->writeEntry( "ColourTheme", colourTheme );
+ for ( int i = 0; i < 16; ++i ) {
+ conf->writeEntry( QString::fromLatin1( "IRC-%1" ).arg( i ), ircColors[i] );
+ conf->writeEntry( QString::fromLatin1( "nickHighlight-%1" ).arg( i ), nickHighlight[i] );
+ }
+ /* Store the font setting */
+ conf->setGroup( "GlobalOptions" );
+ conf->writeEntry("MainFont", defaultFont);
+ /* end of storing the font settings */
+ }
+ if ( sections & Channels )
+ {
+ QStringList servers;
+
+ conf->deleteGroup( "Channel" );
+
+ conf->setGroup( "Channel" );
+ ServerChannelOpMap::Iterator ser;
+ for( ser = channel.begin(); ser != channel.end(); ++ser ){
+ QStringList channels;
+
+ servers << ser.key();
+
+ ChannelOpMap::Iterator chan;
+ for( chan = ser.data().begin(); chan != ser.data().end(); ++chan ){
+ channels << chan.key();
+ conf->writeEntry(ser.key() + chan.key() + "TimeStamp", chan.data().timeStamp);
+ conf->writeEntry(ser.key() + chan.key() + "BeepNotify", chan.data().beepNotify);
+ conf->writeEntry(ser.key() + chan.key() + "BeepOnMsg", chan.data().beepOnMsg);
+ conf->writeEntry(ser.key() + chan.key() + "Logging", chan.data().logging);
+ conf->writeEntry(ser.key() + chan.key() + "TopicShow", chan.data().topicShow);
+ conf->writeEntry(ser.key() + chan.key() + "Encoding", chan.data().encoding);
+ conf->writeEntry(ser.key() + chan.key() + "FilterJoinPart", chan.data().filterJoinPart);
+ conf->writeEntry(ser.key() + chan.key() + "lastUsed", chan.data().lastUsed);
+ }
+ conf->writeEntry(ser.key(), channels);
+ }
+ conf->writeEntry("Servers", servers);
+ conf->writeEntry("globalglobalApplyGlobally", channel["global"]["global"].applyGlobally);
+ }
+ if ( sections & Servers )
+ {
+ QStringList servers;
+
+ conf->deleteGroup( "Servers" );
+
+ conf->setGroup( "Server" );
+ ServerOpMap::Iterator ser;
+ for( ser = server.begin(); ser != server.end(); ++ser ){
+ QStringList channels;
+
+ if(ser.data().globalCopy == true)
+ continue;
+
+ servers << ser.key();
+
+ conf->writeEntry(ser.key() + "nick", ser.data().nick);
+ conf->writeEntry(ser.key() + "altNick", ser.data().altNick);
+ conf->writeEntry(ser.key() + "realName", ser.data().realName);
+ conf->writeEntry(ser.key() + "userID", ser.data().userID);
+ conf->writeEntry(ser.key() + "notifyList", ser.data().notifyList);
+ }
+ conf->writeEntry("Servers", servers);
+ }
+
+ conf->sync();
+}
+
+void KSOptions::channelSetup(QString serv, QString chan)
+{
+ if(channel.contains(serv) == FALSE){
+ ChannelOpMap coMap;
+ channel.insert(serv, coMap);
+ }
+ if(channel[serv].contains(chan) == FALSE){
+ KSOChannel ksoc;
+ ksoc = channel["global"]["global"];
+ channel[serv].insert(chan, ksoc);
+ channel[serv][chan].server = serv;
+ channel[serv][chan].channel = chan;
+ channel[serv][chan].lastUsed = QDateTime::currentDateTime();
+ }
+ else {
+ channel[serv][chan].lastUsed = QDateTime::currentDateTime();
+ }
+}
+
+void KSOptions::applyChannelGlobal(void)
+{
+ ServerChannelOpMap::Iterator ser;
+ for( ser = channel.begin(); ser != channel.end(); ++ser ){
+ ChannelOpMap::Iterator chan;
+ for( chan = ser.data().begin(); chan != ser.data().end(); ++chan ){
+ if((chan.key() == "global") && (ser.key() == "global"))
+ continue;
+
+ chan.data() = channel["global"]["global"];
+ }
+ }
+
+}
+
+void KSOptions::serverSetup(QString serv)
+{
+ if(server.contains(serv) == FALSE){
+ KSOServer ksos;
+ ksos = server["global"];
+ server.insert(serv, ksos);
+ server[serv].server = serv;
+ server[serv].globalCopy = true;
+ server[serv].lastUsed = QDateTime::currentDateTime();
+ }
+ else {
+ server[serv].lastUsed = QDateTime::currentDateTime();
+ }
+}
+
+
+/* vim: et sw=4 ts=4
+ */
diff --git a/ksirc/ksopts.h b/ksirc/ksopts.h
new file mode 100644
index 00000000..5739f6fd
--- /dev/null
+++ b/ksirc/ksopts.h
@@ -0,0 +1,218 @@
+
+#ifndef _KSOPTS_H_
+#define _KSOPTS_H_
+#include <qmap.h>
+#include <qdict.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qcolor.h>
+#include <qfont.h>
+#include <qrect.h>
+#include <qpixmap.h>
+#include <qdatetime.h>
+
+#define IRC_SAFE_MAX_LINE 450
+
+#include "boundscheckingarray.h"
+#include "ksircchannel.h"
+#include "ksircserver.h"
+
+// Central place to hold KSirc's options
+// and manage default values. The base classes
+// are only used directly by the prefs dialog.
+// The constructors initialize all options with default values.
+class KSOGeneral
+{
+public:
+ KSOGeneral();
+
+ enum { SDI, MDI } displayMode;
+ bool autoCreateWin : 1;
+ bool autoCreateWinForNotice : 1;
+ bool nickCompletion : 1;
+ bool displayTopic : 1;
+ bool oneLineEntry : 1;
+ bool runDocked : 1;
+// bool timeStamp : 1;
+// bool beepNotify : 1;
+ bool colorPicker : 1;
+ bool autoRejoin : 1;
+// bool beepOnMsg : 1;
+// bool logging : 1;
+ bool publicAway : 1;
+ bool useColourNickList : 1;
+ // bool topicShow : 1;
+ bool dockPopups : 1;
+ bool autoSaveHistory : 1;
+ int windowLength;
+ QString backgroundFile;
+
+ QPixmap backgroundPixmap();
+
+private:
+ QPixmap m_backgroundPixmap;
+};
+
+class KSOChannel
+{
+public:
+ KSOChannel();
+
+ QString server;
+ QString channel;
+
+ bool timeStamp : 1;
+ bool beepNotify : 1;
+ bool beepOnMsg : 1;
+ bool logging : 1;
+ bool topicShow : 1;
+ bool filterJoinPart : 1;
+ QString encoding;
+
+ QDateTime lastUsed;
+
+ static bool applyGlobally;
+
+
+
+};
+
+class KSOServer
+{
+public:
+ KSOServer();
+
+ QString server;
+ bool globalCopy;
+
+ QString nick;
+ QString altNick;
+ QString realName;
+ QString userID;
+ QStringList notifyList;
+
+ QDateTime lastUsed;
+};
+
+class KSOStartup
+{
+public:
+ KSOStartup();
+
+ QRect geometry;
+// QString nick;
+// QString altNick;
+// QString realName;
+// QString userID;
+// QStringList notifyList;
+};
+
+class KSOColors
+{
+public:
+ enum { numColors = 16 };
+
+ KSOColors();
+
+ QColor textColor;
+ QColor linkColor;
+ QColor infoColor;
+ QColor channelColor;
+ QColor errorColor;
+ QColor ownNickColor;
+ bool ownNickBold : 1;
+ bool ownNickUl : 1;
+ bool ownNickRev : 1;
+
+ QColor msgContainNick; // needs config + impl
+ QColor msg1Contain; // needs config
+ QString msg1String; // needs config
+ bool msg1Regex;
+ QColor msg2Contain; // need config
+ QString msg2String; // needs config
+ bool msg2Regex;
+
+ QColor nickForeground;
+ QColor nickBackground;
+ QColor backgroundColor;
+ QColor selBackgroundColor;
+ QColor selForegroundColor;
+ //QColor ircColors[numColors];
+ BoundsCheckingArray<QColor, numColors> ircColors;
+ BoundsCheckingArray<bool, numColors> nickHighlight;
+
+ QString colourTheme;
+
+ QFont defaultFont;
+ bool ksircColors : 1;
+ bool mircColors : 1;
+ bool nickColourization : 1;
+
+};
+
+class KSORMBMenu
+{
+public:
+ KSORMBMenu();
+};
+
+class KSOServChan
+{
+public:
+ KSOServChan();
+};
+
+typedef QMap<QString, KSOChannel> ChannelOpMap;
+typedef QMap<QString, ChannelOpMap> ServerChannelOpMap;
+typedef QMap<QString, KSOServer> ServerOpMap;
+
+class KSOptions
+ : public KSOGeneral,
+ public KSOStartup,
+ public KSOColors,
+ public KSORMBMenu,
+ public KSOServChan
+{
+public:
+ KSOptions() { s_options = this; }
+
+ void load( int sections = -1 );
+ void save( int sections = -1 );
+
+ static KSOptions *options() { return s_options; }
+
+ ServerChannelOpMap channel;
+ ServerOpMap server;
+
+ KSOChannel &chan( const KSircChannel &chanInfo )
+ {
+ return channel[chanInfo.server()][chanInfo.channel()];
+ }
+
+ KSOServer &serv( const KSircServer &servInfo )
+ {
+ return server[servInfo.server()];
+ }
+
+ void channelSetup(QString serv, QString chan);
+ void applyChannelGlobal(void);
+
+ void serverSetup(QString server);
+ void serverSetup( const KSircServer &servInfo )
+ {
+ serverSetup(servInfo.server());
+ }
+
+ enum {
+ All = -1, General = 1, Startup = 2,
+ Colors = 4, RMBMenu = 8, ServChan = 16,
+ Channels = 32, Servers = 64
+ };
+
+private:
+ static KSOptions *s_options;
+};
+
+#define ksopts (KSOptions::options())
+
+#endif
diff --git a/ksirc/ksparser.cpp b/ksirc/ksparser.cpp
new file mode 100644
index 00000000..587a0723
--- /dev/null
+++ b/ksirc/ksparser.cpp
@@ -0,0 +1,192 @@
+/* This file is part of ksirc
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// $Id$
+
+#include <qstring.h>
+#include <qcolor.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+
+#include "ksopts.h"
+#include "ksparser.h"
+
+QString KSParser::parse( const QString &message )
+{
+ QString res;
+ m_tags.clear();
+ m_attributes.clear();
+ m_beeped = false;
+
+ for (unsigned int i = 0; i < message.length();)
+ {
+ QChar ch = message[i++];
+ if (ch.latin1() == 0x03 || ch == '~' && i < message.length())
+ {
+ QChar next = message[ i++ ];
+ if (next.latin1() >= 0x30 && next.latin1() <= 0x39)
+ {
+ int fg = -1, len;
+ int bg = -1;
+ QRegExp colorRex("^[0-9]+");
+ if (colorRex.search(message.mid(--i)) >= 0)
+ {
+ len = colorRex.matchedLength();
+ fg = message.mid(i, len).toInt();
+ i += len;
+ }
+ if (message[i] == ',')
+ {
+ if (colorRex.search(message.mid(++i)) >= 0)
+ {
+ len = colorRex.matchedLength();
+ bg = message.mid(i, len).toInt();
+ i += len;
+ }
+ }
+ QString at;
+ QColor c = ircColor(fg);
+ if ( c.isValid() ) {
+ at += QString( "color=\"%1\" " ).arg( c.name() );
+ }
+
+ c = ircColor(bg);
+ if ( c.isValid() ) {
+ at += QString( "bgcolor=\"%1\" " ).arg( c.name() );
+ }
+ if(at.length() > 0){
+ res += pushTag( "font", at );
+ }
+
+ }
+ else if (ch.latin1() == 0x03) {
+ res += popTag( "font" );
+ /*
+ * We moved it forward looking for the number, back
+ * up or we miss a character. Don't do
+ * res += next since we need to actaully parse that one
+ */
+ --i;
+ }
+ else if (ch == '~')
+ {
+ switch (next)
+ {
+ case 'c':
+ res += popTag( "font" );
+ break;
+ case 'C':
+ res += popAll();
+ break;
+ case 'r':
+ res += toggleTag( "r" );
+ break;
+ case 's': break;
+ case 'b':
+ res += toggleTag( "b" );
+ break;
+ case 'g':
+ m_beeped = true;
+ break;
+ case 'u':
+ res += toggleTag( "u" );
+ break;
+ case 'n':
+ res += toggleTag( "font", QString( "color=\"%1\"" ).arg( ksopts->nickForeground.name() ) );
+ break;
+ case 'o':
+ res += pushTag( "font", QString( "color=\"%1\"" ).arg( ksopts->msgContainNick.name() ) );
+ break;
+ case '#':
+ res += pushTag( "font", QString( "color=\"#%1\"" ).arg( message.mid(i, 6) ));
+ i+=6;
+ break;
+ case '~':
+ res += ch;
+ break;
+ default:
+ res += ch;
+ res += next;
+ break;
+ }
+ }
+ }
+ else
+ res += ch;
+
+ }
+
+ res.append( popAll() );
+
+ return res;
+}
+
+QString KSParser::pushTag(const QString &tag, const QString &attributes)
+{
+ QString res;
+ m_tags.push(tag);
+ if (!m_attributes.contains(tag))
+ m_attributes.insert(tag, attributes);
+ else if (!attributes.isEmpty())
+ m_attributes.replace(tag, attributes);
+ res.append("<" + tag);
+ if (!m_attributes[tag].isEmpty())
+ res.append(" " + m_attributes[tag]);
+ return res + ">";
+}
+
+QString KSParser::popTag(const QString &tag)
+{
+ if (!m_tags.contains(tag))
+ return QString::null;
+
+ QString res;
+ QValueStack<QString> savedTags;
+ while (m_tags.top() != tag)
+ {
+ savedTags.push(m_tags.pop());
+ res.append("</" + savedTags.top() + ">");
+ }
+ res.append("</" + m_tags.pop() + ">");
+ m_attributes.remove(tag);
+ while (!savedTags.isEmpty())
+ res.append(pushTag(savedTags.pop()));
+ return res;
+}
+
+QString KSParser::toggleTag(const QString &tag, const QString &attributes)
+{
+ return m_attributes.contains(tag) ? popTag(tag) : pushTag(tag, attributes);
+}
+
+QString KSParser::popAll()
+{
+ QString res;
+ while (!m_tags.isEmpty())
+ res.append("</" + m_tags.pop() + ">");
+ m_attributes.clear();
+ return res;
+}
+
+QColor KSParser::ircColor(int code)
+{
+ if (code >= 0 && code < 16)
+ return ksopts->ircColors[code];
+ return QColor();
+}
diff --git a/ksirc/ksparser.h b/ksirc/ksparser.h
new file mode 100644
index 00000000..e7d2647f
--- /dev/null
+++ b/ksirc/ksparser.h
@@ -0,0 +1,43 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Artistic License.
+*/
+#ifndef __ksparser_h__
+#define __ksparser_h__
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qcolor.h>
+#include <qvaluestack.h>
+
+// Helper class to parse IRC colour/style codes and convert them to
+// richtext. The parser maintains an internal stack of the styles
+// applied because the IRC message could contain sequences as
+// (bold)Hello (red)World(endbold)! (blue)blue text
+// which needs to be converted to
+// <b>Hello </b><font color="red"><b>World</b>! </font><font color="blue">blue text</font>
+// to get correctly nested tags. (malte)
+class KSParser
+{
+public:
+ QString parse(const QString &);
+ bool beeped() const { return m_beeped; }
+
+private:
+ QString pushTag(const QString &, const QString & = QString::null);
+ QString popTag(const QString &);
+ QString toggleTag(const QString &, const QString & = QString::null);
+ QString popAll();
+ QColor ircColor(int);
+
+private:
+ QValueStack<QString> m_tags;
+ QMap<QString, QString> m_attributes;
+ bool m_beeped;
+};
+
+#endif
+
+
diff --git a/ksirc/kstextview.cpp b/ksirc/kstextview.cpp
new file mode 100644
index 00000000..aedf31ad
--- /dev/null
+++ b/ksirc/kstextview.cpp
@@ -0,0 +1,2269 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "kstextview.h"
+#include "stringparserstate.h"
+
+#include <qpainter.h>
+#include <qvaluestack.h>
+#include <qdragobject.h>
+#include <qtimer.h>
+#include <qclipboard.h>
+#include <qdict.h>
+#include <kcharsets.h>
+#include <kapplication.h>
+#include <kmimesourcefactory.h>
+#include <kcursor.h>
+#include <kurldrag.h>
+#include <kdebug.h>
+#include <assert.h>
+
+using namespace KSirc;
+
+typedef StringParserState<QChar> ParsingState;
+
+static const int PaintBufferExtend = 128;
+
+// temporary(!)
+static QDict<QPixmap> *ksTextViewPixmapDict = 0;
+static void cleanupKSTextViewPixmapDict()
+{
+ delete ksTextViewPixmapDict;
+ ksTextViewPixmapDict = 0;
+}
+
+QPixmap ksTextViewLoadPixmap( const QString &icon )
+{
+ if ( !ksTextViewPixmapDict )
+ {
+ ksTextViewPixmapDict = new QDict<QPixmap>;
+ ksTextViewPixmapDict->setAutoDelete( true );
+ qAddPostRoutine( cleanupKSTextViewPixmapDict );
+ }
+
+ QPixmap *pix = ksTextViewPixmapDict->find( icon );
+ if ( !pix )
+ {
+ QImage img;
+
+ const QMimeSource *src = kapp->mimeSourceFactory()->data( icon, QString::null );
+ if ( !src || !QImageDrag::decode( src, img ) || img.isNull() )
+ return QPixmap();
+
+ pix = new QPixmap( img );
+ ksTextViewPixmapDict->insert( icon, pix );
+ }
+ return *pix;
+}
+
+Item::Item( TextParag *parag, const ItemProperties &props )
+ : m_extendsDirty( true ), m_minWidth( -1 ), m_width( - 1 ),
+ m_height( - 1 ), m_selection( NoSelection ), m_line( 0 ),
+ m_parag( parag ), m_props( props )
+{
+}
+
+Item::~Item()
+{
+}
+
+int Item::width() const
+{
+ if ( m_extendsDirty )
+ {
+ calcExtends();
+ m_extendsDirty = false;
+ }
+ return m_width;
+}
+
+int Item::minWidth() const
+{
+ if ( m_extendsDirty )
+ {
+ calcExtends();
+ m_extendsDirty = false;
+ }
+ return m_minWidth;
+}
+
+int Item::height() const
+{
+ if ( m_extendsDirty )
+ {
+ calcExtends();
+ m_extendsDirty = false;
+ }
+ return m_height;
+}
+
+Item *Item::breakLine( int )
+{
+ return 0; // can't break by default...
+}
+
+int Item::calcSelectionOffset( int x )
+{
+ return x; // default ...
+}
+
+void Item::selectionOffsets( int &startOffset, int &endOffset )
+{
+ m_parag->textView()->selectionOffsets( startOffset, endOffset );
+}
+
+int Item::maxSelectionOffset() const
+{
+ return text().len - 1;
+}
+
+StringPtr Item::text() const
+{
+ return StringPtr();
+}
+
+void Item::setProps( const ItemProperties &props )
+{
+ m_props = props;
+ m_extendsDirty = true;
+}
+
+Item *Item::create( TextParag *parag, const Token &tok, const ItemProperties &props )
+{
+ assert( tok.id != Token::TagClose );
+
+ if ( tok.id == Token::Text )
+ return new TextChunk( parag, tok.value, props );
+
+ if ( tok.value == "img" )
+ {
+ QString url = CONSTSTRING( tok.attributes[ "src" ] );
+ if ( url.isEmpty() )
+ return 0;
+
+ QPixmap pixmap = ksTextViewLoadPixmap( url );
+ if ( pixmap.isNull() )
+ return 0;
+
+ return new ImageItem( parag, pixmap );
+ }
+
+ return 0;
+}
+
+void Item::setLine(TextLine *line)
+{
+ m_line = line;
+}
+
+TextChunk::TextChunk( TextParag *parag, const StringPtr &text, const ItemProperties &props )
+ : Item( parag, props ), m_text( text ), m_originalTextLength( text.len ),
+ m_metrics( props.font ), m_parent(0)
+{
+}
+
+void TextChunk::paint( QPainter &p )
+{
+ p.setFont( m_props.font );
+
+ if ( m_selection == NoSelection )
+ paintText( p, 0, m_text );
+ else
+ paintSelection( p );
+}
+
+Item *TextChunk::breakLine( int width )
+{
+ ParsingState state( m_text.ptr, m_text.len );
+
+ const int requestedWidth = width;
+ const int spaceWidth = m_metrics.width( ' ' );
+
+ state.skip( ' ' );
+
+ if ( state.atEnd() ) // eh?
+ return 0;
+
+ StringPtr firstWord; firstWord.ptr = state.current();
+ firstWord.len = state.advanceTo( ' ' );
+
+ const int firstWordWidth = m_metrics.width( CONSTSTRING( firstWord ) );
+
+ if ( !state.atBegin() ) // some leading spaces?
+ width -= spaceWidth;
+
+ width -= firstWordWidth;
+
+ if ( width < 0 ) {
+ StringPtr rightHandSide = breakInTheMiddle( requestedWidth );
+ if ( rightHandSide.isNull() )
+ return 0;
+ return hardBreak( rightHandSide );
+ }
+
+ while ( !state.atEnd() )
+ {
+ bool spaceSeen = state.skip( ' ' ) > 0;
+
+ if ( state.atEnd() )
+ break;
+
+ StringPtr word; word.ptr = state.current();
+ word.len = state.advanceTo( ' ' );
+
+ const int wordWidth = m_metrics.width( CONSTSTRING( word ) );
+
+ if ( spaceSeen )
+ {
+ width -= spaceWidth;
+ spaceSeen = false;
+ }
+
+ width -= wordWidth;
+ if ( width > 0 )
+ continue;
+
+ StringPtr split( word.ptr, state.end() - word.ptr );
+ return hardBreak( split );
+ }
+ return 0;
+}
+
+Item::LayoutResetStatus TextChunk::resetLayout()
+{
+
+ if ( m_originalTextLength == 0 )
+ {
+ if ( m_parent )
+ {
+ if ( m_selection == SelectionStart )
+ m_parent->mergeSelection( this, m_parag->textView()->selectionStart() );
+ else if ( m_selection == SelectionEnd )
+ m_parent->mergeSelection( this, m_parag->textView()->selectionEnd() );
+ else if ( m_selection == SelectionBoth )
+ {
+ m_parent->mergeSelection( this, m_parag->textView()->selectionStart() );
+ m_parent->mergeSelection( this, m_parag->textView()->selectionEnd() );
+ }
+ }
+
+ return DeleteItem;
+ }
+
+ m_extendsDirty |= ( m_text.len != m_originalTextLength );
+
+ m_text.len = m_originalTextLength;
+ return KeepItem;
+}
+
+int TextChunk::calcSelectionOffset( int x )
+{
+ // ### how to optimize?
+
+ QConstString tmp( m_text.ptr, m_text.len );
+ const QString &s = tmp.string();
+
+ uint i = 0;
+ int px = 0;
+ for (; i < m_text.len; ++i )
+ {
+ const int partialWidth = m_metrics.width( s, i + 1 );
+ if ( px <= x && x <= partialWidth )
+ return i;
+ px = partialWidth;
+ }
+
+ kdDebug(5008) << "calcSelectionOffset bug width:" << width() << " partialWidth: " << m_metrics.width( s, i + 1 )<< endl;
+ //assert( false );
+ return m_text.len-1;
+}
+
+StringPtr TextChunk::text() const
+{
+ return m_text;
+}
+
+void TextChunk::setProps( const ItemProperties &props )
+{
+ Item::setProps( props );
+ m_metrics = QFontMetrics( props.font );
+}
+
+void TextChunk::calcExtends() const
+{
+ QConstString tmp( m_text.ptr, m_text.len );
+ const QString &text = tmp.string();
+
+ m_width = m_metrics.width( text );
+ m_height = m_metrics.lineSpacing();
+
+ //m_minWidth = 0;
+
+ m_minWidth = m_metrics.charWidth( text, 1 );
+
+ /*
+ ParsingState state( m_text.ptr, m_text.len );
+
+ state.skip( ' ' );
+
+ if ( state.atEnd() ) // eh?
+ return;
+
+ StringPtr firstWord; firstWord.ptr = state.current();
+ firstWord.len = state.advanceTo( ' ' );
+
+ m_minWidth = m_metrics.width( CONSTSTRING( firstWord ) );
+ */
+}
+
+StringPtr TextChunk::breakInTheMiddle( int width )
+{
+ QConstString tmp( m_text.ptr, m_text.len );
+ const QString &s = tmp.string();
+
+ uint i = 0;
+ for (; i < m_text.len; ++i )
+ {
+ const int partialWidth = m_metrics.width( s, i + 1 );
+ if ( partialWidth >= width ) {
+ if ( i == 0 )
+ return StringPtr();
+ return StringPtr( m_text.ptr + i, m_text.len - i );
+ }
+ }
+
+ return StringPtr();
+}
+
+Item *TextChunk::hardBreak( const StringPtr &rightHandSide )
+{
+ TextChunk *chunk = new TextChunk( m_parag, rightHandSide, m_props );
+ chunk->m_originalTextLength = 0; // ### hack... You make the last line dynamic so if it's 1 word it doesn't chop itself up
+ if(m_parent == 0x0)
+ chunk->m_parent = this;
+ else
+ chunk->m_parent = m_parent;
+
+ m_text.len = rightHandSide.ptr - m_text.ptr;
+ m_extendsDirty = true;
+
+ SelectionPoint *selection = 0;
+ if ( m_selection == SelectionStart )
+ selection = m_parag->textView()->selectionStart();
+ else if ( m_selection == SelectionEnd )
+ selection = m_parag->textView()->selectionEnd();
+ else if ( m_selection == SelectionBoth ) {
+ SelectionPoint *selStart = m_parag->textView()->selectionStart();
+ SelectionPoint *selEnd = m_parag->textView()->selectionEnd();
+
+ if ( selStart->offset >= m_text.len ) {
+ selStart->offset -= m_text.len;
+ selEnd->offset -= m_text.len;
+ selStart->item = selEnd->item = chunk;
+ chunk->setSelectionStatus( m_selection );
+ m_selection = NoSelection;
+ } else if ( selEnd->offset >= m_text.len ) {
+ selEnd->offset -= m_text.len;
+ selEnd->item = chunk;
+ chunk->setSelectionStatus( SelectionEnd );
+ m_selection = SelectionStart;
+ }
+ }
+
+ if ( selection && selection->offset >= m_text.len ) {
+ selection->offset -= m_text.len;
+ selection->item = chunk;
+ chunk->setSelectionStatus( m_selection );
+ m_selection = NoSelection;
+ }
+
+ return chunk;
+}
+
+void TextChunk::paintSelection( QPainter &p )
+{
+ int selectionStart = 0;
+ int selectionEnd = 0;
+ selectionOffsets( selectionStart, selectionEnd );
+
+ if ( m_selection == SelectionStart )
+ {
+ const int width = paintText( p, 0, StringPtr( m_text.ptr, selectionStart ) );
+ paintSelection( p, width, StringPtr( m_text.ptr + selectionStart,
+ m_text.len - selectionStart ) );
+ }
+ else if ( m_selection == InSelection )
+ paintSelection( p, 0, m_text );
+ else if ( m_selection == SelectionEnd )
+ {
+ const int width = paintSelection( p, 0, StringPtr( m_text.ptr, selectionEnd + 1 ) );
+ paintText( p, width, StringPtr( m_text.ptr + selectionEnd + 1,
+ m_text.len - selectionEnd - 1 ) );
+ }
+ else if ( m_selection == SelectionBoth )
+ {
+ int width = paintText( p, 0, StringPtr( m_text.ptr, selectionStart ) );
+ width += paintSelection( p, width, StringPtr( m_text.ptr + selectionStart,
+ selectionEnd - selectionStart + 1 ) );
+ paintText( p, width, StringPtr( m_text.ptr + selectionEnd + 1,
+ m_text.len - selectionEnd - 1 ) );
+ }
+}
+
+int TextChunk::paintSelection( QPainter &p, int x, const StringPtr &text )
+{
+ QConstString constString( text.ptr, text.len );
+ const QString &str = constString.string();
+
+ const int width = m_metrics.width( str );
+
+ const QColorGroup &cg = m_parag->textView()->colorGroup();
+
+ if (m_props.bgSelColor.isValid())
+ p.fillRect( x, 0, width, height(), m_props.bgSelColor );
+ else
+ p.fillRect( x, 0, width, height(), cg.highlight() );
+
+ if (m_props.selColor.isValid())
+ p.setPen( m_props.selColor );
+ else
+ p.setPen( cg.highlightedText() );
+
+ p.drawText( x, m_metrics.ascent(), str );
+
+ return width;
+}
+
+int TextChunk::paintText( QPainter &p, int x, const StringPtr &text )
+{
+ QConstString constString( text.ptr, text.len );
+ const QString &str = constString.string();
+
+ const int width = m_metrics.width( str );
+
+ if ( m_props.bgColor.isValid() )
+ p.fillRect( x, 0, width, height(), m_props.bgColor );
+
+ if ( m_props.color.isValid() )
+ p.setPen( m_props.color );
+ else
+ p.setPen( m_parag->textView()->foregroundColor() );
+
+ p.drawText( x, m_metrics.ascent(), str );
+
+ return width;
+}
+
+void TextChunk::mergeSelection( TextChunk *child, SelectionPoint *selection )
+{
+ selection->offset += child->m_text.ptr - m_text.ptr;
+
+ if(selection->offset > m_originalTextLength){
+ kdDebug(5008) << "Child: " << child->m_text.toQString() << " Parent: " << m_text.toQString() << endl;
+ kdDebug(5008) << "Length all wrong!" << endl;
+ //assert(0);
+ }
+
+ selection->item = this;
+
+ if ( ( m_selection == SelectionStart && child->selectionStatus() == SelectionEnd ) ||
+ ( m_selection == SelectionEnd && child->selectionStatus() == SelectionStart ) )
+ m_selection = SelectionBoth;
+ else
+ m_selection = child->selectionStatus();
+}
+
+ImageItem::ImageItem( TextParag *parag, const QPixmap &pixmap )
+ : Item( parag ), m_pixmap( pixmap )
+{
+}
+
+void ImageItem::paint( QPainter &painter )
+{
+ int y = 0;
+ if(m_line) {
+ y = (m_line->maxHeight() - m_pixmap.height())/2;
+ }
+
+ if ( m_selection != NoSelection ) {
+ int h;
+
+ if(m_line)
+ h = m_line->maxHeight();
+ else
+ h = height();
+
+ if (m_props.bgSelColor.isValid())
+ painter.fillRect( 0, 0, width(), h, m_props.bgSelColor );
+ else {
+ const QColorGroup &cg = m_parag->textView()->colorGroup();
+ painter.fillRect( 0, 0, width(), h, cg.highlight() );
+ }
+ }
+
+ painter.drawPixmap( 0, y, m_pixmap );
+}
+
+Item::LayoutResetStatus ImageItem::resetLayout()
+{
+ // nothin' to do
+ return KeepItem;
+}
+
+void ImageItem::calcExtends() const
+{
+ m_width = m_minWidth = m_pixmap.width();
+ m_height = m_pixmap.height();
+}
+
+Tokenizer::Tokenizer( PString &text )
+ : m_text( text.data ), m_tags( text.tags ),
+ m_textBeforeFirstTagProcessed( false ), m_done( false )
+{
+ //qDebug( "Tokenizer::Tokenizer( %s )", m_text.ascii() );
+
+ m_lastTag = m_tags.begin();
+
+ if ( !m_tags.isEmpty() ) {
+ if ( ( *m_tags.begin() ).type != TagIndex::Open ) {
+ qDebug( "something went awfully wrong! bailing out with an assertion" );
+ qDebug( "text input was: %s", text.data.ascii() );
+ }
+ assert( ( *m_tags.begin() ).type == TagIndex::Open );
+ }
+}
+
+Tokenizer::PString Tokenizer::preprocess( const QString &richText )
+{
+ PString result;
+ result.data = richText;
+ result.tags = scanTagIndices( result.data );
+ resolveEntities( result.data, result.tags );
+ return result;
+}
+
+QString Tokenizer::convertToRichText( const PString &ptext )
+{
+ if ( ptext.tags.isEmpty() )
+ return ptext.data;
+
+ QString result = ptext.data;
+ uint i = 0;
+ TagIndexList tags = ptext.tags;
+ TagIndexList::Iterator it = tags.begin();
+ TagIndexList::Iterator end = tags.end();
+
+ for (; i < result.length(); ++i )
+ {
+ if ( it != end && i == (*it).index )
+ {
+ ++it;
+ continue;
+ }
+
+ unsigned short indexAdjustment = 0;
+ const QChar ch = result[ i ];
+ // ### incomplete!
+ /* this doesn't work quite right (when resolving back
+ * KCharSet's fromEntity breaks)
+ if ( ch == '<' || ch == '>' || ch == '&' )
+ {
+ QString entity = KGlobal::charsets()->toEntity( ch );
+ indexAdjustment = entity.length() - 1;
+ result.replace( i, 1, entity );
+ }
+ */
+ if ( ch == '<' )
+ {
+ result.replace( i, 1, "&lt;" );
+ indexAdjustment = 3;
+ }
+ else if ( ch == '>' )
+ {
+ result.replace( i, 1, "&gt;" );
+ indexAdjustment = 3;
+ }
+ else if ( ch == '&' )
+ {
+ result.replace( i, 1, "&amp;" );
+ indexAdjustment = 4;
+ }
+
+ if ( indexAdjustment > 0 )
+ {
+ TagIndexList::Iterator tmpIt = it;
+ for (; tmpIt != end; ++tmpIt )
+ (*tmpIt).index += indexAdjustment;
+ }
+ }
+
+ return result;
+}
+
+bool Tokenizer::parseNextToken( Token &tok )
+{
+ if ( m_done )
+ {
+ //qDebug( "Tokenizer: premature end" );
+ return false;
+ }
+
+ if ( m_tags.isEmpty() )
+ {
+ tok.id = Token::Text;
+ tok.attributes.clear();
+ tok.value = StringPtr( m_text );
+ m_done = true;
+ return true;
+ }
+
+ TagIndexList::ConstIterator it = m_lastTag;
+ ++it;
+
+ if ( it == m_tags.end() )
+ {
+ m_done = true;
+
+ const uint idx = (*m_lastTag).index + 1;
+ if ( idx >= m_text.length() )
+ return false;
+
+ tok.id = Token::Text;
+ tok.value = StringPtr( m_text.unicode() + idx,
+ m_text.length() - idx );
+ tok.attributes.clear();
+ return true;
+ }
+
+ // text before first tag opening?
+ if ( m_lastTag == m_tags.begin() &&
+ (*m_lastTag).index > 0 &&
+ !m_textBeforeFirstTagProcessed )
+ {
+ tok.id = Token::Text;
+ tok.attributes.clear();
+ tok.value = StringPtr( m_text.unicode(),
+ (*m_lastTag).index );
+
+ m_textBeforeFirstTagProcessed = true;
+ return true;
+ }
+
+ const uint index = (*it).index;
+ const int type = (*it).type;
+ const uint lastIndex = (*m_lastTag).index;
+ const uint lastType = (*m_lastTag).type;
+
+ assert( lastIndex < index );
+
+ // a tag
+ if ( lastType == TagIndex::Open &&
+ type == TagIndex::Close )
+ {
+ const QChar *tagStart = m_text.unicode() + lastIndex + 1;
+ uint tagLen = ( index - 1 ) - ( lastIndex + 1 ) + 1;
+ // </bleh> ?
+ if ( *tagStart == '/' )
+ {
+ ++tagStart;
+ --tagLen;
+ tok.id = Token::TagClose;
+ }
+ else
+ tok.id = Token::TagOpen;
+
+ parseTag( StringPtr( tagStart, tagLen ), tok.value, tok.attributes );
+
+ m_lastTag = it;
+ return true;
+ }
+ // text
+ else if ( lastType == TagIndex::Close &&
+ type == TagIndex::Open )
+ {
+ tok.id = Token::Text;
+ tok.attributes.clear();
+ tok.value = StringPtr( m_text.unicode() + lastIndex + 1,
+ ( index - 1 ) - lastIndex );
+
+ m_lastTag = it;
+ return true;
+ }
+ else {
+ qDebug( "EEK, this should never happen. input text was: %s", m_text.ascii() );
+ assert( false );
+ }
+
+ return false;
+}
+
+Tokenizer::TagIndexList Tokenizer::scanTagIndices( const QString &text )
+{
+ const QChar *start = text.unicode();
+ const QChar *p = start;
+ const QChar *endP = p + text.length();
+ bool quoted = false;
+ bool inTag = false;
+
+ TagIndexList tags;
+
+ for (; p < endP; ++p )
+ {
+ const QChar ch = *p;
+ if ( ch == '"' && inTag )
+ {
+ quoted = quoted ? false : true;
+ continue;
+ }
+
+ if( quoted )
+ continue;
+
+ if ( ch == '<' )
+ {
+ inTag = true;
+ tags.append( TagIndex( p - start, TagIndex::Open ) );
+ continue;
+ }
+ else if ( ch == '>' )
+ {
+ inTag = false;
+ tags.append( TagIndex( p - start, TagIndex::Close ) );
+ continue;
+ }
+ }
+
+ return tags;
+}
+
+void Tokenizer::resolveEntities( QString &text, TagIndexList &tags )
+{
+ const QChar *p = text.unicode();
+ const QChar *endP = p + text.length();
+ uint i = 0;
+ bool scanForSemicolon = false;
+ const QChar *ampersand = 0;
+ TagIndexList::Iterator tagInfoIt = tags.begin();
+ TagIndexList::Iterator tagsEnd = tags.end();
+
+ for (; p < endP; ++p, ++i )
+ {
+ if ( tagInfoIt != tagsEnd &&
+ i > (*tagInfoIt).index )
+ ++tagInfoIt;
+
+ const QChar ch = *p;
+
+ if ( ch == '&' ) {
+ ampersand = p;
+ scanForSemicolon = true;
+ continue;
+ }
+
+ if ( ch != ';' || !scanForSemicolon )
+ continue;
+
+ assert( ampersand );
+
+ scanForSemicolon = false;
+
+ const QChar *entityBegin = ampersand + 1;
+
+ const uint entityLength = p - entityBegin;
+ if ( entityLength == 0 )
+ continue;
+
+ const QChar entityValue = KCharsets::fromEntity( QConstString( entityBegin, entityLength ).string() );
+ if ( entityValue.isNull() )
+ continue;
+
+ const uint ampersandPos = ampersand - text.unicode();
+
+ text[ ampersandPos ] = entityValue;
+ text.remove( ampersandPos + 1, entityLength + 1 );
+ i = ampersandPos;
+ p = text.unicode() + i;
+ endP = text.unicode() + text.length();
+ ampersand = 0;
+
+ uint adjustment = entityLength + 1;
+ TagIndexList::Iterator it = tagInfoIt;
+ for (; it != tags.end(); ++it )
+ (*it).index -= adjustment;
+ }
+}
+
+void Tokenizer::parseTag( const StringPtr &text,
+ StringPtr &tag,
+ AttributeMap &attributes )
+{
+ assert( text.len > 0 );
+
+ attributes.clear();
+ tag = StringPtr();
+
+ const QChar *p = text.ptr;
+ const QChar *endP = p + text.len;
+ const QChar *start = p;
+
+ int state = ScanForName;
+
+ StringPtr key;
+
+ while ( p < endP )
+ {
+ const QChar ch = *p;
+
+ if ( ch == ' ' )
+ {
+ start = ++p;
+ continue;
+ }
+
+ if ( state == ScanForEqual )
+ {
+ if ( ch == '=' )
+ {
+ state = ScanForValue;
+ ++p;
+ continue;
+ }
+ state = ScanForName;
+ }
+
+ if ( state == ScanForValue )
+ {
+ if ( ch == '=' ) // eh?
+ {
+ qDebug( "EH?" );
+ ++p;
+ continue;
+ }
+
+ if ( key.isNull() )
+ {
+ qDebug( "Tokenizer: Error, attribute value without key." );
+ // reset
+ state = ScanForName;
+ ++p;
+ continue;
+ }
+
+ start = 0x0;
+ if ( *p == '"' )
+ {
+ ++p;
+ start = p;
+ while ( p < endP && *p != '"' ) {
+ ++p;
+ }
+ }
+ else {
+ while ( p < endP && *p != ' ' && *p != '>') {
+ if(!start)
+ start = p;
+ ++p;
+ }
+ }
+
+ if(start == 0x0) {
+ state = ScanForName;
+ qDebug( "Never found start \" in tag." );
+ ++p;
+ continue;
+ }
+
+ const QChar *valueEnd = p;
+
+ StringPtr value = StringPtr( start, valueEnd - start );
+ attributes[ key ] = value;
+
+ if(*p == '"')
+ ++p; // move p beyond the last "
+ state = ScanForName;
+ continue;
+ }
+
+ if ( state == ScanForName )
+ {
+ while ( p < endP && *p != ' ' && *p != '=' ){
+ ++p;
+ }
+
+ key = StringPtr( start, p - start );
+
+ if ( tag.isNull() )
+ tag = key;
+ else
+ attributes[ key ] = StringPtr();
+
+ state = ScanForEqual;
+ continue;
+ }
+
+ assert( false ); // never reached.
+ }
+
+/*
+ kdDebug(5008) << "tagName: " << tag.toQString() << endl;
+ AttributeMap::ConstIterator it = attributes.begin();
+ for (; it != attributes.end(); ++it )
+ kdDebug(5008) << "attribute: " << it.key().toQString() <<
+ " -> " << it.data().toQString() << endl;
+*/
+}
+
+ItemProperties::ItemProperties()
+ : reversed( false )
+{
+}
+
+ItemProperties::ItemProperties( const QFont &defaultFont )
+ : font( defaultFont ), reversed( false )
+{
+}
+
+ItemProperties::ItemProperties( const ItemProperties &other,
+ const Token &token,
+ TextView *textView )
+ : attributes( token.attributes )
+{
+ // inherit
+ font = other.font;
+ color = other.color;
+ bgColor = other.bgColor;
+ bgSelColor = other.bgSelColor;
+ selColor = other.selColor;
+ reversed = other.reversed;
+
+ if ( token.value == "b" )
+ font.setBold( true );
+ else if ( token.value == "i" )
+ font.setItalic( true );
+ else if ( token.value == "u" )
+ font.setUnderline( true );
+ else if ( token.value == "r" ) {
+ reversed = true;
+ if(other.bgColor.isValid())
+ color = other.bgColor;
+ else
+ color = textView->paletteBackgroundColor();
+
+ if(other.color.isValid())
+ bgColor = other.color;
+ else
+ bgColor = textView->foregroundColor();
+ }
+ else if ( token.value == "font" )
+ {
+ StringPtr colAttr = attributes[ "color" ];
+ if ( !colAttr.isNull() )
+ {
+ QColor col( CONSTSTRING( colAttr ) );
+ if ( col.isValid() ){
+ if(!reversed)
+ color = col;
+ else
+ bgColor = col;
+ }
+ }
+ colAttr = attributes[ "bgcolor" ];
+ if ( !colAttr.isNull() )
+ {
+ QColor col( CONSTSTRING( colAttr ) );
+ if ( col.isValid() ) {
+ if(!reversed)
+ bgColor = col;
+ else
+ color = col;
+ }
+ }
+ }
+ else if ( token.value == "a" )
+ {
+ color = textView->linkColor();
+ font.setUnderline( true );
+ }
+}
+
+ItemProperties::ItemProperties( const ItemProperties &rhs )
+{
+ ( *this ) = rhs;
+}
+
+ItemProperties &ItemProperties::operator=( const ItemProperties &rhs )
+{
+ font = rhs.font;
+ color = rhs.color;
+ bgColor = rhs.bgColor;
+ bgSelColor = rhs.bgSelColor;
+ selColor = rhs.selColor;
+ reversed = rhs.reversed;
+ attributes = rhs.attributes;
+ return *this;
+}
+
+void ItemProperties::updateFont( const QFont &newFont )
+{
+ QFont f = newFont;
+ f.setUnderline( font.underline() );
+ f.setBold( font.bold() );
+ f.setItalic( font.italic() );
+ font = f;
+}
+
+TextLine::TextLine()
+ : m_maxHeight( 0 )
+{
+ m_items.setAutoDelete( true );
+}
+
+TextLine::TextLine( const QPtrList<Item> &items )
+ : m_maxHeight( 0 )
+{
+ m_items.setAutoDelete( true );
+
+ assert( !items.autoDelete() );
+
+ QPtrListIterator<Item> it( items );
+ for (; it.current(); ++it )
+ appendItem( it.current(), UpdateMaxHeight );
+}
+
+QString TextLine::updateSelection( const SelectionPoint &start, const SelectionPoint &end )
+{
+ QString selectedText;
+
+ // fixes a crash where because of an empty list i becomes null
+ if ( m_items.isEmpty() )
+ return QString::null;
+
+ if ( start.line == this )
+ {
+ const int idx = m_items.findRef( start.item );
+ assert( idx != -1 );
+ }
+ else
+ m_items.first();
+
+ Item *i = m_items.current();
+
+ Item *lastItem = 0;
+
+ if ( end.line == this )
+ {
+ const int oldCurrent = m_items.at();
+
+ const int idx = m_items.findRef( end.item );
+ assert( idx != -1 );
+ lastItem = m_items.next();
+
+ m_items.at( oldCurrent );
+ }
+
+ for (; i != lastItem && i!=0L; i = m_items.next() )
+ {
+ if ( i == start.item )
+ {
+ i->setSelectionStatus( Item::SelectionStart );
+
+ StringPtr txt = i->text();
+ if ( !txt.isNull() )
+ selectedText += QString( txt.ptr + start.offset,
+ txt.len - start.offset );
+ }
+ else if ( i == end.item )
+ {
+ i->setSelectionStatus( Item::SelectionEnd );
+
+ StringPtr txt = i->text();
+ if ( !txt.isNull() )
+ selectedText += QString( txt.ptr, end.offset + 1 );
+ }
+ else
+ {
+ i->setSelectionStatus( Item::InSelection );
+
+ selectedText += i->text().toQString();
+ }
+ }
+
+ return selectedText;
+}
+
+void TextLine::clearSelection()
+{
+ Item *i = m_items.first();
+ for (; i; i = m_items.next() )
+ i->setSelectionStatus( Item::NoSelection );
+}
+
+void TextLine::appendItem( Item *i, int layoutUpdatePolicy )
+{
+ m_items.append( i );
+ i->setLine(this);
+
+ if ( layoutUpdatePolicy == UpdateMaxHeight )
+ m_maxHeight = kMax( m_maxHeight, i->height() );
+}
+
+Item *TextLine::resetLayout( QPtrList<Item> &remainingItems)
+{
+ Item *lastLineItem = m_items.getLast();
+ Item *it = m_items.first();
+ // We have to use the tobeDel structure or we call resetLayout on the Item
+ // twice for each item we want to delete
+ QPtrList<Item> tobeDel;
+ while ( it )
+ {
+ if ( it->resetLayout() == Item::KeepItem )
+ remainingItems.append( m_items.take() );
+ else
+ tobeDel.append( m_items.take() );
+
+ it = m_items.current();
+ }
+ m_items = tobeDel;
+ return lastLineItem;
+}
+
+void TextLine::paint( QPainter &p, int y )
+{
+ QPtrListIterator<Item> it( m_items );
+ int x = 0;
+ for (; it.current(); ++it )
+ {
+ p.translate( x, y );
+ it.current()->paint( p );
+ p.translate( -x, -y );
+ x += it.current()->width();
+ }
+}
+
+Item *TextLine::itemAt( int px, SelectionPoint *selectionInfo,
+ Item::SelectionAccuracy accuracy )
+{
+ QPtrListIterator<Item> it( m_items );
+ int x = 0;
+ int width = 0;
+ for (; it.current(); ++it )
+ {
+ width = it.current()->width();
+ if ( x < px && px < ( x + width ) )
+ {
+ Item *i = it.current();
+ if ( selectionInfo )
+ {
+ selectionInfo->pos.setX( x );
+ selectionInfo->offset = i->calcSelectionOffset( px - x );
+ selectionInfo->item = i;
+ selectionInfo->line = this;
+ }
+ return i;
+ }
+ x += width;
+ }
+
+ if ( accuracy == Item::SelectFuzzy && selectionInfo &&
+ !m_items.isEmpty() && width > 0 )
+ {
+ Item *i = m_items.getLast();
+ selectionInfo->pos.setX( x - width );
+ selectionInfo->offset = i->maxSelectionOffset();
+ selectionInfo->item = i;
+ selectionInfo->line = this;
+ }
+
+ return 0;
+}
+
+QString TextLine::plainText() const
+{
+ QString res;
+ QPtrListIterator<Item> it( m_items );
+ for (; it.current(); ++it )
+ res += it.current()->text().toQString();
+ return res;
+}
+
+void TextLine::fontChange( const QFont &newFont )
+{
+ QPtrListIterator<Item> it( m_items );
+ for (; it.current(); ++it )
+ {
+ ItemProperties props = it.current()->props();
+ props.updateFont( newFont );
+ it.current()->setProps( props );
+ }
+}
+
+TextParag::TextParag( TextView *textView, const QString &richText )
+ : m_layouted( false ), m_height( 0 ), m_minWidth( 0 ),
+ m_textView( textView )
+{
+ setRichText( richText );
+ m_lines.setAutoDelete(true);
+}
+
+TextParag::~TextParag()
+{
+}
+
+void TextParag::layout( int width )
+{
+ QPtrList<Item> items;
+
+ TextLine *row = m_lines.first();
+
+ for(;row;row = m_lines.next()){
+ row->resetLayout( items );
+ }
+
+ m_lines.clear();
+
+ // all text chunks are now in a flat list. break them into
+ // pieces of lists of chunks, so they fit with the given width
+
+ m_height = 0;
+ m_minWidth = 0;
+
+ int remainingWidth = width;
+
+ SelectionPoint *selStart = m_textView->selectionStart();
+ SelectionPoint *selEnd = m_textView->selectionEnd();
+ assert( selStart && selEnd );
+
+ QPtrListIterator<Item> it( items );
+ while ( it.current() )
+ {
+ m_minWidth = kMax( m_minWidth, it.current()->minWidth() );
+
+ Item *item = it.current();
+ int itemWidth = item->width();
+
+ if ( remainingWidth >= itemWidth )
+ {
+ remainingWidth -= itemWidth;
+ ++it;
+ continue;
+ }
+
+ Item *newChunk = 0;
+
+ if ( itemWidth > item->minWidth() )
+ newChunk = item->breakLine( remainingWidth );
+
+ if ( newChunk || it.atFirst() )
+ ++it;
+
+ TextLine *line = new TextLine;
+
+ Item *next = it.current();
+
+ items.first();
+
+ while ( items.current() != next )
+ {
+ Item *i = items.take();
+
+ if ( selStart->item == i )
+ selStart->line = line;
+ else if ( selEnd->item == i )
+ selEnd->line = line;
+
+ line->appendItem( i, TextLine::UpdateMaxHeight );
+ }
+
+ assert( !line->isEmpty() );
+
+ m_height += line->maxHeight();
+ m_lines.append( line );
+
+ if ( newChunk )
+ items.prepend( newChunk );
+
+ it.toFirst();
+ remainingWidth = width;
+ }
+
+ // append what's left
+ if ( items.count() > 0 )
+ {
+ TextLine *line = new TextLine( items );
+ m_height += line->maxHeight();
+ m_lines.append( line );
+
+ if ( selStart->parag == this ||
+ selEnd->parag == this )
+ {
+ // ### move to TextLine?
+ QPtrListIterator<Item> it( line->iterator() );
+ for (; it.current(); ++it )
+ {
+ if ( selStart->item == it.current() )
+ selStart->line = line;
+ if ( selEnd->item == it.current() )
+ selEnd->line = line;
+ }
+ }
+ }
+
+ m_layouted = true;
+}
+
+void TextParag::paint( QPainter &p, int y, int maxY )
+{
+ TextLine *row = m_lines.first();
+ for (; row; row = m_lines.next() )
+ {
+ if( (y + row->maxHeight()) >= 0 )
+ row->paint( p, y );
+ y += row->maxHeight();
+ if( y > maxY )
+ break;
+ }
+}
+
+Item *TextParag::itemAt( int px, int py, SelectionPoint *selectionInfo,
+ Item::SelectionAccuracy accuracy )
+{
+ int y = 0;
+ int height = 0;
+ TextLine *row = m_lines.first();
+ for (; row; row = m_lines.next() )
+ {
+ height = row->maxHeight();
+ if ( y <= py && py <= ( y + height ) )
+ {
+ Item *i = row->itemAt( px, selectionInfo, accuracy );
+ if ( selectionInfo )
+ {
+ selectionInfo->pos.setY( y );
+ selectionInfo->parag = this;
+ }
+ return i;
+ }
+ y += height;
+ }
+
+ if ( accuracy == Item::SelectFuzzy && selectionInfo && !m_lines.isEmpty() )
+ {
+ TextLine *row = m_lines.getLast();
+ row->itemAt( px, selectionInfo, accuracy );
+
+ selectionInfo->pos.setY( y - height );
+ selectionInfo->parag = this;
+ }
+
+ return 0;
+}
+
+QString TextParag::updateSelection( const SelectionPoint &start, const SelectionPoint &end )
+{
+ QString selectedText;
+
+ // sanity check
+ // (don't put it lower because it changes the current list item)
+ if ( end.parag == this )
+ assert( m_lines.findRef( end.line ) != -1 );
+
+ if ( start.parag == this )
+ {
+ int idx = m_lines.findRef( start.line );
+ assert( idx != -1 );
+ }
+ else
+ m_lines.first();
+
+ TextLine *line = m_lines.current();
+
+ TextLine *lastLine = m_lines.getLast();
+
+ if ( end.parag == this )
+ lastLine = end.line;
+
+ for (; line != lastLine; line = m_lines.next() )
+ selectedText += line->updateSelection( start, end );
+
+ if ( lastLine )
+ selectedText += lastLine->updateSelection( start, end );
+
+ return selectedText;
+}
+
+void TextParag::clearSelection()
+{
+ // ### optimize, add 'selectionDirty' flag to TextLine and TextParag!
+ TextLine *line = m_lines.first();
+ for (; line; line = m_lines.next() )
+ line->clearSelection();
+}
+
+void TextParag::setRichText( const QString &richText )
+{
+ m_layouted = false;
+ m_height = 0;
+ m_minWidth = 0;
+
+ // ### FIXME SELECTION!!!!!!!!!
+ if ( m_textView->selectionStart()->parag == this ||
+ m_textView->selectionEnd()->parag == this )
+ m_textView->clearSelection();
+
+ m_lines.clear();
+
+ m_processedRichText = Tokenizer::preprocess( richText );
+
+ Tokenizer tokenizer( m_processedRichText );
+ Token tok;
+ Token lastTextToken;
+
+ QValueStack<Tag> tagStack;
+
+ TextLine *line = new TextLine;
+
+ while ( tokenizer.parseNextToken( tok ) )
+ {
+ if ( tok.id == Token::TagOpen )
+ {
+ ItemProperties oldProps( m_textView->font() );
+ if ( !tagStack.isEmpty() )
+ oldProps = tagStack.top().props;
+
+ // ...bleh<foo>... -> finish off 'bleh' first
+ if ( lastTextToken.id != -1 )
+ {
+ Item *item = Item::create( this, lastTextToken, oldProps );
+ if ( item )
+ line->appendItem( item );
+ lastTextToken = Token();
+ }
+
+ ItemProperties props( oldProps, tok, m_textView );
+ tagStack.push( Tag( tok.value, props ) );
+
+ Item *item = Item::create( this, tok, props );
+ if ( item )
+ line->appendItem( item );
+
+ continue;
+ }
+ else if ( tok.id == Token::TagClose )
+ {
+ assert( !tagStack.isEmpty() );
+
+ Tag tag = tagStack.pop();
+
+ if( !( tok.value == tag.name ) ) {
+ kdDebug(5008) << "ASSERT failed! tok.value=" << tok.value.toQString() << " tag.name=" << tag.name.toQString() << endl;
+ kdDebug(5008) << "while parsing " << richText << endl;
+ }
+
+ // ...foo</bleh>... -> finish off 'foo'
+ if ( !lastTextToken.value.isNull() )
+ {
+ Item *item = Item::create( this, lastTextToken, tag.props );
+ if ( item )
+ line->appendItem( item );
+ }
+
+ lastTextToken = Token();
+ }
+ else
+ lastTextToken = tok;
+ }
+
+ // some plain text at the very end, outside of any tag?
+ if ( !lastTextToken.value.isNull() )
+ {
+ Item *item = Item::create( this, lastTextToken );
+ if ( item )
+ line->appendItem( item );
+ }
+
+ m_lines.append( line );
+}
+
+QString TextParag::plainText() const
+{
+ QString result;
+ QPtrListIterator<TextLine> it( m_lines );
+ for (; it.current(); ++it )
+ result += it.current()->plainText();
+ return result;
+}
+
+void TextParag::fontChange( const QFont &newFont )
+{
+ QPtrListIterator<TextLine> it( m_lines );
+ for (; it.current(); ++it )
+ it.current()->fontChange( newFont );
+}
+
+ContentsPaintAlgorithm::ContentsPaintAlgorithm( const QPtrListIterator<TextParag> &paragIt,
+ QWidget *viewport, QPixmap &paintBuffer,
+ QPainter &painter, int clipX, int clipY,
+ int clipHeight )
+ : m_paragIt( paragIt ), m_viewport( viewport ), m_paintBuffer( paintBuffer ),
+ m_painter( painter ), m_clipX( clipX ), m_clipY( clipY ), m_clipHeight( clipHeight ),
+ m_overshoot( 0 )
+{
+}
+
+int ContentsPaintAlgorithm::goToFirstVisibleParagraph()
+{
+ int y = 0;
+
+ while ( y < m_clipY && m_paragIt.current() ) {
+ y += m_paragIt.current()->height();
+ ++m_paragIt;
+ }
+
+ y = adjustYAndIterator( y, y, m_clipY );
+ return y;
+}
+
+int ContentsPaintAlgorithm::paint( QPainter &bufferedPainter, int currentY )
+{
+ const int startY = currentY;
+
+ int nextY = startY + PaintBufferExtend;
+
+ if ( !m_paragIt.current() )
+ return nextY;
+
+ while ( currentY < nextY && m_paragIt.current() ) {
+
+ TextParag *parag = m_paragIt.current();
+
+ //kdDebug(5008) << "Painting[" << currentY << "/" << parag->height() << "]: " << parag->plainText() << endl;
+
+ int drawPos = currentY;
+ int newY = parag->height();
+
+ if(m_overshoot != 0) {
+ drawPos = currentY - parag->height() + m_overshoot;
+ newY = m_overshoot;
+ m_overshoot = 0;
+ }
+
+ parag->paint( bufferedPainter, drawPos, nextY );
+ currentY += newY;
+
+ ++m_paragIt;
+ }
+
+ nextY = adjustYAndIterator( startY, currentY, nextY );
+ return nextY;
+}
+
+int ContentsPaintAlgorithm::adjustYAndIterator( int , int currentY, int nextY )
+{
+ // nothing to adjust?
+ if ( currentY <= nextY || m_paragIt.atFirst() )
+ return currentY;
+
+ if ( m_paragIt.current() )
+ --m_paragIt;
+ else
+ m_paragIt.toLast();
+
+ m_overshoot = currentY - nextY;
+ if(m_overshoot < 0)
+ m_overshoot = 0;
+
+ return nextY;
+}
+
+void ContentsPaintAlgorithm::paint()
+{
+ int y = goToFirstVisibleParagraph();
+
+ int yEnd = m_clipY + m_clipHeight;
+
+ while ( y < yEnd )
+ {
+ m_paintBuffer.fill( m_viewport, 0, y );
+ QPainter bufferedPainter( &m_paintBuffer );
+ bufferedPainter.translate( -m_clipX, -y );
+ int nextY = paint( bufferedPainter, y );
+
+
+ bufferedPainter.end();
+
+ m_painter.drawPixmap( m_clipX, y, m_paintBuffer );
+
+ y = nextY;
+ }
+}
+
+TextView::TextView( QWidget *parent, const char *name )
+ : QScrollView( parent, name, WRepaintNoErase ),
+ m_paintBuffer( PaintBufferExtend, PaintBufferExtend ),
+ m_selectionEndBeforeStart( false ), m_mousePressed( false ),
+ m_mmbPressed( false ),
+ m_linkColor( Qt::blue ), m_height(-1), m_inScroll(false),
+ m_lastScroll(0)
+{
+ m_parags.setAutoDelete( true );
+ viewport()->setBackgroundMode( PaletteBase );
+ viewport()->setMouseTracking( true );
+ m_autoScrollTimer = new QTimer( this );
+ connect(verticalScrollBar(), SIGNAL(valueChanged( int ) ),
+ this, SLOT(scrolling( int )));
+
+ setDragAutoScroll( false );
+
+// setStaticBackground( true );
+}
+
+TextView::~TextView()
+{
+}
+
+void TextView::drawContents( QPainter *painter, int clipX, int clipY, int , int clipHeight )
+{
+ if ( m_parags.isEmpty() )
+ return;
+
+ if ( m_paintBuffer.width() != visibleWidth() )
+ m_paintBuffer.resize( visibleWidth(), PaintBufferExtend );
+
+ QPtrListIterator<TextParag> paragIt( m_parags );
+
+ ContentsPaintAlgorithm( paragIt,
+ viewport(), m_paintBuffer, *painter, clipX, clipY,
+ clipHeight )
+ .paint();
+}
+
+void TextView::viewportResizeEvent( QResizeEvent *ev )
+{
+ QScrollView::viewportResizeEvent(ev);
+
+ if ( ev->size().width() != ev->oldSize().width() )
+ layout();
+
+ int newdiff = ev->size().height() - ev->oldSize().height();
+ setContentsPos( 0, contentsY()-newdiff );
+
+ if(m_lastScroll == newdiff){
+ m_inScroll = false;
+ m_lastScroll = 0;
+ }
+
+ scrollToBottom();
+}
+
+void TextView::scrolling( int value )
+{
+ int tl = m_height-visibleHeight();
+ int offset = 25;
+
+ TextParag *parag = m_parags.last();
+ if(parag){
+ if(parag->height() > offset)
+ offset = parag->height();
+ }
+
+ if((tl - value) > offset)
+ m_inScroll = true;
+ else
+ m_inScroll = false;
+
+ m_lastScroll = tl-value;
+
+}
+
+void TextView::scrollToBottom( bool force )
+{
+ bool scroll = true;
+ if(force == true){
+ scroll = true;
+ }
+ else {
+ if(m_inScroll){
+ scroll = false;
+ }
+ else {
+ if(m_mousePressed == true){
+ scroll = false;
+ }
+ else {
+ scroll = true;
+ }
+ }
+ }
+
+ if(scroll == true)
+ setContentsPos( 0, m_height-visibleHeight() );
+}
+
+void TextView::clear()
+{
+ stopAutoScroll();
+ clearSelection();
+ m_parags.clear();
+ layout();
+ viewport()->erase();
+}
+
+TextParagIterator TextView::appendParag( const QString &richText )
+{
+ TextParag *parag = new TextParag( this, richText );
+ m_parags.append( parag );
+ layout( false );
+ scrollToBottom();
+ QPtrListIterator<TextParag> it( m_parags );
+ it.toLast();
+ return TextParagIterator( it );
+}
+
+bool TextView::removeParag( const TextParagIterator &parag )
+{
+
+ if ( parag.atEnd() )
+ return false;
+
+ TextParag *paragPtr = parag.m_paragIt.current();
+ const int idx = m_parags.findRef( paragPtr );
+ if ( idx == -1 )
+ return false;
+
+ if ( m_selectionStart.parag == paragPtr ||
+ m_selectionEnd.parag == paragPtr )
+ clearSelection( false );
+
+ int height = paragPtr->height();
+ m_parags.removeRef( paragPtr );
+
+ if(m_selectionStart.item != 0)
+ m_selectionStart.pos.ry() -= height;
+ if(m_selectionEnd.item != 0)
+ m_selectionEnd.pos.ry() -= height;
+
+ //layout( false );
+ contentsChange(-height, true);
+
+
+ if ( isUpdatesEnabled() )
+ updateContents();
+
+ return true;
+}
+
+void TextView::clearSelection( bool repaint )
+{
+ m_selectionStart = SelectionPoint();
+ m_selectionEnd = SelectionPoint();
+ m_selectionEndBeforeStart = false;
+ m_selectedText = QString::null;
+ clearSelectionInternal();
+ if ( repaint )
+ updateContents();
+}
+
+TextParagIterator TextView::firstParag() const
+{
+ return TextParagIterator( QPtrListIterator<TextParag>( m_parags ) );
+}
+
+QString TextView::plainText() const
+{
+ if ( m_parags.isEmpty() )
+ return QString::null;
+
+ QString result;
+ QPtrListIterator<TextParag> paragIt( m_parags );
+ while ( paragIt.current() )
+ {
+ result += paragIt.current()->plainText();
+ ++paragIt;
+ if ( paragIt.current() )
+ result += '\n';
+ }
+
+ return result;
+}
+
+QColor TextView::linkColor() const
+{
+ return m_linkColor;
+}
+
+void TextView::setLinkColor( const QColor &linkColor )
+{
+ m_linkColor = linkColor;
+}
+
+void TextView::copy()
+{
+ QApplication::clipboard()->setText( m_selectedText );
+}
+
+void TextView::clearSelectionInternal()
+{
+ m_selectionEndBeforeStart = false;
+ TextParag *p = m_parags.first();
+ for (; p; p = m_parags.next() )
+ p->clearSelection();
+}
+
+void TextView::contentsMousePressEvent( QMouseEvent *ev )
+{
+ if ( ev->button() & RightButton ) {
+ emitLinkClickedForMouseEvent( ev );
+ return;
+ }
+
+ if ( !( ev->button() & LeftButton ) && !(ev->button() & MidButton ) )
+ return;
+
+ clearSelection( true );
+ SelectionPoint p;
+ Item *itemUnderMouse = itemAt( ev->pos(), &p, Item::SelectFuzzy );
+ if ( p.item && ( ev->button() & LeftButton ) ) {
+ m_selectionMaybeStart = p;
+ p.item->setSelectionStatus( Item::NoSelection );
+ }
+ if ( TextChunk *text = dynamic_cast<TextChunk *>( itemUnderMouse ) ) {
+ StringPtr href = text->props().attributes[ "href" ];
+ if ( !href.isNull() ) {
+ m_dragStartPos = ev->pos();
+ m_dragURL = href.toQString();
+ if ( ev->button() & LeftButton )
+ m_mousePressed = true;
+ else
+ m_mmbPressed = true;
+ }
+ }
+}
+
+void TextView::contentsMouseMoveEvent( QMouseEvent *ev )
+{
+ if ( m_mousePressed && ev->state() == NoButton )
+ {
+ m_mousePressed = false;
+ m_mmbPressed = false;
+ }
+
+ if ( m_mousePressed && !m_dragURL.isEmpty() &&
+ ( m_dragStartPos - ev->pos() ).manhattanLength() > QApplication::startDragDistance() ) {
+
+ m_mousePressed = false;
+ m_dragStartPos = QPoint();
+
+ startDrag();
+
+ m_dragURL = QString::null;
+ return;
+ }
+
+
+ SelectionPoint p;
+ Item *i = itemAt( ev->pos(), &p, Item::SelectFuzzy );
+ if ( !i && !p.item )
+ return;
+
+ if ( (ev->state() & LeftButton && m_selectionStart.item && p.item) ||
+ (ev->state() & LeftButton && m_selectionMaybeStart.item && p.item))
+ {
+
+ if(m_selectionMaybeStart.item != 0){
+ m_selectionStart = m_selectionMaybeStart;
+ m_selectionMaybeStart = SelectionPoint();
+ }
+
+ m_selectionEnd = p;
+
+ clearSelectionInternal();
+
+ updateSelectionOrder();
+
+ SelectionPoint start = m_selectionStart;
+ SelectionPoint end = m_selectionEnd;
+
+ if ( m_selectionEndBeforeStart )
+ {
+ if ( start.item == end.item )
+ {
+ if ( start.offset > end.offset )
+ qSwap( start.offset, end.offset );
+ }
+ else
+ qSwap( start, end );
+ }
+
+ m_selectedText = updateSelection( start, end );
+
+ emit selectionChanged();
+
+ updateContents();
+
+ startAutoScroll();
+
+ return;
+ }
+ else if ( i )
+ {
+ TextChunk *text = dynamic_cast<TextChunk *>( i );
+ if ( text )
+ {
+ StringPtr href = text->props().attributes[ "href" ];
+ if ( !href.isNull() )
+ {
+ viewport()->setCursor( KCursor::handCursor() );
+ return;
+ }
+ }
+ }
+
+ QCursor c = KCursor::arrowCursor();
+ if ( viewport()->cursor().handle() != c.handle() )
+ viewport()->setCursor( c );
+}
+
+void TextView::contentsMouseReleaseEvent( QMouseEvent *ev )
+{
+ stopAutoScroll();
+
+ bool clicked = (m_mousePressed || m_mmbPressed) &&
+ (m_dragStartPos - ev->pos()).manhattanLength() < QApplication::startDragDistance();
+ m_mousePressed = false;
+ m_mmbPressed = false;
+ m_dragStartPos = QPoint();
+ m_dragURL = QString::null;
+
+ m_selectionMaybeStart = SelectionPoint();
+
+ if ( (ev->button() & Qt::LeftButton) && !m_selectedText.isEmpty() )
+ QApplication::clipboard()->setText( m_selectedText, QClipboard::Selection );
+
+ if ( clicked ) {
+ emitLinkClickedForMouseEvent( ev );
+ return;
+ }
+
+ if (ev->button() & Qt::MidButton)
+ {
+ emit pasteReq( KApplication::clipboard()->text( QClipboard::Selection ) );
+ return;
+ }
+}
+
+void TextView::fontChange( const QFont & )
+{
+ QPtrListIterator<TextParag> it( m_parags );
+ for (; it.current(); ++it )
+ it.current()->fontChange( font() );
+
+ layout( true );
+}
+
+void TextView::startDrag()
+{
+ QDragObject *dragObj = dragObject( m_dragURL );
+ if ( !dragObj )
+ return;
+
+ stopAutoScroll();
+
+ dragObj->drag();
+}
+
+QDragObject *TextView::dragObject( const QString &dragURL )
+{
+#if KDE_IS_VERSION(3,1,92)
+ return new KURLDrag( KURL( dragURL ), viewport() );
+#else
+ return KURLDrag::newDrag( KURL( dragURL ), viewport() );
+#endif
+}
+
+void TextView::autoScroll()
+{
+ QPoint cursor = viewport()->mapFromGlobal( QCursor::pos() );
+
+ QPoint contentsPos = viewportToContents( cursor );
+
+ cursor.rx() -= viewport()->x();
+ cursor.ry() -= viewport()->y();
+
+ if ( ( cursor.x() < 0 || cursor.x() > visibleWidth() ) ||
+ ( cursor.y() < 0 || cursor.y() > visibleHeight() ) ) {
+ ensureVisible( contentsPos.x(), contentsPos.y(),
+ 0, 5 );
+ }
+}
+
+void TextView::emitLinkClickedForMouseEvent( QMouseEvent *ev )
+{
+ TextChunk *text = dynamic_cast<TextChunk *>( itemAt( ev->pos() ) );
+ if ( !text )
+ return;
+
+ StringPtr href = text->props().attributes[ "href" ];
+ if ( href.isNull() )
+ return;
+
+ emit linkClicked( ev, CONSTSTRING( href ) );
+}
+
+void TextView::startAutoScroll()
+{
+ if(m_autoScrollTimer->isActive() == false){
+ connect( m_autoScrollTimer, SIGNAL( timeout() ),
+ this, SLOT( autoScroll() ) );
+ m_autoScrollTimer->start( 75, false );
+ }
+}
+
+void TextView::stopAutoScroll()
+{
+ disconnect( m_autoScrollTimer, SIGNAL( timeout() ),
+ this, SLOT( autoScroll() ) );
+ m_autoScrollTimer->stop();
+}
+
+void TextView::selectionOffsets( int &startOffset, int &endOffset )
+{
+ assert( m_selectionStart.item );
+
+ if ( m_selectionEndBeforeStart )
+ {
+ startOffset = m_selectionEnd.offset;
+ endOffset = m_selectionStart.offset;
+ }
+ else
+ {
+ startOffset = m_selectionStart.offset;
+ endOffset = m_selectionEnd.offset;
+ }
+
+ if ( m_selectionStart.item == m_selectionEnd.item && startOffset > endOffset )
+ qSwap( startOffset, endOffset );
+}
+
+void TextView::updateSelectionOrder()
+{
+ int start = m_selectionStart.pos.y();
+ int end = m_selectionEnd.pos.y();
+
+ if ( start == end )
+ {
+ start = m_selectionStart.pos.x();
+ end = m_selectionEnd.pos.x();
+
+ if ( start == end )
+ {
+ start = m_selectionStart.offset;
+ end = m_selectionEnd.offset;
+ }
+ }
+
+ m_selectionEndBeforeStart = end < start;
+}
+
+SelectionPoint *TextView::selectionStart()
+{
+ return m_selectionEndBeforeStart ? &m_selectionEnd : &m_selectionStart;
+}
+
+SelectionPoint *TextView::selectionEnd()
+{
+ return m_selectionEndBeforeStart ? &m_selectionStart : &m_selectionEnd;
+}
+
+QString TextView::updateSelection( const SelectionPoint &start, const SelectionPoint &end )
+{
+ QString selectedText;
+
+ if ( start.item == end.item )
+ {
+ Item *i = start.item;
+
+
+ if ( start.offset == end.offset )
+ {
+ if ( start.pos.x() == end.pos.x() )
+ {
+ i->setSelectionStatus( Item::NoSelection );
+ return QString::null;
+ }
+
+ i->setSelectionStatus( Item::SelectionBoth );
+
+ // ### ugly
+ const TextChunk *t = dynamic_cast<TextChunk *>( i );
+ if ( t )
+ {
+ StringPtr text = t->text();
+ selectedText = QString( text.ptr + start.offset, 1 );
+ }
+ }
+ else
+ {
+ i->setSelectionStatus( Item::SelectionBoth );
+
+ // ### ugly
+ TextChunk *t = dynamic_cast<TextChunk *>( i );
+ if ( t )
+ {
+ StringPtr text = t->text();
+ if (end.offset > start.offset)
+ selectedText = QString( text.ptr + start.offset,
+ end.offset - start.offset + 1 );
+ else
+ selectedText = QString( text.ptr + end.offset,
+ start.offset - end.offset + 1 );
+
+ }
+ }
+ }
+ else
+ {
+ assert( m_parags.findRef( end.parag ) != -1 );
+ const int idx = m_parags.findRef( start.parag );
+ assert( idx != -1 );
+
+ TextParag *p = m_parags.current();
+ for (; p && p != end.parag; p = m_parags.next() )
+ {
+ selectedText += p->updateSelection( start, end );
+ selectedText += '\n';
+ }
+
+ if ( p )
+ selectedText += p->updateSelection( start, end );
+ }
+
+ return selectedText;
+}
+
+void TextView::layout( bool force )
+{
+ int height = 0;
+ int contentsWidth = visibleWidth();
+ int width = contentsWidth;
+
+ QPtrListIterator<TextParag> it( m_parags );
+ for (; it.current(); ++it )
+ {
+ if ( !it.current()->isLayouted() || force )
+ it.current()->layout( width );
+
+ height += it.current()->height();
+ contentsWidth = kMax( contentsWidth, it.current()->minWidth() );
+ }
+
+ if ( m_selectionStart.item && m_selectionEnd.item )
+ updateSelection( *selectionStart(), *selectionEnd() );
+
+ m_height = height;
+ resizeContents( contentsWidth, height );
+}
+
+void TextView::contentsChange(int heightChange, bool force)
+{
+ if(m_height == -1){
+ layout(force);
+ }
+ else {
+ m_height += heightChange;
+ resizeContents( visibleWidth(), m_height );
+ }
+
+ if ( m_selectionStart.item && m_selectionEnd.item )
+ updateSelection( *selectionStart(), *selectionEnd() );
+
+
+}
+
+Item *TextView::itemAt( const QPoint &pos, SelectionPoint *selectionInfo,
+ Item::SelectionAccuracy accuracy )
+{
+ int px = pos.x();
+ int py = pos.y();
+
+ int y = 0;
+ int height = 0;
+ QPtrListIterator<TextParag> it( m_parags );
+ for (; it.current(); ++it )
+ {
+ height = it.current()->height();
+ if ( y <= py && py <= ( y + height ) )
+ {
+ Item *res = it.current()->itemAt( px, py - y, selectionInfo, accuracy );
+ if ( selectionInfo )
+ {
+ selectionInfo->pos.ry() += y;
+ selectionInfo->pos.rx() = px;
+ }
+ return res;
+ }
+ y += height;
+ }
+
+ if ( accuracy == Item::SelectFuzzy && selectionInfo && !m_parags.isEmpty() )
+ {
+ TextParag *parag = m_parags.getLast();
+ parag->itemAt( px, height - 1, selectionInfo, accuracy );
+
+ selectionInfo->pos.ry() += y - height;
+ selectionInfo->pos.rx() = px;
+ }
+
+ return 0;
+}
+
+QString TextParagIterator::richText() const
+{
+ if ( atEnd() )
+ return QString::null;
+
+ return Tokenizer::convertToRichText( m_paragIt.current()->processedRichText() );
+}
+
+void TextParagIterator::setRichText( const QString &richText )
+{
+ if ( atEnd() )
+ return;
+
+ m_paragIt.current()->setRichText( richText );
+
+ TextView *textView = m_paragIt.current()->textView();
+ textView->layout( false );
+
+ if ( textView->isUpdatesEnabled() )
+ textView->updateContents();
+}
+
+QString TextParagIterator::plainText() const
+{
+ if ( atEnd() )
+ return QString::null;
+
+ return m_paragIt.current()->plainText();
+}
+
+#include "kstextview.moc"
+
+/*
+ * vim: et sw=4
+ */
diff --git a/ksirc/kstextview.h b/ksirc/kstextview.h
new file mode 100644
index 00000000..7d29cbe9
--- /dev/null
+++ b/ksirc/kstextview.h
@@ -0,0 +1,577 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+#ifndef __kstextview_h__
+#define __kstextview_h__
+
+#include <qscrollview.h>
+#include <qpen.h>
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+#include <qpixmap.h>
+
+class QTimer;
+class QDragObject;
+
+namespace KSirc
+{
+
+class TextView;
+
+struct StringPtr
+{
+ StringPtr() : ptr( 0 ), len( 0 ) {}
+ StringPtr( const QChar *_ptr, uint _len )
+ : ptr( _ptr ), len( _len ) {}
+ explicit StringPtr( const QString &s ) // use with care!
+ : ptr( s.unicode() ), len( s.length() ) {}
+
+ inline bool isNull() const { return ptr == 0; }
+
+ // makes deep copy
+ inline QString toQString() const
+ { return ( ptr && len > 0 ) ? QString( ptr, len ) : QString::null; }
+
+ const QChar *ptr;
+ uint len;
+};
+
+#define CONSTSTRING( substr ) QConstString( substr.ptr, substr.len ).string()
+
+inline bool operator<( const StringPtr &s1, const StringPtr &s2 )
+{
+ return CONSTSTRING( s1 ) < CONSTSTRING( s2 );
+}
+
+inline bool operator==( const StringPtr &s1, const StringPtr &s2 )
+{
+ return CONSTSTRING( s1 ) == CONSTSTRING( s2 );
+}
+
+inline bool operator==( const StringPtr &s1, const char *s2 )
+{
+ return CONSTSTRING( s1 ) == s2;
+}
+
+class AttributeMap : public QMap<StringPtr, StringPtr>
+{
+public:
+ AttributeMap() {}
+ AttributeMap( const AttributeMap &rhs ) : QMap<StringPtr, StringPtr>( rhs ) {}
+ AttributeMap &operator=( const AttributeMap &rhs )
+ { QMap<StringPtr, StringPtr>::operator=( rhs ); return *this; }
+
+ // helper for 'const char *' key...
+ ConstIterator findAttribute( const char *key ) const
+ {
+ QString qkey( key );
+ return find( StringPtr( qkey ) );
+ }
+ Iterator findAttribute( const char *key )
+ {
+ QString qkey( key );
+ return find( StringPtr( qkey ) );
+ }
+
+ StringPtr operator[]( const char *key ) const
+ {
+ ConstIterator it = findAttribute( key );
+ if ( it == end() )
+ return StringPtr();
+ return it.data();
+ }
+ StringPtr &operator[]( const StringPtr &key )
+ {
+ return QMap<StringPtr, StringPtr>::operator[]( key );
+ }
+};
+
+struct Token
+{
+ Token() : id( -1 ) {}
+
+ enum Id { TagOpen, Text, TagClose };
+ int id;
+ StringPtr value;
+ AttributeMap attributes;
+};
+
+struct ItemProperties
+{
+ ItemProperties();
+ ItemProperties( const QFont &defaultFont );
+ ItemProperties( const ItemProperties &other,
+ const Token &token,
+ TextView *textView );
+ ItemProperties( const ItemProperties &rhs );
+ ItemProperties &operator=( const ItemProperties &rhs );
+
+ void updateFont( const QFont &newFont );
+
+ // these three are inherited/merged
+ QFont font;
+ QColor color;
+ QColor selColor;
+ QColor bgColor;
+ QColor bgSelColor;
+ bool reversed;
+ // ### todo: inherit these, too
+ AttributeMap attributes;
+};
+
+class TextParag;
+class TextLine;
+class SelectionPoint;
+
+class Item
+{
+public:
+ enum LayoutResetStatus { DeleteItem, KeepItem };
+ enum SelectionStatus { SelectionStart = 0, InSelection, SelectionEnd, SelectionBoth,
+ NoSelection };
+ enum SelectionAccuracy { SelectExact, SelectFuzzy };
+
+ Item( TextParag *parag, const ItemProperties &props = ItemProperties() );
+
+ virtual ~Item();
+
+ virtual const char *type() { return "Item"; }
+
+ virtual void paint( QPainter &painter ) = 0;
+
+ int width() const;
+
+ int minWidth() const;
+
+ int height() const;
+
+ virtual Item *breakLine( int width );
+
+ virtual LayoutResetStatus resetLayout() = 0;
+
+ virtual int calcSelectionOffset( int x );
+
+ void setSelectionStatus( SelectionStatus status ) { m_selection = status; }
+
+ SelectionStatus selectionStatus() const { return m_selection; }
+
+ void selectionOffsets( int &startOffset, int &endOffset );
+
+ int maxSelectionOffset() const;
+
+ void setLine(TextLine *line);
+
+ // ###
+ virtual StringPtr text() const;
+
+ virtual void setProps( const ItemProperties &props );
+ ItemProperties &props() { return m_props; }
+
+ static Item *create( TextParag *parag, const Token &tok,
+ const ItemProperties &props = ItemProperties() );
+
+protected:
+ mutable bool m_extendsDirty;
+ mutable int m_minWidth;
+ mutable int m_width;
+ mutable int m_height;
+
+ virtual void calcExtends() const = 0;
+
+ SelectionStatus m_selection;
+ TextLine *m_line;
+ TextParag *m_parag;
+ ItemProperties m_props;
+};
+
+class TextChunk : public Item
+{
+public:
+ TextChunk( TextParag *parag, const StringPtr &text, const ItemProperties &props );
+
+ virtual const char *type() { return "TextChunk"; }
+
+ virtual void paint( QPainter &painter );
+
+ virtual Item *breakLine( int width );
+
+ virtual LayoutResetStatus resetLayout();
+
+ virtual int calcSelectionOffset( int x );
+
+ virtual StringPtr text() const;
+
+ virtual void setProps( const ItemProperties &props );
+
+protected:
+ virtual void calcExtends() const;
+
+private:
+ StringPtr breakInTheMiddle( int width );
+ Item *hardBreak( const StringPtr &rightHandSide );
+
+ void paintSelection( QPainter &p );
+ int paintSelection( QPainter &p, int x, const StringPtr &text );
+ int paintText( QPainter &p, int x, const StringPtr &text );
+
+ void mergeSelection( TextChunk *child, SelectionPoint *selection );
+
+ StringPtr m_text;
+ uint m_originalTextLength;
+ QFontMetrics m_metrics;
+ class TextChunk *m_parent;
+};
+
+class ImageItem : public Item
+{
+public:
+ ImageItem( TextParag *parag, const QPixmap &pixmap );
+
+ virtual const char *type() { return "Image"; }
+
+ virtual void paint( QPainter &painter );
+
+ virtual LayoutResetStatus resetLayout();
+
+protected:
+ virtual void calcExtends() const;
+
+private:
+ QPixmap m_pixmap;
+};
+
+class Tokenizer
+{
+public:
+ struct TagIndex
+ {
+ enum Type { Open, Close };
+ TagIndex() : index( 0 ), type( -1 ) {}
+ TagIndex( int _index, int _type )
+ : index( _index ), type( _type ) {}
+ uint index;
+ int type;
+ };
+ typedef QValueList<TagIndex> TagIndexList;
+
+ // preprocessed string
+ struct PString
+ {
+ QString data;
+ TagIndexList tags;
+ };
+
+ Tokenizer( PString &text );
+
+ static PString preprocess( const QString &richText );
+
+ static QString convertToRichText( const PString &ptext );
+
+ bool parseNextToken( Token &tok );
+
+private:
+ void parseTag( const StringPtr &text,
+ StringPtr &tag,
+ AttributeMap &attributes );
+
+ static TagIndexList scanTagIndices( const QString &text );
+ static void resolveEntities( QString &text, TagIndexList &tags );
+
+ enum TagParsingState { ScanForName, ScanForEqual, ScanForValue };
+
+ QString &m_text;
+ TagIndexList m_tags;
+ TagIndexList::ConstIterator m_lastTag;
+ bool m_textBeforeFirstTagProcessed;
+ bool m_done;
+
+ Tokenizer( const Tokenizer & );
+ Tokenizer &operator=( const Tokenizer & );
+};
+
+class SelectionPoint;
+
+class TextLine
+{
+public:
+ enum LayoutPolicy { NoUpdate, UpdateMaxHeight };
+
+ TextLine();
+ // tranfers ownership of items! make sure that 'items' does not
+ // have autodeletion enabled!
+ TextLine( const QPtrList<Item> &items );
+
+ int maxHeight() const { return m_maxHeight; }
+
+ QString updateSelection( const SelectionPoint &start, const SelectionPoint &end );
+ void clearSelection();
+
+ // transfers ownership
+ void appendItem( Item *i, int layoutUpdatePolicy = NoUpdate );
+
+ bool isEmpty() const { return m_items.isEmpty(); }
+
+ Item *resetLayout( QPtrList<Item> &remainingItems);
+
+ void paint( QPainter &p, int y );
+
+ Item *itemAt( int px, SelectionPoint *selectionInfo,
+ Item::SelectionAccuracy accuracy = Item::SelectExact );
+
+ QPtrListIterator<Item> iterator() const { return QPtrListIterator<Item>( m_items ); }
+
+ QString plainText() const;
+
+ void fontChange( const QFont &newFont );
+
+private:
+ QPtrList<Item> m_items;
+ int m_maxHeight;
+};
+
+class SelectionPoint;
+
+class TextParag
+{
+public:
+ TextParag( TextView *textView, const QString &richText );
+
+ ~TextParag();
+
+ void layout( int width );
+
+ void paint( QPainter &p, int y, int maxY );
+
+ inline void setLayouted( bool l ) { m_layouted = l; }
+ inline bool isLayouted() const { return m_layouted; }
+
+ inline int minWidth() const { return m_minWidth; }
+ inline int height() const { return m_height; }
+
+ Item *itemAt( int px, int py, SelectionPoint *selectionInfo,
+ Item::SelectionAccuracy accuracy = Item::SelectExact );
+
+ TextView *textView() const { return m_textView; }
+
+ QString updateSelection( const SelectionPoint &start, const SelectionPoint &end );
+
+ void clearSelection();
+
+ void setRichText( const QString &richText );
+
+ Tokenizer::PString processedRichText() const { return m_processedRichText; }
+
+ QString plainText() const;
+
+ void fontChange( const QFont &newFont );
+
+private:
+ Tokenizer::PString m_processedRichText;
+ QPtrList<TextLine> m_lines;
+ bool m_layouted;
+ int m_height;
+ int m_minWidth;
+ TextView *m_textView;
+
+ struct Tag
+ {
+ Tag() {}
+ Tag( const StringPtr &_name, const ItemProperties &_props )
+ : name( _name ), props( _props ) {}
+
+ StringPtr name;
+ ItemProperties props;
+ };
+
+ TextParag( const TextParag & );
+ TextParag &operator=( const TextParag & );
+};
+
+struct SelectionPoint
+{
+ SelectionPoint() : item( 0 ), line( 0 ), parag( 0 ), offset( 0 ) {}
+ Item *item;
+ TextLine *line;
+ TextParag *parag;
+ uint offset;
+ QPoint pos;
+};
+
+class TextParagIterator
+{
+ friend class TextView;
+public:
+ TextParagIterator( const TextParagIterator &rhs )
+ : m_paragIt( rhs.m_paragIt ) {}
+ TextParagIterator &operator=( const TextParagIterator &rhs )
+ { m_paragIt = rhs.m_paragIt; return *this; }
+
+ QString richText() const;
+ void setRichText( const QString &richText );
+
+ QString plainText() const;
+
+ bool atEnd() const { return m_paragIt.current() == 0; }
+
+ TextParagIterator &operator++() { ++m_paragIt; return *this; }
+ TextParagIterator &operator++( int steps ) { m_paragIt += steps; return *this; }
+ TextParagIterator &operator--() { --m_paragIt; return *this; }
+ TextParagIterator &operator--( int steps ) { m_paragIt -= steps; return *this; }
+
+protected:
+ TextParagIterator( const QPtrListIterator<TextParag> &paragIt )
+ : m_paragIt( paragIt ) {}
+
+private:
+ QPtrListIterator<TextParag> m_paragIt;
+};
+
+class ContentsPaintAlgorithm
+{
+public:
+ ContentsPaintAlgorithm( const QPtrListIterator<TextParag> &paragIt,
+ QWidget *viewport, QPixmap &paintBuffer,
+ QPainter &painter, int clipX, int clipY, int clipHeight );
+
+ void paint();
+
+private:
+ int goToFirstVisibleParagraph();
+ int paint( QPainter &bufferedPainter, int currentY );
+ int adjustYAndIterator( int startY, int currentY, int nextY );
+
+ QPtrListIterator<TextParag> m_paragIt;
+ QWidget *m_viewport;
+ QPixmap &m_paintBuffer;
+ QPainter &m_painter;
+ int m_clipX, m_clipY, m_clipHeight;
+ int m_overshoot;
+};
+
+class TextView : public QScrollView
+{
+ Q_OBJECT
+ friend class Item;
+ friend class TextChunk;
+ friend class TextParag;
+ friend class TextParagIterator;
+public:
+ TextView( QWidget *parent, const char *name = 0 );
+ virtual ~TextView();
+
+ virtual void clear();
+
+ TextParagIterator appendParag( const QString &richText );
+
+ bool removeParag( const TextParagIterator &parag );
+
+ void clearSelection( bool repaint = false ); // ### re-consider the repaint arg...
+
+ QString selectedText() const { return m_selectedText; }
+
+ TextParagIterator firstParag() const;
+
+ QString plainText() const;
+
+ QColor linkColor() const;
+ void setLinkColor( const QColor &linkColor );
+
+ void scrollToBottom( bool force = false );
+
+signals:
+ void selectionChanged();
+ void pasteReq(const QString&);
+ void linkClicked( const QMouseEvent *ev, const QString &url );
+
+public slots:
+ void copy();
+
+protected slots:
+ void scrolling(int value);
+
+protected:
+ virtual void viewportResizeEvent( QResizeEvent *ev );
+ virtual void drawContents( QPainter *p, int cx, int cy, int cw, int ch );
+ virtual void contentsMousePressEvent( QMouseEvent *ev );
+ virtual void contentsMouseMoveEvent( QMouseEvent *ev );
+ virtual void contentsMouseReleaseEvent( QMouseEvent *ev );
+ virtual void fontChange( const QFont & );
+
+ virtual void startDrag();
+
+ virtual QDragObject *dragObject( const QString &dragURL );
+
+private slots:
+ void autoScroll();
+
+private:
+ void emitLinkClickedForMouseEvent( QMouseEvent *ev );
+
+ void startAutoScroll();
+
+ void stopAutoScroll();
+
+ void selectionOffsets( int &startOffset, int &endOffset );
+
+ void updateSelectionOrder();
+
+ QString updateSelection( const SelectionPoint &start, const SelectionPoint &end );
+
+ SelectionPoint *selectionStart();
+ SelectionPoint *selectionEnd();
+
+ void layout( bool force = true );
+
+ Item *itemAt( const QPoint &pos, SelectionPoint *selectionInfo = 0,
+ Item::SelectionAccuracy accuracy = Item::SelectExact );
+
+ void clearSelectionInternal();
+
+ void contentsChange(int heightChange, bool force = false);
+
+ QPtrList<TextParag> m_parags;
+ QPixmap m_paintBuffer;
+
+ SelectionPoint m_selectionMaybeStart;
+ SelectionPoint m_selectionStart;
+ SelectionPoint m_selectionEnd;
+ bool m_selectionEndBeforeStart;
+
+ QTimer *m_autoScrollTimer;
+
+ QString m_selectedText;
+
+ QPoint m_dragStartPos;
+ QString m_dragURL;
+ bool m_mousePressed : 1;
+ bool m_mmbPressed : 1;
+ QColor m_linkColor;
+ QColor m_selectionBackgroundColor;
+
+ int m_height;
+ bool m_inScroll;
+ int m_lastScroll;
+};
+
+} // namespace KSirc
+
+#endif
+/*
+ * vim: et sw=4
+ */
diff --git a/ksirc/kstextviewtest.cpp b/ksirc/kstextviewtest.cpp
new file mode 100644
index 00000000..f3326351
--- /dev/null
+++ b/ksirc/kstextviewtest.cpp
@@ -0,0 +1,51 @@
+#include <kapplication.h>
+
+#include "kstextview.h"
+
+
+class Timer : public QObject
+{
+public:
+ Timer( KSirc::TextView *view )
+ : m_view( view ), m_lines( 0 )
+ {
+ //startTimer( 5000 );
+ }
+ void timerEvent( QTimerEvent * )
+ {
+ m_lines++;
+ if ( m_lines > 15 )
+ m_view->removeParag( m_view->firstParag() );
+ m_view->appendParag( QString::fromLatin1( "<font color=#0000ff>color test</font><font color=#00ff00>color test</font><font color=#ff0000>color test</font><font color=#000088>color test</font><font color=#008800>color test</font><font color=#880000>color test</font><font color=#0000ff>color test</font><font color=#02ff00>color test</font><font color=#2000ff>color test</font>" ) );
+ m_view->appendParag( QString::fromLatin1( "<r>aaaaaa</r> bbbbbb cccccccc ddddddddd eeeeeee " ) );
+ m_view->setContentsPos( 0, m_view->contentsHeight() );
+ }
+private:
+ KSirc::TextView *m_view;
+ int m_lines;
+};
+
+int main( int argc, char **argv )
+{
+ KApplication app( argc, argv, "kstextviewtest" );
+
+ KSirc::TextView view( 0 );
+ app.setMainWidget( &view );
+
+ view.show();
+ view.appendParag( QString::fromLatin1( "<b>bold</b>Normal<i>Italic hey!</i><r>reverse!</r>" ) );
+ view.appendParag( QString::fromLatin1( "bleh foo hey bar schubidu bliep blop" ) );
+ view.appendParag( QString::fromLatin1( "more longish paragraphs .. yaddayadda yadda" ) );
+ view.appendParag( QString::fromLatin1( "&lt;tronical&gt; hah! &amp;" ) );
+ view.appendParag( QString::fromLatin1( "<a href=\"http://www.kde.org/\">url</a>" ) );
+ view.appendParag( QString::fromLatin1( "<font color=#0000ff bgcolor=#ff0000>color test</font>" ) );
+ view.appendParag( QString::fromLatin1( "<font color=\"#00ff00\">another color test</font>" ) );
+ view.appendParag( QString::fromLatin1( "<font color=\"#00ff00\" bgcolor=\"#ff0000\">another color test</font>" ) );
+ view.appendParag( QString::fromLatin1( "<i bleh>simple attr test</i><b leh foo=15 doo=\"&amp; > 123 \" oof>complicated attr test</b>" ) );
+ view.appendParag( QString::fromLatin1( "\"<b doo=\"&amp; > 123 \" oof>\"third attr test 2</b>\"" ) );
+ view.appendParag( QString::fromLatin1( "aaaaaa bbbbbb cccccccc ddddddddd eeeeeee" ) );
+ Timer t( &view );
+
+ return app.exec();
+}
+
diff --git a/ksirc/ksview.cpp b/ksirc/ksview.cpp
new file mode 100644
index 00000000..76ec57d8
--- /dev/null
+++ b/ksirc/ksview.cpp
@@ -0,0 +1,344 @@
+/* This file is part of ksirc
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// $Id$
+
+#include <qclipboard.h>
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qdragobject.h>
+#include <qvaluestack.h>
+#include <qstylesheet.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <krun.h>
+#include <kpopupmenu.h>
+#include <kstringhandler.h>
+#include <knotifyclient.h>
+#include <kfiledialog.h>
+#include <kio/job.h>
+#include <kurldrag.h>
+
+#include "ksopts.h"
+#include "ksview.moc"
+#include "ksparser.h"
+#include "nickColourMaker.h"
+#include "ksircprocess.h"
+
+KSircView::KSircView(KSircProcess *proc, QWidget *parent, const char *name)
+ : KSirc::TextView(parent, name), m_proc(proc)
+{
+ m_acceptFiles = false;
+ m_timestamps = false;
+ viewport()->setAcceptDrops(true);
+ clear();
+ connect( this, SIGNAL( linkClicked( const QMouseEvent *, const QString & ) ),
+ this, SLOT( anchorClicked( const QMouseEvent *, const QString & ) ) );
+
+ QPixmap background = ksopts->backgroundPixmap();
+ if ( !background.isNull() )
+ viewport()->setBackgroundPixmap( background );
+
+ setLinkColor( ksopts->linkColor );
+}
+
+KSircView::~KSircView()
+{
+}
+
+void KSircView::clear()
+{
+ m_lines = 0;
+ m_timeStamps.clear();
+ KSirc::TextView::clear();
+}
+
+QString KSircView::makeTimeStamp()
+{
+ QTime now = QTime::currentTime();
+ QString timeStamp = QString::fromLatin1( "[%1:%2:%3] " )
+ .arg( QString::number( now.hour() ).rightJustify( 2, '0' ) )
+ .arg( QString::number( now.minute() ).rightJustify( 2, '0' ) )
+ .arg( QString::number( now.second() ).rightJustify( 2, '0' ) );
+ return timeStamp;
+}
+
+void KSircView::saveURL( const QString &url )
+{
+ KURL kurl( url );
+
+ KFileDialog *dlg = new KFileDialog( QString::null, QString::null /*filter*/, this /*parent*/, "filedialog" /*name*/, true /*modal*/ );
+
+ dlg->setKeepLocation( true );
+
+ dlg->setCaption( i18n( "Save As" ) );
+
+ if ( !kurl.fileName().isEmpty() )
+ dlg->setSelection( kurl.fileName() );
+
+ if ( dlg->exec() ) {
+ KURL destURL( dlg->selectedURL() );
+ if ( destURL.isValid() ) {
+ KIO::Job *job = KIO::copy( kurl, destURL );
+ job->setAutoErrorHandlingEnabled( true );
+ }
+ }
+
+ delete dlg;
+}
+
+QString KSircView::addLine(const QString &pixmap, const QColor &color, const QString &_text)
+{
+ //kdDebug(5008) << "Start Text: " << _text << endl;
+
+ QString richText( "<font color=\"%1\">" );
+ richText = richText.arg( color.name() );
+
+ if ( !pixmap.isEmpty() )
+ richText.prepend( QString::fromLatin1( "<img src=\"%1\"></img>" ).arg( pixmap ) );
+
+ QString timeStamp = QString::fromLatin1( "<font color=\"%1\">%2</font>" )
+ .arg( ksopts->textColor.name() )
+ .arg( makeTimeStamp() );
+ m_timeStamps.append(timeStamp);
+ if ( m_timestamps )
+ richText.prepend( timeStamp );
+
+ QString text = QStyleSheet::escape(_text);
+
+ // ### a bit of a hack: turn '&lt;nick&gt; message' into
+ // <span>&lt;nick&gt;<span> message' . span itself isn't supported but it
+ // enforces the creation of separate item objects and hence separate
+ // drawing of '<nick>' and 'message' , which is needed for BiDi users,
+ // according to UV Kochavi <uv1st@yahoo.com> , to prevent output like
+ // '<nick message<' , which is supposedly a bug in Qt's reordering. The
+ // same is done for [nick] and >nick< to catch queries.
+ QRegExp bidiRe( "^(&lt;\\S+&gt;)(.+)$" );
+ text.replace( bidiRe, QString::fromLatin1( "<span>\\1</span>\\2" ) );
+ QRegExp bidiRe2( "^(\\[\\S+\\])(.+)$" );
+ text.replace( bidiRe2, QString::fromLatin1( "<span>\\1</span>\\2" ) );
+ QRegExp bidiRe3( "^(&gt;\\S+&lt;)(.+)$" );
+ text.replace( bidiRe3, QString::fromLatin1( "<span>\\1</span>\\2" ) );
+
+ QRegExp nickCol( "~n(.+)~n" );
+ nickCol.setMinimal(true);
+ int pos;
+
+ while( (pos = nickCol.search(text)) >= 0 ){
+ //kdDebug(5008) << "Found nick: " << nickCol.cap(1) << endl;
+ QString newText = nickCol.cap(1);
+ if( nickCol.cap(1) != m_proc->getNick()){
+ QColor col = nickColourMaker::colourMaker()->findFg(nickCol.cap(1));
+
+ newText.prepend(QString("<font color=\"%1\">").arg(col.name()));
+ newText.append("</font>");
+ } else {
+ QColor col = ksopts->ownNickColor.name();
+ if( ! col.isValid())
+ nickColourMaker::colourMaker()->findFg(nickCol.cap(1));
+ newText.prepend(QString("<font color=\"%1\">").arg(col.name()));
+ newText.append("</font>");
+ if(ksopts->ownNickBold){
+ newText.prepend("<b>");
+ newText.append("</b>");
+ }
+ if(ksopts->ownNickUl){
+ newText.prepend("<u>");
+ newText.append("</u>");
+ }
+ if(ksopts->ownNickRev){
+ newText.prepend("<r>");
+ newText.append("</r>");
+ }
+ }
+ text.replace(pos, nickCol.matchedLength(), newText);
+ }
+
+ //kdDebug(5008) << "After Text: " << text << endl;
+
+ KSParser parser;
+ richText += parser.parse( text );
+
+ richText += "</font>";
+
+
+ //kdDebug(5008) << "Text: " << _text << endl;
+
+
+ richText = KStringHandler::tagURLs( richText );
+ //kdDebug(5008) << "Rich text: " << richText << endl;
+
+ KSirc::TextParagIterator parag = appendParag( richText );
+
+ m_lines++;
+ if ( ksopts->windowLength && m_lines > ksopts->windowLength )
+ {
+ while ( m_lines > ksopts->windowLength )
+ {
+ removeParag( firstParag() );
+ m_timeStamps.remove( m_timeStamps.begin() );
+ m_lines--;
+ }
+ }
+
+ if (parser.beeped()) {
+ KNotifyClient::event(winId(), QString::fromLatin1("BeepReceived"),
+ i18n("Beep Received"));
+ }
+
+ QString logText = parag.plainText();
+ // append timestamp if it's not already there
+ if ( ! m_timestamps )
+ logText.prepend( makeTimeStamp() );
+
+ return logText + '\n';
+}
+
+void KSircView::addRichText(const QString &_text)
+{
+ //kdDebug(5008) << "Start Text: " << _text << endl;
+
+ QString text = _text;
+
+ QRegExp re("^(<font color=\"[^\"]+\">\\[[0-9:]+\\] </font>)");
+ QString timeStamp;
+
+ if(re.search(text) >= 0){
+ timeStamp = re.cap(1);
+ }
+ else {
+ timeStamp = QString::fromLatin1( "<font color=\"%1\">%2</font>" )
+ .arg( ksopts->textColor.name() )
+ .arg( makeTimeStamp() );
+ if ( m_timestamps )
+ text.prepend( timeStamp );
+ }
+ m_timeStamps.append(timeStamp);
+
+ KSirc::TextParagIterator parag = appendParag( text );
+
+ m_lines++;
+ if ( ksopts->windowLength && m_lines > ksopts->windowLength )
+ {
+ while ( m_lines > ksopts->windowLength )
+ {
+ removeParag( firstParag() );
+ m_timeStamps.remove( m_timeStamps.begin() );
+ m_lines--;
+ }
+ }
+
+}
+
+void KSircView::enableTimeStamps(bool enable)
+{
+ if(enable == m_timestamps)
+ return;
+ setUpdatesEnabled( false );
+ m_timestamps = enable;
+ KSirc::TextParagIterator paragIt = firstParag();
+ QStringList::ConstIterator timeStampIt = m_timeStamps.begin();
+ for (; !paragIt.atEnd(); ++paragIt, ++timeStampIt )
+ {
+ QString text = paragIt.richText();
+ if ( enable )
+ text.prepend( *timeStampIt );
+ else
+ text.remove( 0, (*timeStampIt).length() );
+ paragIt.setRichText( text );
+ }
+ setUpdatesEnabled( true );
+ updateContents();
+}
+
+void KSircView::anchorClicked(const QMouseEvent *ev, const QString &url)
+{
+ if ( (ev->button() & LeftButton) && (ev->state() & ShiftButton ) )
+ saveURL( url );
+ else if ( (ev->button() & LeftButton) || (ev->button() & MidButton) )
+ {
+ openBrowser( url );
+ }
+ else if ( ev->button() & RightButton )
+ {
+ static const int openURLID = 0;
+ static const int copyLinkLocationID = 1;
+
+ // Adding a nice contextmenu
+ KPopupMenu* menu = new KPopupMenu( this );
+ menu->insertTitle( i18n( "URL" ) );
+ menu->insertItem( i18n("Open URL"), openURLID );
+ menu->insertItem( i18n("Copy Link Address"), copyLinkLocationID );
+ switch( menu->exec( ( ev->globalPos() ) ) )
+ {
+ case openURLID :
+ openBrowser( url );
+ break;
+ case copyLinkLocationID :
+ copyLinkToClipboard( url );
+ break;
+ default:
+ break;
+ }
+ delete menu;
+ }
+}
+
+void KSircView::openBrowser(const QString &url )
+{
+ (void) new KRun( KURL( url.startsWith("www") ? QString::fromLatin1("http://") + url : url));
+}
+
+void KSircView::copyLinkToClipboard( const QString &url )
+{
+ QApplication::clipboard()->setText( url, QClipboard::Clipboard );
+}
+
+QColor KSircView::ircColor(int code)
+{
+ if (code >= 0 && code < 16)
+ return ksopts->ircColors[code];
+ return QColor();
+}
+
+void KSircView::contentsDragEnterEvent(QDragEnterEvent* event)
+{
+ event->accept((QTextDrag::canDecode(event) ||
+ (m_acceptFiles && KURLDrag::canDecode(event))) &&
+ (!event->source() || event->source() != viewport()));
+}
+
+void KSircView::contentsDragMoveEvent(QDragMoveEvent* event)
+{
+ event->accept(!event->source() || event->source() != viewport());
+}
+
+void KSircView::contentsDropEvent(QDropEvent* event)
+{
+ QStringList urls;
+ QString text;
+
+ if (m_acceptFiles && KURLDrag::decodeLocalFiles(event, urls))
+ emit urlsDropped(urls);
+ else if (QTextDrag::decode(event, text))
+ emit textDropped(text);
+}
+
+// vim: ts=4 sw=4 noet
diff --git a/ksirc/ksview.h b/ksirc/ksview.h
new file mode 100644
index 00000000..b1f3766a
--- /dev/null
+++ b/ksirc/ksview.h
@@ -0,0 +1,74 @@
+#ifndef ksview_h
+#define ksview_h
+
+/* This file is part of ksirc
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// $Id$
+//
+#include "kstextview.h"
+
+class KSircProcess;
+
+class KSircView : public KSirc::TextView
+{
+ Q_OBJECT
+public:
+ KSircView(KSircProcess *proc, QWidget *parent, const char *name);
+ virtual ~KSircView();
+
+ virtual void clear();
+ // returns the plain-text string added (for logging)
+ QString addLine(const QString &pixmap, const QColor &color, const QString &text);
+ void addRichText(const QString &_text);
+ void enableTimeStamps(bool enable);
+
+ void setAcceptFiles(bool _acceptFiles) { m_acceptFiles = _acceptFiles; }
+signals:
+ void urlsDropped(const QStringList&);
+ void textDropped(const QString&);
+
+protected:
+ virtual void contentsDragEnterEvent(QDragEnterEvent *);
+ virtual void contentsDragMoveEvent(QDragMoveEvent *);
+ virtual void contentsDropEvent(QDropEvent *);
+
+private:
+ virtual bool linksEnabled() const { return true; }
+ void openBrowser( const QString &url );
+ void copyLinkToClipboard( const QString &url );
+ static QString makeTimeStamp();
+
+ void saveURL( const QString &url );
+
+private slots:
+ void anchorClicked(const QMouseEvent *ev, const QString &url);
+
+ QColor ircColor(int);
+
+private:
+ int m_lines;
+ QStringList m_timeStamps;
+ bool m_acceptFiles;
+ bool m_timestamps;
+ KSircProcess *m_proc;
+};
+
+// vim: ts=4 sw=4 noet
+
+#endif
diff --git a/ksirc/logfile.cpp b/ksirc/logfile.cpp
new file mode 100644
index 00000000..6a15e51e
--- /dev/null
+++ b/ksirc/logfile.cpp
@@ -0,0 +1,93 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Artistic License.
+*/
+
+#include "logfile.h"
+
+#include <assert.h>
+
+#include <qdir.h>
+
+#include <kstandarddirs.h>
+
+LogFile::LogFile( const QString &channel, const QString &server )
+ : m_channel( channel ), m_server( server ), m_file( new QFile() ),
+ m_flushTimerId( -1 )
+{
+}
+
+LogFile::~LogFile()
+{
+ closeLog();
+ delete m_file;
+}
+
+void LogFile::open()
+{
+ int suffix = 1;
+
+ m_file->setName( makeLogFileName( m_channel, m_server ) );
+
+ while ( !m_file->open( IO_WriteOnly | IO_Append ) && suffix < 16000 ) // arbitrary limit ;)
+ {
+ m_file->setName( makeLogFileName( m_channel, m_server, suffix ) );
+ suffix++;
+ }
+
+ assert( m_file->isOpen() == true );
+
+ log( QString::fromLatin1( "### Log session started at " )
+ + QDateTime::currentDateTime().toString()
+ + QString::fromLatin1( "###\n" ) );
+}
+
+void LogFile::closeLog()
+{
+ log( QString::fromLatin1( "### Log session terminated at " )
+ + QDateTime::currentDateTime().toString()
+ + QString::fromLatin1( "###\n" ) );
+
+ if ( m_flushTimerId != -1 )
+ killTimer( m_flushTimerId );
+
+ m_file->close();
+}
+
+void LogFile::log( const QString &message )
+{
+ m_file->writeBlock( message.local8Bit(), message.length() );
+
+ if ( m_flushTimerId == -1 )
+ m_flushTimerId = startTimer( 60000 ); // flush each minute
+}
+
+void LogFile::timerEvent( QTimerEvent * )
+{
+ if ( m_file )
+ m_file->flush();
+
+ killTimer( m_flushTimerId );
+ m_flushTimerId = -1;
+}
+
+QString LogFile::makeLogFileName( const QString &channel, const QString &server, int suffix )
+{
+ QString res = channel + '_';
+
+ QDate dt = QDate::currentDate();
+ QString dateStr;
+ dateStr.sprintf( "%.4d_%.2d_%.2d_", dt.year(), dt.month(), dt.day() );
+ res += dateStr;
+
+ res += server;
+
+ res += ".log";
+
+ if ( suffix > -1 )
+ res += '.' + QString::number( suffix );
+
+ return locateLocal( "appdata", "logs/" + res );
+}
diff --git a/ksirc/logfile.h b/ksirc/logfile.h
new file mode 100644
index 00000000..337b9912
--- /dev/null
+++ b/ksirc/logfile.h
@@ -0,0 +1,40 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Artistic License.
+*/
+#ifndef __logfile_h__
+#define __logfile_h__
+
+#include <qobject.h>
+
+class QFile;
+
+class LogFile : public QObject
+{
+public:
+ LogFile( const QString &channel, const QString &server );
+ virtual ~LogFile();
+
+ void open();
+
+ void closeLog();
+
+ void log( const QString &message );
+
+protected:
+ virtual void timerEvent( QTimerEvent * );
+
+private:
+ QString m_channel;
+ QString m_server;
+
+ QFile *m_file;
+
+ int m_flushTimerId;
+
+ QString makeLogFileName( const QString &channel, const QString &server, int suffix = -1 );
+};
+
+#endif
diff --git a/ksirc/mditoplevel.cpp b/ksirc/mditoplevel.cpp
new file mode 100644
index 00000000..3f35d464
--- /dev/null
+++ b/ksirc/mditoplevel.cpp
@@ -0,0 +1,260 @@
+
+#include <qguardedptr.h>
+
+#include <qtabbar.h>
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kaction.h>
+
+#include "mditoplevel.h"
+#include "toplevel.h"
+#include "servercontroller.h"
+
+#define ID_CLOSE 5
+
+void KSTabWidget::mousePressEvent(QMouseEvent *e)
+{
+ if(e->button() == RightButton){
+ QPoint p = tabBar()->mapFromParent(e->pos());
+ QTab *tab = tabBar()->selectTab(p);
+ if(tab){
+ int id = tab->identifier();
+ emit showContexMenu(page(id), tabBar()->mapToGlobal(p));
+ }
+ }
+}
+
+MDITopLevel::MDITopLevel(QWidget *parent, const char *name)
+ : KMainWindow(parent, name)
+{
+ m_closing = false;
+
+ m_tab = new KSTabWidget( this );
+ m_tab->setTabPosition( QTabWidget::Bottom );
+
+ setCentralWidget( m_tab );
+
+ connect( m_tab, SIGNAL( currentChanged( QWidget * ) ),
+ this, SLOT( slotCurrentChanged( QWidget * ) ) );
+
+ connect( m_tab, SIGNAL( showContexMenu(QWidget *, const QPoint &) ),
+ this, SLOT( slotShowContexMenu(QWidget *, const QPoint &) ) );
+
+ KConfig *config = kapp->config();
+ config->setGroup("MDI");
+ QSize s( 600, 360 );
+ resize(config->readSizeEntry( "TopLevelSize", &s ));
+
+ m_dirtyIcon = UserIcon( "star" );
+ m_addressedIcon = UserIcon( "info" );
+
+ m_pop = new KPopupMenu(m_tab, "");
+ m_pop->insertItem( SmallIcon("fileclose"), i18n("Close"), this, SLOT( slotCloseLastWid() ));
+
+}
+
+MDITopLevel::~MDITopLevel()
+{
+ kdDebug(5008) << "~MDITopLevel in" << endl;
+
+ KConfig *config = kapp->config();
+ config->setGroup( "MDI" );
+ config->writeEntry( "TopLevelSize", this->size() );
+ config->sync();
+
+ QPtrListIterator<QWidget> it( m_tabWidgets );
+ for (; it.current(); ++it )
+ it.current()->disconnect( this, 0 );
+ kdDebug(5008) << "~MDITopLevel out" << endl;
+
+}
+
+void MDITopLevel::addWidget( QWidget *widget, bool show )
+{
+ if ( m_tabWidgets.containsRef( widget ) )
+ return;
+
+ kdDebug(5008) << "In add widget" << endl;
+
+ widget->reparent( m_tab, 0, QPoint( 0, 0 ), show );
+
+ if(show == TRUE){
+ showWidget(widget);
+ }
+
+ m_tabWidgets.append( widget );
+
+ connect( widget, SIGNAL( destroyed() ) ,
+ this, SLOT( slotWidgetDestroyed() ) );
+
+ connect( widget, SIGNAL( changeChannel( const QString &, const QString & ) ),
+ this, SLOT( slotChangeChannelName( const QString &, const QString & ) ) );
+
+ widget->installEventFilter( this );
+
+ connect( widget, SIGNAL( changed( bool, QString ) ),
+ this, SLOT( slotMarkPageDirty( bool ) ) );
+}
+
+void MDITopLevel::removeWidget( QWidget *widget )
+{
+ if (m_closing)
+ return;
+ m_tabWidgets.removeRef( widget );
+ removeFromAddressedList( widget );
+ m_tab->removePage( widget );
+ widget->removeEventFilter( this );
+ widget->disconnect( this, 0 );
+}
+
+void MDITopLevel::hideWidget( QWidget *widget )
+{
+ m_tab->removePage( widget );
+ widget->hide();
+}
+
+void MDITopLevel::showWidget( QWidget *widget )
+{
+ if(m_tab->indexOf(widget) == -1){
+ int space = widget->caption().find(" ");
+ QString cap = space < 1 ? widget->caption():widget->caption().left(space);
+ m_tab->addTab( widget, cap);
+ m_tab->showPage( widget );
+ m_tab->setCurrentPage( m_tab->indexOf(widget) );
+ }
+}
+
+void MDITopLevel::next()
+{
+ if (m_tab->currentPageIndex() < m_tab->count() - 1)
+ m_tab->setCurrentPage(m_tab->currentPageIndex() + 1);
+ else
+ m_tab->setCurrentPage(0);
+}
+
+void MDITopLevel::previous()
+{
+ if (m_tab->currentPageIndex() > 0)
+ m_tab->setCurrentPage(m_tab->currentPageIndex() - 1);
+ else
+ m_tab->setCurrentPage(m_tab->count() - 1);
+}
+
+void MDITopLevel::closeEvent( QCloseEvent *ev )
+{
+ m_closing = true;
+ // Don't use iterators on a list while deleting elements
+ // from it (Antonio)
+ int i = 0;
+ kdDebug(5008) << "Mdi got close event " << endl;
+ while ( m_tabWidgets.count() && (i++ < 100000)) {
+ kdDebug(5008) << "MDITopLevel trying to close: " << m_tabWidgets.first()->name() << endl;
+ QGuardedPtr<QWidget> w = m_tabWidgets.take(0);
+ w->show();
+ w->close( false );
+ if(w)
+ delete (QWidget *)w;
+ }
+
+ KMainWindow::closeEvent( ev );
+ m_closing = false;
+}
+
+void MDITopLevel::slotWidgetDestroyed()
+{
+ const QWidget *widget = static_cast<const QWidget *>( sender() );
+
+ m_tabWidgets.removeRef( widget );
+ removeFromAddressedList( widget );
+}
+
+bool MDITopLevel::eventFilter( QObject *obj, QEvent *ev )
+{
+ if ( ev->type() != QEvent::CaptionChange )
+ return false;
+
+ QWidget *widget = dynamic_cast<QWidget *>( obj );
+
+ if ( !widget || !m_tabWidgets.containsRef( widget ) )
+ return false;
+
+ if ( m_tab->currentPage() == widget )
+ setPlainCaption( widget->caption() );
+
+ return false;
+}
+
+void MDITopLevel::slotCurrentChanged( QWidget *page )
+{
+
+ m_tab->setTabIconSet( page, QIconSet() );
+ removeFromAddressedList( page );
+
+ setPlainCaption( page->QWidget::caption() );
+
+ KSircTopLevel *kst = dynamic_cast<KSircTopLevel *>( page );
+ if ( !kst )
+ return;
+ kst->lineEdit()->setFocus();
+}
+
+void MDITopLevel::slotMarkPageDirty( bool addressed )
+{
+ // This is called when a line appeared in this channel.
+ // addressed is true if it was addressed to the user
+ KMainWindow *window = dynamic_cast<KMainWindow *>( const_cast<QObject *>( sender() ) );
+
+ if ( !window )
+ return;
+
+ if ( window != m_tab->currentPage() )
+ {
+ if ( m_addressed.containsRef( window ) )
+ addressed = true;
+ else if ( addressed ) {
+ m_addressed.append( window );
+ }
+ m_tab->setTabIconSet( window, addressed ? m_addressedIcon : m_dirtyIcon );
+ }
+}
+
+void MDITopLevel::slotChangeChannelName( const QString &, const QString &channelName )
+{
+ KMainWindow *window = dynamic_cast<KMainWindow *>( const_cast<QObject *>( sender() ) );
+
+ if ( !window )
+ return;
+
+ QString esc = channelName;
+ esc.replace("&", "&&");
+ m_tab->setTabLabel( window, esc );
+ removeFromAddressedList( window );
+}
+
+void MDITopLevel::removeFromAddressedList( const QWidget* w )
+{
+ // If this tab was showing a "you're being talked to" icon, remove it
+ // and tell the servercontroller (so that it can update the docked icon).
+ m_addressed.removeRef( w );
+}
+
+void MDITopLevel::slotShowContexMenu(QWidget *w, const QPoint &p)
+{
+ m_last_pop_wid = w;
+ m_pop->popup(p);
+}
+
+void MDITopLevel::slotCloseLastWid()
+{
+ m_last_pop_wid->close();
+
+}
+
+#include "mditoplevel.moc"
+
+// vim: ts=4 sw=4 et
diff --git a/ksirc/mditoplevel.h b/ksirc/mditoplevel.h
new file mode 100644
index 00000000..7f58619c
--- /dev/null
+++ b/ksirc/mditoplevel.h
@@ -0,0 +1,75 @@
+#ifndef __mditoplevel_h__
+#define __mditoplevel_h__
+
+#include <qptrlist.h>
+#include <qtabwidget.h>
+
+#include <kmainwindow.h>
+
+class KSTabWidget : public QTabWidget
+{
+ Q_OBJECT
+public:
+ KSTabWidget ( QWidget * parent = 0, const char * name = 0, WFlags f = 0 )
+ : QTabWidget(parent, name, f)
+ {
+ }
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *e);
+
+signals:
+ void showContexMenu(QWidget *, const QPoint &);
+
+};
+
+class QLabel;
+class KPopupMenu;
+
+class MDITopLevel : public KMainWindow
+{
+ Q_OBJECT
+public:
+ MDITopLevel(QWidget *parent = 0, const char *name = 0);
+ virtual ~MDITopLevel();
+
+ void addWidget( QWidget *widget, bool show );
+
+ void removeWidget( QWidget *widget );
+
+ QTabWidget *tabWidget() const { return m_tab; }
+ void next();
+ void previous();
+
+ QPtrList<QWidget> &widgets() { return m_tabWidgets; }
+
+ void hideWidget( QWidget *widget );
+ void showWidget( QWidget *widget );
+
+ virtual bool eventFilter( QObject *obj, QEvent *ev );
+ bool closing() const { return m_closing; }
+
+protected:
+ void removeFromAddressedList( const QWidget* w );
+ virtual void closeEvent( QCloseEvent *ev );
+
+private slots:
+ void slotWidgetDestroyed();
+ void slotCurrentChanged( QWidget *page );
+ void slotMarkPageDirty( bool );
+ void slotChangeChannelName( const QString &, const QString &newName );
+ void slotShowContexMenu(QWidget *, const QPoint &);
+ void slotCloseLastWid();
+
+private:
+ KSTabWidget *m_tab;
+ KPopupMenu *m_pop;
+ QWidget *m_last_pop_wid;
+ QPtrList<QWidget> m_tabWidgets;
+ QPtrList<QWidget> m_addressed;
+ QPixmap m_dirtyIcon;
+ QPixmap m_addressedIcon;
+ bool m_closing;
+};
+
+#endif
diff --git a/ksirc/messageReceiver.cpp b/ksirc/messageReceiver.cpp
new file mode 100644
index 00000000..f2ac6ee0
--- /dev/null
+++ b/ksirc/messageReceiver.cpp
@@ -0,0 +1,73 @@
+#include "messageReceiver.h"
+
+#include <qtextcodec.h>
+#include <kcharsets.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <assert.h>
+
+KSircMessageReceiver::KSircMessageReceiver( KSircProcess * _proc )
+{
+ proc = _proc;
+ broadcast = TRUE;
+}
+
+KSircMessageReceiver::~KSircMessageReceiver()
+{
+}
+
+void KSircMessageReceiver::setBroadcast(bool bd)
+{
+ broadcast = bd;
+}
+
+bool KSircMessageReceiver::getBroadcast()
+{
+ return broadcast;
+}
+
+filterRuleList *KSircMessageReceiver::defaultRules()
+{
+ return new filterRuleList();
+}
+
+UnicodeMessageReceiver::UnicodeMessageReceiver( KSircProcess *process )
+ : KSircMessageReceiver( process ), m_encoder( 0 )
+{
+}
+
+void UnicodeMessageReceiver::sirc_receive( QCString str, bool broadcast )
+{
+ assert( encoder() );
+ //kdDebug(5008) << "Encoder: " << encoder()->name() << endl;
+ //kdDebug(5008) << "It gives us: " << encoder()->toUnicode( str ).utf8() << endl;
+ sirc_receive( encoder()->toUnicode( str ), broadcast );
+}
+
+void UnicodeMessageReceiver::setEncoding( const QString &encoding )
+{
+ m_encoding = encoding;
+ m_encoder = 0;
+}
+
+QString UnicodeMessageReceiver::encoding() const
+{
+ if ( m_encoding.isEmpty() )
+ return QTextCodec::codecForLocale()->mimeName();
+ return m_encoding;
+}
+
+QTextCodec *UnicodeMessageReceiver::encoder() const
+{
+ if ( m_encoding.isEmpty() ) {
+ return QTextCodec::codecForLocale();
+ }
+
+ if ( !m_encoder ) {
+ const_cast<UnicodeMessageReceiver *>( this )->m_encoder = KGlobal::charsets()->codecForName( m_encoding );
+ assert( m_encoder );
+ }
+
+ return m_encoder;
+}
+
diff --git a/ksirc/messageReceiver.h b/ksirc/messageReceiver.h
new file mode 100644
index 00000000..a86817b0
--- /dev/null
+++ b/ksirc/messageReceiver.h
@@ -0,0 +1,62 @@
+
+#ifndef KMESSAGERECEIVER_H
+#define KMESSAGERECEIVER_H
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+class KSircProcess;
+class QTextCodec;
+
+struct filterRule {
+ const char *desc;
+ const char *search;
+ const char *from;
+ const char *to;
+};
+
+typedef QPtrList<filterRule> filterRuleList;
+
+class KSircMessageReceiver
+{
+public:
+ KSircMessageReceiver(KSircProcess *_proc);
+ virtual ~KSircMessageReceiver();
+
+ virtual void sirc_receive(QCString str, bool broadcast = false) = 0;
+
+ virtual void control_message(int, QString) = 0;
+
+ bool getBroadcast();
+ void setBroadcast(bool bd);
+
+ virtual filterRuleList *defaultRules();
+
+ KSircProcess *ksircProcess() const { return proc; }
+
+private:
+ KSircProcess *proc;
+ bool broadcast;
+
+};
+
+class UnicodeMessageReceiver : public KSircMessageReceiver
+{
+public:
+ UnicodeMessageReceiver( KSircProcess *process );
+
+ virtual void sirc_receive(QCString str, bool broadcast = false);
+ virtual void sirc_receive(QString str, bool broadcast = false) = 0;
+
+protected:
+ void setEncoding( const QString &encoding );
+ QString encoding() const;
+
+ QTextCodec *encoder() const;
+
+private:
+ QString m_encoding;
+ QTextCodec *m_encoder;
+};
+
+#endif
diff --git a/ksirc/nickColourMaker.cpp b/ksirc/nickColourMaker.cpp
new file mode 100644
index 00000000..22c09b66
--- /dev/null
+++ b/ksirc/nickColourMaker.cpp
@@ -0,0 +1,86 @@
+/* This file is part of ksirc
+ Copyright (c) 2003 Andrew Stanley-Jones <asj@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// $Id$
+
+#include <qstring.h>
+#include <qcolor.h>
+#include <qregexp.h>
+#include <kdebug.h>
+
+#include "nickColourMaker.h"
+#include "ksopts.h"
+
+nickColourMaker *nickColourMaker::s_ncm = 0;
+
+nickColourMaker::nickColourMaker()
+{
+ s_ncm = this;
+}
+
+int nickColourMaker::findIdx(QString nick) const
+{
+ unsigned int value = 0;
+ uint i;
+ ushort c;
+
+ if(ksopts->nickColourization == false)
+ return -1;
+
+ for(i = 0; i < nick.length(); i++){
+ c = nick[i].unicode();
+ switch(c){
+ case '|':
+ case '-':
+ case '_':
+ if(i != 0)
+ i = nick.length();
+ else
+ value += c;
+ break;
+ default:
+ value += c;
+ }
+ }
+ value %= ksopts->numColors;
+ uint start = value;
+ while(ksopts->nickHighlight[value] == false){
+ value = (value + 1) % ksopts->numColors;
+ if(start == value)
+ return -1;
+
+ }
+
+
+ return value;
+
+}
+
+QColor nickColourMaker::findFg(QString nick) const
+{
+
+ int value = findIdx(nick);
+
+ if(value >= 0)
+ return ksopts->ircColors[value];
+ else if(ksopts->nickForeground.isValid())
+ return ksopts->nickForeground;
+ else
+ return ksopts->textColor;
+}
+
diff --git a/ksirc/nickColourMaker.h b/ksirc/nickColourMaker.h
new file mode 100644
index 00000000..239a7935
--- /dev/null
+++ b/ksirc/nickColourMaker.h
@@ -0,0 +1,44 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Andrew Stanley-Jones
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GPL.
+*/
+#ifndef __nickcolourmaker_h__
+#define __nickcolourmaker_h__
+
+#include <qdict.h>
+#include <qstring.h>
+#include <qmap.h>
+#include <qcolor.h>
+#include "ksopts.h"
+
+struct nickColourInfo
+{
+ nickColourInfo(int _fg) { fg = _fg; }
+ int fg;
+};
+
+// Helper class to parse IRC colour nicks in the
+// irc channel and the nick list
+class nickColourMaker
+{
+public:
+ nickColourMaker();
+
+ int findIdx(QString nick) const;
+ QColor findFg(QString nick) const;
+ QColor operator[]( QString nick ) const
+ {
+ return findFg(nick);
+ }
+
+ static nickColourMaker *colourMaker() { return s_ncm; }
+
+
+private:
+ static nickColourMaker *s_ncm;
+ QDict<nickColourInfo> m_nicks;
+};
+
+#endif
diff --git a/ksirc/objFinder.cpp b/ksirc/objFinder.cpp
new file mode 100644
index 00000000..4625b6cf
--- /dev/null
+++ b/ksirc/objFinder.cpp
@@ -0,0 +1,160 @@
+#include "objFinder.h"
+
+#include <qapplication.h>
+#include <qobjectlist.h>
+#include <qwidgetlist.h>
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <kdebug.h>
+
+QDict<QObject> *objFinder::objList = new QDict<QObject>;
+
+/*
+ * So we can connect to the slots, etc
+ */
+objFinder *objFind = new objFinder();
+
+objFinder::objFinder()
+ : QObject()
+{
+}
+
+objFinder::~objFinder()
+{
+}
+
+void objFinder::insert(QObject *obj, const char *key){
+ QString name;
+
+ if(obj == 0x0){
+ qWarning("objFinder: Passed Null Object");
+ return;
+ }
+
+ if(key != 0){
+ name = key;
+ }
+ else {
+ name = obj->name();
+ if(name == 0){
+ name = randString();
+ }
+ }
+ objList->insert(name, obj);
+ connect(obj, SIGNAL(destroyed()),
+ objFind, SLOT(objDest()));
+
+ emit objFind->inserted(obj);
+}
+
+QObject *objFinder::find(const char *name, const char *inherits){
+ QObject *found;
+ QDictIterator<QObject> it(*objList);
+ uint len = strlen(name);
+ while(it.current()){
+ if(len == strlen(it.current()->name()) &&
+ strcmp(it.current()->name(), name) == 0)
+ return it.current();
+ QObjectList *qobl = it.current()->queryList(inherits, name, FALSE);
+ QObjectListIt itql( *qobl );
+ if(itql.current() != 0x0){
+ found = itql.current();
+ delete qobl;
+ return found;
+ }
+ delete qobl;
+ ++it;
+ }
+ QWidgetList *all = QApplication::allWidgets();
+ QWidgetListIt itW(*all);
+ while(itW.current()){
+ if(len == strlen(itW.current()->name()) &&
+ strcmp(itW.current()->name(), name) == 0){
+ if(inherits != 0x0 && itW.current()->inherits(inherits) == FALSE){
+ ++itW;
+ continue;
+ }
+ found = itW.current();
+ delete all;
+ return found;
+ }
+ ++itW;
+ }
+ delete all;
+
+ return 0x0;
+}
+
+void objFinder::dumpTree(){
+ QDictIterator<QObject> it(*objList);
+ while(it.current()){
+ it.current()->dumpObjectTree();
+ ++it;
+ }
+ QWidgetList *all = QApplication::allWidgets();
+ QWidgetListIt itW(*all);
+ while(itW.current()){
+ kdDebug(5008) << itW.current()->className() << "::" << itW.current()->name("unnamed") << endl;
+ ++itW;
+ }
+
+}
+
+QStringList objFinder::allObjects(){
+ QStringList allNames;
+ QDictIterator<QObject> it(*objList);
+ while(it.current()){
+ QObjectList *qobl = it.current()->queryList(); // Matches everything
+ QObjectListIt itql( *qobl );
+ while(itql.current()){
+ QString name;
+ name = itql.current()->className();
+ name += "::";
+ name += itql.current()->name("unnamed");
+ allNames.append(name);
+ ++itql;
+ }
+ delete qobl;
+ ++it;
+ }
+ QWidgetList *all = QApplication::allWidgets();
+ QWidgetListIt itW(*all);
+ while(itW.current()){
+ QString name;
+ name = itW.current()->className();
+ name += "::";
+ name += itW.current()->name("unnamed");
+ allNames.append(name);
+ ++itW;
+ }
+ delete all;
+ return allNames;
+}
+
+QString objFinder::randString(){
+ static bool runSrand = 0;
+ QString str = "";
+ if(runSrand == 0){
+ srand(time(NULL));
+ }
+ for(int i = 0; i <= 8; i++){
+ str.insert(0, (char) (1+(int) (94.0*rand()/(RAND_MAX+1.0))) + 0x20);
+ }
+ return str;
+}
+
+void objFinder::objDest(){
+ if(sender() == 0x0){
+ return;
+ }
+ QDictIterator<QObject> it(*objList);
+ while(it.current()){
+ if(it.current() == sender()){
+ objList->remove(it.currentKey());
+ }
+ ++it;
+ }
+}
+#include "objFinder.moc"
diff --git a/ksirc/objFinder.h b/ksirc/objFinder.h
new file mode 100644
index 00000000..8777dd68
--- /dev/null
+++ b/ksirc/objFinder.h
@@ -0,0 +1,41 @@
+#ifndef OBJFINGER_H
+#define OBJFINGER_H
+
+#include <qobject.h>
+#include <qdict.h>
+#include <qstringlist.h>
+
+class objFinder : public QObject {
+ Q_OBJECT
+public:
+
+ objFinder();
+ virtual ~objFinder();
+
+ static void insert(QObject *obj, const char *key = 0);
+ static QObject *find(const char *name, const char *inherits);
+ static void dumpTree();
+ static QStringList allObjects();
+
+signals:
+ void inserted(QObject *obj);
+
+protected slots:
+ void objDest();
+
+private:
+ /*
+ * Don't allow the object to be created, all it's members are static
+ */
+
+ static QString randString();
+
+
+ static QDict<QObject> *objList;
+
+};
+
+extern objFinder *objFind;
+
+#endif
+
diff --git a/ksirc/openksircproc.dlg b/ksirc/openksircproc.dlg
new file mode 100644
index 00000000..1378f569
--- /dev/null
+++ b/ksirc/openksircproc.dlg
@@ -0,0 +1,76 @@
+DlgEdit:v2.0:Dialog:
+Dialog {
+ ClassHeader {open_ksirc.h}
+ ClassSource {open_ksirc.cpp}
+ ClassName {open_ksirc}
+ DataHeader {open_ksircData.h}
+ DataSource {open_ksircData.cpp}
+ DataName {open_ksircData}
+ WindowBaseClass {QDialog}
+ IsModal {FALSE}
+ WindowCaption {Connect to Server}
+ WindowFlags {45056}
+}
+WidgetLayout {
+InitialPos {-1 -1}
+Size {400 90}
+MinSize {400 90}
+MaxSize {400 90}
+Grid {10}
+
+Label {
+ Text {Server:}
+ Alignment {33}
+ AutoResize {FALSE}
+ Margin {-1}
+ Rect {10 10 100 30}
+ Name {Label_1}
+ Font {"helvetica" 12 63 0 0 0 0 0 0}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {TRUE}
+ Text {Ok}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {200 50 190 30}
+ Name {PushButton_1}
+ Variable {okButton}
+ Font {"helvetica" 12 63 0 0 0 0 0 0}
+ Signal {[Protected] clicked --> create_toplevel ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+PushButton {
+ ToggleButton {FALSE}
+ Default {FALSE}
+ AutoDefault {FALSE}
+ Text {Cancel}
+ AutoRepeat {FALSE}
+ AutoResize {FALSE}
+ Rect {10 50 180 30}
+ Name {PushButton_2}
+ Signal {[Protected] clicked --> terminate ()}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+ComboBox {
+ Style {ReadWrite}
+ SizeLimit {10}
+ Policy {NoInsertion}
+ AutoResize {FALSE}
+ Rect {70 10 320 30}
+ Name {ComboBox_1}
+ Variable {nameSLE}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+Layout {None}
+}
diff --git a/ksirc/puke/HOWTO-PUKE.pod b/ksirc/puke/HOWTO-PUKE.pod
new file mode 100644
index 00000000..cf44e77e
--- /dev/null
+++ b/ksirc/puke/HOWTO-PUKE.pod
@@ -0,0 +1,325 @@
+=head1 OVERVIEW
+
+This document describes how to write puke addons and additional
+widgets. It assumes a good knowledge of C++, perl and X/Qt workings
+under Linux.
+
+=head1 1. Description and Background
+
+=over 6
+
+Puke's a generic protocol allowing dsirc to communicate with ksirc.
+Communications works over a unix domain socket between multiple
+client dsirc process's to a single ksirc process. All communications
+is done via a variable length message with the following layout:
+
+=begin text
+
+struct PukeMessage {
+unsigned int iHeader;
+int iCommand;
+int iWinId;
+int iArg;
+int iTextSize;
+char *cArg;
+}
+
+=end text
+
+None of the fields except for iCommand, iWinId and iHeader have any restrictions
+on their content and may contain arbitrary values. iCommand and iWinId must
+contain an int and it used by ksirc to determine the destination and
+handler of the actual command. (and of course it's meaning). iHeader is a
+fixed pattern used to identify the start of a header message should it loose
+syncronization. The current pattern used it 2863311530, which is:
+10101010101010101010101010101010.
+
+=item Internal handling by kSirc:
+
+Messages are received by a generic handler, PukeController where the message
+is passed to the iWinId's messageDipatcher for final processing. The
+iWinId of 1 through 10 are reserved for internal use, and 1 is
+currently set at the window ID for the PukeController itself.
+
+Connect a signal to PukeControllers writeBuffer (signal's generally
+called outputMessage) and pass the fd and PukeMessage to be sent to
+the client. No parsing of the output message is done.
+
+=item Internal handling by dsirc:
+
+All received messages are handled by an internal callback methods. 3
+sets of callbacks are checked for handlers in the following order:
+
+$PUKE_HANDLER{$cmd}{$winid}
+$PUKE_HANDLER{-$cmd}{$winid}
+$PUKE_DEF_HANDLER{$cmd}
+
+If no handler is found an error is printed.
+
+Output is handled by the PukeSendMessage function. PBase defines an
+alternate routine sendMessage which should be a lot friendlier.
+
+=head1 2. How to create a new widget
+
+There are 2 parts to creating a widget, the C++ code and the
+supporting perl5-oop object.
+
+=head2 2.1 C++ Widget code
+
+The C++ code must be able to hand all required settings and messages
+for the widget. Each new widget iherites it's parent and so forth
+allowing for a nice oop layout. The widget structure the author is
+following is the same as Qt's. Their seems to work well, why
+re-invent the wheel?
+
+=item 2.1.1 General Layout, etc
+
+Figure where your new widget goes in the heirachy. If it's a simple
+Qt widget, I recommend using their existing layout. Man pages list
+what widgets inherit what.
+
+The general idea behind the widget layout should be to be to provide
+all the functionality of the widget to dsirc perl script. Incoming
+messages are handled via the messageHandler and ALL messages should
+return an ACK with current state info.
+
+New widgets are created as shared objects and loaded on the fly. This
+means you don't need to recompile ksirc to use new widgets etc.
+
+Generally you'll have to inherit PWidget at a minimum.
+
+Functions you HAVE TO overrite:
+
+B<1. createWidget>
+
+This function creates a new widget of your type and returns a
+*PWidget.
+
+B<2. messageHandler>
+
+This function receives ALL your commands.
+
+B<3. widget() and setWidget(YourWidget *)>
+
+These set and return your widget.
+
+
+If you care about inheritance, which you should, all these functions
+should be virtual. (Since we are using pointers to PWidget's
+everywhere, it's a good bet you want your children's overriden
+functions called, not yours)
+
+The structure internally will have to hold a local copy of the widget,
+and connect to it's destroy signal so you can know when it has been
+destroyed.
+
+=item 2.1.2 createWidget
+
+createWidget is defined as:
+
+PWidget *createWidget(widgetId *pwi, PWidget *parent);
+
+It is called everytime a new widget of yours is required. The
+widgetId will be the identifier for your widget and must be kept for
+all future commands. PWidget::setWidgetId(pwi) should be called to
+set the widget id. The *parent is the parent of the current widget.
+Generally PWidget->widget() is passed to the contructor of your
+widget. If it's 0, there is no parent. Simeplfied code for a the
+PFrame is:
+
+=begin text
+
+extern "C" {
+PWidget *createWidget(widgetId *pwi, PWIdget *parent);
+}
+
+PWidget *createWidget(widgetId *pwi, PWIdget *parent){
+ QFrame *f;
+ PFrame *pf = new PFrame(parent);
+ if(parent != 0){
+ f = new QFrame(parent->widget());
+ }
+ else{
+ f = new QPFrame();
+ }
+ pf->setWidget(f);
+ pf->setWidgetId(pwi);
+ return pf;
+}
+
+=end text
+
+Note: you have to check parent for null since calling NULL->widget()
+results in Bad Things (tm).
+
+=item 2.1.3 messageHandler
+
+This receives all commands, etc. It should process required commands,
+if a command is unkown pass it to the parent. PFrame example:
+
+=begin text
+
+class PFrame : public PWidget
+...
+void messageHandler(int fd, PukeMessage *pm);
+...
+
+void PFrame::messageHandler(int fd, PukeMessage *pm) {
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_QFRAME_SET_FRAME:
+ widget()->setFrameStyle(pm->iArg);
+ pmRet.iCommand = PUKE_QFRAME_SET_FRAME_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->frameStyle();
+ pmRet.cArg[0] = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ default:
+ PWidget::messageHandler(fd, pm);
+ }
+}
+
+=end text
+
+=item 2.1.4 widget and setWidget
+
+Both these functions should be overriden and return your widget type,
+and set your widget. For setWidget you should connect required
+signals and eventFilters you are using.
+
+Make sure to call the parents setWidget in setWidget so it can connect
+filters etc.
+
+BEWARE: You might get the widget into setWidget being null (from the
+destructor).
+
+Another PFrame example (APE ;) ):
+
+=begin text
+void PFrame::setWidget(QFrame *_f)
+{
+ frame = _f;
+ PWidget::setWidget(_f);
+
+}
+
+
+QFrame *PFrame::widget()
+{
+ return frame;
+}
+
+=end text
+
+=item 2.1.5 Destructor
+
+Ok, unfortunaly since we have this internal widget floating arround
+the destructor has to a little maigc.
+
+Call the destructor as such:
+
+delete widget();
+setWidget(0);
+
+This will clear the widget from now and all parents and delete it.
+you never want it deleted twice. (deleting 0 won't hurt)
+
+=head2 2.2 The Perl code
+
+Most of the perl oop is pretty straight forward, command simply issue
+a require sendMessage and off everything goes. There's one problem.
+
+You can't get information back on the current read cycle. Huh? I can
+hear most people saying. It means say someone wanted to do $widget =
+$widget->height() and you didn't have the height information locally,
+there's no way to get the information and return it to them. Why? You
+issue a sendMessage(...) but until dsirc returns to the main select()
+loop, we never know there's more to read. We can't return to the main
+select loop until we return from our current function. What does this
+mean? We have to store all the information locally.
+
+This also brings up another intresting aspect. Sometimes a widget may
+depend on a prior command before it can complete. This is the purpose
+of canRun function, and onNext. It's use will have to be explained
+latter.
+
+To help with this problem, pbase.pm sets up a fairly complicated set
+of message and event queues. Be warned when you issue a sendMessage,
+it might not get sent right away.
+
+I'll provide example bellow of how I've done certain functions, this
+is certainly not the only way to do it. Feel free to use any format
+you like aslong as it get's the job done.
+
+Ok, so how do we do this?
+
+=item 2.2.1 Perl oop? where do I start?
+
+Read the perltoot and perlobj man pages.
+
+=item 2.2.2 What to inherit etc.
+
+You probably want to inherit the same object as your C function does.
+At very least you'll want to inherit PWidget.
+
+=item 2.2.3 new and DESTROY
+
+Your new function should look something like (APE?):
+
+=begin text
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_FRAME;
+
+ if($class eq 'PFrame'){
+ $self->create();
+ }
+
+ return $self;
+}
+
+=end text
+
+$self is the blessed variable and it returned from the super class.
+You should always do it this way. Setting widgetType defines the type
+of widget, and needs to be set before calling create.
+
+If we are creating an object of our own class we call create() which
+acutally sends out the correct creation messages, etc. You can
+override the create function, but do be warned it might not be a good
+idea. Make sure you understand what and how it does it first!
+
+=item 2.2.4 sendMessage
+
+sendMessage is the main form of communicating with kSirc. Generable
+arguments are:
+
+=begin text
+
+sendMessage('iCommand' => command number,
+ 'iArg' => interger argument,
+ 'cArg' => character string,
+ 'CallBack' => pointer to sub, generally sub{...}
+ );
+
+=end text
+
+You'll note it's a hash so order doesn't count. The callback is a 1
+shot call back (should be) so don't count on it getting hit twice.
+The call back's first argument will be a \%ARGS with the return
+arguments.
+
+=item 2.2.5 Final notes on perl
+
+Most of the function calls will just send out messages, etc. For call
+backs the general form I've found works well is: sub {$self->blah()}.
+
+=head1 3. Interfacing with the kSirc's main windows and functions
+
+NOT implemented yet.
+
+=back
diff --git a/ksirc/puke/Makefile.am b/ksirc/puke/Makefile.am
new file mode 100644
index 00000000..de25d641
--- /dev/null
+++ b/ksirc/puke/Makefile.am
@@ -0,0 +1,43 @@
+KDE_CXXFLAGS = $(USE_RTTI) $(USE_EXCEPTIONS) -UQT_NO_ASCII_CAST
+
+INCLUDES= $(all_includes)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libpuke.la
+
+libpuke_la_SOURCES = pwidget.cpp pobject.cpp \
+ playout.cpp controller.cpp pframe.cpp \
+ plined.cpp pbutton.cpp ppushbt.cpp \
+ pprogress.cpp ptablevw.cpp plistbox.cpp \
+ plabel.cpp pmenudta.cpp ppopmenu.cpp \
+ palistbox.cpp ptabdialog.cpp \
+ pkfiledialog.cpp pobjfinder.cpp
+
+$(srcdir)/HOWTO-PUKE.txt: HOWTO-PUKE.pod
+ pod2text $(srcdir)/HOWTO-PUKE.pod > HOWTO-PUKE.txt
+
+# no install headers
+
+noinst_HEADERS = \
+ commands.h plined.h pwidget.h widgethdlr.h \
+ controller.h pframe.h pmessage.h HOWTO-PUKE.pod \
+ commands-handler.pl pboxlayout.pm pwidget.pm \
+ commands-perl.pl pframe.pm test.pl convert_commands.pl \
+ plined.pm tester.pl pbase.pm puke.pl ppushbt.h \
+ pbutton.h pprogress.h ptablevw.h plistbox.h \
+ plabel.h pobject.h playout.h pmenudta.h ppopmenu.h \
+ palistbox.h ptabdialog.h
+
+# Datafiles to install / uninstall : *.pl *.pm
+perl_DATA = commands-handler.pl commands-perl.pl convert_commands.pl \
+ puke.pl small.pl test.pl tester.pl \
+ dcc_progress.pm dcc_status.pm load_all.pm \
+ palistbox.pm pbase.pm pboxlayout.pm pbutton.pm pframe.pm \
+ pkfiledialog.pm plabel.pm plined.pm plistbox.pm pmenudta.pm \
+ ppopmenu.pm pprogress.pm ppushbt.pm ptabdialog.pm ptablevw.pm \
+ pwidget.pm pobjfinder.pm
+
+# Where to install them
+perldir = $(kde_datadir)/ksirc
+
diff --git a/ksirc/puke/commands-handler.pl b/ksirc/puke/commands-handler.pl
new file mode 100644
index 00000000..191353cf
--- /dev/null
+++ b/ksirc/puke/commands-handler.pl
@@ -0,0 +1,61 @@
+sub puke_invalid_cmd {
+ print "*E* Puke: Invalid command 0 ack'ed\n";
+ #
+ # Stop waiting, things are messed up
+ #
+ $wait = 0;
+}
+$PUKE_DEF_HANDLER{"$PUKE_INVALID"} = \&puke_invalid_cmd;
+
+
+#sub puke_widget_create_ack {
+# my %ARG = %{$_[0]};
+#
+# $ARG{cArg} =~ /^(.{8,8})/;
+# my $string = $1;
+#
+# if($PUKE_CREATOR{$string}){
+# &{$PUKE_CREATOR{$string}}(%ARG); # added %ARG
+# }
+# else {
+# print "*E* Widget created: $string but no handler\n";
+# }
+#}
+
+#$PUKE_DEF_HANDLER{"$PUKE_WIDGET_CREATE_ACK"} = \&puke_widget_create_ack;
+#$PUKE_DEF_HANDLER{"$PUKE_LAYOUT_NEW_ACK"} = \&puke_widget_create_ack;
+
+
+# By default we ignore all the EVENT's we get sent at us.
+
+$PUKE_DEF_HANDLER{"$PUKE_WIDGET_EVENT_NONE"} = sub {};
+$PUKE_DEF_HANDLER{"$PUKE_WIDGET_EVENT_TIME"} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_MOUSEBUTTONPRESS} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_MOUSEBUTTONRELEASE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_MOUSEDBLCLICK} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_MOUSEMOVE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_KEYPRESS} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_KEYRELEASE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_KEYPRESS} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_FOCUSIN} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_FOCUSOUT} = sub {};
+$PUKE_DEF_HANDLER{"$PUKE_WIDGET_EVENT_ENTER"} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_LEAVE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_PAINT} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_MOVE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_RESIZE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_CREATE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_DESTORY} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_SHOW} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_HIDE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_CLOSE} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_EVENT_TIMER} = sub {};
+
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_RESIZE_ACK} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_REPAINT_ACK} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_MOVE_ACK} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_SHOW_ACK} = sub {};
+$PUKE_DEF_HANDLER{$PUKE_WIDGET_HIDE_ACK} = sub {};
+
+$PUKE_DEF_HANDLER{$PUKE_LINED_SET_TEXT_ACK} = sub {};
+1;
diff --git a/ksirc/puke/commands-perl.pl b/ksirc/puke/commands-perl.pl
new file mode 100644
index 00000000..1499daa9
--- /dev/null
+++ b/ksirc/puke/commands-perl.pl
@@ -0,0 +1,605 @@
+$PUKE_INVALID = 0;
+$PUKE_NAME2NUM{'PUKE_INVALID'} = 0;
+$PUKE_NUM2NAME{'0'} = 'PUKE_INVALID';
+$PUKE_SETUP = 1;
+$PUKE_NAME2NUM{'PUKE_SETUP'} = 1;
+$PUKE_NUM2NAME{'1'} = 'PUKE_SETUP';
+$PUKE_SETUP_ACK = -1;
+$PUKE_NAME2NUM{'PUKE_SETUP_ACK'} = -1;
+$PUKE_NUM2NAME{'-1'} = 'PUKE_SETUP_ACK';
+$PUKE_ECHO = 5;
+$PUKE_NAME2NUM{'PUKE_ECHO'} = 5;
+$PUKE_NUM2NAME{'5'} = 'PUKE_ECHO';
+$PUKE_ECHO_ACK = -5;
+$PUKE_NAME2NUM{'PUKE_ECHO_ACK'} = -5;
+$PUKE_NUM2NAME{'-5'} = 'PUKE_ECHO_ACK';
+$PUKE_EVENT_UNKOWN = -999;
+$PUKE_NAME2NUM{'PUKE_EVENT_UNKOWN'} = -999;
+$PUKE_NUM2NAME{'-999'} = 'PUKE_EVENT_UNKOWN';
+$PUKE_DUMPTREE = 997;
+$PUKE_NAME2NUM{'PUKE_DUMPTREE'} = 997;
+$PUKE_NUM2NAME{'997'} = 'PUKE_DUMPTREE';
+$PUKE_DUMPTREE_ACK = -997;
+$PUKE_NAME2NUM{'PUKE_DUMPTREE_ACK'} = -997;
+$PUKE_NUM2NAME{'-997'} = 'PUKE_DUMPTREE_ACK';
+$PUKE_RELEASEWIDGET = 996;
+$PUKE_NAME2NUM{'PUKE_RELEASEWIDGET'} = 996;
+$PUKE_NUM2NAME{'996'} = 'PUKE_RELEASEWIDGET';
+$PUKE_RELEASEWIDGET_ACK = -996;
+$PUKE_NAME2NUM{'PUKE_RELEASEWIDGET_ACK'} = -996;
+$PUKE_NUM2NAME{'-996'} = 'PUKE_RELEASEWIDGET_ACK';
+$PUKE_FETCHWIDGET = 998;
+$PUKE_NAME2NUM{'PUKE_FETCHWIDGET'} = 998;
+$PUKE_NUM2NAME{'998'} = 'PUKE_FETCHWIDGET';
+$PUKE_FETCHWIDGET_ACK = -998;
+$PUKE_NAME2NUM{'PUKE_FETCHWIDGET_ACK'} = -998;
+$PUKE_NUM2NAME{'-998'} = 'PUKE_FETCHWIDGET_ACK';
+$PUKE_WIDGET_CREATE = 1000;
+$PUKE_NAME2NUM{'PUKE_WIDGET_CREATE'} = 1000;
+$PUKE_NUM2NAME{'1000'} = 'PUKE_WIDGET_CREATE';
+$PUKE_WIDGET_CREATE_ACK = -1000;
+$PUKE_NAME2NUM{'PUKE_WIDGET_CREATE_ACK'} = -1000;
+$PUKE_NUM2NAME{'-1000'} = 'PUKE_WIDGET_CREATE_ACK';
+$PUKE_WIDGET_DELETE = 1001;
+$PUKE_NAME2NUM{'PUKE_WIDGET_DELETE'} = 1001;
+$PUKE_NUM2NAME{'1001'} = 'PUKE_WIDGET_DELETE';
+$PUKE_WIDGET_DELETE_ACK = -1001;
+$PUKE_NAME2NUM{'PUKE_WIDGET_DELETE_ACK'} = -1001;
+$PUKE_NUM2NAME{'-1001'} = 'PUKE_WIDGET_DELETE_ACK';
+$PUKE_WIDGET_SHOW = 1002;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SHOW'} = 1002;
+$PUKE_NUM2NAME{'1002'} = 'PUKE_WIDGET_SHOW';
+$PUKE_WIDGET_SHOW_ACK = -1002;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SHOW_ACK'} = -1002;
+$PUKE_NUM2NAME{'-1002'} = 'PUKE_WIDGET_SHOW_ACK';
+$PUKE_WIDGET_HIDE = 1003;
+$PUKE_NAME2NUM{'PUKE_WIDGET_HIDE'} = 1003;
+$PUKE_NUM2NAME{'1003'} = 'PUKE_WIDGET_HIDE';
+$PUKE_WIDGET_HIDE_ACK = -1003;
+$PUKE_NAME2NUM{'PUKE_WIDGET_HIDE_ACK'} = -1003;
+$PUKE_NUM2NAME{'-1003'} = 'PUKE_WIDGET_HIDE_ACK';
+$PUKE_WIDGET_REPAINT = 1005;
+$PUKE_NAME2NUM{'PUKE_WIDGET_REPAINT'} = 1005;
+$PUKE_NUM2NAME{'1005'} = 'PUKE_WIDGET_REPAINT';
+$PUKE_WIDGET_REPAINT_ACK = -1005;
+$PUKE_NAME2NUM{'PUKE_WIDGET_REPAINT_ACK'} = -1005;
+$PUKE_NUM2NAME{'-1005'} = 'PUKE_WIDGET_REPAINT_ACK';
+$PUKE_WIDGET_UPDATE = 1010;
+$PUKE_NAME2NUM{'PUKE_WIDGET_UPDATE'} = 1010;
+$PUKE_NUM2NAME{'1010'} = 'PUKE_WIDGET_UPDATE';
+$PUKE_WIDGET_UPDATE_ACK = -1010;
+$PUKE_NAME2NUM{'PUKE_WIDGET_UPDATE_ACK'} = -1010;
+$PUKE_NUM2NAME{'-1010'} = 'PUKE_WIDGET_UPDATE_ACK';
+$PUKE_WIDGET_RESIZE = 1015;
+$PUKE_NAME2NUM{'PUKE_WIDGET_RESIZE'} = 1015;
+$PUKE_NUM2NAME{'1015'} = 'PUKE_WIDGET_RESIZE';
+$PUKE_WIDGET_RESIZE_ACK = -1015;
+$PUKE_NAME2NUM{'PUKE_WIDGET_RESIZE_ACK'} = -1015;
+$PUKE_NUM2NAME{'-1015'} = 'PUKE_WIDGET_RESIZE_ACK';
+$PUKE_WIDGET_EVENT_NONE = -1020;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_NONE'} = -1020;
+$PUKE_NUM2NAME{'-1020'} = 'PUKE_WIDGET_EVENT_NONE';
+$PUKE_WIDGET_EVENT_TIMER = -1021;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_TIMER'} = -1021;
+$PUKE_NUM2NAME{'-1021'} = 'PUKE_WIDGET_EVENT_TIMER';
+$PUKE_WIDGET_EVENT_MOUSEBUTTONPRESS = -1022;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_MOUSEBUTTONPRESS'} = -1022;
+$PUKE_NUM2NAME{'-1022'} = 'PUKE_WIDGET_EVENT_MOUSEBUTTONPRESS';
+$PUKE_WIDGET_EVENT_MOUSEBUTTONRELEASE = -1023;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_MOUSEBUTTONRELEASE'} = -1023;
+$PUKE_NUM2NAME{'-1023'} = 'PUKE_WIDGET_EVENT_MOUSEBUTTONRELEASE';
+$PUKE_WIDGET_EVENT_MOUSEDBLCLICK = -1024;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_MOUSEDBLCLICK'} = -1024;
+$PUKE_NUM2NAME{'-1024'} = 'PUKE_WIDGET_EVENT_MOUSEDBLCLICK';
+$PUKE_WIDGET_EVENT_MOUSEMOVE = -1025;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_MOUSEMOVE'} = -1025;
+$PUKE_NUM2NAME{'-1025'} = 'PUKE_WIDGET_EVENT_MOUSEMOVE';
+$PUKE_WIDGET_EVENT_KEYPRESS = -1026;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_KEYPRESS'} = -1026;
+$PUKE_NUM2NAME{'-1026'} = 'PUKE_WIDGET_EVENT_KEYPRESS';
+$PUKE_WIDGET_EVENT_KEYRELEASE = -1027;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_KEYRELEASE'} = -1027;
+$PUKE_NUM2NAME{'-1027'} = 'PUKE_WIDGET_EVENT_KEYRELEASE';
+$PUKE_WIDGET_EVENT_FOCUSIN = -1028;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_FOCUSIN'} = -1028;
+$PUKE_NUM2NAME{'-1028'} = 'PUKE_WIDGET_EVENT_FOCUSIN';
+$PUKE_WIDGET_EVENT_FOCUSOUT = -1029;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_FOCUSOUT'} = -1029;
+$PUKE_NUM2NAME{'-1029'} = 'PUKE_WIDGET_EVENT_FOCUSOUT';
+$PUKE_WIDGET_EVENT_ENTER = -1030;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_ENTER'} = -1030;
+$PUKE_NUM2NAME{'-1030'} = 'PUKE_WIDGET_EVENT_ENTER';
+$PUKE_WIDGET_EVENT_LEAVE = -1031;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_LEAVE'} = -1031;
+$PUKE_NUM2NAME{'-1031'} = 'PUKE_WIDGET_EVENT_LEAVE';
+$PUKE_WIDGET_EVENT_PAINT = -1032;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_PAINT'} = -1032;
+$PUKE_NUM2NAME{'-1032'} = 'PUKE_WIDGET_EVENT_PAINT';
+$PUKE_WIDGET_EVENT_MOVE = -1033;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_MOVE'} = -1033;
+$PUKE_NUM2NAME{'-1033'} = 'PUKE_WIDGET_EVENT_MOVE';
+$PUKE_WIDGET_EVENT_RESIZE = -1034;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_RESIZE'} = -1034;
+$PUKE_NUM2NAME{'-1034'} = 'PUKE_WIDGET_EVENT_RESIZE';
+$PUKE_WIDGET_EVENT_CREATE = -1035 ;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_CREATE'} = -1035 ;
+$PUKE_NUM2NAME{'-1035 '} = 'PUKE_WIDGET_EVENT_CREATE';
+$PUKE_WIDGET_EVENT_DESTROY = -1036;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_DESTROY'} = -1036;
+$PUKE_NUM2NAME{'-1036'} = 'PUKE_WIDGET_EVENT_DESTROY';
+$PUKE_WIDGET_EVENT_SHOW = -1037 ;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_SHOW'} = -1037 ;
+$PUKE_NUM2NAME{'-1037 '} = 'PUKE_WIDGET_EVENT_SHOW';
+$PUKE_WIDGET_EVENT_HIDE = -1038 ;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_HIDE'} = -1038 ;
+$PUKE_NUM2NAME{'-1038 '} = 'PUKE_WIDGET_EVENT_HIDE';
+$PUKE_WIDGET_EVENT_CLOSE = -1039 ;
+$PUKE_NAME2NUM{'PUKE_WIDGET_EVENT_CLOSE'} = -1039 ;
+$PUKE_NUM2NAME{'-1039 '} = 'PUKE_WIDGET_EVENT_CLOSE';
+$PUKE_WIDGET_MOVE = 1050;
+$PUKE_NAME2NUM{'PUKE_WIDGET_MOVE'} = 1050;
+$PUKE_NUM2NAME{'1050'} = 'PUKE_WIDGET_MOVE';
+$PUKE_WIDGET_MOVE_ACK = -1050;
+$PUKE_NAME2NUM{'PUKE_WIDGET_MOVE_ACK'} = -1050;
+$PUKE_NUM2NAME{'-1050'} = 'PUKE_WIDGET_MOVE_ACK';
+$PUKE_WIDGET_LOAD = 1055;
+$PUKE_NAME2NUM{'PUKE_WIDGET_LOAD'} = 1055;
+$PUKE_NUM2NAME{'1055'} = 'PUKE_WIDGET_LOAD';
+$PUKE_WIDGET_LOAD_ACK = -1055;
+$PUKE_NAME2NUM{'PUKE_WIDGET_LOAD_ACK'} = -1055;
+$PUKE_NUM2NAME{'-1055'} = 'PUKE_WIDGET_LOAD_ACK';
+$PUKE_WIDGET_UNLOAD = 1060;
+$PUKE_NAME2NUM{'PUKE_WIDGET_UNLOAD'} = 1060;
+$PUKE_NUM2NAME{'1060'} = 'PUKE_WIDGET_UNLOAD';
+$PUKE_WIDGET_UNLOAD_ACK = -1060;
+$PUKE_NAME2NUM{'PUKE_WIDGET_UNLOAD_ACK'} = -1060;
+$PUKE_NUM2NAME{'-1060'} = 'PUKE_WIDGET_UNLOAD_ACK';
+$PUKE_WIDGET_SETMINSIZE = 1065;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SETMINSIZE'} = 1065;
+$PUKE_NUM2NAME{'1065'} = 'PUKE_WIDGET_SETMINSIZE';
+$PUKE_WIDGET_SETMINSIZE_ACK = -1065;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SETMINSIZE_ACK'} = -1065;
+$PUKE_NUM2NAME{'-1065'} = 'PUKE_WIDGET_SETMINSIZE_ACK';
+$PUKE_WIDGET_SETMAXSIZE = 1070;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SETMAXSIZE'} = 1070;
+$PUKE_NUM2NAME{'1070'} = 'PUKE_WIDGET_SETMAXSIZE';
+$PUKE_WIDGET_SETMAXSIZE_ACK = -1070;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SETMAXSIZE_ACK'} = -1070;
+$PUKE_NUM2NAME{'-1070'} = 'PUKE_WIDGET_SETMAXSIZE_ACK';
+$PUKE_WIDGET_SETCAPTION = 1075;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SETCAPTION'} = 1075;
+$PUKE_NUM2NAME{'1075'} = 'PUKE_WIDGET_SETCAPTION';
+$PUKE_WIDGET_SETCAPTION_ACK = -1075;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SETCAPTION_ACK'} = -1075;
+$PUKE_NUM2NAME{'-1075'} = 'PUKE_WIDGET_SETCAPTION_ACK';
+$PUKE_WIDGET_GET_BACKGROUND_COLOUR = 1080;
+$PUKE_NAME2NUM{'PUKE_WIDGET_GET_BACKGROUND_COLOUR'} = 1080;
+$PUKE_NUM2NAME{'1080'} = 'PUKE_WIDGET_GET_BACKGROUND_COLOUR';
+$PUKE_WIDGET_GET_BACKGROUND_COLOUR_ACK = -1080;
+$PUKE_NAME2NUM{'PUKE_WIDGET_GET_BACKGROUND_COLOUR_ACK'} = -1080;
+$PUKE_NUM2NAME{'-1080'} = 'PUKE_WIDGET_GET_BACKGROUND_COLOUR_ACK';
+$PUKE_WIDGET_SET_BACKGROUND_COLOUR = 1085;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_BACKGROUND_COLOUR'} = 1085;
+$PUKE_NUM2NAME{'1085'} = 'PUKE_WIDGET_SET_BACKGROUND_COLOUR';
+$PUKE_WIDGET_SET_BACKGROUND_COLOUR_ACK = -1085;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_BACKGROUND_COLOUR_ACK'} = -1085;
+$PUKE_NUM2NAME{'-1085'} = 'PUKE_WIDGET_SET_BACKGROUND_COLOUR_ACK';
+$PUKE_WIDGET_SET_BACKGROUND_PIXMAP = 1086;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_BACKGROUND_PIXMAP'} = 1086;
+$PUKE_NUM2NAME{'1086'} = 'PUKE_WIDGET_SET_BACKGROUND_PIXMAP';
+$PUKE_WIDGET_SET_BACKGROUND_PIXMAP_ACK = -1086;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_BACKGROUND_PIXMAP_ACK'} = -1086;
+$PUKE_NUM2NAME{'-1086'} = 'PUKE_WIDGET_SET_BACKGROUND_PIXMAP_ACK';
+$PUKE_WIDGET_SET_BACKGROUND_MODE = 1087;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_BACKGROUND_MODE'} = 1087;
+$PUKE_NUM2NAME{'1087'} = 'PUKE_WIDGET_SET_BACKGROUND_MODE';
+$PUKE_WIDGET_SET_BACKGROUND_MODE_ACK = -1087;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_BACKGROUND_MODE_ACK'} = -1087;
+$PUKE_NUM2NAME{'-1087'} = 'PUKE_WIDGET_SET_BACKGROUND_MODE_ACK';
+$PUKE_WIDGET_SET_ENABLED = 1090;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_ENABLED'} = 1090;
+$PUKE_NUM2NAME{'1090'} = 'PUKE_WIDGET_SET_ENABLED';
+$PUKE_WIDGET_SET_ENABLED_ACK = -1090;
+$PUKE_NAME2NUM{'PUKE_WIDGET_SET_ENABLED_ACK'} = -1090;
+$PUKE_NUM2NAME{'-1090'} = 'PUKE_WIDGET_SET_ENABLED_ACK';
+$PUKE_WIDGET_RECREATE = 1091;
+$PUKE_NAME2NUM{'PUKE_WIDGET_RECREATE'} = 1091;
+$PUKE_NUM2NAME{'1091'} = 'PUKE_WIDGET_RECREATE';
+$PUKE_WIDGET_RECREATE_ACK = -1091;
+$PUKE_NAME2NUM{'PUKE_WIDGET_RECREATE_ACK'} = -1091;
+$PUKE_NUM2NAME{'-1091'} = 'PUKE_WIDGET_RECREATE_ACK';
+$PUKE_QFRAME_SET_FRAME = 1100;
+$PUKE_NAME2NUM{'PUKE_QFRAME_SET_FRAME'} = 1100;
+$PUKE_NUM2NAME{'1100'} = 'PUKE_QFRAME_SET_FRAME';
+$PUKE_QFRAME_SET_FRAME_ACK = -1100;
+$PUKE_NAME2NUM{'PUKE_QFRAME_SET_FRAME_ACK'} = -1100;
+$PUKE_NUM2NAME{'-1100'} = 'PUKE_QFRAME_SET_FRAME_ACK';
+$PUKE_QFRAME_SET_LINEWIDTH = 1105;
+$PUKE_NAME2NUM{'PUKE_QFRAME_SET_LINEWIDTH'} = 1105;
+$PUKE_NUM2NAME{'1105'} = 'PUKE_QFRAME_SET_LINEWIDTH';
+$PUKE_QFRAME_SET_LINEWIDTH_ACK = -1105;
+$PUKE_NAME2NUM{'PUKE_QFRAME_SET_LINEWIDTH_ACK'} = -1105;
+$PUKE_NUM2NAME{'-1105'} = 'PUKE_QFRAME_SET_LINEWIDTH_ACK';
+$PUKE_LINED_SET_MAXLENGTH = 1200;
+$PUKE_NAME2NUM{'PUKE_LINED_SET_MAXLENGTH'} = 1200;
+$PUKE_NUM2NAME{'1200'} = 'PUKE_LINED_SET_MAXLENGTH';
+$PUKE_LINED_SET_MAXLENGTH_ACK = -1200;
+$PUKE_NAME2NUM{'PUKE_LINED_SET_MAXLENGTH_ACK'} = -1200;
+$PUKE_NUM2NAME{'-1200'} = 'PUKE_LINED_SET_MAXLENGTH_ACK';
+$PUKE_LINED_SET_ECHOMODE = 1205;
+$PUKE_NAME2NUM{'PUKE_LINED_SET_ECHOMODE'} = 1205;
+$PUKE_NUM2NAME{'1205'} = 'PUKE_LINED_SET_ECHOMODE';
+$PUKE_LINED_SET_ECHOMODE_ACK = -1205;
+$PUKE_NAME2NUM{'PUKE_LINED_SET_ECHOMODE_ACK'} = -1205;
+$PUKE_NUM2NAME{'-1205'} = 'PUKE_LINED_SET_ECHOMODE_ACK';
+$PUKE_LINED_SET_TEXT = 1210;
+$PUKE_NAME2NUM{'PUKE_LINED_SET_TEXT'} = 1210;
+$PUKE_NUM2NAME{'1210'} = 'PUKE_LINED_SET_TEXT';
+$PUKE_LINED_SET_TEXT_ACK = -1210;
+$PUKE_NAME2NUM{'PUKE_LINED_SET_TEXT_ACK'} = -1210;
+$PUKE_NUM2NAME{'-1210'} = 'PUKE_LINED_SET_TEXT_ACK';
+$PUKE_LINED_GET_TEXT = 1215;
+$PUKE_NAME2NUM{'PUKE_LINED_GET_TEXT'} = 1215;
+$PUKE_NUM2NAME{'1215'} = 'PUKE_LINED_GET_TEXT';
+$PUKE_LINED_GET_TEXT_ACK = -1215;
+$PUKE_NAME2NUM{'PUKE_LINED_GET_TEXT_ACK'} = -1215;
+$PUKE_NUM2NAME{'-1215'} = 'PUKE_LINED_GET_TEXT_ACK';
+$PUKE_LINED_RETURN_PRESSED = 1220;
+$PUKE_NAME2NUM{'PUKE_LINED_RETURN_PRESSED'} = 1220;
+$PUKE_NUM2NAME{'1220'} = 'PUKE_LINED_RETURN_PRESSED';
+$PUKE_LINED_RETURN_PRESSED_ACK = -1220;
+$PUKE_NAME2NUM{'PUKE_LINED_RETURN_PRESSED_ACK'} = -1220;
+$PUKE_NUM2NAME{'-1220'} = 'PUKE_LINED_RETURN_PRESSED_ACK';
+$PUKE_BUTTON_SET_TEXT = 1300;
+$PUKE_NAME2NUM{'PUKE_BUTTON_SET_TEXT'} = 1300;
+$PUKE_NUM2NAME{'1300'} = 'PUKE_BUTTON_SET_TEXT';
+$PUKE_BUTTON_SET_TEXT_ACK = -1300;
+$PUKE_NAME2NUM{'PUKE_BUTTON_SET_TEXT_ACK'} = -1300;
+$PUKE_NUM2NAME{'-1300'} = 'PUKE_BUTTON_SET_TEXT_ACK';
+$PUKE_BUTTON_SET_PIXMAP = 1305;
+$PUKE_NAME2NUM{'PUKE_BUTTON_SET_PIXMAP'} = 1305;
+$PUKE_NUM2NAME{'1305'} = 'PUKE_BUTTON_SET_PIXMAP';
+$PUKE_BUTTON_SET_PIXMAP_ACK = -1305;
+$PUKE_NAME2NUM{'PUKE_BUTTON_SET_PIXMAP_ACK'} = -1305;
+$PUKE_NUM2NAME{'-1305'} = 'PUKE_BUTTON_SET_PIXMAP_ACK';
+$PUKE_BUTTON_SET_AUTORESIZE = 1310;
+$PUKE_NAME2NUM{'PUKE_BUTTON_SET_AUTORESIZE'} = 1310;
+$PUKE_NUM2NAME{'1310'} = 'PUKE_BUTTON_SET_AUTORESIZE';
+$PUKE_BUTTON_SET_AUTORESIZE_ACK = -1310;
+$PUKE_NAME2NUM{'PUKE_BUTTON_SET_AUTORESIZE_ACK'} = -1310;
+$PUKE_NUM2NAME{'-1310'} = 'PUKE_BUTTON_SET_AUTORESIZE_ACK';
+$PUKE_BUTTON_PRESSED = 1350;
+$PUKE_NAME2NUM{'PUKE_BUTTON_PRESSED'} = 1350;
+$PUKE_NUM2NAME{'1350'} = 'PUKE_BUTTON_PRESSED';
+$PUKE_BUTTON_PRESSED_ACK = -1350;
+$PUKE_NAME2NUM{'PUKE_BUTTON_PRESSED_ACK'} = -1350;
+$PUKE_NUM2NAME{'-1350'} = 'PUKE_BUTTON_PRESSED_ACK';
+$PUKE_BUTTON_RELEASED = 1351;
+$PUKE_NAME2NUM{'PUKE_BUTTON_RELEASED'} = 1351;
+$PUKE_NUM2NAME{'1351'} = 'PUKE_BUTTON_RELEASED';
+$PUKE_BUTTON_RELEASED_ACK = -1351;
+$PUKE_NAME2NUM{'PUKE_BUTTON_RELEASED_ACK'} = -1351;
+$PUKE_NUM2NAME{'-1351'} = 'PUKE_BUTTON_RELEASED_ACK';
+$PUKE_BUTTON_CLICKED = 1352;
+$PUKE_NAME2NUM{'PUKE_BUTTON_CLICKED'} = 1352;
+$PUKE_NUM2NAME{'1352'} = 'PUKE_BUTTON_CLICKED';
+$PUKE_BUTTON_CLICKED_ACK = -1352;
+$PUKE_NAME2NUM{'PUKE_BUTTON_CLICKED_ACK'} = -1352;
+$PUKE_NUM2NAME{'-1352'} = 'PUKE_BUTTON_CLICKED_ACK';
+$PUKE_BUTTON_TOGGLED = 1353;
+$PUKE_NAME2NUM{'PUKE_BUTTON_TOGGLED'} = 1353;
+$PUKE_NUM2NAME{'1353'} = 'PUKE_BUTTON_TOGGLED';
+$PUKE_BUTTON_TOGGLED_ACK = -1353;
+$PUKE_NAME2NUM{'PUKE_BUTTON_TOGGLED_ACK'} = -1353;
+$PUKE_NUM2NAME{'-1353'} = 'PUKE_BUTTON_TOGGLED_ACK';
+$PUKE_KSPROGRESS_SET_RANGE = 1400;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_RANGE'} = 1400;
+$PUKE_NUM2NAME{'1400'} = 'PUKE_KSPROGRESS_SET_RANGE';
+$PUKE_KSPROGRESS_SET_RANGE_ACK = -1400;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_RANGE_ACK'} = -1400;
+$PUKE_NUM2NAME{'-1400'} = 'PUKE_KSPROGRESS_SET_RANGE_ACK';
+$PUKE_KSPROGRESS_SET_TOPTEXT = 1410;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_TOPTEXT'} = 1410;
+$PUKE_NUM2NAME{'1410'} = 'PUKE_KSPROGRESS_SET_TOPTEXT';
+$PUKE_KSPROGRESS_SET_TOPTEXT_ACK = -1410;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_TOPTEXT_ACK'} = -1410;
+$PUKE_NUM2NAME{'-1410'} = 'PUKE_KSPROGRESS_SET_TOPTEXT_ACK';
+$PUKE_KSPROGRESS_SET_BOTTEXT = 1415;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_BOTTEXT'} = 1415;
+$PUKE_NUM2NAME{'1415'} = 'PUKE_KSPROGRESS_SET_BOTTEXT';
+$PUKE_KSPROGRESS_SET_BOTTEXT_ACK = -1415;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_BOTTEXT_ACK'} = -1415;
+$PUKE_NUM2NAME{'-1415'} = 'PUKE_KSPROGRESS_SET_BOTTEXT_ACK';
+$PUKE_KSPROGRESS_SET_VALUE = 1420;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_VALUE'} = 1420;
+$PUKE_NUM2NAME{'1420'} = 'PUKE_KSPROGRESS_SET_VALUE';
+$PUKE_KSPROGRESS_SET_VALUE_ACK = -1420;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_SET_VALUE_ACK'} = -1420;
+$PUKE_NUM2NAME{'-1420'} = 'PUKE_KSPROGRESS_SET_VALUE_ACK';
+$PUKE_KSPROGRESS_CANCEL = 1425;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_CANCEL'} = 1425;
+$PUKE_NUM2NAME{'1425'} = 'PUKE_KSPROGRESS_CANCEL';
+$PUKE_KSPROGRESS_CANCEL_ACK = -1425;
+$PUKE_NAME2NUM{'PUKE_KSPROGRESS_CANCEL_ACK'} = -1425;
+$PUKE_NUM2NAME{'-1425'} = 'PUKE_KSPROGRESS_CANCEL_ACK';
+$PUKE_LISTBOX_INSERT = 1600;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_INSERT'} = 1600;
+$PUKE_NUM2NAME{'1600'} = 'PUKE_LISTBOX_INSERT';
+$PUKE_LISTBOX_INSERT_ACK = -1600;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_INSERT_ACK'} = -1600;
+$PUKE_NUM2NAME{'-1600'} = 'PUKE_LISTBOX_INSERT_ACK';
+$PUKE_LISTBOX_INSERT_SORT = 1605;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_INSERT_SORT'} = 1605;
+$PUKE_NUM2NAME{'1605'} = 'PUKE_LISTBOX_INSERT_SORT';
+$PUKE_LISTBOX_INSERT_SORT_ACK = -1605;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_INSERT_SORT_ACK'} = -1605;
+$PUKE_NUM2NAME{'-1605'} = 'PUKE_LISTBOX_INSERT_SORT_ACK';
+$PUKE_LISTBOX_INSERT_PIXMAP = 1610;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_INSERT_PIXMAP'} = 1610;
+$PUKE_NUM2NAME{'1610'} = 'PUKE_LISTBOX_INSERT_PIXMAP';
+$PUKE_LISTBOX_INSERT_PIXMAP_ACK = -1610;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_INSERT_PIXMAP_ACK'} = -1610;
+$PUKE_NUM2NAME{'-1610'} = 'PUKE_LISTBOX_INSERT_PIXMAP_ACK';
+$PUKE_LISTBOX_HIGHLIGHT = 1615;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_HIGHLIGHT'} = 1615;
+$PUKE_NUM2NAME{'1615'} = 'PUKE_LISTBOX_HIGHLIGHT';
+$PUKE_LISTBOX_HIGHLIGHT_ACK = -1615;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_HIGHLIGHT_ACK'} = -1615;
+$PUKE_NUM2NAME{'-1615'} = 'PUKE_LISTBOX_HIGHLIGHT_ACK';
+$PUKE_LISTBOX_REMOVE = 1620;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_REMOVE'} = 1620;
+$PUKE_NUM2NAME{'1620'} = 'PUKE_LISTBOX_REMOVE';
+$PUKE_LISTBOX_REMOVE_ACK = -1620;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_REMOVE_ACK'} = -1620;
+$PUKE_NUM2NAME{'-1620'} = 'PUKE_LISTBOX_REMOVE_ACK';
+$PUKE_LISTBOX_GETTEXT = 1625;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_GETTEXT'} = 1625;
+$PUKE_NUM2NAME{'1625'} = 'PUKE_LISTBOX_GETTEXT';
+$PUKE_LISTBOX_GETTEXT_ACK = -1625 ;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_GETTEXT_ACK'} = -1625 ;
+$PUKE_NUM2NAME{'-1625 '} = 'PUKE_LISTBOX_GETTEXT_ACK';
+$PUKE_LISTBOX_CLEAR = 1630;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_CLEAR'} = 1630;
+$PUKE_NUM2NAME{'1630'} = 'PUKE_LISTBOX_CLEAR';
+$PUKE_LISTBOX_CLEAR_ACK = -1630;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_CLEAR_ACK'} = -1630;
+$PUKE_NUM2NAME{'-1630'} = 'PUKE_LISTBOX_CLEAR_ACK';
+$PUKE_LISTBOX_SET_SCROLLBAR = 1635;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_SET_SCROLLBAR'} = 1635;
+$PUKE_NUM2NAME{'1635'} = 'PUKE_LISTBOX_SET_SCROLLBAR';
+$PUKE_LISTBOX_SET_SCROLLBAR_ACK = -1635;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_SET_SCROLLBAR_ACK'} = -1635;
+$PUKE_NUM2NAME{'-1635'} = 'PUKE_LISTBOX_SET_SCROLLBAR_ACK';
+$PUKE_LISTBOX_SET_AUTO_SCROLLBAR = 1636;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_SET_AUTO_SCROLLBAR'} = 1636;
+$PUKE_NUM2NAME{'1636'} = 'PUKE_LISTBOX_SET_AUTO_SCROLLBAR';
+$PUKE_LISTBOX_SET_AUTO_SCROLLBAR_ACK = -1636;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_SET_AUTO_SCROLLBAR_ACK'} = -1636;
+$PUKE_NUM2NAME{'-1636'} = 'PUKE_LISTBOX_SET_AUTO_SCROLLBAR_ACK';
+$PUKE_LISTBOX_HIGHLIGHTED = 1690;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_HIGHLIGHTED'} = 1690;
+$PUKE_NUM2NAME{'1690'} = 'PUKE_LISTBOX_HIGHLIGHTED';
+$PUKE_LISTBOX_HIGHLIGHTED_ACK = -1690;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_HIGHLIGHTED_ACK'} = -1690;
+$PUKE_NUM2NAME{'-1690'} = 'PUKE_LISTBOX_HIGHLIGHTED_ACK';
+$PUKE_LISTBOX_SELECTED = 1690;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_SELECTED'} = 1690;
+$PUKE_NUM2NAME{'1690'} = 'PUKE_LISTBOX_SELECTED';
+$PUKE_LISTBOX_SELECTED_ACK = -1690;
+$PUKE_NAME2NUM{'PUKE_LISTBOX_SELECTED_ACK'} = -1690;
+$PUKE_NUM2NAME{'-1690'} = 'PUKE_LISTBOX_SELECTED_ACK';
+$PUKE_LABEL_SETTEXT = 1700;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETTEXT'} = 1700;
+$PUKE_NUM2NAME{'1700'} = 'PUKE_LABEL_SETTEXT';
+$PUKE_LABEL_SETTEXT_ACK = -1700;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETTEXT_ACK'} = -1700;
+$PUKE_NUM2NAME{'-1700'} = 'PUKE_LABEL_SETTEXT_ACK';
+$PUKE_LABEL_SETPIXMAP = 1705;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETPIXMAP'} = 1705;
+$PUKE_NUM2NAME{'1705'} = 'PUKE_LABEL_SETPIXMAP';
+$PUKE_LABEL_SETPIXMAP_ACK = -1705;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETPIXMAP_ACK'} = -1705;
+$PUKE_NUM2NAME{'-1705'} = 'PUKE_LABEL_SETPIXMAP_ACK';
+$PUKE_LABEL_SETMOVIE = 1710;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETMOVIE'} = 1710;
+$PUKE_NUM2NAME{'1710'} = 'PUKE_LABEL_SETMOVIE';
+$PUKE_LABEL_SETMOVIE_ACK = -1710;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETMOVIE_ACK'} = -1710;
+$PUKE_NUM2NAME{'-1710'} = 'PUKE_LABEL_SETMOVIE_ACK';
+$PUKE_LABEL_SETALIGNMENT = 1715;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETALIGNMENT'} = 1715;
+$PUKE_NUM2NAME{'1715'} = 'PUKE_LABEL_SETALIGNMENT';
+$PUKE_LABEL_SETALIGNMENT_ACK = -1715;
+$PUKE_NAME2NUM{'PUKE_LABEL_SETALIGNMENT_ACK'} = -1715;
+$PUKE_NUM2NAME{'-1715'} = 'PUKE_LABEL_SETALIGNMENT_ACK';
+$PUKE_MENUDATA_INSERT_TEXT = 1800;
+$PUKE_NAME2NUM{'PUKE_MENUDATA_INSERT_TEXT'} = 1800;
+$PUKE_NUM2NAME{'1800'} = 'PUKE_MENUDATA_INSERT_TEXT';
+$PUKE_MENUDATA_INSERT_TEXT_ACK = -1800;
+$PUKE_NAME2NUM{'PUKE_MENUDATA_INSERT_TEXT_ACK'} = -1800;
+$PUKE_NUM2NAME{'-1800'} = 'PUKE_MENUDATA_INSERT_TEXT_ACK';
+$PUKE_MENUDATA_INSERT_PIXMAP = 1801;
+$PUKE_NAME2NUM{'PUKE_MENUDATA_INSERT_PIXMAP'} = 1801;
+$PUKE_NUM2NAME{'1801'} = 'PUKE_MENUDATA_INSERT_PIXMAP';
+$PUKE_MENUDATA_INSERT_PIXMAP_ACK = -1801;
+$PUKE_NAME2NUM{'PUKE_MENUDATA_INSERT_PIXMAP_ACK'} = -1801;
+$PUKE_NUM2NAME{'-1801'} = 'PUKE_MENUDATA_INSERT_PIXMAP_ACK';
+$PUKE_POPUPMENU_ACTIVATED = 1805;
+$PUKE_NAME2NUM{'PUKE_POPUPMENU_ACTIVATED'} = 1805;
+$PUKE_NUM2NAME{'1805'} = 'PUKE_POPUPMENU_ACTIVATED';
+$PUKE_POPUPMENU_ACTIVATED_ACK = -1805;
+$PUKE_NAME2NUM{'PUKE_POPUPMENU_ACTIVATED_ACK'} = -1805;
+$PUKE_NUM2NAME{'-1805'} = 'PUKE_POPUPMENU_ACTIVATED_ACK';
+$PUKE_POPUPMENU_POPUP_CURRENT = 1810;
+$PUKE_NAME2NUM{'PUKE_POPUPMENU_POPUP_CURRENT'} = 1810;
+$PUKE_NUM2NAME{'1810'} = 'PUKE_POPUPMENU_POPUP_CURRENT';
+$PUKE_POPUPMENU_POPUP_CURRENT_ACK = -1810;
+$PUKE_NAME2NUM{'PUKE_POPUPMENU_POPUP_CURRENT_ACK'} = -1810;
+$PUKE_NUM2NAME{'-1810'} = 'PUKE_POPUPMENU_POPUP_CURRENT_ACK';
+$PUKE_MENUDATA_REMOVE_ITEM = 1815;
+$PUKE_NAME2NUM{'PUKE_MENUDATA_REMOVE_ITEM'} = 1815;
+$PUKE_NUM2NAME{'1815'} = 'PUKE_MENUDATA_REMOVE_ITEM';
+$PUKE_MENUDATA_REMOVE_ITEM_ACK = -1815;
+$PUKE_NAME2NUM{'PUKE_MENUDATA_REMOVE_ITEM_ACK'} = -1815;
+$PUKE_NUM2NAME{'-1815'} = 'PUKE_MENUDATA_REMOVE_ITEM_ACK';
+$PUKE_ALISTBOX_ISTOP = 1900;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_ISTOP'} = 1900;
+$PUKE_NUM2NAME{'1900'} = 'PUKE_ALISTBOX_ISTOP';
+$PUKE_ALISTBOX_ISTOP_ACK = -1900;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_ISTOP_ACK'} = -1900;
+$PUKE_NUM2NAME{'-1900'} = 'PUKE_ALISTBOX_ISTOP_ACK';
+$PUKE_ALISTBOX_SMALL_HIGHLIGHT = 1905;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_SMALL_HIGHLIGHT'} = 1905;
+$PUKE_NUM2NAME{'1905'} = 'PUKE_ALISTBOX_SMALL_HIGHLIGHT';
+$PUKE_ALISTBOX_SMALL_HIGHLIGHT_ACK = -1905;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_SMALL_HIGHLIGHT_ACK'} = -1905;
+$PUKE_NUM2NAME{'-1905'} = 'PUKE_ALISTBOX_SMALL_HIGHLIGHT_ACK';
+$PUKE_ALISTBOX_BIG_HIGHLIGHT = 1910;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_BIG_HIGHLIGHT'} = 1910;
+$PUKE_NUM2NAME{'1910'} = 'PUKE_ALISTBOX_BIG_HIGHLIGHT';
+$PUKE_ALISTBOX_BIG_HIGHLIGHT_ACK = -1910;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_BIG_HIGHLIGHT_ACK'} = -1910;
+$PUKE_NUM2NAME{'-1910'} = 'PUKE_ALISTBOX_BIG_HIGHLIGHT_ACK';
+$PUKE_ALISTBOX_FIND_NICK = 1915;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_FIND_NICK'} = 1915;
+$PUKE_NUM2NAME{'1915'} = 'PUKE_ALISTBOX_FIND_NICK';
+$PUKE_ALISTBOX_FIND_NICK_ACK = -1915;
+$PUKE_NAME2NUM{'PUKE_ALISTBOX_FIND_NICK_ACK'} = -1915;
+$PUKE_NUM2NAME{'-1915'} = 'PUKE_ALISTBOX_FIND_NICK_ACK';
+$PUKE_TABDIALOG_ADDTAB = 2001;
+$PUKE_NAME2NUM{'PUKE_TABDIALOG_ADDTAB'} = 2001;
+$PUKE_NUM2NAME{'2001'} = 'PUKE_TABDIALOG_ADDTAB';
+$PUKE_TABDIALOG_ADDTAB_ACK = -2001;
+$PUKE_NAME2NUM{'PUKE_TABDIALOG_ADDTAB_ACK'} = -2001;
+$PUKE_NUM2NAME{'-2001'} = 'PUKE_TABDIALOG_ADDTAB_ACK';
+$PUKE_KSIRCLISTBOX_TOBOTTOM = 2100;
+$PUKE_NAME2NUM{'PUKE_KSIRCLISTBOX_TOBOTTOM'} = 2100;
+$PUKE_NUM2NAME{'2100'} = 'PUKE_KSIRCLISTBOX_TOBOTTOM';
+$PUKE_KSIRCLISTBOX_TOBOTTOM_ACK = -2100;
+$PUKE_NAME2NUM{'PUKE_KSIRCLISTBOX_TOBOTTOM_ACK'} = -2100;
+$PUKE_NUM2NAME{'-2100'} = 'PUKE_KSIRCLISTBOX_TOBOTTOM_ACK';
+$PWIDGET_OBJECT = 1;
+$PUKE_NAME2NUM{'PWIDGET_OBJECT'} = 1;
+$PUKE_NUM2NAME{'1'} = 'PWIDGET_OBJECT';
+$PWIDGET_WIDGET = 2;
+$PUKE_NAME2NUM{'PWIDGET_WIDGET'} = 2;
+$PUKE_NUM2NAME{'2'} = 'PWIDGET_WIDGET';
+$PWIDGET_FRAME = 3;
+$PUKE_NAME2NUM{'PWIDGET_FRAME'} = 3;
+$PUKE_NUM2NAME{'3'} = 'PWIDGET_FRAME';
+$PWIDGET_LINED = 4;
+$PUKE_NAME2NUM{'PWIDGET_LINED'} = 4;
+$PUKE_NUM2NAME{'4'} = 'PWIDGET_LINED';
+$PWIDGET_BUTTON = 5;
+$PUKE_NAME2NUM{'PWIDGET_BUTTON'} = 5;
+$PUKE_NUM2NAME{'5'} = 'PWIDGET_BUTTON';
+$PWIDGET_PUSHBT = 6;
+$PUKE_NAME2NUM{'PWIDGET_PUSHBT'} = 6;
+$PUKE_NUM2NAME{'6'} = 'PWIDGET_PUSHBT';
+$PWIDGET_KSPROGRESS = 7;
+$PUKE_NAME2NUM{'PWIDGET_KSPROGRESS'} = 7;
+$PUKE_NUM2NAME{'7'} = 'PWIDGET_KSPROGRESS';
+$PWIDGET_TABLEVW = 8;
+$PUKE_NAME2NUM{'PWIDGET_TABLEVW'} = 8;
+$PUKE_NUM2NAME{'8'} = 'PWIDGET_TABLEVW';
+$PWIDGET_LISTBOX = 9;
+$PUKE_NAME2NUM{'PWIDGET_LISTBOX'} = 9;
+$PUKE_NUM2NAME{'9'} = 'PWIDGET_LISTBOX';
+$PWIDGET_LABEL = 10;
+$PUKE_NAME2NUM{'PWIDGET_LABEL'} = 10;
+$PUKE_NUM2NAME{'10'} = 'PWIDGET_LABEL';
+$POBJECT_LAYOUT = 11;
+$PUKE_NAME2NUM{'POBJECT_LAYOUT'} = 11;
+$PUKE_NUM2NAME{'11'} = 'POBJECT_LAYOUT';
+$PWIDGET_MENUDATA = 12;
+$PUKE_NAME2NUM{'PWIDGET_MENUDATA'} = 12;
+$PUKE_NUM2NAME{'12'} = 'PWIDGET_MENUDATA';
+$PWIDGET_POPMENU = 13;
+$PUKE_NAME2NUM{'PWIDGET_POPMENU'} = 13;
+$PUKE_NUM2NAME{'13'} = 'PWIDGET_POPMENU';
+$PWIDGET_ALISTBOX = 14;
+$PUKE_NAME2NUM{'PWIDGET_ALISTBOX'} = 14;
+$PUKE_NUM2NAME{'14'} = 'PWIDGET_ALISTBOX';
+$PWIDGET_KSIRCLISTBOX = 15;
+$PUKE_NAME2NUM{'PWIDGET_KSIRCLISTBOX'} = 15;
+$PUKE_NUM2NAME{'15'} = 'PWIDGET_KSIRCLISTBOX';
+$PWIDGET_TABDIALOG = 16;
+$PUKE_NAME2NUM{'PWIDGET_TABDIALOG'} = 16;
+$PUKE_NUM2NAME{'16'} = 'PWIDGET_TABDIALOG';
+$PWIDGET_KFILEDIALOG = 17;
+$PUKE_NAME2NUM{'PWIDGET_KFILEDIALOG'} = 17;
+$PUKE_NUM2NAME{'17'} = 'PWIDGET_KFILEDIALOG';
+$PWIDGET_OBJFINDER = 18;
+$PUKE_NAME2NUM{'PWIDGET_OBJFINDER'} = 18;
+$PUKE_NUM2NAME{'18'} = 'PWIDGET_OBJFINDER';
+$PUKE_LAYOUT_NEW = 11000;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_NEW'} = 11000;
+$PUKE_NUM2NAME{'11000'} = 'PUKE_LAYOUT_NEW';
+$PUKE_LAYOUT_NEW_ACK = -11000;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_NEW_ACK'} = -11000;
+$PUKE_NUM2NAME{'-11000'} = 'PUKE_LAYOUT_NEW_ACK';
+$PUKE_LAYOUT_ADDLAYOUT = 11005;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ADDLAYOUT'} = 11005;
+$PUKE_NUM2NAME{'11005'} = 'PUKE_LAYOUT_ADDLAYOUT';
+$PUKE_LAYOUT_ADDLAYOUT_ACK = -11005;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ADDLAYOUT_ACK'} = -11005;
+$PUKE_NUM2NAME{'-11005'} = 'PUKE_LAYOUT_ADDLAYOUT_ACK';
+$PUKE_LAYOUT_ADDWIDGET = 11010;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ADDWIDGET'} = 11010;
+$PUKE_NUM2NAME{'11010'} = 'PUKE_LAYOUT_ADDWIDGET';
+$PUKE_LAYOUT_ADDWIDGET_ACK = -11010;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ADDWIDGET_ACK'} = -11010;
+$PUKE_NUM2NAME{'-11010'} = 'PUKE_LAYOUT_ADDWIDGET_ACK';
+$PUKE_LAYOUT_ADDSTRUT = 11015;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ADDSTRUT'} = 11015;
+$PUKE_NUM2NAME{'11015'} = 'PUKE_LAYOUT_ADDSTRUT';
+$PUKE_LAYOUT_ADDSTRUT_ACK = -11015;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ADDSTRUT_ACK'} = -11015;
+$PUKE_NUM2NAME{'-11015'} = 'PUKE_LAYOUT_ADDSTRUT_ACK';
+$PUKE_LAYOUT_ACTIVATE = 11020;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ACTIVATE'} = 11020;
+$PUKE_NUM2NAME{'11020'} = 'PUKE_LAYOUT_ACTIVATE';
+$PUKE_LAYOUT_ACTIVATE_ACK = -11020;
+$PUKE_NAME2NUM{'PUKE_LAYOUT_ACTIVATE_ACK'} = -11020;
+$PUKE_NUM2NAME{'-11020'} = 'PUKE_LAYOUT_ACTIVATE_ACK';
+$PUKE_CONTROLLER = 1;
+$PUKE_NAME2NUM{'PUKE_CONTROLLER'} = 1;
+$PUKE_NUM2NAME{'1'} = 'PUKE_CONTROLLER';
+$PUKE_KBFD_SET_PATH = 2200;
+$PUKE_NAME2NUM{'PUKE_KBFD_SET_PATH'} = 2200;
+$PUKE_NUM2NAME{'2200'} = 'PUKE_KBFD_SET_PATH';
+$PUKE_BFD_SET_PATH_ACK = -2200;
+$PUKE_NAME2NUM{'PUKE_BFD_SET_PATH_ACK'} = -2200;
+$PUKE_NUM2NAME{'-2200'} = 'PUKE_BFD_SET_PATH_ACK';
+$PUKE_KBFD_SET_FILTER = 2201;
+$PUKE_NAME2NUM{'PUKE_KBFD_SET_FILTER'} = 2201;
+$PUKE_NUM2NAME{'2201'} = 'PUKE_KBFD_SET_FILTER';
+$PUKE_KBFD_SET_FILTER_ACK = -2201;
+$PUKE_NAME2NUM{'PUKE_KBFD_SET_FILTER_ACK'} = -2201;
+$PUKE_NUM2NAME{'-2201'} = 'PUKE_KBFD_SET_FILTER_ACK';
+$PUKE_KBFD_SET_SELECTION = 2202;
+$PUKE_NAME2NUM{'PUKE_KBFD_SET_SELECTION'} = 2202;
+$PUKE_NUM2NAME{'2202'} = 'PUKE_KBFD_SET_SELECTION';
+$PUKE_KBFD_SET_SELECTION_ACK = -2202;
+$PUKE_NAME2NUM{'PUKE_KBFD_SET_SELECTION_ACK'} = -2202;
+$PUKE_NUM2NAME{'-2202'} = 'PUKE_KBFD_SET_SELECTION_ACK';
+$PUKE_KBFD_FILE_SELECTED = 2203;
+$PUKE_NAME2NUM{'PUKE_KBFD_FILE_SELECTED'} = 2203;
+$PUKE_NUM2NAME{'2203'} = 'PUKE_KBFD_FILE_SELECTED';
+$PUKE_KBFD_FILE_SELECTED_ACK = -2203;
+$PUKE_NAME2NUM{'PUKE_KBFD_FILE_SELECTED_ACK'} = -2203;
+$PUKE_NUM2NAME{'-2203'} = 'PUKE_KBFD_FILE_SELECTED_ACK';
+$PUKE_OBJFINDER_ALLOBJECTS = 2300;
+$PUKE_NAME2NUM{'PUKE_OBJFINDER_ALLOBJECTS'} = 2300;
+$PUKE_NUM2NAME{'2300'} = 'PUKE_OBJFINDER_ALLOBJECTS';
+$PUKE_OBJFINDER_ALLOBJECTS_ACK = -2300;
+$PUKE_NAME2NUM{'PUKE_OBJFINDER_ALLOBJECTS_ACK'} = -2300;
+$PUKE_NUM2NAME{'-2300'} = 'PUKE_OBJFINDER_ALLOBJECTS_ACK';
+$PUKE_OBJFINDER_NEWOBJECT = 2301;
+$PUKE_NAME2NUM{'PUKE_OBJFINDER_NEWOBJECT'} = 2301;
+$PUKE_NUM2NAME{'2301'} = 'PUKE_OBJFINDER_NEWOBJECT';
+$PUKE_OBJFINDER_NEWOBJECT_ACK = -2301;
+$PUKE_NAME2NUM{'PUKE_OBJFINDER_NEWOBJECT_ACK'} = -2301;
+$PUKE_NUM2NAME{'-2301'} = 'PUKE_OBJFINDER_NEWOBJECT_ACK';
+
+1;
diff --git a/ksirc/puke/commands.h b/ksirc/puke/commands.h
new file mode 100644
index 00000000..3e45d8ba
--- /dev/null
+++ b/ksirc/puke/commands.h
@@ -0,0 +1,1052 @@
+
+// 0 is special "invalid character"
+// Value > 0 indicates from dsirc -> ksirc
+// Value < 0 indicates from ksirc -> dsirc
+
+// Desc: INVALID command
+// iWinId: not defined
+// iArg: not defined
+// cArg: not defined
+#define PUKE_INVALID 0
+
+// Desc: associantes server name with fd.
+// iWinId: not defined, but pass unchanged
+// iArg: not defined
+// cArg: name of the server
+#define PUKE_SETUP 1
+
+// Desc: replies to make sure association was valid
+// iWinId: not defined, but pass unchanged
+// iArg: size of Message
+// cArg: not defined
+#define PUKE_SETUP_ACK -1
+
+
+// Desc: sends the ack back. Used for doing actions after returning to select.
+// iWinId: window id
+// iArg: not defined
+// cArg: not define
+#define PUKE_ECHO 5
+
+// Desc: sends the ack back. Used for doing actions after returning to select.
+// iWinId: window id
+// iArg: not defined
+// cArg: not define
+#define PUKE_ECHO_ACK -5
+
+
+// From ksirc to sirc, event command unkown.
+// There should be somewhere better for this!!!
+
+#define PUKE_EVENT_UNKOWN -999
+
+// Dumps object tree
+// iWinId: puke controller
+// iArg: not defined
+// cArg: undef
+#define PUKE_DUMPTREE 997
+
+// Desc: dump object tree ack
+// iWinId: undef
+// iArg: undef
+// cArg: undef
+#define PUKE_DUMPTREE_ACK -997
+
+// Release a widget without delete'ing it, used after fetching a widget
+// iWinId: window id
+// iArg: undef
+// cArg: undef
+#define PUKE_RELEASEWIDGET 996
+
+// Desc: release ack
+// iWinId: window id
+// iArg: undef
+// cArg: undef
+#define PUKE_RELEASEWIDGET_ACK -996
+
+
+// Fetch widgets
+// Desc: get widget from parent
+// iWinId: not defined
+// iArg: not defined
+// cArg: 2 feilds, tab sperated, must be returned unchanged. 1. random string. 3. Object Name.
+#define PUKE_FETCHWIDGET 998
+
+// Desc: Fetch widget ack
+// iWinId: new widget id
+// iArg: not defined
+// cArg: 2 feilds, tab sperated, must be returned unchanged. 1. random string. 3. Object Name.
+#define PUKE_FETCHWIDGET_ACK -998
+
+
+// Widget commands starts at 1000 and end at 10000
+
+// Desc: create new widget
+// iWinId: parent widget id
+// iArg: widget type as defined by PWIDGET_*
+// cArg: Must be return unchanged
+#define PUKE_WIDGET_CREATE 1000
+
+// Desc: ack for newly created new widget
+// iWinId: new widget Id, 0 if failed
+// iArg: widget type as defined by PWIDGET_*
+// cArg: Returned unchanged
+#define PUKE_WIDGET_CREATE_ACK -1000
+
+
+// Desc: shows requested widget
+// iWinId: widget to show
+// iArg: not defined
+// cArg: not define
+#define PUKE_WIDGET_DELETE 1001
+
+// Desc: ack for show requested widget
+// iWinId: widget to show
+// iArg: not defined
+// cArg: not define
+#define PUKE_WIDGET_DELETE_ACK -1001
+
+// Desc: shows requested widget
+// iWinId: widget to show
+// iArg: not defined
+// cArg: not define
+#define PUKE_WIDGET_SHOW 1002
+
+// Desc: ack for show requested widget
+// iWinId: widget to show
+// iArg: not defined
+// cArg: not define
+#define PUKE_WIDGET_SHOW_ACK -1002
+
+// Desc: hidess requested widget
+// iWinId: widget to hide
+// iArg: not defined
+// cArg: not define
+#define PUKE_WIDGET_HIDE 1003
+
+// Desc: ack for hide requested widget
+// iWinId: widget to hide
+// iArg: not defined
+// cArg: not define
+#define PUKE_WIDGET_HIDE_ACK -1003
+
+// Desc: repaint widget
+// iWinId: widget to repaint
+// iArg: erase, 0 for false, 1 for true
+// cArg: no defines
+#define PUKE_WIDGET_REPAINT 1005
+
+// Desc: repaint widget ack
+// iWinId: widget to repaint
+// iArg: not defined
+// cArg: not defined
+#define PUKE_WIDGET_REPAINT_ACK -1005
+
+// Desc: update widget on next event loop
+// iWinId: widget to repaint
+// iArg: erase, 0 for false, 1 for true
+// cArg: no defines
+#define PUKE_WIDGET_UPDATE 1010
+
+// Desc: repaint widget ack
+// iWinId: widget to repaint
+// iArg: not defined
+// cArg: not defined
+#define PUKE_WIDGET_UPDATE_ACK -1010
+
+// Desc: resize the widget
+// iWinId: widget to repaint
+// iArg: width in the low 16 bit, height in next 16 bits
+// cArg: not defined
+#define PUKE_WIDGET_RESIZE 1015
+
+// Desc: repaint widget ack
+// iWinId: widget to repaint
+// iArg: new widget in lower 16 bit, new height in lower 16 bits
+// cArg: not defined
+#define PUKE_WIDGET_RESIZE_ACK -1015
+
+// -1020 to -1040 defines QEvent types
+// All arguments are 0 unless otherwise stated
+#define PUKE_WIDGET_EVENT_NONE -1020
+// iArg: timerId
+#define PUKE_WIDGET_EVENT_TIMER -1021
+// All EVENT_MOUSE are:
+// cArg: cast to int[25], int[0] = x(), int[1] = y(), int[2] = button()
+// int[3] = state()
+#define PUKE_WIDGET_EVENT_MOUSEBUTTONPRESS -1022
+#define PUKE_WIDGET_EVENT_MOUSEBUTTONRELEASE -1023
+#define PUKE_WIDGET_EVENT_MOUSEDBLCLICK -1024
+#define PUKE_WIDGET_EVENT_MOUSEMOVE -1025
+// All EVENT_KEY
+// cArg: cast to int[25], int[0] = key(), int[1] = ascii(), int[2] = state()
+#define PUKE_WIDGET_EVENT_KEYPRESS -1026
+#define PUKE_WIDGET_EVENT_KEYRELEASE -1027
+// All EVENT_FOCUS
+// cArg[0] = gotFocus()
+// cArg[1] = lostFocus()
+#define PUKE_WIDGET_EVENT_FOCUSIN -1028
+#define PUKE_WIDGET_EVENT_FOCUSOUT -1029
+#define PUKE_WIDGET_EVENT_ENTER -1030
+#define PUKE_WIDGET_EVENT_LEAVE -1031
+// Paint event
+#define PUKE_WIDGET_EVENT_PAINT -1032
+// cArg: int[0] = pos()->x() int[1] = pos->y()
+// int[2] = oldPos->x() int[3] = oldPos->y()
+#define PUKE_WIDGET_EVENT_MOVE -1033
+// cArg: int[0] = size()->width() int[1] = size()->height()
+// int[2] = oldSize()->width() int[3] = oldSize()->height()
+#define PUKE_WIDGET_EVENT_RESIZE -1034
+#define PUKE_WIDGET_EVENT_CREATE -1035
+#define PUKE_WIDGET_EVENT_DESTROY -1036
+#define PUKE_WIDGET_EVENT_SHOW -1037
+#define PUKE_WIDGET_EVENT_HIDE -1038
+#define PUKE_WIDGET_EVENT_CLOSE -1039
+
+// Desc: move widget
+// iWinId: widget id
+// iArg: new location, lower short is x, upper short is y
+// cArg: not define
+#define PUKE_WIDGET_MOVE 1050
+
+// Desc: move widget
+// iWinId: widget id
+// iArg: new location, lower short is x, upper short is y
+// cArg: not define
+#define PUKE_WIDGET_MOVE_ACK -1050
+
+// Desc: open and load library file
+// iWinid: not defined
+// iArg: type of widget
+// cArg: file name
+#define PUKE_WIDGET_LOAD 1055
+
+// Desc: ack the open library file
+// iWinid: not defined
+// iArg: widget number
+// cArg: not defined
+#define PUKE_WIDGET_LOAD_ACK -1055
+
+// Desc: unload library file
+// iWinid: not define
+// iArg: type of widget to unload
+// cArg: no define
+#define PUKE_WIDGET_UNLOAD 1060
+
+// Desc: ack open and load library file
+// iWinid: not defined
+// iArg: not defined
+// cArg: no defined
+#define PUKE_WIDGET_UNLOAD_ACK -1060
+
+// Desc: set's a a minimum size
+// iWinid: window id
+// iArg: 2 ints, lower is width , upper is height
+// cArg: not define
+#define PUKE_WIDGET_SETMINSIZE 1065
+
+// Desc: ack for set size
+// iWinid: window id
+// iArg: 2 ints, lower is new width, upper is new height
+// cArg: not defined
+#define PUKE_WIDGET_SETMINSIZE_ACK -1065
+
+// Desc: set's a a minimum size
+// iWinid: window id
+// iArg: 2 ints, lower is width , upper is height
+// cArg: not define
+#define PUKE_WIDGET_SETMAXSIZE 1070
+
+// Desc: ack for set size
+// iWinid: window id
+// iArg: 2 ints, lower is new width, upper is new height
+// cArg: not defined
+#define PUKE_WIDGET_SETMAXSIZE_ACK -1070
+
+// Desc: set widget caption
+// iWinid: window id
+// iArg: not defined
+// cArg: widget caption
+#define PUKE_WIDGET_SETCAPTION 1075
+
+// Desc: ack for set caption
+// iWinid: window id
+// iArg: not define
+// cArg: new caption
+#define PUKE_WIDGET_SETCAPTION_ACK -1075
+
+// Desc: get background colour
+// iWinid: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_WIDGET_GET_BACKGROUND_COLOUR 1080
+
+// Desc: get background colour ack
+// iWinid: window id
+// iArg: not defined
+// cArg: 3 ints packed in rbg combo
+#define PUKE_WIDGET_GET_BACKGROUND_COLOUR_ACK -1080
+
+// Desc: set background colour
+// iWinid: window id
+// iArg: not defined
+// cArg: 3 ints packed in rbg combo
+#define PUKE_WIDGET_SET_BACKGROUND_COLOUR 1085
+
+// Desc: set background colour ack
+// iWinid: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_WIDGET_SET_BACKGROUND_COLOUR_ACK -1085
+
+// Desc: set background pixmap
+// iWinid: window id
+// iArg: not defined
+// cArg: path name to pixmap
+#define PUKE_WIDGET_SET_BACKGROUND_PIXMAP 1086
+
+// Desc: set background pixmap ack
+// iWinid: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_WIDGET_SET_BACKGROUND_PIXMAP_ACK -1086
+
+// Desc: set background mode
+// iWinid: window id
+// iArg: mode
+// cArg: not defined
+#define PUKE_WIDGET_SET_BACKGROUND_MODE 1087
+
+// Desc: set background mode ack
+// iWinid: window id
+// iArg: new mode
+// cArg: not defined
+#define PUKE_WIDGET_SET_BACKGROUND_MODE_ACK -1087
+
+// Desc: set widget enabled or disabled
+// iWinid: window id
+// iArg: 0 for disabled, 1 for enabled
+// cArg: not defined
+#define PUKE_WIDGET_SET_ENABLED 1090
+
+// Desc: ack for enable/disable
+// iWinid: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_WIDGET_SET_ENABLED_ACK -1090
+
+// Desc: recreate widget with new parent, etc
+// IwinId: window id
+// iArg: window ID for new parent, 0x0 for no parent, toplevel
+// cArg: 3 packed ints, 0 = x, 1 = y, 2 = showit
+#define PUKE_WIDGET_RECREATE 1091
+
+// Desc: ACK recreate widget with new parent, etc
+// IwinId: window id
+// iArg: 0 (for all ok, other for error)
+// cArg: 0
+#define PUKE_WIDGET_RECREATE_ACK -1091
+
+// QFrame gets 1100
+
+// 1100 defines QFrame
+// Desc: set Frame style
+// iWinId: widget to chanse
+// iArg: frame style to set.
+// cArg: no define
+#define PUKE_QFRAME_SET_FRAME 1100
+
+// Desc: get/ack Frame style
+// iWinId: widget to changed
+// iArg: frame style.
+// cArg: no define
+#define PUKE_QFRAME_SET_FRAME_ACK -1100
+
+// Desc: set Frame line width
+// iWinId: widget to chanse
+// iArg: newline width.
+// cArg: no define
+#define PUKE_QFRAME_SET_LINEWIDTH 1105
+
+// Desc: get/ack Frame line width
+// iWinId: widget to changed
+// iArg: line width.
+// cArg: no define
+#define PUKE_QFRAME_SET_LINEWIDTH_ACK -1105
+
+//----------------------------------------------------
+// 1200 is a QLineEdit
+
+// Desc: set max line length
+// iWinId: widget to change
+// iArg: max line length
+// cArg: not defined
+#define PUKE_LINED_SET_MAXLENGTH 1200
+
+// Desc: set max line length
+// iWinId: widget to change
+// iArg: new max line length
+// cArg: not defined
+#define PUKE_LINED_SET_MAXLENGTH_ACK -1200
+
+// Desc: set echo mode, normal password, no echo, etc
+// iWinId: widget to change
+// iArg: echo mode
+// cArg: not defined
+#define PUKE_LINED_SET_ECHOMODE 1205
+
+// Desc: ack for set
+// iWinId: widget to change
+// iArg: current echo mode
+// cArg: not define
+#define PUKE_LINED_SET_ECHOMODE_ACK -1205
+
+// Desc: set text contents of widget
+// iWinId: widget to change
+// iArg: not defined
+// cArg: text to set widget too
+#define PUKE_LINED_SET_TEXT 1210
+
+// Desc: ack for set
+// iWinId: widget to change
+// iArg: not define
+// cArg: current test
+#define PUKE_LINED_SET_TEXT_ACK -1210
+
+// Desc: get current text
+// iWinId: widget to change
+// iArg:not define
+// cArg: not defined
+#define PUKE_LINED_GET_TEXT 1215
+
+// Desc: returned info for get text
+// iWinId: widget to change
+// iArg: not defined
+// cArg: text in widget
+#define PUKE_LINED_GET_TEXT_ACK -1215
+
+// Desc: return was pressed, action not defined
+// iWinId:
+// iArg:
+// cArg:
+#define PUKE_LINED_RETURN_PRESSED 1220
+
+// Desc: return was pressed, return information
+// iWinId: widget pressed in
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LINED_RETURN_PRESSED_ACK -1220
+
+//------------------------------------------------
+
+// Desc: set's button's current text
+// iWinId: window id
+// iArg: not defined
+// cArg: text
+#define PUKE_BUTTON_SET_TEXT 1300
+
+// Desc: ack for set text
+// iWinId: widget id
+// iArg: not defined
+// cArg: text
+#define PUKE_BUTTON_SET_TEXT_ACK -1300
+
+// Desc: set button to pixmap
+// iWinId: window id
+// iArg: not defined
+// cArg: path to pixmap
+#define PUKE_BUTTON_SET_PIXMAP 1305
+
+// Desc: ack for set pixmap
+// iWinId: widget id
+// iArg: pixmap()->isNull()
+// cArg: not defined
+#define PUKE_BUTTON_SET_PIXMAP_ACK -1305
+
+// Desc: set if button resizes with content changes
+// iWinId: window id
+// iArg: reisze, 0 false, 1 true
+// cArg: not defined
+#define PUKE_BUTTON_SET_AUTORESIZE 1310
+
+// Desc: ack for autreisze
+// iWinId: widget id
+// iArg: autoresize()
+// cArg: not defined
+#define PUKE_BUTTON_SET_AUTORESIZE_ACK -1310
+
+// Desc: button was pressed, not used
+// iWinId: not defined
+// iArg: not defined
+// cArg: not define
+#define PUKE_BUTTON_PRESSED 1350
+
+// Desc: signal button was pressed
+// iWinId: winid
+// iArg: not define
+// cArg: not defined
+#define PUKE_BUTTON_PRESSED_ACK -1350
+
+// Desc: button was relased, not used
+// iWinId: not defined
+// iArg: not defined
+// cArg: not define
+#define PUKE_BUTTON_RELEASED 1351
+
+// Desc: signal button was released
+// iWinId: winid
+// iArg: not define
+// cArg: not defined
+#define PUKE_BUTTON_RELEASED_ACK -1351
+
+// Desc: button was clicked, not used
+// iWinId: not defined
+// iArg: not defined
+// cArg: not define
+#define PUKE_BUTTON_CLICKED 1352
+
+// Desc: signal button was clicked
+// iWinId: winid
+// iArg: not defined
+// cArg: not defined
+#define PUKE_BUTTON_CLICKED_ACK -1352
+
+// Desc: button was toggled, not used
+// iWinId: not defined
+// iArg: not defined
+// cArg: not define
+#define PUKE_BUTTON_TOGGLED 1353
+
+// Desc: signal button was toggled
+// iWinId: winid
+// iArg: not define
+// cArg: not defined
+#define PUKE_BUTTON_TOGGLED_ACK -1353
+
+
+//------------------------------------------------
+
+// Desc: set's the range of the control
+// iWinId: window id
+// iArg: two packed short ints. Lower is lower, upper is upper
+// cArg: not define
+#define PUKE_KSPROGRESS_SET_RANGE 1400
+
+// Desc: ack set's the range of the control
+// iWinId: window id
+// iArg: not define
+// cArg: not defined
+#define PUKE_KSPROGRESS_SET_RANGE_ACK -1400
+
+// Desc: set the top text line
+// iWinId: window id
+// iArg: not define
+// cArg: top line
+#define PUKE_KSPROGRESS_SET_TOPTEXT 1410
+
+// Desc: ack set the top text line
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_KSPROGRESS_SET_TOPTEXT_ACK -1410
+
+// Desc: set the bottom text line
+// iWinId: window id
+// iArg: not define
+// cArg: bottom line
+#define PUKE_KSPROGRESS_SET_BOTTEXT 1415
+
+// Desc: ack set the top text line
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_KSPROGRESS_SET_BOTTEXT_ACK -1415
+
+// Desc: set status value
+// iWinId: window id
+// iArg: not define
+// cArg: current value
+#define PUKE_KSPROGRESS_SET_VALUE 1420
+
+// Desc: ack set the top text line
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_KSPROGRESS_SET_VALUE_ACK -1420
+
+
+// Desc: cancel pressed, typically only ack sent.
+// iWinId: window id
+// iArg: not define
+// cArg: current value
+#define PUKE_KSPROGRESS_CANCEL 1425
+
+// Desc: send message saying cancel button was pressed
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_KSPROGRESS_CANCEL_ACK -1425
+
+// QTable View at 1500
+
+// none yet
+
+// QListBox at 1600
+
+// Desc: insert string item
+// iWinId: window id
+// iArg: number of items now in list
+// cArg: undef
+#define PUKE_LISTBOX_INSERT 1600
+
+// Desc: insert string item ack
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_INSERT_ACK -1600
+
+
+// Desc: insert string item in sorted order
+// iWinId: window id
+// iArg: number of items in list
+// cArg: undef
+#define PUKE_LISTBOX_INSERT_SORT 1605
+
+// Desc: ack insert string item in sorted order
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_INSERT_SORT_ACK -1605
+
+// Desc: insert pixmap
+// iWinId: window id
+// iArg: not defined
+// cArg: file name
+#define PUKE_LISTBOX_INSERT_PIXMAP 1610
+
+// Desc: ack insert pixmap
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_INSERT_PIXMAP_ACK -1610
+
+// Desc: highligth number
+// iWinId: window id
+// iArg: item index to highlight
+// cArg: undef
+#define PUKE_LISTBOX_HIGHLIGHT 1615
+
+// Desc: ack
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_HIGHLIGHT_ACK -1615
+
+// Desc: remove number
+// iWinId: window id
+// iArg: item index to remove
+// cArg: undef
+#define PUKE_LISTBOX_REMOVE 1620
+
+// Desc: ack
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_REMOVE_ACK -1620
+
+// Desc: Get text from item number
+// iWinId: window id
+// iArg: list item
+// cArg: not defined
+#define PUKE_LISTBOX_GETTEXT 1625
+
+// Desc: ack for get text with cArg set to text
+// iWinId: window id
+// iArg: 1 for sucsess, 0 for failure
+// cArg: text
+#define PUKE_LISTBOX_GETTEXT_ACK -1625
+
+// Desc: Clear list box
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_CLEAR 1630
+
+// Desc: ack for clear list box
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_CLEAR_ACK -1630
+
+// Desc: set scroll bar
+// iWinId: window id
+// iArg: bool, enable/disable
+// cArg: undef
+#define PUKE_LISTBOX_SET_SCROLLBAR 1635
+
+// Desc: set scroll bar ack
+// iWinId: window id
+// iArg: undef
+// cArg: undef
+#define PUKE_LISTBOX_SET_SCROLLBAR_ACK -1635
+
+// Desc: set auto scroll bar
+// iWinId: window id
+// iArg: bool, enable/disable
+// cArg: undef
+#define PUKE_LISTBOX_SET_AUTO_SCROLLBAR 1636
+
+// Desc: set auto scroll bar ack
+// iWinId: window id
+// iArg: undef
+// cArg: undef
+#define PUKE_LISTBOX_SET_AUTO_SCROLLBAR_ACK -1636
+
+// Desc: item highlighted, not used signal to dsirc
+// iWinId: undef
+// iArg: undef
+// cArg: undef
+#define PUKE_LISTBOX_HIGHLIGHTED 1690
+
+// Desc: item highlighted
+// iWinId: window id
+// iArg: index
+// cArg: contents
+#define PUKE_LISTBOX_HIGHLIGHTED_ACK -1690
+
+// Desc: item selected
+// iWinId: window id
+// iArg: index
+// cArg: contents
+#define PUKE_LISTBOX_SELECTED 1690
+
+// Desc: send message saying cancel button was pressed
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LISTBOX_SELECTED_ACK -1690
+
+// *** 1700 goes to the Plabel
+
+// Desc: Set label to text in carg
+// iWinId: window id
+// iArg: not defined
+// cArg: text to be set to
+#define PUKE_LABEL_SETTEXT 1700
+
+// Desc: Set label to text in carg, ack
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LABEL_SETTEXT_ACK -1700
+
+// Desc: Set label pixmap specified by filane name
+// iWinId: window id
+// iArg: not defined
+// cArg: filena,me for pixmap
+#define PUKE_LABEL_SETPIXMAP 1705
+
+// Desc: Set label pixmap specified by filane name ACK
+// iWinId: window id
+// iArg: not defined
+// cArg: not defined
+#define PUKE_LABEL_SETPIXMAP_ACK -1705
+
+// Desc: Set label to movie specified by filename
+// iWinId: window id
+// iArg: not defined
+// cArg: movie's filename
+#define PUKE_LABEL_SETMOVIE 1710
+
+// Desc: Set label to movie specified by filename, ACK
+// iWinId: window id
+// iArg: not defined
+// cArg: not deefine
+#define PUKE_LABEL_SETMOVIE_ACK -1710
+
+// Desc: Set label's allignment
+// iWinId: window id
+// iArg: alignment
+// cArg: not defined
+#define PUKE_LABEL_SETALIGNMENT 1715
+
+// Desc: Set label's allignment, ACK
+// iWinId: window id
+// iArg: alignment
+// cArg: not defined
+#define PUKE_LABEL_SETALIGNMENT_ACK -1715
+
+// -----------------------------------------------------------------------
+// PMenuData
+
+// Desc: Inserts newtext menu item
+// iWinId: window id
+// iArg: keyboard accelerator (-1 for none)
+// cArg: Text
+#define PUKE_MENUDATA_INSERT_TEXT 1800
+
+// Desc: ack for insert
+// iWinId: window id
+// iArg: object id
+// cArg: undef
+#define PUKE_MENUDATA_INSERT_TEXT_ACK -1800
+
+// Desc: Inserts new pixmap into menu
+// iWinId: window id
+// iArg: keyboard accelerator (-1 for none)
+// cArg: Text
+#define PUKE_MENUDATA_INSERT_PIXMAP 1801
+
+// Desc: ack for insert
+// iWinId: window id
+// iArg: object id
+// cArg: undef
+#define PUKE_MENUDATA_INSERT_PIXMAP_ACK -1801
+
+
+// Desc: Item got activated, not used, only ack
+// iWinId: undef
+// iArg: undef
+// cArg: uidef
+#define PUKE_POPUPMENU_ACTIVATED 1805
+
+// Desc: Item got activate
+// iWinId: window id
+// iArg: item id
+// cArg: undef
+#define PUKE_POPUPMENU_ACTIVATED_ACK -1805
+
+// Desc: Popup to current cursor position
+// iWinId: menu id
+// iArg: undef
+// cArg: uidef
+#define PUKE_POPUPMENU_POPUP_CURRENT 1810
+
+// Desc: Ack for popup
+// iWinId: window id
+// iArg: 1 for success
+// cArg: undef
+#define PUKE_POPUPMENU_POPUP_CURRENT_ACK -1810
+
+// Desc: Remvoes an item from a popup menu
+// iWinId: menu id
+// iArg: undef
+// cArg: uidef
+#define PUKE_MENUDATA_REMOVE_ITEM 1815
+
+// Desc: Ack for remove item
+// iWinId: window id
+// iArg: 1 for success
+// cArg: undef
+#define PUKE_MENUDATA_REMOVE_ITEM_ACK -1815
+
+// -----------------------------------------------------------------------
+// PAMenuData
+
+// Desc: is the item in the top of the list?
+// iWinId: window id
+// iArg: index
+// cArg: not defined
+#define PUKE_ALISTBOX_ISTOP 1900
+
+// Desc: ack for istop
+// iWinId: window id
+// iArg: 1 for top, 0 for bottom
+// cArg: not defined
+#define PUKE_ALISTBOX_ISTOP_ACK -1900
+
+// Desc: set green highligh (voice)
+// iWinId: window id
+// iArg: highligh, 1 for set, 0 for not
+// cArg: string
+#define PUKE_ALISTBOX_SMALL_HIGHLIGHT 1905
+
+// Desc: ack for set green highligh
+// iWinId: window id
+// iArg: 0 for success, 1 for failure
+// cArg: not defined
+#define PUKE_ALISTBOX_SMALL_HIGHLIGHT_ACK -1905
+
+// Desc: set red highligh and raise to the top (op)
+// iWinId: window id
+// iArg: highlight, 1 for set, 0 for remove
+// cArg: string
+#define PUKE_ALISTBOX_BIG_HIGHLIGHT 1910
+
+// Desc: ack for set red and raise
+// iWinId: window id
+// iArg: 0 for success, 1 for failure
+// cArg: not defined
+#define PUKE_ALISTBOX_BIG_HIGHLIGHT_ACK -1910
+
+// Desc: finds nick index
+// iWinId: window id
+// iArg: not defined
+// cArg: string
+#define PUKE_ALISTBOX_FIND_NICK 1915
+
+// Desc: ack for find nick
+// iWinId: window id
+// iArg: index
+// cArg: not defined
+#define PUKE_ALISTBOX_FIND_NICK_ACK -1915
+
+// -----------------------------------------------------------------------
+// PTabDialog
+
+// Desc: add Widget defined by iArg's widget id
+// iWinId: window id
+// iArg: widget to add, widget id, in current fd
+// cArg: not defined
+#define PUKE_TABDIALOG_ADDTAB 2001
+
+// Desc: ack for istop
+// iWinId: window id
+// iArg: 1 for failure, 0 for success
+// cArg: not defined
+#define PUKE_TABDIALOG_ADDTAB_ACK -2001
+
+// -----------------------------------------------------------------------
+// PKSircListBox
+
+// Desc: is the item in the top of the list?
+// iWinId: window id
+// iArg: index
+// cArg: not defined
+#define PUKE_KSIRCLISTBOX_TOBOTTOM 2100
+
+// Desc: ack for istop
+// iWinId: window id
+// iArg: 1 for top, 0 for bottom
+// cArg: not defined
+#define PUKE_KSIRCLISTBOX_TOBOTTOM_ACK -2100
+
+// 2200 for PKFileDialog
+// 2300 for PObjFinder
+
+
+// ***********************************************************************
+// ***********************************************************************
+
+//
+// Base commands are done, next describes Widget's
+//
+
+// OBJECT base class
+#define PWIDGET_OBJECT 1
+
+// WIDGET defines a base QWidget class
+#define PWIDGET_WIDGET 2
+
+// FRAME defines a base class
+#define PWIDGET_FRAME 3
+
+// LINED defines the simple SLE
+#define PWIDGET_LINED 4
+
+// BUTTON defines the abstract class QButton
+#define PWIDGET_BUTTON 5
+
+// PUSH defined the push button
+#define PWIDGET_PUSHBT 6
+
+// Progress window for dcc and stuff
+#define PWIDGET_KSPROGRESS 7
+
+// Table view, not really used for much, base class for lots
+#define PWIDGET_TABLEVW 8
+
+// List box
+#define PWIDGET_LISTBOX 9
+
+// Label
+#define PWIDGET_LABEL 10
+
+// BoxLayout
+#define POBJECT_LAYOUT 11
+
+// MenuData
+#define PWIDGET_MENUDATA 12
+
+// PopupMenu
+
+#define PWIDGET_POPMENU 13
+
+// PAListBox
+
+#define PWIDGET_ALISTBOX 14
+
+// PKSircListBox
+
+#define PWIDGET_KSIRCLISTBOX 15
+
+// PTabDialog
+
+#define PWIDGET_TABDIALOG 16
+
+// PKFileDialog
+
+#define PWIDGET_KFILEDIALOG 17
+
+// PObjFinder
+
+#define PWIDGET_OBJFINDER 18
+
+
+// Group layout commands exist between 10000 and 11000
+
+// Desc: create new box layout
+// iWinId: PWidget parent
+// iArg: 2 shorts, short[0] direction, short[1] border
+// cArg: random character string
+#define PUKE_LAYOUT_NEW 11000
+// Desc: ack for box layout
+// iWinId: Layout ID.
+// iArg: not define
+// cArg: same random m character string as PUKE_LAYOUT_NEW
+#define PUKE_LAYOUT_NEW_ACK -11000
+
+#define PUKE_LAYOUT_ADDLAYOUT 11005
+#define PUKE_LAYOUT_ADDLAYOUT_ACK -11005
+
+// Desc: add widget into layout manager
+// iWinId: Layout Manager to add widget too
+// iArg: Widget Id to be added
+// cArg: 2 characters, char[0] strech, char[1] alignment
+#define PUKE_LAYOUT_ADDWIDGET 11010
+// Desc: ack for add widget
+// iWinId: Layout manager
+// iArg: not defined
+// cArg: not define
+#define PUKE_LAYOUT_ADDWIDGET_ACK -11010
+
+// Desc: adds a strut for the current box, ie can'be be bigger then int
+// iWinId: Layout Manager to add strut
+// iArg: strut size
+// cArg: not define
+#define PUKE_LAYOUT_ADDSTRUT 11015
+
+// Desc: ack for strut add widget
+// iWinId: Layout manager
+// iArg: not defined
+// cArg: not define
+#define PUKE_LAYOUT_ADDSTRUT_ACK -11015
+
+// Desc: activates layout management, like show() for widget
+// iWinId: Layout Manager to activate
+// iArg: undef
+// cArg: undef
+#define PUKE_LAYOUT_ACTIVATE 11020
+
+// Desc: ack for strut add widget
+// iWinId: Layout manager
+// iArg: 1 on failure, 0 on success
+// cArg: not define
+#define PUKE_LAYOUT_ACTIVATE_ACK -11020
+
+/*
+ * ----------------------------------------------------------------------
+ * persistant objects
+ */
+
+#define PUKE_CONTROLLER 1
diff --git a/ksirc/puke/controller.cpp b/ksirc/puke/controller.cpp
new file mode 100644
index 00000000..1e798be7
--- /dev/null
+++ b/ksirc/puke/controller.cpp
@@ -0,0 +1,974 @@
+#include <config.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <iostream>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+
+using namespace std; // iostream.h include cstring which puts strlen into
+ // std:: namespace, which breaks Qt's strlen() call
+ // in qcstring.h (in gcc3's libstdc++)
+
+#include <klibloader.h>
+#include <kdebug.h>
+
+
+#include "controller.h"
+
+#include "../../config.h"
+#include "../objFinder.h"
+
+#include "palistbox.h"
+#include "pbutton.h"
+#include "pframe.h"
+#include "pkfiledialog.h"
+#include "plabel.h"
+#include "playout.h"
+#include "plined.h"
+#include "plistbox.h"
+#include "pmenudta.h"
+#include "pmessage.h"
+#include "pobject.h"
+#include "pobjfinder.h"
+#include "ppopmenu.h"
+#include "pprogress.h"
+#include "ppushbt.h"
+#include "ptabdialog.h"
+#include "ptablevw.h"
+#include "pwidget.h"
+
+#undef DEBUG
+
+uint PukeController::uiBaseWinId = 10; // Gives a little seperation from the controller id
+
+PukeController::PukeController(QString sock, QObject *parent, const char *name) : PObject( parent, name )
+{
+ int len, prev_umask;
+ struct sockaddr_un unix_addr;
+
+ running = FALSE; // Running has to be true before we do any work
+ bClosing = FALSE; // we're not trying to close so set this false.
+
+ // Set the umask to something sane that doesn't allow others to take over ksirc
+ prev_umask = umask(0177);
+
+ if(sock.length() == 0){
+ qsPukeSocket = getenv("HOME");
+ if(qsPukeSocket.length() == 0){
+ qsPukeSocket = "/tmp";
+ }
+ qsPukeSocket += "/.ksirc.socket";
+ }
+ else{
+ qsPukeSocket = sock;
+ }
+
+ unlink(qsPukeSocket);
+ iListenFd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(iListenFd < 0){
+ perror("PUKE: Unix Domain Socket create failed");
+ return;
+ }
+ memset(&unix_addr, 0, sizeof(unix_addr));
+ unix_addr.sun_family = AF_UNIX;
+ strlcpy(unix_addr.sun_path, qsPukeSocket, sizeof(unix_addr.sun_path));
+
+ len = sizeof(unix_addr.sun_family) + qsPukeSocket.length();
+#if defined(__FreeBSD__)
+ if( bind(iListenFd, (struct sockaddr *) &unix_addr, len+1) < 0){
+#else
+ if( bind(iListenFd, (struct sockaddr *) &unix_addr, len) < 0){
+#endif
+ perror("PUKE: Could not bind to Unix Domain Socket");
+ return;
+ }
+
+ if(listen(iListenFd, 5) < 0){
+ perror("PUKE: Could not listen for inbound connections");
+ return;
+ }
+
+ running = TRUE;
+
+ fcntl(iListenFd, F_SETFL, O_NONBLOCK); // Set it non-block so that
+ // accept() never blocks.
+
+ qsnListen = new QSocketNotifier(iListenFd, QSocketNotifier::Read, this, QString(name) + "_iListen");
+ connect(qsnListen, SIGNAL(activated(int)),
+ this, SLOT(NewConnect(int)));
+
+ connect(objFind, SIGNAL(inserted(QObject *)),
+ this, SLOT(slotInserted(QObject *)));
+
+ qidConnectFd.setAutoDelete(TRUE);
+
+ qidCommandTable.setAutoDelete(TRUE);
+
+ /*
+ * Setup widget data trees
+ */
+ WidgetList.setAutoDelete(TRUE);
+ revWidgetList.setAutoDelete(TRUE);
+ widgetCF.setAutoDelete(TRUE);
+
+ /*
+ * Connect outputMessage to the acutal write buffer function
+ * outputMessage signals from pobjects are chained until they finally reach us.
+ */
+ connect(this, SIGNAL(outputMessage(int, PukeMessage *)),
+ this, SLOT(writeBuffer(int, PukeMessage *)));
+
+ initHdlr(); // Setup message command handlers.
+
+ // Set umask back so it doesn't affect dcc's and so forth.
+ umask(prev_umask);
+
+ /*
+ * We are a PObject so do some init code
+ */
+ // We're always terminate by someone else so set manTerm() right now
+ manTerm();
+ setWidget(0x0);
+
+}
+
+void
+PukeController::slotInserted(QObject *obj)
+{
+ emit inserted(obj);
+}
+
+PukeController::~PukeController()
+{
+ close(iListenFd);
+ disconnect(this); // We call disconnect this so don't listen to our own destroy() signal go out
+ unlink(qsPukeSocket);
+}
+
+QStrList PukeController::allObjects()
+{
+ return objFinder::allObjects();
+}
+
+void PukeController::NewConnect(int)
+{
+ int cfd;
+ ksize_t len = 0;
+ struct sockaddr_un unix_addr;
+
+ cfd = accept(iListenFd, (struct sockaddr *)&unix_addr, &len);
+ if(cfd < 0){
+ perror("PUKE: NewConnect fired, but no new connect");
+ return;
+ }
+ fcntl(cfd, F_SETFL, O_NONBLOCK); // Set it non-block so that
+ // cfd() never blocks.
+
+ fdStatus *fds = new fdStatus();
+ fds->sr = new QSocketNotifier(cfd, QSocketNotifier::Read, this);
+ fds->sw = new QSocketNotifier(cfd, QSocketNotifier::Write, this);
+ connect(fds->sr, SIGNAL(activated(int)),
+ this, SLOT(Traffic(int)));
+ connect(fds->sw, SIGNAL(activated(int)),
+ this, SLOT(Writeable(int)));
+ qidConnectFd.insert(cfd, fds);
+ qsnListen->setEnabled(TRUE);
+
+ /*
+ * Now we add ourselves as a client to the fd so we can process messages going to us
+ */
+ WidgetS *ws = new WidgetS;
+ ws->pwidget = this;
+ ws->type = 1;
+ insertPObject(cfd, ControllerWinId, ws);
+
+}
+
+
+void PukeController::Writeable(int fd)
+{
+ if(qidConnectFd[fd]){
+ qidConnectFd[fd]->writeable = TRUE;
+ qidConnectFd[fd]->sw->setEnabled(FALSE);
+ //
+ // Insert buffer flushing code here.
+ //
+ }
+ else{
+ kdDebug(5008) << "PUKE: Unkonwn fd: " << fd << endl;
+ }
+}
+
+void PukeController::writeBuffer(int fd, PukeMessage *message)
+{
+ if(qidConnectFd[fd]){
+ // if(qidConnectFd[fd]->writeable == FALSE){
+ // kdDebug(5008) << "PUKE: Writing to FD that's not writeable: " << fd << endl;
+ // }
+ if(message != 0){
+ int bytes = 0;
+ message->iHeader = iPukeHeader;
+ if(message->iTextSize == 0 || message->cArg == 0){
+ message->iTextSize = 0;
+ message->cArg = 0;
+#ifdef DEBUG
+ printf("Traffic on: %d <= %d %d %d %d 0x%x\n",
+ fd,
+ message->iCommand,
+ message->iWinId,
+ message->iArg,
+ message->iTextSize,
+ message->cArg);
+#endif
+ bytes = write(fd, message, 5 * sizeof(int));
+ }
+ else{
+ /*
+ struct OutMessageS {
+ unsigned int iHeader;
+ int iCommand;
+ int iWinId;
+ int iArg;
+ int iTextSize;
+ char cArg[message->iTextSize];
+ } OutMessage;
+ OutMessage.iHeader = iPukeHeader;
+ OutMessage.iCommand = message->iCommand;
+ OutMessage.iWinId = message->iWinId;
+ OutMessage.iArg = message->iArg;
+ OutMessage.iTextSize = message->iTextSize;
+ memcpy(OutMessage.cArg, message->cArg, OutMessage.iTextSize);
+ // OutMessage.cArg[OutMessage.iTextSize] = 0; // Don't need to null out the last character
+ bytes = write(fd, &OutMessage, 5*sizeof(int) + (OutMessage.iTextSize) * sizeof(char));
+ */
+#ifdef DEBUG
+ printf("Traffic on: %d <= %d %d %d %d 0x%x\n",
+ fd,
+ message->iCommand,
+ message->iWinId,
+ message->iArg,
+ message->iTextSize,
+ message->cArg);
+#endif /* DEBUG */
+
+ struct iovec iov[2];
+ iov[0].iov_base = (char *) message;
+ iov[0].iov_len = 5*sizeof(int);
+ iov[1].iov_base = (char *) message->cArg;
+ iov[1].iov_len = message->iTextSize;
+ bytes = writev(fd, iov, 2);
+ }
+ // kdDebug(5008) << "Wrote: " << bytes << endl;
+ if(bytes <= 0){
+ switch(errno){
+ case EAGAIN: // Don't do anything for try again
+ break;
+// default:
+// perror("Puke: write on socket failed");
+ // Don't call closefd() since deletes are called on write's
+ // since write is being called from the destructors, etc of
+ // the widgets. (bad things happend when you call write
+ // then your return; path ceasaes to exist.
+ // closefd(fd);
+ }
+ }
+ }
+ }
+ else{
+ closefd(fd);
+ kdDebug(5008) << "PUKE: Attempt to write to unkown fd:" << fd << endl;
+ }
+}
+
+void PukeController::Traffic(int fd)
+{
+ PukeMessage pm;
+ int bytes = -1;
+ memset(&pm, 0, sizeof(pm));
+ while((bytes = read(fd, &pm, 5*sizeof(int))) > 0){
+ if(bytes != 5*sizeof(int)){
+ kdDebug(5008) << "Short message, Got: " << bytes << " Wanted: " << sizeof(PukeMessage) << " NULL Padded" << endl;
+ }
+#ifdef DEBUG
+ printf("Traffic on: %d => %d %d %d %d",
+ fd,
+ pm.iCommand,
+ pm.iWinId,
+ pm.iArg,
+ pm.iTextSize);
+ if(pm.iCommand == 0x0){
+ abort();
+ }
+#endif /* DEBUG */
+ if(pm.iHeader != iPukeHeader){
+ qWarning("Invalid packet received, discarding!");
+ return;
+ }
+ if(pm.iTextSize > 0){
+ pm.cArg = new char[pm.iTextSize + 1];
+ read(fd, pm.cArg, pm.iTextSize * sizeof(char));
+ pm.cArg[pm.iTextSize] = 0x0; // Null terminate the string.
+// printf(" %s\n", pm.cArg);
+ }
+ else {
+ pm.cArg = 0;
+// printf("\n");
+ }
+ MessageDispatch(fd, &pm);
+ delete[] pm.cArg; // Free up cArg is used
+ memset(&pm, 0, 5*sizeof(int));
+ }
+ if(bytes <= 0){ // Shutdown the socket!
+ switch(errno){
+ case EAGAIN: // Don't do anything for try again
+ break;
+ // case 0:
+ // break; // We just read nothing, don't panic
+ case EIO:
+ case EISDIR:
+ case EBADF:
+ case EINVAL:
+ case EFAULT:
+ default:
+ // perror("PukeController: read failed");
+ closefd(fd);
+ close(fd);
+ }
+ }
+ else{
+ qidConnectFd[fd]->sr->setEnabled(TRUE);
+ }
+}
+
+
+void PukeController::ServMessage(QString, int, QString)
+{
+
+}
+
+// Message Dispatcher is in messagedispatcher.cpp
+
+
+void PukeController::MessageDispatch(int fd, PukeMessage *pm)
+{
+ try {
+
+ /*
+ * Get the object id, this may produce a errorNuSuchWidget
+ */
+ PObject *obj = id2pobject(fd, pm->iWinId);
+
+ /*
+ * Call the message hanlder for the widget
+ */
+ obj->messageHandler(fd, pm);
+ }
+ catch(errorNoSuchWidget &err){
+ PukeMessage pmRet;
+ pmRet.iCommand = PUKE_INVALID;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = 0;
+ emit outputMessage(fd, &pmRet);
+ return;
+ }
+ catch (errorCommandFailed &err){
+ PukeMessage pmRet;
+ pmRet.iCommand = err.command();
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = err.iarg();
+ pmRet.iTextSize = 0;
+ emit outputMessage(fd, &pmRet);
+ return;
+ }
+}
+
+void PukeController::initHdlr()
+{
+
+ widgetCreate *wc;
+
+ wc = new widgetCreate;
+ wc->wc = PWidget::createWidget;
+ widgetCF.insert(PWIDGET_WIDGET, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PObject::createWidget;
+ widgetCF.insert(PWIDGET_OBJECT, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PLayout::createWidget;
+ widgetCF.insert(POBJECT_LAYOUT, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PFrame::createWidget;
+ widgetCF.insert(PWIDGET_FRAME, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PLineEdit::createWidget;
+ widgetCF.insert(PWIDGET_LINED, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PButton::createWidget;
+ widgetCF.insert(PWIDGET_BUTTON, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PPushButton::createWidget;
+ widgetCF.insert(PWIDGET_PUSHBT, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PProgress::createWidget;
+ widgetCF.insert(PWIDGET_KSPROGRESS, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PTableView::createWidget;
+ widgetCF.insert(PWIDGET_TABLEVW, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PListBox::createWidget;
+ widgetCF.insert(PWIDGET_LISTBOX, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PLabel::createWidget;
+ widgetCF.insert(PWIDGET_LABEL, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PPopupMenu::createWidget;
+ widgetCF.insert(PWIDGET_POPMENU, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PAListBox::createWidget;
+ widgetCF.insert(PWIDGET_ALISTBOX, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PTabDialog::createWidget;
+ widgetCF.insert(PWIDGET_TABDIALOG, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PKFileDialog::createWidget;
+ widgetCF.insert(PWIDGET_KFILEDIALOG, wc);
+
+ wc = new widgetCreate;
+ wc->wc = PObjFinder::createWidget;
+ widgetCF.insert(PWIDGET_OBJFINDER, wc);
+
+ // Each function handler gets an entry in the qidCommandTable
+ commandStruct *cs;
+
+
+ // Invalid is the default invalid handler
+ cs = new commandStruct;
+ cs->cmd = &PukeController::hdlrPukeInvalid;
+ cs->library = 0;
+ qidCommandTable.insert(PUKE_INVALID, cs);
+
+
+ // Setup's handled by the setup handler
+ cs = new commandStruct;
+ cs->cmd = &PukeController::hdlrPukeSetup;
+ cs->library = 0;
+ qidCommandTable.insert(PUKE_SETUP, cs);
+
+ // We don't receive PUKE_SETUP_ACK's we send them.
+ cs = new commandStruct;
+ cs->cmd = &PukeController::hdlrPukeInvalid;
+ cs->library = 0;
+ qidCommandTable.insert(PUKE_SETUP_ACK, cs);
+
+ cs = new commandStruct;
+ cs->cmd = &PukeController::hdlrPukeEcho;
+ cs->library = 0;
+ qidCommandTable.insert(PUKE_ECHO, cs);
+
+ // Fetch widget gets the requested widget from the ServerController
+ cs = new commandStruct;
+ cs->cmd = &PukeController::hdlrPukeFetchWidget;
+ cs->library = 0;
+ qidCommandTable.insert(PUKE_FETCHWIDGET, cs);
+
+ // Fetch widget gets the requested widget from the ServerController
+ cs = new commandStruct;
+ cs->cmd = &PukeController::hdlrPukeDumpTree;
+ cs->library = 0;
+ qidCommandTable.insert(PUKE_DUMPTREE, cs);
+
+ // Fetch widget gets the requested widget from the ServerController
+ cs = new commandStruct;
+ cs->cmd = &PukeController::hdlrPukeDeleteWidget;
+ cs->library = 0;
+ qidCommandTable.insert(PUKE_WIDGET_DELETE, cs);
+
+}
+
+// Start message handlers
+
+void PukeController::hdlrPukeInvalid(int fd, PukeMessage *)
+{
+ PukeMessage pmOut;
+ memset(&pmOut, 0, sizeof(pmOut));
+ this->writeBuffer(fd, &pmOut);
+}
+
+
+void PukeController::hdlrPukeSetup(int fd, PukeMessage *pm)
+{
+ PukeMessage pmOut;
+ memset(&pmOut, 0, sizeof(pmOut));
+ pmOut.iCommand = PUKE_SETUP_ACK;
+ pmOut.iArg = 1;
+ if((strlen(pm->cArg) > 0) &&
+ (this->qidConnectFd[fd] != NULL)){
+ this->qidConnectFd[fd]->server = qstrdup(pm->cArg);
+ pmOut.iWinId = pm->iWinId;
+ pmOut.iArg = sizeof(PukeMessage) - sizeof(char *);
+ }
+ this->writeBuffer(fd, &pmOut);
+}
+
+void PukeController::hdlrPukeEcho(int fd, PukeMessage *pm)
+{
+ PukeMessage pmOut;
+ memcpy(&pmOut, pm, sizeof(PukeMessage));
+ pmOut.iCommand = PUKE_ECHO_ACK;
+ pmOut.iWinId = pm->iWinId;
+ pmOut.iArg = pm->iArg;
+ this->writeBuffer(fd, &pmOut);
+}
+
+void PukeController::hdlrPukeDumpTree(int fd, PukeMessage *pm)
+{
+ objFinder::dumpTree();
+
+ PukeMessage pmOut;
+ memcpy(&pmOut, pm, sizeof(PukeMessage));
+ pmOut.iCommand = -pm->iCommand;
+ pmOut.iWinId = pm->iWinId;
+ pmOut.iArg = pm->iArg;
+ this->writeBuffer(fd, &pmOut);
+}
+
+
+void PukeController::hdlrPukeFetchWidget(int fd, PukeMessage *pm)
+{
+ widgetId wIret;
+
+ /*
+ * The parent widget ID and type are packed into the iArg
+ * the pattern is 2 shorts.
+ */
+
+ int iParent=-1, iType=-1;
+
+ char rand[50],name[50];
+ int found = sscanf(pm->cArg, "%d\t%d\t%49s\t%49s", &iParent, &iType, rand, name);
+ if(found != 4){
+ throw(errorCommandFailed(PUKE_INVALID,6));
+ }
+
+ uiBaseWinId++; // Get a new base win id
+
+ // wIret holds the current widget id for the new widget
+ wIret.iWinId = uiBaseWinId;
+ wIret.fd = fd;
+
+ // CreateArgs arg = CreateArgs(this, pm, &wIret, parent)
+ CreateArgs arg(this, pm, &wIret, 0);
+
+ // Let's go looking for the widget
+ // Match any class with the right name
+ QObject *obj = 0x0;
+ if(parent() && (strcmp(name, parent()->name()) == 0)){
+ obj = parent();
+ }
+ else {
+ obj = objFinder::find(name, 0x0);
+ if(obj == 0){
+ wIret.fd = 0;
+ wIret.iWinId = 0;
+ throw(errorCommandFailed(PUKE_INVALID,5));
+ }
+
+ }
+
+ arg.fetchedObj = obj;
+
+ WidgetS *ws = new WidgetS;
+ ws->pwidget = (widgetCF[iType]->wc)(arg);
+ if (ws->pwidget->hasError())
+ {
+ throw(errorCommandFailed(PUKE_INVALID, 0));
+ }
+ ws->type = iType;
+
+ connect(ws->pwidget, SIGNAL(outputMessage(int, PukeMessage*)),
+ this, SIGNAL(outputMessage(int, PukeMessage*)));
+
+ // insertPBoject(fd, uiBaseWinId, ws);
+ // The widget list has to exist since we have ourselves in the list
+ // WidgetList[wIret.fd]->insert(wIret.iWinId, ws);
+ insertPObject(wIret.fd, wIret.iWinId, ws);
+
+ PukeMessage pmRet;
+ pmRet.iCommand = PUKE_WIDGET_CREATE_ACK;
+ pmRet.iWinId = wIret.iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = pm->iTextSize;
+ pmRet.cArg = pm->cArg;
+ emit outputMessage(fd, &pmRet);
+
+}
+
+void PukeController::hdlrPukeDeleteWidget(int fd, PukeMessage *pm)
+{
+ widgetId wI;
+ wI.fd = fd;
+ wI.iWinId = pm->iWinId;
+
+ if(pm->iWinId == ControllerWinId) // Don't try and delete ourselves
+ throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_CONTROL));
+
+ /*
+ QIntDict<WidgetS> *qidWS = WidgetList[fd];
+ if(qidWS == 0){
+ kdDebug(5008) << "WidgetRunner:: no such set of widget descriptors?" << endl;
+ throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_SUCH_CONNECTION));
+ }
+ if(qidWS->find(wI.iWinId)){
+ // Remove the list item then delete the widget. This will stop
+ // the destroyed signal from trying to remove it again.
+ PObject *pw = qidWS->find(wI.iWinId)->pwidget;
+ qidWS->remove(wI.iWinId);
+ delete pw; pw = 0;
+ pmRet.iCommand = PUKE_WIDGET_DELETE_ACK;
+ }
+ else {
+ qWarning("WidgetRunner: no such widget: %d", wI.iWinId);
+ throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_SUCH_WIDGET));
+ }
+ */
+
+ if(checkWidgetId(&wI) == FALSE){
+ qWarning("WidgetRunner: no such widget: %d", wI.iWinId);
+ throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_SUCH_WIDGET));
+ }
+
+ WidgetList[fd]->find(wI.iWinId)->pwidget->manTerm();
+ delete WidgetList[fd]->find(wI.iWinId)->pwidget;
+
+ PukeMessage pmRet = *pm;
+ pmRet.iCommand = PUKE_WIDGET_DELETE_ACK;
+
+ emit outputMessage(fd, &pmRet);
+}
+
+void PukeController::closefd(int fd)
+{
+ if(bClosing == TRUE)
+ return;
+ bClosing = TRUE;
+ if(qidConnectFd[fd] == NULL){
+ kdDebug(5008) << "PukeController: Connect table NULL, closed twice?" << endl;
+ return;
+ }
+ // Shutof the listener before closing the socket, just in case.
+ qidConnectFd[fd]->sr->setEnabled(FALSE); // Shut them off
+ qidConnectFd[fd]->sw->setEnabled(FALSE);
+ delete qidConnectFd[fd]->sr;
+ delete qidConnectFd[fd]->sw;
+ qidConnectFd[fd]->server.truncate(0);
+ qidConnectFd.remove(fd);
+ close(fd);
+
+ /*
+ * Now let's remove all traces of the widgets
+ */
+ QIntDict<WidgetS> *qidWS = WidgetList[fd];
+ if(qidWS == 0){
+ kdDebug(5008) << "WidgetRunner:: Close called twice?" << endl;
+ bClosing = FALSE;
+ return;
+ }
+
+ qidWS->remove(PUKE_CONTROLLER);
+
+ do {
+
+ QIntDictIterator<WidgetS> it(*qidWS);
+ if(it.count() == 0){
+ kdDebug(5008) << "WidgetRunner: nothing left to delete\n" << endl;
+ break;
+ }
+
+ PObject *po = 0x0;
+ while(it.current()){
+ /*
+ * Delete all the layouts first
+ *
+ */
+ if(it.current()->type == POBJECT_LAYOUT){
+ po = it.current()->pwidget;
+ break;
+ }
+ ++it;
+ }
+
+ if(po != 0x0){
+ po->manTerm();
+ delete po;
+ continue;
+ }
+
+ /*
+ * reset
+ */
+ it.toFirst();
+ po = it.current()->pwidget;
+ po->manTerm();
+ delete po;
+
+
+ } while (qidWS->count() > 0);
+
+ WidgetList.remove(fd);
+ bClosing = FALSE;
+}
+
+bool PukeController::checkWidgetId(widgetId *pwi)
+{
+ if(WidgetList[pwi->fd] != NULL)
+ if(WidgetList[pwi->fd]->find(pwi->iWinId) != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+PObject *PukeController::id2pobject(widgetId *pwi){
+ if(checkWidgetId(pwi) == TRUE){
+ return WidgetList[pwi->fd]->find(pwi->iWinId)->pwidget;
+ }
+ throw(errorNoSuchWidget(*pwi));
+ return 0; // never reached
+}
+
+PObject *PukeController::id2pobject(int fd, int iWinId){
+ widgetId wi;
+ wi.fd = fd;
+ wi.iWinId = iWinId;
+
+ return id2pobject(&wi);
+}
+
+PWidget *PukeController::id2pwidget(widgetId *pwi){
+ PObject *obj = id2pobject(pwi);
+ if(obj->widget()->isWidgetType())
+ return (PWidget *) obj;
+ else
+ throw(errorNoSuchWidget(*pwi));
+ return NULL;
+}
+void PukeController::insertPObject(int fd, int iWinId, WidgetS *obj){
+ // If no widget list exists for this fd, create one
+ if(WidgetList[fd] == NULL){
+ QIntDict<WidgetS> *qidWS = new QIntDict<WidgetS>;
+ qidWS->setAutoDelete(TRUE);
+ WidgetList.insert(fd, qidWS);
+ }
+ // Set main widget structure list
+ WidgetList[fd]->insert(iWinId, obj);
+
+ // Set reverse list used durring delete to remove the widget
+ widgetId *pwi = new widgetId;
+ pwi->fd = fd;
+ pwi->iWinId = iWinId;
+ char key[keySize];
+ memset(key, 0, keySize);
+ sprintf(key, "%p", obj->pwidget);
+ revWidgetList.insert(key, pwi);
+
+ // Now connect to the destroyed signal so we can remove the object from the lists
+ // Once it is deleted
+ connect(obj->pwidget, SIGNAL(destroyed()),
+ this, SLOT(pobjectDestroyed()));
+}
+
+void PukeController::pobjectDestroyed(){
+
+ char key[keySize];
+ memset(key, 0, keySize);
+ sprintf(key, "%p", this->sender());
+
+ widgetId *pwi = revWidgetList[key];
+
+ if(pwi == NULL){
+ kdDebug(5008) << "Someone broke the rules for pwi: " << pwi->fd << ", " << pwi->iWinId << endl;
+ return;
+ }
+
+ if(checkWidgetId(pwi) == TRUE){
+ WidgetList[pwi->fd]->remove(pwi->iWinId);
+ }
+ else {
+ kdDebug(5008) << "Someone stole pwi: " << pwi->fd << ", " << pwi->iWinId << endl;
+ }
+
+ pwi = 0x0; // remove deletes pwi
+ revWidgetList.remove(key);
+
+}
+
+void PukeController::messageHandler(int fd, PukeMessage *pm) {
+ widgetId wI, wIret;
+ wI.fd = fd;
+ wI.iWinId = pm->iWinId;
+
+ commandStruct *cs;
+
+ cs = qidCommandTable[pm->iCommand];
+
+ if(cs != NULL){
+ (this->*(cs->cmd))(fd,pm);
+ }
+ else if(pm->iCommand == PUKE_WIDGET_CREATE){
+ wIret = wI;
+ wIret.iWinId = createWidget(wI, pm).iWinId; // Create the acutal pw
+
+ PukeMessage pmRet;
+ pmRet.iCommand = PUKE_WIDGET_CREATE_ACK;
+ pmRet.iWinId = wIret.iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = strdup(pm->cArg);
+ pmRet.iTextSize = strlen(pm->cArg);
+ emit outputMessage(fd, &pmRet);
+ free(pmRet.cArg);
+ }
+ else if(pm->iCommand == PUKE_WIDGET_LOAD){
+ PukeMessage pmRet = *pm;
+ KLibrary *library;
+ PObject *(*wc)(CreateArgs &ca);
+ widgetCreate *wC;
+
+ if(widgetCF[pm->iArg]){
+ pmRet.iCommand = -pm->iCommand;
+ pmRet.iTextSize = 0;
+ emit outputMessage(fd, &pmRet);
+ return;
+ }
+
+ if(pm->iTextSize == 0){
+ emit(errorCommandFailed(-pm->iCommand, 1));
+ return;
+ }
+
+ QString libName = "ksirc/lib"+QString::fromLatin1(pm->cArg);
+ if (libName.right(3) == ".so")
+ libName = libName.left(libName.length()-2)+"la";
+
+ library = KLibLoader::self()->library(libName);
+ if (!library) {
+ emit(errorCommandFailed(-pm->iCommand, 1));
+ return;
+ }
+ wc = (PObject *(*)(CreateArgs &ca) )
+ library->symbol("createWidget");
+
+ wC = new widgetCreate;
+ wC->wc = wc;
+ wC->library = library;
+ widgetCF.insert(pm->iArg, wC);
+
+ pmRet.iCommand = -pm->iCommand;
+ pmRet.iTextSize = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ else if(pm->iCommand == PUKE_WIDGET_UNLOAD){
+ if(widgetCF[pm->iArg]){
+// delete widgetCF[pm->iArg]->library;
+ widgetCF.remove(pm->iArg);
+ pm->iCommand = -pm->iCommand;
+ emit outputMessage(fd, pm);
+ }
+ }
+ else{
+ if(checkWidgetId(&wI) == TRUE){
+ WidgetList[wI.fd]->find(wI.iWinId)->pwidget->messageHandler(fd, pm);
+ }
+ else{
+ PukeMessage pmRet;
+ pmRet.iCommand = PUKE_INVALID;
+ pmRet.iWinId = wI.iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ }
+}
+
+widgetId PukeController::createWidget(widgetId wI, PukeMessage *pm)
+{
+ widgetId wIret;
+ PWidget *parent = 0; // Defaults to no parent
+ WidgetS *ws = new WidgetS;
+
+ /*
+ * The parent widget ID and type are packed into the iArg
+ * the pattern is 2 shorts.
+ */
+
+ int iParent, iType;
+ int found = sscanf(pm->cArg, "%d\t%d", &iParent, &iType);
+ if(found != 2)
+ throw(errorCommandFailed(PUKE_INVALID,7));
+
+ wI.iWinId = iParent; // wI is the identifier for the parent widget
+
+ if(widgetCF[iType] == NULL){ // No such widget, bail out.
+ wIret.fd = 0;
+ wIret.iWinId = 0;
+ throw(errorCommandFailed(PUKE_INVALID,1));
+ }
+
+ uiBaseWinId++; // Get a new base win id
+
+ // wIret holds the current widget id for the new widget
+ wIret.iWinId = uiBaseWinId;
+ wIret.fd = wI.fd;
+
+ if(checkWidgetId(&wI) == TRUE){
+ PObject *obj = WidgetList[wI.fd]->find(wI.iWinId)->pwidget;
+ if(obj->widget()->isWidgetType() == FALSE){
+ throw(errorCommandFailed(PUKE_INVALID, 0));
+ }
+ parent = (PWidget *) obj;
+ }
+
+ // CreateArgs arg = CreateArgs(this, pm, &wIret, parent)
+ CreateArgs arg(this, pm, &wIret, parent);
+ ws->pwidget = (widgetCF[iType]->wc)(arg);
+ if (ws->pwidget->hasError())
+ {
+ throw(errorCommandFailed(PUKE_INVALID, 0));
+ }
+ ws->type = iType;
+
+ connect(ws->pwidget, SIGNAL(outputMessage(int, PukeMessage*)),
+ this, SIGNAL(outputMessage(int, PukeMessage*)));
+
+ // insertPBoject(fd, uiBaseWinId, ws);
+ // The widget list has to exist since we have ourselves in the list
+ insertPObject(wIret.fd, wIret.iWinId, ws);
+// WidgetList[wIret.fd]->insert(wIret.iWinId, ws);
+ return wIret;
+}
+
+
+#include "controller.moc"
+
diff --git a/ksirc/puke/controller.h b/ksirc/puke/controller.h
new file mode 100644
index 00000000..80728224
--- /dev/null
+++ b/ksirc/puke/controller.h
@@ -0,0 +1,211 @@
+/*
+ * Main controller for:
+ *
+ * PUKE = Perl gUi Kontrol Environment
+ *
+ */
+
+#ifndef PUKE_CONTROLLER_H
+#define PUKE_CONTROLLER_H
+
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#include <qstring.h>
+#include <qdict.h>
+#include <qintdict.h>
+#include <qstrlist.h>
+
+#include "pmessage.h"
+#include "pobject.h"
+#include "pwidget.h"
+#include "commands.h"
+
+class PukeController;
+class KLibrary;
+
+typedef struct {
+ QString server;
+ bool writeable;
+ QSocketNotifier *sr,*sw;
+} fdStatus;
+
+
+struct commandStruct {
+ void (PukeController::*cmd)(int, PukeMessage*);
+ KLibrary *library;
+};
+
+typedef struct {
+ PObject *pwidget; // The widget
+ int type; // The type so casting is "safer"
+} WidgetS; // WidgetStruct
+
+typedef struct {
+ PObject *(*wc)(CreateArgs &ca);
+ KLibrary *library;
+} widgetCreate;
+
+class errorNoSuchWidget {
+public:
+ errorNoSuchWidget(widgetId &_wi)
+ {
+ wi = _wi;
+ }
+
+ widgetId &widgetIden() {
+ return wi;
+ }
+private:
+ widgetId wi;
+};
+
+class errorCommandFailed {
+public:
+ errorCommandFailed(int _command, int _iarg){
+ __command = _command;
+ __iarg = _iarg;
+ }
+
+ int command() { return __command; }
+ int iarg() { return __iarg; }
+
+private:
+ int __command, __iarg;
+};
+
+#define INVALID_DEL_NO_CONTROL 100
+#define INVALID_DEL_NO_SUCH_CONNECTION 101
+#define INVALID_DEL_NO_SUCH_WIDGET 102
+
+class PukeController : public PObject
+{
+ Q_OBJECT
+public:
+ PukeController(QString socket = "", QObject *parent=0, const char *name=0);
+ virtual ~PukeController();
+ bool running;
+
+ /**
+ * Verifies the widgetId exists and is a valid widget.
+ * True is valid, false if invalid.
+ */
+ bool checkWidgetId(widgetId *pwI);
+
+ /**
+ * id2pobject takes a window id and returns the reuired object
+ * it throw an errorNoSuchWidget on failures
+ */
+ PObject *id2pobject(int fd, int iWinId);
+ PObject *id2pobject(widgetId *pwi);
+ /**
+ * Return a PWidget if it's a widget, throws an exception if not found
+ */
+ PWidget *id2pwidget(widgetId *pwi);
+
+ QStrList allObjects();
+
+signals:
+ void PukeMessages(QString server, int command, QString args);
+ void inserted(QObject *);
+
+public slots:
+ void ServMessage(QString, int, QString);
+
+protected slots:
+ void Traffic(int);
+ void Writeable(int);
+ void NewConnect(int);
+ void slotInserted(QObject *obj);
+
+ /**
+ * When we delete a widget, this removes it from our internal
+ * list of widgets. We never remove a widget ourselfs, we call delete
+ * and this function removes it.
+ */
+ void pobjectDestroyed();
+
+ /**
+ * Fd to write to
+ * PukeMessage message to be written, if null buffer is flushed.
+ */
+ void writeBuffer(int fd, PukeMessage *message);
+
+
+private:
+ QString qsPukeSocket;
+ int iListenFd;
+ bool bClosing; // Set true if we are closing, we don't try and close twice at the same time.
+ QSocketNotifier *qsnListen;
+ QIntDict<fdStatus> qidConnectFd;
+
+ /**
+ * Controller ID is defined as 1
+ */
+ enum { ControllerWinId = PUKE_CONTROLLER };
+
+
+ // List of widgets and the fle descriptors they belong too
+ QIntDict<QIntDict<WidgetS> > WidgetList;
+ // I use a char * key that's the %p (hex address) of the pwidget
+ QDict<widgetId> revWidgetList;
+ enum { keySize = 10 };
+
+ // Funtions used to create new widget
+ QIntDict<widgetCreate> widgetCF; // widgetCreatingFuntion List
+
+ QIntDict<commandStruct> qidCommandTable;
+
+ void initHdlr();
+
+ void closefd(int fd);
+
+ void MessageDispatch(int fd, PukeMessage *pm);
+
+ /**
+ * WinId comes from a static unsigned int we increment for each new window
+ */
+ static uint uiBaseWinId;
+
+ /**
+ * Create new Widget, returns new iWinId for it.
+ * Takes server fd and parent winid, and type as arguments
+ */
+ widgetId createWidget(widgetId wI, PukeMessage *pm);
+
+ /**
+ * Used to process messages going to controller, winId #1
+ *
+ */
+ void messageHandler(int fd, PukeMessage *pm);
+
+ /**
+ * NOT APPLICAABLE
+ */
+ void setWidget(QObject *) { }
+ /**
+ * NOT APPLICAABLE
+ */
+ virtual QObject *widget() { return 0x0; }
+
+ /**
+ * Inserts a PObject into our internal list
+ */
+ void insertPObject(int fd, int iWinId, WidgetS *obj);
+
+ /**
+ * Closes a widget, checking for sanity
+ */
+// void closeWidget(widgetId wI);
+
+ // Message handlers
+ void hdlrPukeSetup(int fd, PukeMessage *pm);
+ void hdlrPukeInvalid(int fd, PukeMessage *pm);
+ void hdlrPukeEcho(int fd, PukeMessage *pm);
+ void hdlrPukeDumpTree(int fd, PukeMessage *pm);
+ void hdlrPukeFetchWidget(int fd, PukeMessage *pm);
+ void hdlrPukeDeleteWidget(int fd, PukeMessage *pm);
+
+};
+
+#endif
+
diff --git a/ksirc/puke/convert_commands.pl b/ksirc/puke/convert_commands.pl
new file mode 100755
index 00000000..98ad7e35
--- /dev/null
+++ b/ksirc/puke/convert_commands.pl
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+
+open(CMD, "cat commands.h *-cmd.h|");
+open(CMDP, ">commands-perl.pl");
+while(<CMD>){
+ if(/#define (\S+) (.+)/){
+ print CMDP "\$${1} = $2;\n";
+ print CMDP "\$PUKE_NAME2NUM\{'$1'\} = $2;\n";
+ print CMDP "\$PUKE_NUM2NAME\{'$2'\} = '$1';\n";
+ }
+}
+
+print CMDP "\n1;\n";
diff --git a/ksirc/puke/dcc_progress.pm b/ksirc/puke/dcc_progress.pm
new file mode 100644
index 00000000..a21ee26e
--- /dev/null
+++ b/ksirc/puke/dcc_progress.pm
@@ -0,0 +1,55 @@
+
+&docommand("/load pprogress.pm");
+
+package DCCProgress;
+
+@ISA = qw(PProgress);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->create();
+
+ $self->installHandler($::PUKE_KSPROGRESS_CANCEL_ACK,
+ sub {$self->cancelPressed(@_)});
+
+ return $self;
+}
+
+
+sub setRange {
+ my $self = shift;
+ my $min = shift;
+ my $max = shift;
+
+ $self->{'min'} = $min;
+ $self->{'max'} = $max;
+ $self->{'step'} = ($max - $min) / 100;
+ $self->{'step'} = 10240 if $self->{'step'} == 0; # if sized messed don't divide by 0 :)
+ $self->PProgress::setRange(0, 100);
+}
+
+sub setValue {
+ my $self = shift;
+
+ my $value = shift;
+
+ my $steps = int($value / $self->{'step'});
+
+ $self->PProgress::setValue($steps);
+}
+
+sub setCancel {
+ my $self = shift;
+ $self->{'cancelMessage'} = shift;
+}
+
+sub cancelPressed {
+ my $self = shift;
+
+ &::docommand($self->{'cancelMessage'});
+ $self->hide;
+
+} \ No newline at end of file
diff --git a/ksirc/puke/dcc_status.pm b/ksirc/puke/dcc_status.pm
new file mode 100644
index 00000000..65bc1b07
--- /dev/null
+++ b/ksirc/puke/dcc_status.pm
@@ -0,0 +1,525 @@
+#use lib "/opt/kde/share/apps/ksirc";
+
+&docommand("/load pbase.pm");
+&docommand("/load pwidget.pm");
+&docommand("/load pframe.pm");
+&docommand("/load ptablevw.pm");
+&docommand("/load plistbox.pm");
+&docommand("/load pbutton.pm");;
+&docommand("/load pboxlayout.pm");
+&docommand("/load plabel.pm");
+&docommand("/load pbutton.pm");
+&docommand("/load ppushbt.pm");
+&docommand("/load plined.pm");
+&docommand("/load pkfiledialog.pm");
+&docommand("/load ppopmenu.pm");
+
+&docommand("/load dcc_progress.pm");
+
+&docommand("/load plined.pm");
+&docommand("/load pprogress.pm");
+
+use POSIX qw(getcwd);
+use strict;
+
+package DCCSendDialog;
+use vars qw(@ISA);
+@ISA = qw(PFrame);
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+ $self->create();
+
+ my $gm_main = new PBoxLayout($self, $PBoxLayout::TopToBottom, 5);
+
+ my $gm_to = new PBoxLayout($PBoxLayout::LeftToRight, 5);
+ $gm_main->addLayout($gm_to);
+
+ my $label_to = new PLabel($self);
+ $label_to->setText("To Nick:");
+ $label_to->setMaximumSize(1000,30);
+ $label_to->setMinimumSize(50,30);
+ $gm_to->addWidget($label_to, 0, $PBoxLayout::AlignCenter);
+
+ my $line_to = new PLineEdit($self);
+ $gm_to->addWidget($line_to, 5, $PBoxLayout::AlignCenter);
+
+ my $gm_file = new PBoxLayout($PBoxLayout::LeftToRight, 5);
+ $gm_main->addLayout($gm_file);
+
+ my $label_file = new PLabel($self);
+ $label_file->setText("Filename:");
+ $label_file->setMaximumSize(1000,30);
+ $label_file->setMinimumSize(50,30);
+ $gm_file->addWidget($label_file, 0, $PBoxLayout::AlignCenter);
+
+ my $line_file = new PLineEdit($self);
+ $gm_file->addWidget($line_file, 5, $PBoxLayout::AlignLeft);
+
+ my $button_file = new PPushButton($self);
+ $button_file->setText("&Browse");
+ $button_file->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub{$self->browseClicked});
+ $gm_file->addWidget($button_file, 2, $PBoxLayout::AlignRight);
+
+ my $button_send = new PPushButton($self);
+ $button_send->setText("&Send");
+ $button_send->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub{$self->sendClicked});
+ $gm_main->addWidget($button_send, 4, $PBoxLayout::AlignRight);
+
+ @$self{'gm_main', 'gm_to', 'gm_file', 'label_to', 'line_to', 'label_file', 'line_file', 'button_file', 'button_send'}
+ = ($gm_main, $gm_to, $gm_file, $label_to, $line_to, $label_file, $line_file, $button_file, $button_send);
+
+ print "*I* Finished creating DCCSend\n";
+
+ $self->{fileDialog} = new PKFileDialog();
+ my $dlg = $self->{fileDialog};
+ $dlg->setDir(POSIX::getcwd());
+ $dlg->installHandler($::PUKE_KBFD_FILE_SELECTED_ACK, sub{$self->fileSelected(shift())});
+
+ $self->setMinimumSize(450, 110);
+ $self->setMaximumSize(2000, 2000);
+ $self->resize(450, 110);
+
+ return $self;
+
+}
+
+sub browseClicked {
+ my $self = shift;
+
+ $self->{fileDialog}->show();
+
+}
+
+sub fileSelected {
+ my $self = shift;
+
+ my $hargs = shift;
+
+ $self->{fileDialog}->hide();
+
+ my $file = $hargs->{'cArg'};
+
+ if($file ne ''){
+ $self->{'line_file'}->setText($file);
+ }
+}
+
+sub sendClicked {
+ my $self = shift;
+
+ my $to_nick = $self->{'line_to'}->text();
+ my $to_file = $self->{'line_file'}->text();
+
+ if($to_nick eq '' || $to_file eq ''){
+ return;
+ }
+
+ &::docommand("dcc send $to_nick $to_file");
+ $self->hide();
+}
+
+
+use vars qw(@ISA $KSIRC_DCC %KSIRC_DCC);
+
+package DCCStatus;
+use vars qw(@ISA);
+@ISA = qw(PFrame);
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+ $self->create();
+
+ my $gm_main = new PBoxLayout($self, $PBoxLayout::TopToBottom, 5);
+
+ my $label = new PLabel($self);
+ $label->setText("Pending DCC");
+ $label->setMaximumSize(1000,20);
+ $gm_main->addWidget($label, 5, $PBoxLayout::AlignCenter);
+ my $lb = new PListBox($self);
+ $gm_main->addWidget($lb, 5, $PBoxLayout::AlignCenter);
+
+ my $gm_but1 = new PBoxLayout($PBoxLayout::LeftToRight, 5);
+ $gm_main->addLayout($gm_but1);
+
+ my $button_get = new PPushButton($self);
+ $button_get->setText("&Open Connection");
+ $button_get->setMaximumSize(1000,30);
+ $button_get->setMinimumSize(10,30);
+ $button_get->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub{$self->openClicked});
+ $gm_but1->addWidget($button_get, 5);
+
+ my $button_forget = new PPushButton($self);
+ $button_forget->setText("&Forget Connection");
+ $button_forget->setMaximumSize(1000,30);
+ $button_forget->setMinimumSize(10,30);
+ $button_forget->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub{$self->forgetClicked});
+ $gm_but1->addWidget($button_forget, 5);
+
+ my $gm_but2 = new PBoxLayout($PBoxLayout::LeftToRight, 5);
+ $gm_main->addLayout($gm_but2);
+
+ my $button_send = new PPushButton($self);
+ $button_send->setText("&Send File");
+ $button_send->setMaximumSize(1000,30);
+ $button_send->setMinimumSize(10,30);
+ $button_send->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub{$self->sendClicked});
+ $gm_but2->addWidget($button_send, 5);
+
+ $gm_main->activate();
+
+ $self->setMinimumSize(400, 275);
+ $self->setMaximumSize(2000, 2000);
+ $self->resize(400, 275);
+
+ @$self{'gm_main', 'label1', 'lb', 'button_get', 'button_chat', 'button_forget', 'gm_but1', 'gm_but2', 'button_send' }
+ = ( $gm_main, $label, $lb, $button_get, $button_send, $button_forget, $gm_but1, $gm_but2, $button_send );
+
+
+ print "*I* Finished creating DCCStatus\n";
+
+ return $self;
+}
+
+sub addItem {
+ my $self = shift;
+
+ my %hargs = @_;
+
+ my $line = $hargs{'line'};
+
+ if($self->{'lines'}->{$line}){
+ return -1;
+ }
+
+ $self->{'lines'}->{$line}->{'OpenCode'} = $hargs{'open'};
+ $self->{'lines'}->{$line}->{'ForgetCode'} = $hargs{'forget'};
+
+ $self->{'lb'}->insertText($line, -1);
+ if($self->{'lb'}->currentText() eq ''){
+ $self->{'lb'}->setCurrentItem(0);
+ }
+
+ return 0;
+}
+
+sub openClicked {
+ my $self = shift;
+
+ my $line = $self->{'lb'}->currentText();
+ if($line eq ''){
+ return;
+ }
+
+ &{$self->{'lines'}->{$line}->{'OpenCode'}};
+ $self->{'lb'}->removeItem($self->{'lb'}->current());
+ if($self->{'lb'}->{count} == 0){
+ $self->hide();
+ }
+
+ delete $self->{'lines'}->{$line};
+
+}
+
+sub forgetClicked {
+ my $self = shift;
+
+ my $line = $self->{'lb'}->currentText();
+ if($line eq ''){
+ return;
+ }
+
+ &{$self->{'lines'}->{$line}->{'ForgetCode'}};
+ $self->{'lb'}->removeItem($self->{'lb'}->current());
+ if($self->{'lb'}->{count} == 0){
+ $self->hide();
+ }
+
+
+ delete $self->{'lines'}->{$line};
+
+}
+
+sub sendClicked {
+ my $self = shift;
+
+ if(!$self->{sendDialog}){
+ my $dlg = new DCCSendDialog();
+ if($dlg == undef){
+ &print("*E* Could not load DCCSendDialog");
+ return;
+ }
+ $self->{sendDialog} = $dlg;
+ }
+
+ $self->{sendDialog}->show();
+}
+
+sub DESTROY {
+ print "*E* Destroying dcc status widget\n";
+ shift()->close();
+}
+
+sub close {
+ my $self = shift;
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_DELETE,
+ 'CallBack' => sub {},
+ 'WaitFor' => 1);
+ # $self->{'gm_main'}->DESTROY;
+ #elete $self->{'gm_main'};
+}
+
+package DCCPopupMenu;
+use vars qw(@ISA);
+@ISA = qw(PPopupMenu);
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+ $self->create();
+ return $self;
+}
+
+sub insertText {
+ my $self = shift;
+
+ my $id = $self->SUPER::insertText(@_);
+
+ my @arr;
+
+ if(ref($self->{'Ids'}) ne 'ARRAY'){
+ $self->{'Ids'} = \@arr;
+ }
+
+ @arr = @{$self->{'Ids'}};
+
+ $arr[$#arr+1] = $id;
+
+ $self->{'Ids'} = \@arr;
+
+ return $id;
+}
+
+sub DESTROY {
+ my $self = shift;
+
+ my @arr = @{$self->{'Ids'}};
+ my $id;
+
+ foreach $id (@arr) {
+ $self->removeItem($id);
+ }
+
+ $self->sendMessage('iCommand' => $::PUKE_RELEASEWIDGET,
+ 'CallBack' => sub {});
+
+
+}
+
+
+package main;
+use vars qw($KSIRC_DCC %KSIRC_DCC $who $KSIRC_DCCSTATUS $silent $nick $KSIRC_POPSC $KSIRC_POPDOCK);
+
+sub hook_ksirc_dcc_request {
+ my($type) = shift;
+ my($machine) = shift;
+ my($port) = shift;
+ my($file) = shift;
+ my($size) = shift;
+ my($mwho) = $who;
+ if($KSIRC_DCCSTATUS == undef){
+ $KSIRC_DCCSTATUS = new DCCStatus;
+ $KSIRC_DCCSTATUS->resize(400, 275);
+ }
+
+ if($type eq 'SEND'){
+ my $open = sub {
+ &docommand("/dcc get $mwho $file");
+ };
+ my $forget = sub {
+ &docommand("/dcc close get $mwho $file");
+ };
+ $::KSIRC_FILE_SIZES{$file} = $size;
+ $KSIRC_DCCSTATUS->addItem('line' => "SEND: $who offered $file at size $size",
+ 'open' => $open,
+ 'forget' => $forget);
+ }
+ elsif($type eq 'CHAT'){
+ $KSIRC_DCCSTATUS->addItem('line' => "CHAT: $who",
+ 'open' => sub { &docommand("/dcc chat $mwho"); },
+ 'forget' => sub { &docommand("/dcc close chat $mwho"); });
+
+ }
+ $KSIRC_DCCSTATUS->show;
+
+}
+
+&addhook("dcc_request", "ksirc_dcc_request");
+
+sub hook_ksirc_dcc_send {
+ my $nick = shift;
+ my $file = shift;
+ my $size = shift;
+ my $fh = shift;
+
+ # print "*I* Starting dcc into with: $nick, $file, $size, $fh\n";
+
+ my($window) = new DCCProgress;
+ $size = 10240 if $size == 0;
+ $window->setRange(0, $size);
+ $window->setCaption("$file=>$nick");
+ $window->setTopText("Sending: $file Size: $size");
+ $window->setBotText("Status: pending");
+ $window->setCancel("dcc close send $nick $file");
+ $KSIRC_DCC{$fh}{$file}{'Window'} = $window;
+ $KSIRC_DCC{$fh}{$file}{'StartTime'} = time() - 1;
+ $window->show;
+}
+
+&addhook("dcc_send", "ksirc_dcc_send");
+
+sub hook_ksirc_dcc_send_status {
+ my $file = shift;
+ my $bytes = shift;
+ my $fh = shift;
+
+ my $window = $KSIRC_DCC{$fh}{$file}{'Window'};
+ if($window == undef){
+ my($window) = new DCCProgress;
+ $window->setRange(0, 1);
+ $window->setCaption("$file=>$nick");
+ $window->setTopText("Sending: $file Size: Unkown");
+ $window->setCancel("dcc close send $nick $file");
+ $KSIRC_DCC{$fh}{$file}{'Window'} = $window;
+ $KSIRC_DCC{$fh}{$file}{'StartTime'} = time() - 1;
+ $window->show;
+ }
+ $window->setBotText("BPS: " . int($bytes/(time() - $KSIRC_DCC{$fh}{$file}{'StartTime'})));
+ $window->setValue($bytes);
+}
+
+&addhook("dcc_send_status", "ksirc_dcc_send_status");
+
+sub hook_ksirc_dcc_get {
+ my $nick = shift;
+ my $file = shift;
+ my $fh = shift;
+
+ my $size = $::KSIRC_FILE_SIZES{$file};
+
+#print "*I* Starting dcc into with: $nick, $file, $size, $fh\n";
+
+ if($KSIRC_DCC{$fh}{$file}{'Window'} == undef){
+ my($window) = new DCCProgress;
+ $size = 10240 if $size == 0;
+ $window->setRange(0, $size);
+ $window->setCaption("$file<=$nick");
+ $window->setTopText("Receiver: $file Size: $size");
+ $window->setBotText("Status: pending");
+ $window->setCancel("dcc close get $nick $file");
+ $KSIRC_DCC{$fh}{$file}{'Window'} = $window;
+ $KSIRC_DCC{$fh}{$file}{'StartTime'} = time() - 1;
+ $window->show;
+ }
+}
+
+&addhook("dcc_get", "ksirc_dcc_get");
+
+sub hook_ksirc_dcc_get_status {
+ my $file = shift;
+ my $bytes = shift;
+ my $fh = shift;
+
+ my $window = $KSIRC_DCC{$fh}{$file}{'Window'};
+ if($window == undef){
+ my($window) = new DCCProgress;
+ $window->setRange(0, 1);
+ $window->setCaption("$file<=$nick");
+ $window->setTopText("Receiver: $file Size: Unkown");
+ $window->setBotText("Status: pending");
+ $window->setCancel("dcc close get $nick $file");
+ $KSIRC_DCC{$fh}{$file}{'Window'} = $window;
+ $KSIRC_DCC{$fh}{$file}{'StartTime'} = time() - 1;
+ $window->show;
+ }
+ $window->setBotText("BPS: " . int($bytes/(time() - $KSIRC_DCC{$fh}{$file}{'StartTime'})));
+ $window->setValue($bytes);
+}
+
+&addhook("dcc_get_status", "ksirc_dcc_get_status");
+
+
+sub hook_ksirc_dcc_disconnect {
+ my $nick = shift;
+ my $file = shift;
+ my $bytes = shift;
+ my $time = shift;
+ my $fh = shift;
+
+ if($fh){
+ my $window = $KSIRC_DCC{$fh}{$file}{'Window'};
+ $window->close();
+ delete $KSIRC_DCC{$fh}{$file};
+ delete $KSIRC_DCC{$fh};
+ print "*D* DCC transfer with $nick ($file) terminated; $bytes transferred in $time seconds (" . int(($bytes/($time+1))/1024) . "KBps)";
+ $silent = 1;
+ }
+}
+
+addhook("dcc_disconnect", "ksirc_dcc_disconnect");
+
+
+
+&print("*I* Done DCC Status");
+#$::test = new DCCStatus;
+#$::test->resize(400, 275);
+#$::test->show();
+
+sub popup_dccstatus{
+ if($KSIRC_DCCSTATUS == undef){
+ $KSIRC_DCCSTATUS = new DCCStatus;
+ $KSIRC_DCCSTATUS->resize(400, 275);
+ }
+ $KSIRC_DCCSTATUS->show();
+}
+
+sub popup_dccsend{
+ if($KSIRC_DCCSTATUS == undef){
+ $KSIRC_DCCSTATUS = new DCCStatus;
+ $KSIRC_DCCSTATUS->resize(400, 275);
+ }
+ $KSIRC_DCCSTATUS->sendClicked();
+}
+
+=cut
+if(!$KSIRC_POPSC){
+ $KSIRC_POPSC = new DCCPopupMenu();
+ if($KSIRC_POPSC->fetchWidget("servercontroller_menu_file") >= 0){
+ my $id_control = $KSIRC_POPSC->insertText("Show DCC Control ($::server)");
+ my $id_send = $KSIRC_POPSC->insertText("Show DCC Send ($::server)");
+ $KSIRC_POPSC->installMenu($id_control, sub{&popup_dccstatus();});
+ $KSIRC_POPSC->installMenu($id_send, sub{&popup_dccsend();});
+ }
+}
+
+if(!$KSIRC_POPDOCK){
+ $KSIRC_POPDOCK = new DCCPopupMenu();
+ if($KSIRC_POPDOCK->fetchWidget("dockServerController_menu_pop") >= 0){
+ my $id_control = $KSIRC_POPDOCK->insertText("Show DCC Control ($::server)");
+ my $id_send = $KSIRC_POPDOCK->insertText("Show DCC Send ($::server)");
+ $KSIRC_POPDOCK->installMenu($id_control, sub { &popup_dccstatus(); } );
+ $KSIRC_POPDOCK->installMenu($id_send, sub { &popup_dccsend(); } );
+ }
+}
+=cut
+
+sub hook_quit_release {
+ $KSIRC_POPDOCK->DESTROY();
+ $KSIRC_POPSC->DESTROY();
+}
+
+&addhook("quit", "quit_release");
+
+1;
diff --git a/ksirc/puke/load_all.pm b/ksirc/puke/load_all.pm
new file mode 100644
index 00000000..26594c0f
--- /dev/null
+++ b/ksirc/puke/load_all.pm
@@ -0,0 +1,14 @@
+&docommand("/load pbase.pm");
+&docommand("/load pwidget.pm");
+&docommand("/load pframe.pm");
+&docommand("/load pboxlayout.pm");
+&docommand("/load plined.pm");
+&docommand("/load pbutton.pm");
+&docommand("/load ppushbt.pm");
+&docommand("/load pprogress.pm");
+&docommand("/load ptablevw.pm");
+&docommand("/load plistbox.pm");
+&docommand("/load ppopmenu.pm");
+&docommand("/load ptabdialog.pm");
+&docommand("/load pkfiledialog.pm");
+&docommand("/load pobjfinder.pm");
diff --git a/ksirc/puke/palistbox.cpp b/ksirc/puke/palistbox.cpp
new file mode 100644
index 00000000..8f3f22f1
--- /dev/null
+++ b/ksirc/puke/palistbox.cpp
@@ -0,0 +1,156 @@
+#include <kdebug.h>
+
+
+#include "palistbox.h"
+
+PObject *
+PAListBox::createWidget(CreateArgs &ca)
+{
+ PAListBox *plb = new PAListBox(ca.parent);
+ aListBox *lb;
+ if(ca.fetchedObj != 0 && ca.fetchedObj->inherits("aListBox") == TRUE){
+ lb = (aListBox *) ca.fetchedObj;
+ plb->setDeleteAble(FALSE);
+ }
+ else if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ lb = new aListBox((QWidget *) ca.parent->widget());
+ else
+ lb = new aListBox();
+ plb->setWidget(lb);
+ plb->setWidgetId(ca.pwI);
+ return plb;
+}
+
+
+PAListBox::PAListBox(PObject *parent)
+ : PListBox(parent)
+{
+ // kdDebug(5008) << "PListBox PListBox called" << endl;
+ lb = 0;
+ setWidget(lb);
+}
+
+PAListBox::~PAListBox()
+{
+ // kdDebug(5008) << "PListBox: in destructor" << endl;
+ /*
+ delete widget(); // Delete the frame
+ lb=0; // Set it to 0
+ setWidget(lb); // Now set all widget() calls to 0.
+ */
+}
+
+void PAListBox::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_LISTBOX_INSERT_SORT:
+ if(!checkWidget())
+ return;
+
+ widget()->inSort(pm->cArg, (bool) pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->count();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_ALISTBOX_ISTOP:
+ if(!checkWidget())
+ return;
+
+ pmRet.iArg = widget()->isTop(pm->iArg);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_ALISTBOX_FIND_NICK:
+ if(!checkWidget())
+ return;
+
+ pmRet.iArg = widget()->findNick(pm->cArg);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_ALISTBOX_SMALL_HIGHLIGHT:
+ {
+ if(!checkWidget())
+ return;
+
+ int index = widget()->findNick(pm->cArg);
+ nickListItem *item = new nickListItem();
+ *item = *widget()->item(index);
+ widget()->removeItem(index);
+ item->setVoice(pm->iArg);
+ widget()->inSort(item);
+ widget()->repaint(TRUE);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+ case PUKE_ALISTBOX_BIG_HIGHLIGHT:
+ {
+ if(!checkWidget())
+ return;
+
+ int index = widget()->findNick(pm->cArg);
+ nickListItem *item = new nickListItem();
+ *item = *widget()->item(index);
+ widget()->removeItem(index);
+ item->setOp(pm->iArg);
+ widget()->inSort(item);
+ widget()->repaint(TRUE);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+
+ default:
+ PListBox::messageHandler(fd, pm);
+ }
+}
+
+void PAListBox::setWidget(QObject *_lb)
+{
+ if(_lb != 0 && _lb->inherits("aListBox") == FALSE)
+ {
+ errorInvalidSet(_lb);
+ return;
+ }
+
+ lb = (aListBox *) _lb;
+ if(lb != 0){
+ }
+ PListBox::setWidget(lb);
+
+}
+
+
+aListBox *PAListBox::widget()
+{
+ return lb;
+}
+
+bool PAListBox::checkWidget(){
+ if(widget() == 0){
+ kdDebug(5008) << "PAListBox: No Widget set" << endl;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#include "palistbox.moc"
+
diff --git a/ksirc/puke/palistbox.h b/ksirc/puke/palistbox.h
new file mode 100644
index 00000000..0731bef9
--- /dev/null
+++ b/ksirc/puke/palistbox.h
@@ -0,0 +1,35 @@
+#ifndef PALISTBOX_H
+#define PALISTBOX_H
+
+class PAListBox;
+
+#include "../alistbox.h"
+#include "pmessage.h"
+#include "plistbox.h"
+#include "controller.h"
+
+class PAListBox : public PListBox
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PAListBox ( PObject * parent );
+ virtual ~PAListBox ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_lb = 0x0);
+ virtual aListBox *widget();
+
+public slots:
+
+protected:
+ bool checkWidget();
+
+private:
+ aListBox *lb;
+
+};
+
+#endif
diff --git a/ksirc/puke/palistbox.pm b/ksirc/puke/palistbox.pm
new file mode 100644
index 00000000..e1dcb691
--- /dev/null
+++ b/ksirc/puke/palistbox.pm
@@ -0,0 +1,117 @@
+
+&::PukeSendMessage($::PUKE_WIDGET_LOAD,
+ $::PUKE_CONTROLLER,
+ $::PWIDGET_ALISTBOX,
+ "palistbox.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PAListBox Load failed!\n";
+ }
+ }
+ );
+
+
+package PAListBox;
+@ISA = qw(PListBox);
+use strict;
+
+if($PListBox::usage == undef){
+ $PListBox::usage = 0;
+}
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_ALISTBOX;
+
+ if($class eq 'PAListBox'){
+ $self->create();
+ }
+
+ $self->installHandler($::PUKE_LISTBOX_SELECTED_ACK, sub{$self->selected(@_)});
+
+ return $self;
+
+}
+
+sub DESTROY {
+ my $self = shift;
+ $self->SUPER::DESTROY(@_);
+ $PAListBox::usage--;
+ if($PAListBox::usage == 0){
+ &::PukeSendMessage($::PUKE_WIDGET_UNLOAD,
+ 0,
+ $::PWIDGET_ALISTBOX,
+ "",
+ sub {}
+ );
+
+ }
+}
+
+sub inSort {
+ my $self = shift;
+ my $text = shift;
+ my $top = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_INSERT_SORT,
+ 'cArg' => $text,
+ 'iArg' => $text >= 1 ? 1 : 0,
+ 'CallBack' => sub {});
+
+}
+
+sub isTop {
+ my $self = shift;
+ my $text = shift;
+
+ my %ret = $self->sendMessage('iCommand' => $::PUKE_ALISTBOX_ISTOP,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+ return $ret{'iArg'};
+
+}
+
+sub findNick {
+ my $self = shift;
+ my $text = shift;
+
+ my %ret = $self->sendMessage('iCommand' => $::PUKE_ALISTBOX_FIND_NICK,
+ 'cArg' => $text,
+ 'CallBack' => sub {},
+ 'WaitFor' => 1);
+
+ return $ret{'iArg'};
+
+}
+
+sub smallHighligh {
+ my $self = shift;
+ my $text = shift;
+ my $highlight = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_ALISTBOX_SMALL_HIGHLIGHT,
+ 'cArg' => $text,
+ 'iArg' => $highlight,
+ 'CallBack' => sub {});
+
+}
+
+sub bigHighligh {
+ my $self = shift;
+ my $text = shift;
+ my $highlight = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_ALISTBOX_BIG_HIGHLIGHT,
+ 'cArg' => $text,
+ 'iArg' => $highlight,
+ 'CallBack' => sub {});
+
+}
+
+
+package main;
+
+1;
diff --git a/ksirc/puke/pbase.pm b/ksirc/puke/pbase.pm
new file mode 100644
index 00000000..b8345cdb
--- /dev/null
+++ b/ksirc/puke/pbase.pm
@@ -0,0 +1,265 @@
+
+package PBase;
+use Carp;
+#use Data::Dumper;
+use strict;
+
+$PBase::NO_WIDGET = -1;
+
+$::AlignLeft = 0x0001;
+$::AlignRight = 0x0002;
+$::AlignHCenter = 0x0004;
+$::AlignTop = 0x0008;
+$::AlignBottom = 0x0010;
+$::AlignVCenter = 0x0020;
+$::AlignCenter = $::AlignVCenter | $::AlignHCenter;
+
+sub sendMessage {
+ my $self = shift;
+
+ my %ARG = @_;
+ $ARG{"iWinId"} = $self->{iWinId} if($ARG{"iWinId"} == undef);
+
+ return &::PukeSendMessage($ARG{"iCommand"},
+ $ARG{"iWinId"},
+ $ARG{"iArg"},
+ $ARG{"cArg"},
+ $ARG{"CallBack"},
+ $ARG{"WaitFor"}
+ );
+}
+
+sub rndchr {
+ my $string = "";
+ my $i;
+ for($i = 0; $i < 8; $i++){
+ $string .= chr(int(rand(93)) + 0x21); # 0x21 since we don't want spaces and 0x20 is space.
+ }
+ return $string;
+}
+
+sub new {
+ my $class = shift;
+ my $parent = $_[$#_];
+
+ my $self = {};
+
+
+# print "Parent: $parent\n";
+
+ bless($self, $class);
+
+ $parent = 0 if($parent == undef);
+
+ $self->{iWinId} = -1;
+ $self->{Parent} = $parent if $parent != 0;
+ $self->{initId} = $self->rndchr();
+ $self->{widgetType} = $PBase::NO_WIDGET;
+ $self->{cmdQueue} = ();
+
+ if($::PUKE_FETCH_WIDGET == 1) {
+ $self->{Fetch} = 1;
+ }
+
+ # $self->installHandler($::PUKE_WIDGET_DELETE_ACK, sub{$self->DESTROY});
+
+ return $self;
+
+}
+
+sub create {
+ my $self = shift;
+
+ if($self->{widgetType} == undef ||
+ $self->{widgetType} == $PBase::NO_WIDGET) {
+ print("*E* PBase: Widget type was undefined, $self is really broken\n");
+ print("*E* PBase: Giving up\n");
+ return;
+ }
+
+ my $parent = $self->{Parent} ? $self->{Parent}->{iWinId} : 0;
+
+ # print "*I* Createing widget of type: " . $self->{widgetType} . " with parent " . $parent . "\n";
+
+ $self->{runable} = 1;
+
+ my $carg = $parent . "\t" . $self->{widgetType} . "\t" . $self->{initId};
+
+ my %REPLY = $self->sendMessage('iCommand' => $::PUKE_WIDGET_CREATE,
+ 'iWinId' => $::PUKE_CONTROLLER,
+ 'cArg' => $carg,
+ 'CallBack' => sub { },
+ 'WaitFor' => 1);
+
+ if($REPLY{iWinId} <= 0){
+ print "*E* Widget Create Failed!\n";
+ }
+
+ $self->ackWinId(%REPLY);
+
+ $self->clearQueue();
+ # $self->setRunable(0);
+}
+
+sub fetchWidget {
+ my $self = shift;
+
+ $self->{objName} = shift;
+ my $regex = shift;
+
+# $self->sendMessage('iCommand' => $::PUKE_WIDGET_DELETE,
+# 'CallBack' => sub { print "Deleted\n"; });
+
+ $regex = "0" if($regex eq '');
+ my $carg = $regex . "\t" . $self->{widgetType} . "\t" . $self->{initId} . "\t" . $self->{objName};
+
+ my %REPLY = $self->sendMessage('iCommand' => $::PUKE_FETCHWIDGET,
+ 'iWinId' => $::PUKE_CONTROLLER,
+ 'cArg' => $carg,
+ 'CallBack' => sub { },
+ 'WaitFor' => 1);
+
+ if($REPLY{iWinId} <= 0){
+ print "*E* Widget Fetch Failed!\n";
+ return -1;
+ }
+ my $winid;
+ my $cmd;
+ foreach $cmd (values %::PUKE_W_HANDLER){
+ next unless ref $cmd eq 'CODE';
+ foreach $winid (values %{$::PUKE_W_HANDLER{$cmd}}){
+ if($winid == $self->{'iWinId'}){
+ $::PUKE_W_HANDLER{$cmd}{$REPLY{iWinId}} = $::PUKE_W_HANDLER{$cmd}{$self->{iWinId}};
+ delete $::PUKE_W_HANDLER{$cmd}{$self->{iWinId}};
+ }
+ }
+ }
+
+ $self->ackWinId(%REPLY);
+ $self->{'Fetch'} = 1;
+ # $self->setRunable(0);
+ return 0;
+}
+
+sub releaseWidget {
+ my $self = shift;
+ $self->sendMessage('iCommand' => $::PUKE_RELEASEWIDGET,
+ 'CallBack' => sub {});
+}
+
+sub treeInfo {
+ my $self = shift;
+
+ my %REPLY = $self->sendMessage('iCommand' => $::PUKE_DUMPTREE,
+ 'iWinId' => $::PUKE_CONTROLLER,
+ 'CallBack' => sub { },
+ 'WaitFor' => 0);
+
+}
+
+
+sub DESTROY {
+ my $self = shift;
+
+ # print "*I* Widget Deleted\n";
+ eval{ $self->hide(); }; # Hide doesn't exist for all PBase's
+
+ # $self->setRunable(1);
+
+ delete($::PBASE_IMORTALS{$self->{IMMORTAL}});
+
+ if($self->{'Fetch'} != 1 && $self->{DESTROYED} != 1 && $self->{Parent} == 0){
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_DELETE,
+ 'CallBack' => sub {});
+ }
+
+ if($self->{'Fetch'} == 1){
+ $self->sendMessage('iCommand' => $::PUKE_RELEASEWIDGET,
+ 'CallBack' => sub {});
+
+ }
+
+ # $self->setRunable(0);
+ $self->{iWinId} = -1;
+ $self->{DESTROYED} = 1;
+
+}
+
+sub close {
+ my $self = shift;
+
+ $self->hide();
+
+ $self->DESTROY;
+
+}
+
+sub ackWinId {
+ my $self = shift;
+ my %ARG = @_;
+
+ if($ARG{'iWinId'} <= 1){
+ die("Failed on ack'ing Window ID, stopping!");
+ }
+
+ $self->{iWinId} = $ARG{'iWinId'};
+}
+
+
+sub installHandler {
+ my $self = shift;
+
+ my $command = shift;
+ my $handler = shift;
+
+ my $cmd =
+ sub {
+ $::PUKE_W_HANDLER{$command}{$self->{iWinId}} = $handler;
+ };
+
+ if($self->{iWinId} == -1){
+ $self->addQueue($cmd);
+ }
+ else{
+ &$cmd();
+ }
+
+}
+
+sub onNext {
+ my $self = shift;
+
+ my $cb = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_ECHO,
+ 'iArg' => 0,
+ 'iWinId' => $self->{iWinId},
+ 'cArg' => "",
+ 'CallBack' => $cb);
+}
+
+sub immortal {
+ my $self = shift;
+ $self->{IMMORTAL} = &rndchr;
+ $::PBASE_IMORTALS{$self->{IMMORTAL}} = $self;
+ return $self;
+}
+
+sub addQueue {
+ my $self = shift;
+
+ push(@{$self->{cmdQueue}}, shift());
+}
+
+sub clearQueue {
+ my $self = shift;
+
+ my $cmd;
+ while($cmd = pop(@{$self->{cmdQueue}})){
+ &$cmd;
+ }
+}
+
+package main;
+
+1;
diff --git a/ksirc/puke/pboxlayout.pm b/ksirc/puke/pboxlayout.pm
new file mode 100644
index 00000000..505ddc0d
--- /dev/null
+++ b/ksirc/puke/pboxlayout.pm
@@ -0,0 +1,201 @@
+
+package PBoxLayout;
+@ISA = qw(PBase);
+use strict;
+
+# setup default handlers
+
+$PBoxLayout::LeftToRight = 0;
+$PBoxLayout::RightToLeft = 1;
+$PBoxLayout::TopToBottom = 2;
+$PBoxLayout::BottomToTop = 3;
+
+$PBoxLayout::AlignLeft = 0x0001;
+$PBoxLayout::AlignRight = 0x0002;
+$PboxLayout::AlignHCenter = 0x0004;
+$PBoxLayout::AlignTop = 0x0008;
+$PBoxLayout::AlignBottom = 0x0010;
+$PBoxLayout::AlignVCenter = 0x0020;
+$PBoxLayout::AlignCenter = $PBoxLayout::AlignVCenter |
+ $PBoxLayout::AlignHCenter;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ my $widget = shift;
+
+ # print "Widget: " . ref($widget) . "\n";
+
+ # if(ref($widget) eq ''){
+ # print "*E* Error Creating PBoxLayout, did not give valid parent\n";
+ # return;
+ #}
+ # elsif(ref($widget) eq 'PBoxLayout'){
+ # $self->{Parent} = $widget;
+ # $self->{ParentType} = 'Layout';
+ # $self->{Direction} = shift;
+ # $self->{Border} = shift;
+ # $self->{Added} = 0;
+ #}
+ # else{
+ if(ref($widget) ne ''){
+ # print "*\cbI\cb* Generic Non-topleve layout type\n";
+ $self->{Parent} = $widget;
+ $self->{ParentType} = 'Widget';
+ $self->{Direction} = shift;
+ $self->{Border} = shift;
+ $self->{Added} = 1;
+ }
+ else{
+ $self->{Parent} = undef;
+ $self->{ParentType} = 'Layout';
+ $self->{Direction} = $widget;
+ $self->{Border} = shift;
+ $self->{Added} = 0;
+
+ }
+
+ $self->{IAmALayout} = 1;
+ $self->{Widgets} = ();
+
+ $self->create();
+
+ return $self;
+
+}
+
+sub create {
+ my $self = shift;
+
+ #
+ # PLayout redefines create since it uses a special cArg
+ #
+ my($paren_id) = 0;
+ $paren_id = $self->{Parent}->{iWinId} if $self->{Parent} != -1;
+
+ if($paren_id eq ''){
+ $paren_id = "0";
+ }
+
+ my $carg = $paren_id . "\t" . $::POBJECT_LAYOUT . "\t" . $self->{Direction} . "\t" . $self->{Border} . "\t" . $self->{initId},
+
+ my %REPLY;
+ %REPLY = $self->sendMessage('iCommand' => $::PUKE_WIDGET_CREATE,
+ 'iWinId' => $::PUKE_CONTROLLER,
+ 'cArg' => $carg,
+ 'CallBack' => sub { },
+ 'WaitFor' => 1);
+
+ $self->ackWinId(%REPLY);
+
+}
+
+sub addWidget {
+ my $self = shift;
+
+ my $widget = shift;
+ my $stretch = shift;
+ my $align = shift;
+
+ if($self->{Added} == 0){
+ print "*E* Burp: Can't add widget without first being added to parent layout\n";
+ return;
+ }
+
+ $align = $PBoxLayout::AlignCenter if $align == undef;
+ $stretch = 0 if $stretch == undef;
+
+ # $widget->immortal(); # If it's a widget, it cannot be deleted
+ if($widget->{iWinId} <= 0){
+ print "*E* Trying to add invalid widget " . ref($widget) . "\n";
+ return;
+ }
+
+ my $cArg = pack("CC", $stretch, $align);
+
+ $self->sendMessage('iCommand' => $::PUKE_LAYOUT_ADDWIDGET,
+ 'iArg' => $widget->{iWinId},
+ 'cArg' => $cArg,
+ 'CallBack' => sub { },
+ 'WaitFor' => 1);
+
+ $self->{Widgets}->[ $#{$self->{Widgets}} + 1] = $widget;
+
+}
+
+sub addLayout {
+ my $self = shift;
+
+ if($self->{Added} == 0){
+ print "*E* Burp: Can't add layout without first being added to parent layout\n";
+ }
+
+
+ my $layout = shift;
+ if(ref($layout) ne 'PBoxLayout'){
+ print "*E* Passed non layout type to addLayout\n";
+ return 1;
+ }
+
+ if($layout->{iWinId} <= 0){
+ print "*E* Trying to add invalid layout " . ref($layout) . "\n";
+ return;
+ }
+
+
+ # make sure we can run, and the widget we want to add can run.
+ # my @ARG = ($layout);
+ #$self->canRun($self, \&PBoxLayout::addLayout, \@ARG) || return;
+ #$layout->canRun($self, \&PBoxLayout::addLayout, \@ARG) || return;
+
+ my %REPLY = $self->sendMessage('iCommand' => $::PUKE_LAYOUT_ADDLAYOUT,
+ 'iWinId' => $self->{iWinId},
+ 'iArg' => $layout->{iWinId},
+ 'cArg' => pack("C", 0),
+ 'CallBack' => sub { },
+ 'WaitFor' => 1);
+
+ # print "*I* Adding layout\n";
+ if($REPLY{'iArg'} != 0){
+ print "*E* AddLayout call failed\n";
+ }
+ else{
+ # print "*I* Added new Layout for " . $layout->{iWinId} . "\n";
+ $layout->{Added} = 1;
+ }
+
+}
+
+sub DESTROY {
+ my $self = shift;
+
+ # print "*I* Layout Deleted\n";
+
+ # if($self->{DESTROYED} != 1){
+ # $self->sendMessage('iCommand' => $::PUKE_WIDGET_DELETE,
+ # 'CallBack' => sub { print "Deleted\n"; });
+ #}
+
+ $self->{iWinId} = -1;
+ $self->{DESTROYED} = 1;
+
+}
+
+sub activate {
+ my $self = shift;
+
+ if($self->{ParentType} != 'Widget'){
+ print "*E* Only call for TopLevel managers\n";
+ return;
+ }
+
+ $self->sendMessage('iCommand' => $::PUKE_LAYOUT_ACTIVATE,
+ 'CallBack' => sub { },
+ 'WaitFor' => 1);
+
+}
+
+
+package main;
+1;
diff --git a/ksirc/puke/pbutton.cpp b/ksirc/puke/pbutton.cpp
new file mode 100644
index 00000000..309f2ac7
--- /dev/null
+++ b/ksirc/puke/pbutton.cpp
@@ -0,0 +1,157 @@
+#include <stdio.h>
+
+
+#include <qpixmap.h>
+
+#include <kdebug.h>
+
+#include "pbutton.h"
+
+PObject *
+PButton::createWidget(CreateArgs &ca)
+{
+ PButton *pb = new PButton(ca.parent);
+ QButton *qb;
+ if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ qb = new QButton((QWidget *) ca.parent->widget());
+ else
+ qb = new QButton();
+ pb->setWidget(qb);
+ pb->setWidgetId(ca.pwI);
+ return pb;
+}
+
+
+PButton::PButton(PObject *parent)
+ : PWidget(parent)
+{
+ // kdDebug(5008) << "PLineEdit PLineEdit called" << endl;
+ button = 0;
+ setWidget(0);
+}
+
+PButton::~PButton()
+{
+ // kdDebug(5008) << "PLineEdit: in destructor" << endl;
+ /*
+ delete widget(); // Delete the frame
+ button=0; // Set it to 0
+ setWidget(button); // Now set all widget() calls to 0.
+ */
+}
+
+void PButton::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_BUTTON_SET_TEXT:
+ if(checkWidget() == FALSE)
+ return;
+
+ widget()->setText(pm->cArg); // set the text
+
+ pmRet.iCommand = - pm->iCommand;// Create ack
+ pmRet.iWinId = pm->iWinId;
+ pmRet.cArg = (char*) widget()->text().ascii(); // It's const, but we don't mess with it anyways
+ pmRet.iTextSize = strlen(pmRet.cArg);
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_BUTTON_SET_PIXMAP:
+ if(checkWidget() == FALSE)
+ return;
+
+ widget()->setPixmap(QPixmap(pm->cArg));
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->pixmap()->isNull();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_BUTTON_SET_AUTORESIZE:
+ if(checkWidget() == FALSE)
+ return;
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = - pm->iWinId;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ default:
+ PWidget::messageHandler(fd, pm);
+ }
+}
+
+void PButton::setWidget(QObject *_qb)
+{
+ if(_qb != 0 && _qb->inherits("QButton") == FALSE)
+ {
+ errorInvalidSet(_qb);
+ return;
+ }
+
+ button = (QButton *) _qb;
+ if(button != 0){
+ connect(button, SIGNAL(pressed()),
+ this, SLOT(buttonPressed()));
+ connect(button, SIGNAL(released()),
+ this, SLOT(buttonReleased()));
+ connect(button, SIGNAL(clicked()),
+ this, SLOT(buttonClicked()));
+ connect(button, SIGNAL(toggled(bool)),
+ this, SLOT(buttonToggled(bool)));
+
+ }
+ PWidget::setWidget(_qb);
+
+}
+
+
+QButton *PButton::widget()
+{
+ return button;
+}
+
+void PButton::buttonMessage(int iCommand)
+{
+ PukeMessage pmRet;
+
+ pmRet.iCommand = iCommand;
+ pmRet.iArg = 0;
+ pmRet.iWinId = widgetIden().iWinId;
+ pmRet.cArg = 0;
+
+ emit outputMessage(widgetIden().fd, &pmRet);
+}
+
+void PButton::buttonPressed()
+{
+ buttonMessage(PUKE_BUTTON_PRESSED_ACK);
+}
+
+void PButton::buttonReleased()
+{
+ buttonMessage(PUKE_BUTTON_RELEASED_ACK);
+}
+
+void PButton::buttonClicked()
+{
+ buttonMessage(PUKE_BUTTON_CLICKED_ACK);
+}
+
+void PButton::buttonToggled(bool)
+{
+ buttonMessage(PUKE_BUTTON_TOGGLED_ACK);
+}
+
+bool PButton::checkWidget()
+{
+ if(widget() == 0){
+ kdDebug(5008) << "PButton: No Widget set" << endl;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#include "pbutton.moc"
+
diff --git a/ksirc/puke/pbutton.h b/ksirc/puke/pbutton.h
new file mode 100644
index 00000000..e43bd681
--- /dev/null
+++ b/ksirc/puke/pbutton.h
@@ -0,0 +1,40 @@
+#ifndef PBUTTON_H
+#define PBUTTON_H
+
+class PButton;
+
+#include <qbutton.h>
+#include "pmessage.h"
+#include "pwidget.h"
+#include "pobject.h"
+#include "controller.h"
+
+
+class PButton : public PWidget
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PButton ( PObject * parent );
+ virtual ~PButton ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_qb = 0x0);
+ virtual QButton *widget();
+
+public slots:
+ void buttonPressed();
+ void buttonReleased();
+ void buttonClicked();
+ void buttonToggled(bool);
+
+private:
+ QButton *button;
+
+ void buttonMessage(int iCommand);
+ bool checkWidget();
+};
+
+#endif
diff --git a/ksirc/puke/pbutton.pm b/ksirc/puke/pbutton.pm
new file mode 100644
index 00000000..81e524fc
--- /dev/null
+++ b/ksirc/puke/pbutton.pm
@@ -0,0 +1,79 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $PUKE_CONTROLLER,
+ $PWIDGET_BUTTON,
+ "pbutton.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PButton Load failed!\n";
+ }
+ }
+ );
+
+package PButton;
+@ISA = qw(PWidget);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_BUTTON;
+
+ if($class eq 'PButton'){
+ $self->create();
+ }
+
+ $self->installHandler($::PUKE_BUTTON_PRESSED_ACK, sub{});
+ $self->installHandler($::PUKE_BUTTON_RELEASED_ACK, sub{});
+ $self->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub{});
+ $self->installHandler($::PUKE_BUTTON_TOGGLED_ACK, sub{});
+
+ return $self;
+
+}
+
+sub setText {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->{text} = $text;
+
+ $self->sendMessage('iCommand' => $::PUKE_BUTTON_SET_TEXT,
+ 'cArg' => $text,
+ 'CallBack' => sub {}
+ );
+}
+
+sub setPixmap {
+ my $self = shift;
+
+ my $file = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_BUTTON_SET_PIXMAP,
+ 'cArg' => $file,
+ 'CallBack' =>
+ sub {
+ my $arg = shift();
+ # if($arg == undef){ return; }
+ #my %ARG = %{shift()};
+ #if($ARG{'iArg'} == 0){
+ #print "*E* Pixmap set failed\n";
+ #}
+ }
+ );
+}
+
+sub setAutoResize {
+ my $self = shift;
+
+ my $resize = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_BUTTON_SET_PIXMAP,
+ 'iArg' => $resize,
+ 'CallBack' => sub {}
+ );
+}
+
+package main;
diff --git a/ksirc/puke/pframe.cpp b/ksirc/puke/pframe.cpp
new file mode 100644
index 00000000..fcff1d96
--- /dev/null
+++ b/ksirc/puke/pframe.cpp
@@ -0,0 +1,84 @@
+#include "pframe.h"
+
+
+PObject *
+PFrame::createWidget(CreateArgs &ca)
+{
+ PFrame *pw = new PFrame(ca.parent);
+ QFrame *tf;
+ if(ca.parent != 0 &&
+ ca.parent->widget()->isWidgetType() == TRUE)
+ tf = new QFrame((QWidget *) ca.parent->widget());
+ else
+ tf = new QFrame();
+ pw->setWidget(tf);
+ pw->setWidgetId(ca.pwI);
+ pw->setPukeController(ca.pc);
+ return pw;
+}
+
+
+PFrame::PFrame( PObject *parent)
+ : PWidget(parent)
+{
+ // kdDebug(5008) << "PFrame PFrame called" << endl;
+ frame = 0;
+}
+
+PFrame::~PFrame()
+{
+ // kdDebug(5008) << "PFrame: in destructor" << endl;
+ /*
+ delete frame; // Delete the frame
+ frame=0; // Set it to 0
+ setWidget(frame); // Now set all widget() calls to 0.
+ */
+}
+
+void PFrame::messageHandler(int fd, PukeMessage *pm)
+{
+ // kdDebug(5008) << "PFrame handler called" << endl;
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_QFRAME_SET_FRAME:
+ widget()->setFrameStyle(pm->iArg);
+ pmRet.iCommand = PUKE_QFRAME_SET_FRAME_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->frameStyle();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_QFRAME_SET_LINEWIDTH:
+ widget()->setLineWidth(pm->iArg);
+ pmRet.iCommand = PUKE_QFRAME_SET_LINEWIDTH_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->lineWidth();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ default:
+ PWidget::messageHandler(fd, pm);
+ }
+}
+
+void PFrame::setWidget(QObject *w)
+{
+ if(w != 0 && w->inherits("QFrame") == FALSE)
+ {
+ errorInvalidSet(w);
+ return;
+ }
+
+ frame = (QFrame *) w;
+ PWidget::setWidget((QWidget *) w);
+}
+
+
+QFrame *PFrame::widget()
+{
+ // kdDebug(5008) << "PFrame widget called" << endl;
+ return frame;
+}
+
+#include "pframe.moc"
+
diff --git a/ksirc/puke/pframe.h b/ksirc/puke/pframe.h
new file mode 100644
index 00000000..e98750aa
--- /dev/null
+++ b/ksirc/puke/pframe.h
@@ -0,0 +1,28 @@
+#ifndef PFRAME_H
+#define PFRAME_H
+
+class PFrame;
+
+#include <qframe.h>
+#include "pmessage.h"
+#include "pwidget.h"
+
+class PFrame : public PWidget
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PFrame ( PObject * parent );
+ virtual ~PFrame ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *w = 0x0);
+ virtual QFrame *widget();
+
+private:
+ QFrame *frame;
+};
+
+#endif
diff --git a/ksirc/puke/pframe.pm b/ksirc/puke/pframe.pm
new file mode 100644
index 00000000..f851cdb8
--- /dev/null
+++ b/ksirc/puke/pframe.pm
@@ -0,0 +1,57 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $PUKE_CONTROLLER,
+ $PWIDGET_FRAME,
+ "pframe.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PFrame Load failed!\n";
+ }
+ }
+ );
+
+package PFrame;
+@ISA = qw(PWidget);
+use strict;
+
+$PFrame::NoFrame = 0;
+$PFrame::Box = 0x0001;
+$PFrame::Panel = 0x0002;
+$PFrame::WinPanel = 0x0003;
+$PFrame::HLine = 0x0004;
+$PFrame::VLine = 0x0005;
+$PFrame::MShape = 0x000f;
+$PFrame::Plain = 0x0010;
+$PFrame::Raised = 0x0020;
+$PFrame::Sunken = 0x0030;
+$PFrame::MShadow = 0x00f0;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_FRAME;
+
+ if($class eq 'PFrame'){
+ $self->create();
+ }
+
+ return $self;
+
+}
+
+sub setFrameStyle {
+ my $self = shift;
+
+ my $frame = shift;
+ my $repaint = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_QFRAME_SET_FRAME,
+ 'iArg' => $frame,
+ 'CallBack' => sub {});
+
+ $self->repaint(1) if($repaint == 1);
+
+}
+
+package main;
diff --git a/ksirc/puke/pkfiledialog-cmd.h b/ksirc/puke/pkfiledialog-cmd.h
new file mode 100644
index 00000000..6aebd59e
--- /dev/null
+++ b/ksirc/puke/pkfiledialog-cmd.h
@@ -0,0 +1,56 @@
+#ifndef PKFILEDIALOG_CMD_H
+#define PKFILEDIALOG_CMD_H
+
+/*
+ * We get 2200
+ */
+
+// Desc: sets the current directory
+// iWinId: widget
+// iArg: not defined
+// cArg: path
+#define PUKE_KBFD_SET_PATH 2200
+
+// Desc: ack for the set
+// iWinId: widget
+// iArg: not defined
+// cArg: actual path
+#define PUKE_BFD_SET_PATH_ACK -2200
+
+// Desc: sets the current filter
+// iWinId: widget
+// iArg: not defined
+// cArg: filter, as defined in KFileBaseDialog::setFilter
+#define PUKE_KBFD_SET_FILTER 2201
+
+// Desc: ack for the set
+// iWinId: widget
+// iArg: not defined
+// cArg: not define
+#define PUKE_KBFD_SET_FILTER_ACK -2201
+
+// Desc: sets the current file
+// iWinId: widget
+// iArg: not defined
+// cArg: filename (does it need the full path?)
+#define PUKE_KBFD_SET_SELECTION 2202
+
+// Desc: ack for the set
+// iWinId: widget
+// iArg: not defined
+// cArg: not define
+#define PUKE_KBFD_SET_SELECTION_ACK -2202
+
+// Desc: ack for current file select
+// iWinId: not defined
+// iArg: not defined
+// cArg: not defined
+#define PUKE_KBFD_FILE_SELECTED 2203
+
+// Desc: ack for current file select
+// iWinId: widget
+// iArg: not defined
+// cArg: filename
+#define PUKE_KBFD_FILE_SELECTED_ACK -2203
+
+#endif
diff --git a/ksirc/puke/pkfiledialog.cpp b/ksirc/puke/pkfiledialog.cpp
new file mode 100644
index 00000000..c99aea9f
--- /dev/null
+++ b/ksirc/puke/pkfiledialog.cpp
@@ -0,0 +1,123 @@
+#include <stdio.h>
+
+
+#include <kdebug.h>
+
+#include "pkfiledialog.h"
+#include "pkfiledialog-cmd.h"
+
+PObject *
+PKFileDialog::createWidget(CreateArgs &ca)
+{
+ PKFileDialog *pw = new PKFileDialog(ca.parent);
+ KFileDialog *kfbd;
+ if(ca.fetchedObj != 0 && ca.fetchedObj->inherits("KFileDialog") == TRUE){
+ kfbd = (KFileDialog *) ca.fetchedObj;
+ pw->setDeleteAble(FALSE);
+ }
+ else // Never takes a parent in Puke
+ kfbd = new KFileDialog("/", QString::null, 0L, "PukeKFileDialog", TRUE);
+ pw->setWidget(kfbd);
+ pw->setWidgetId(ca.pwI);
+ return pw;
+}
+
+
+PKFileDialog::PKFileDialog(PObject *parent)
+ : PWidget(parent)
+{
+ kfbd = 0;
+ setWidget(kfbd);
+}
+
+PKFileDialog::~PKFileDialog()
+{
+ // kdDebug(5008) << "PLineEdit: in destructor" << endl;
+ /*
+ delete widget(); // Delete the frame
+ kfbd=0; // Set it to 0
+ setWidget(kfbd); // Now set all widget() calls to 0.
+ */
+}
+
+void PKFileDialog::messageHandler(int fd, PukeMessage *pm)
+{
+ QString selFile;
+ PukeMessage pmRet;
+ if(widget() == 0){
+ kdDebug(5008) << "PKFileDialog: No Widget set" << endl;
+ return;
+ }
+ switch(pm->iCommand){
+ case PUKE_KBFD_SET_PATH:
+ ((KFileDialog*)widget())->setURL(KURL(pm->cArg));
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = widget()->baseURL().path().length();
+#warning check if the cast is okay
+ pmRet.cArg = (char*) widget()->baseURL().path().ascii();
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_KBFD_SET_FILTER:
+ widget()->setFilter(pm->cArg);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_KBFD_SET_SELECTION:
+ widget()->setSelection(pm->cArg);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ selFile = widget()->selectedURL().path();
+ pmRet.iTextSize = selFile.length();
+#warning check if the cast is okay
+ pmRet.cArg = (char*) selFile.ascii();
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_WIDGET_SHOW:
+ widget()->exec();
+ pmRet.iCommand = PUKE_KBFD_FILE_SELECTED_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = new char[selFile.length()];
+ selFile = widget()->selectedURL().path();
+ // #### HPB: using strlen() 'cause we want the length of the .ascii()
+ // string. We should probably replace in the future.
+ memcpy(pmRet.cArg, selFile.ascii(), strlen(selFile.ascii()));
+ pmRet.iTextSize = selFile.length();
+ emit outputMessage(widgetIden().fd, &pmRet);
+ delete pmRet.cArg;
+ break;
+
+ default:
+ PWidget::messageHandler(fd, pm);
+ }
+}
+
+void PKFileDialog::setWidget(QObject *_kbfd)
+{
+ if(_kbfd != 0 && _kbfd->inherits("KFileBaseDialog") == FALSE)
+ {
+ errorInvalidSet(_kbfd);
+ return;
+ }
+
+ kfbd = (KFileDialog *) _kbfd;
+ PWidget::setWidget(kfbd);
+}
+
+
+KFileDialog *PKFileDialog::widget()
+{
+ return kfbd;
+}
+
+#include "pkfiledialog.moc"
diff --git a/ksirc/puke/pkfiledialog.h b/ksirc/puke/pkfiledialog.h
new file mode 100644
index 00000000..c8dbea3f
--- /dev/null
+++ b/ksirc/puke/pkfiledialog.h
@@ -0,0 +1,31 @@
+#ifndef PKFILEDIALOG_H
+#define PKFILEDIALOG_H
+
+class PKFileDialog;
+
+#include <kfiledialog.h>
+#include "pmessage.h"
+#include "pwidget.h"
+#include "controller.h"
+
+class PKFileDialog : public PWidget
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PKFileDialog ( PObject * parent );
+ virtual ~PKFileDialog ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_f = 0x0);
+ virtual KFileDialog *widget();
+
+public slots:
+
+private:
+ KFileDialog *kfbd;
+};
+
+#endif
diff --git a/ksirc/puke/pkfiledialog.pm b/ksirc/puke/pkfiledialog.pm
new file mode 100644
index 00000000..6da8c229
--- /dev/null
+++ b/ksirc/puke/pkfiledialog.pm
@@ -0,0 +1,76 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $::PUKE_CONTROLLER,
+ $PWIDGET_KFILEDIALOG,
+ "pkfiledialog.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PKFileDialog Load failed!\n";
+ }
+ }
+ );
+
+use strict;
+
+package PKFileDialog;
+use vars qw(@ISA);
+@ISA = qw(PWidget);
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_KFILEDIALOG;
+
+ if($class eq 'PKFileDialog'){
+ $self->create();
+ }
+
+ $self->installHandler($::PUKE_KBFD_FILE_SELECTED_ACK, sub{$self->fileSelected(shift())});
+
+ return $self;
+
+}
+
+sub setDir {
+ my $self = shift;
+
+ my $dir = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_KBFD_SET_PATH,
+ 'cArg' => $dir,
+ 'CallBack' => sub{});
+
+}
+
+sub setFilter {
+ my $self = shift;
+
+ my $filter = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_KBFD_SET_FILTER,
+ 'cArg' => $filter,
+ 'CallBack' => sub{});
+
+}
+
+sub setSelected {
+ my $self = shift;
+
+ my $sel = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_KBFD_SET_SELECTION,
+ 'cArg' => $sel,
+ 'CallBack' => sub{});
+
+}
+
+sub fileSelected {
+ my $self = shift;
+ my $rargs = shift;
+
+ &::print("*I* File Selected: " . $rargs->{'cArg'});
+
+}
+
+package main;
diff --git a/ksirc/puke/plabel.cpp b/ksirc/puke/plabel.cpp
new file mode 100644
index 00000000..17ca851d
--- /dev/null
+++ b/ksirc/puke/plabel.cpp
@@ -0,0 +1,127 @@
+#include <qmovie.h>
+
+
+#include <kdebug.h>
+
+#include "plabel.h"
+
+PObject *
+PLabel::createWidget(CreateArgs &ca)
+{
+ PLabel *pw = new PLabel(ca.parent);
+ QLabel *le;
+ if(ca.fetchedObj != 0 && ca.fetchedObj->inherits("QLabel") == TRUE){
+ le = (QLabel *) ca.fetchedObj;
+ pw->setDeleteAble(FALSE);
+ }
+ else if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ le = new QLabel((QWidget *) ca.parent->widget());
+ else
+ le = new QLabel((QWidget *)0L);
+ pw->setWidget(le);
+ pw->setWidgetId(ca.pwI);
+ return pw;
+}
+
+
+PLabel::PLabel(PObject *parent)
+ : PFrame(parent)
+{
+ // kdDebug(5008) << "PLabel PLabel called" << endl;
+ label = 0;
+ setWidget(label);
+}
+
+PLabel::~PLabel()
+{
+ // kdDebug(5008) << "PLabel: in destructor" << endl;
+ /*
+ delete widget(); // Delete the frame
+ label=0; // Set it to 0
+ setWidget(label); // Now set all widget() calls to 0.
+ */
+}
+
+void PLabel::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_LABEL_SETTEXT:
+ if(!checkWidget())
+ return;
+
+ widget()->setText(pm->cArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LABEL_SETPIXMAP:
+ if(!checkWidget())
+ return;
+
+ widget()->setPixmap(QPixmap(pm->cArg));
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LABEL_SETMOVIE:
+ if(!checkWidget())
+ return;
+
+ widget()->setMovie(QMovie(pm->cArg));
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LABEL_SETALIGNMENT:
+ if(!checkWidget())
+ return;
+
+ widget()->setAlignment(pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ default:
+ PFrame::messageHandler(fd, pm);
+ }
+}
+
+void PLabel::setWidget(QObject *_l)
+{
+ if(_l != 0 && _l->inherits("QLabel") == FALSE)
+ {
+ errorInvalidSet(_l);
+ return;
+ }
+
+ label = (QLabel *) _l;
+ PWidget::setWidget(_l);
+
+}
+
+
+QLabel *PLabel::widget()
+{
+ return label;
+}
+
+bool PLabel::checkWidget(){
+ if(widget() == 0){
+ kdDebug(5008) << "PLabel: No Widget set" << endl;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+#include "plabel.moc"
+
diff --git a/ksirc/puke/plabel.h b/ksirc/puke/plabel.h
new file mode 100644
index 00000000..c53705b1
--- /dev/null
+++ b/ksirc/puke/plabel.h
@@ -0,0 +1,34 @@
+#ifndef PLABEL_H
+#define PLABEL_H
+
+class PLabel;
+
+#include <qlabel.h>
+#include "pmessage.h"
+#include "pframe.h"
+#include "controller.h"
+
+class PLabel : public PFrame
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PLabel ( PObject * parent );
+ virtual ~PLabel ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_obj = 0);
+ virtual QLabel *widget();
+
+public slots:
+
+protected:
+ bool checkWidget();
+
+private:
+ QLabel *label;
+};
+
+#endif
diff --git a/ksirc/puke/plabel.pm b/ksirc/puke/plabel.pm
new file mode 100644
index 00000000..bc557b5e
--- /dev/null
+++ b/ksirc/puke/plabel.pm
@@ -0,0 +1,105 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $::PUKE_CONTROLLER,
+ $PWIDGET_LABEL,
+ "plabel.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PLabel Load failed!\n";
+ }
+ }
+ );
+
+package PLabel;
+@ISA = qw(PFrame);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_LABEL;
+
+ if($class eq 'PLabel'){
+ $self->create();
+ }
+
+ return $self;
+
+}
+
+sub setText {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->{text} = $text;
+
+ # Don't need the ouput since GET_TEXT_ACK will be called and
+ # we'll set it there
+ $self->sendMessage('iCommand' => $::PUKE_LABEL_SETTEXT,
+ 'iArg' => 0,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+sub setPixmap {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->{text} = "***PIXMAP***" . $text;
+
+ # Don't need the ouput since GET_TEXT_ACK will be called and
+ # we'll set it there
+ $self->sendMessage('iCommand' => $::PUKE_LABEL_SETPIXMAP,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+sub setMovie {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->{text} = "***MOVIE***" . $text;
+
+ # Don't need the ouput since GET_TEXT_ACK will be called and
+ # we'll set it there
+ $self->sendMessage('iCommand' => $::PUKE_LABEL_SETMOVIE,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+
+sub text {
+ my $self = shift;
+
+ return $self->{text};
+}
+
+
+
+sub setAlignment {
+ my $self = shift;
+
+ my $align = shift;
+
+
+ $self->{align} = $align;
+
+ # Don't need the ouput since GET_TEXT_ACK will be called and
+ # we'll set it there
+ $self->sendMessage('iCommand' => $::PUKE_LABEL_SETALIGNMENT,
+ 'iArg' => $align,
+ 'CallBack' => sub {});
+
+}
+
+
+
+package main;
+
diff --git a/ksirc/puke/playout.cpp b/ksirc/puke/playout.cpp
new file mode 100644
index 00000000..9690f418
--- /dev/null
+++ b/ksirc/puke/playout.cpp
@@ -0,0 +1,157 @@
+#include <stdio.h>
+
+
+#include "playout.h"
+#include "commands.h"
+
+PLayout::PLayout(QObject *pobject)
+ : PObject(pobject)
+{
+ // Connect slots as needed
+ setWidget();
+}
+
+PLayout::~PLayout()
+{
+ // kdDebug(5008) << "PObject: in destructor" << endl;
+ /*
+ delete widget();
+ layout = 0;
+ setWidget();
+ */
+}
+
+PObject *PLayout::createWidget(CreateArgs &ca)
+{
+ PLayout *pw = new PLayout(ca.parent);
+ QBoxLayout *qbl;
+ int direction, border, iType, iParent;
+ // Retreive the border and direction information out of the
+ // carg string
+ if(sscanf(ca.pm->cArg, "%d\t%d\t%d\t%d", &iParent, &iType, &direction, &border) < 4)
+ throw(errorCommandFailed(-ca.pm->iCommand, -1));
+
+ if((ca.parent != 0) &&
+ (ca.parent->widget()->isWidgetType() == TRUE)){
+ qbl = new QBoxLayout((QWidget *) ca.parent->widget(), (QBoxLayout::Direction) direction, border);
+ // kdDebug(5008) << "Creating layout with parent: " << parent.iWinId << endl;
+
+ }
+ else{
+ qbl = new QBoxLayout((QBoxLayout::Direction) direction, border);
+ // kdDebug(5008) << "Creating layout NO PARENT" << endl;
+ }
+ pw->setWidget(qbl);
+ pw->setWidgetId(ca.pwI);
+ pw->setPukeController(ca.pc);
+ return pw;
+}
+
+void PLayout::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+
+// kdDebug(5008) << "In PLayout: " << pm->iCommand << endl;
+
+ if(pm->iCommand == PUKE_LAYOUT_ADDWIDGET){
+ if(pm->iTextSize != 2*sizeof(char)){
+ qWarning("PLayout/addwidget: incorrent cArg size, bailing out. Needed: %u wanted: %d\n", sizeof(int), pm->iTextSize);
+ pmRet.iCommand = PUKE_LAYOUT_ADDWIDGET_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 1;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ return;
+ }
+ widgetId wiWidget;
+ wiWidget.fd = fd;
+ wiWidget.iWinId = pm->iArg;
+ PWidget *pw = controller()->id2pwidget(&wiWidget);
+ // kdDebug(5008) << "Adding widget with stretch: " << (int) pm->cArg[0] << " and align: " << // (int) pm->cArg[1] << endl;
+ widget()->addWidget(pw->widget(), pm->cArg[0], pm->cArg[1]);
+
+ pmRet.iCommand = PUKE_LAYOUT_ADDWIDGET_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ else if(pm->iCommand == PUKE_LAYOUT_ADDLAYOUT){
+ if(pm->iTextSize != sizeof(char)){
+ qWarning("PLayout: incorrent cArg size, bailing out. Needed: %u wanted: %d\n", sizeof(int), pm->iTextSize);
+ pmRet.iCommand = PUKE_LAYOUT_ADDLAYOUT_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 1;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ return;
+ }
+ PObject *pld = controller()->id2pobject(fd, pm->iWinId);
+ PObject *pls = controller()->id2pobject(fd, pm->iArg);
+ if( (pld->widget()->inherits("QBoxLayout") == FALSE) || (pls->widget()->inherits("QBoxLayout") == FALSE))
+ throw(errorCommandFailed(PUKE_LAYOUT_ADDLAYOUT_ACK, 1));
+ PLayout *plbd = (PLayout *) pld;
+ PLayout *plbs = (PLayout *) pls;
+ plbd->widget()->addLayout(plbs->widget(), pm->cArg[0]);
+
+ pmRet.iCommand = PUKE_LAYOUT_ADDLAYOUT_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ else if(pm->iCommand == PUKE_LAYOUT_ADDSTRUT){
+ PObject *po = controller()->id2pobject(fd, pm->iWinId);
+ if(po->widget()->inherits("PBoxLayout") != TRUE)
+ throw(errorCommandFailed(PUKE_LAYOUT_ADDSTRUT_ACK, 1));
+ PLayout *pl = (PLayout *) po;
+
+ pl->widget()->addStrut(pm->iArg);
+
+ pmRet.iCommand = PUKE_LAYOUT_ADDSTRUT_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ else if(pm->iCommand == PUKE_LAYOUT_ACTIVATE){
+ PObject *po = controller()->id2pobject(fd, pm->iWinId);
+ if(po->widget()->inherits("PBoxLayout") != TRUE)
+ throw(errorCommandFailed(PUKE_LAYOUT_ACTIVATE_ACK, 1));
+ PLayout *pl = (PLayout *) po;
+
+ pmRet.iArg = 0; // setup failure case
+ pl->widget()->activate();
+
+ pmRet.iCommand = PUKE_LAYOUT_ACTIVATE_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ else {
+ PObject::messageHandler(fd, pm);
+ }
+
+}
+
+void PLayout::setWidget(QObject *_layout)
+{
+ // kdDebug(5008) << "PObject setwidget called" << endl;
+ if(_layout != 0 && _layout->inherits("QBoxLayout") == FALSE)
+ {
+ errorInvalidSet(_layout);
+ return;
+ }
+
+ layout = (QBoxLayout *) _layout;
+ PObject::setWidget(_layout);
+
+}
+
+QBoxLayout *PLayout::widget()
+{
+ return layout;
+}
+
+
+#include "playout.moc"
+
diff --git a/ksirc/puke/playout.h b/ksirc/puke/playout.h
new file mode 100644
index 00000000..4aec01a1
--- /dev/null
+++ b/ksirc/puke/playout.h
@@ -0,0 +1,42 @@
+#ifndef PLAYOUT_H
+#define PLAYOUT_H
+
+class PLayout;
+
+#include <qobject.h>
+#include <qlayout.h>
+#include "pmessage.h"
+#include "pobject.h"
+
+class PLayout : public PObject
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PLayout(QObject *parent = 0);
+ virtual ~PLayout();
+
+ /**
+ * Handles messages from dsirc
+ * PObject can't get messages so return an error
+ */
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ /**
+ * Sets the current opbect
+ */
+ virtual void setWidget(QObject *qb = 0x0);
+
+ /**
+ * Returns the current object
+ */
+ virtual QBoxLayout *widget();
+
+private:
+
+ QBoxLayout *layout;
+
+};
+
+#endif
diff --git a/ksirc/puke/plined.cpp b/ksirc/puke/plined.cpp
new file mode 100644
index 00000000..3f3e6a09
--- /dev/null
+++ b/ksirc/puke/plined.cpp
@@ -0,0 +1,153 @@
+#include <stdio.h>
+
+
+#include <kdebug.h>
+
+#include "plined.h"
+
+PObject *
+PLineEdit::createWidget(CreateArgs &ca)
+{
+ PLineEdit *pw = new PLineEdit(ca.parent);
+ QLineEdit *le;
+ if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ le = new QLineEdit((QWidget *) ca.parent->widget());
+ else
+ le = new QLineEdit(0L);
+ pw->setWidget(le);
+ pw->setWidgetId(ca.pwI);
+ return pw;
+}
+
+
+PLineEdit::PLineEdit(PObject *parent)
+ : PWidget(parent)
+{
+ // kdDebug(5008) << "PLineEdit PLineEdit called" << endl;
+ lineedit = 0;
+ setWidget(lineedit);
+}
+
+PLineEdit::~PLineEdit()
+{
+ // kdDebug(5008) << "PLineEdit: in destructor" << endl;
+ /*
+ delete widget(); // Delete the frame
+ lineedit=0; // Set it to 0
+ setWidget(lineedit); // Now set all widget() calls to 0.
+ */
+}
+
+void PLineEdit::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_LINED_SET_MAXLENGTH:
+ if(widget() == 0){
+ kdDebug(5008) << "PLineEdit: No Widget set" << endl;
+ return;
+ }
+ widget()->setMaxLength(pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->maxLength();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LINED_SET_ECHOMODE:
+ if(widget() == 0){
+ kdDebug(5008) << "PLineEdit: No Widget set" << endl;
+ return;
+ }
+ widget()->setEchoMode((QLineEdit::EchoMode) pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->echoMode();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LINED_SET_TEXT:
+ if(widget() == 0){
+ kdDebug(5008) << "PLineEdit: No Widget set" << endl;
+ return;
+ }
+ kdDebug(5008) << "PukeLine Edit: Got: " << pm->cArg << endl;
+ widget()->setText(pm->cArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = strlen(widget()->text());
+ pmRet.cArg = new char[strlen(widget()->text())+1];
+ strcpy(pmRet.cArg, widget()->text());
+ emit outputMessage(fd, &pmRet);
+ delete[] pmRet.cArg;
+ break;
+ case PUKE_LINED_GET_TEXT:
+ if(widget() == 0){
+ kdDebug(5008) << "PLineEdit: No Widget set" << endl;
+ return;
+ }
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = strlen(widget()->text());
+ pmRet.cArg = new char[strlen(widget()->text())+1];
+ strcpy(pmRet.cArg, widget()->text());
+ emit outputMessage(fd, &pmRet);
+ delete[] pmRet.cArg;
+ break;
+ default:
+ PWidget::messageHandler(fd, pm);
+ }
+}
+
+void PLineEdit::setWidget(QObject *_le)
+{
+ if(_le != 0 && _le->inherits("QLineEdit") == FALSE)
+ {
+ errorInvalidSet(_le);
+ return;
+ }
+
+ lineedit = (QLineEdit *) _le;
+ if(lineedit != 0){
+ connect(lineedit, SIGNAL(textChanged(const char *)),
+ this, SLOT(updateText(const char *)));
+ connect(lineedit, SIGNAL(returnPressed()),
+ this, SLOT(returnPress()));
+ }
+ PWidget::setWidget(_le);
+
+}
+
+
+QLineEdit *PLineEdit::widget()
+{
+ return lineedit;
+}
+
+void PLineEdit::updateText(const char *text){
+ PukeMessage pmRet;
+
+ pmRet.iCommand = PUKE_LINED_GET_TEXT_ACK;
+ pmRet.iWinId = widgetIden().iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = strlen(text);
+ pmRet.cArg = new char[strlen(text)+1];
+ strcpy(pmRet.cArg, text);
+ emit outputMessage(widgetIden().fd, &pmRet);
+ delete[] pmRet.cArg;
+}
+
+void PLineEdit::returnPress() {
+ PukeMessage pmRet;
+
+ pmRet.iCommand = PUKE_LINED_RETURN_PRESSED_ACK;
+ pmRet.iWinId = widgetIden().iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(widgetIden().fd, &pmRet);
+}
+
+#include "plined.moc"
+
diff --git a/ksirc/puke/plined.h b/ksirc/puke/plined.h
new file mode 100644
index 00000000..78f04bdf
--- /dev/null
+++ b/ksirc/puke/plined.h
@@ -0,0 +1,33 @@
+#ifndef PLINEEDIT_H
+#define PLINEEDIT_H
+
+class PLineEdit;
+
+#include <qlineedit.h>
+#include "pmessage.h"
+#include "pwidget.h"
+#include "controller.h"
+
+class PLineEdit : public PWidget
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PLineEdit ( PObject * parent );
+ virtual ~PLineEdit ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_f);
+ virtual QLineEdit *widget();
+
+public slots:
+ void updateText(const char *);
+ void returnPress();
+
+private:
+ QLineEdit *lineedit;
+};
+
+#endif
diff --git a/ksirc/puke/plined.pm b/ksirc/puke/plined.pm
new file mode 100644
index 00000000..fbff6f96
--- /dev/null
+++ b/ksirc/puke/plined.pm
@@ -0,0 +1,84 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $::PUKE_CONTROLLER,
+ $PWIDGET_LINED,
+ "plined.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PLineEdit Load failed!\n";
+ }
+ }
+ );
+
+package PLineEdit;
+@ISA = qw(PWidget);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_LINED;
+ $self->{maxLength} = -1;
+
+ if($class eq 'PLineEdit'){
+ $self->create();
+ }
+
+ $self->installHandler($::PUKE_WIDGET_EVENT_TIMER, sub{});
+ $self->installHandler($::PUKE_LINED_GET_TEXT_ACK, sub{
+ my %ARG = %{shift()};
+ $ARG{'cArg'} =~ s/^([^\000]*).*/$1/;
+ $self->{text} = $ARG{'cArg'};});
+
+ return $self;
+
+}
+
+sub setMaxLength {
+ my $self = shift;
+
+ my $length = shift;
+
+ $self->{maxLength} = $length;
+ $self->sendMessage('iCommand' => $::PUKE_LINED_SET_MAXLENGTH,
+ 'iArg' => $length,
+ 'CallBack' => sub {my %ARG = %{shift()};
+ $self->{maxLength} = $ARG{'iArg'};});
+
+}
+
+sub setEchoMode {
+ my $self = shift;
+
+ my $mode = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_LINED_SET_ECHOMODE,
+ 'iArg' => $mode,
+ 'CallBack' => sub {my %ARG = %{shift()};
+ $self->{echoMode} = $ARG{'iArg'};});
+
+}
+
+sub setText {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->{text} = $text;
+
+ # Don't need the ouput since GET_TEXT_ACK will be called and
+ # we'll set it there
+ $self->sendMessage('iCommand' => $::PUKE_LINED_SET_TEXT,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+sub text {
+ my $self = shift;
+
+ return $self->{text};
+}
+
+package main;
diff --git a/ksirc/puke/plistbox.cpp b/ksirc/puke/plistbox.cpp
new file mode 100644
index 00000000..482e08c7
--- /dev/null
+++ b/ksirc/puke/plistbox.cpp
@@ -0,0 +1,224 @@
+#include <kdebug.h>
+
+
+#include "plistbox.h"
+
+PObject *
+PListBox::createWidget(CreateArgs &ca)
+{
+ PListBox *plb = new PListBox(ca.parent);
+ QListBox *lb;
+ if(ca.fetchedObj != 0 && ca.fetchedObj->inherits("QListBox") == TRUE){
+ lb = (QListBox *) ca.fetchedObj;
+ plb->setDeleteAble(FALSE);
+ }
+ else if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ lb = new QListBox((QWidget *) ca.parent->widget());
+ else
+ lb = new QListBox();
+ plb->setWidget(lb);
+ plb->setWidgetId(ca.pwI);
+ return plb;
+}
+
+
+PListBox::PListBox(PObject *parent)
+ : PFrame(parent)
+{
+ // kdDebug(5008) << "PListBox PListBox called" << endl;
+ lb = 0;
+ setWidget(lb);
+}
+
+PListBox::~PListBox()
+{
+ // kdDebug(5008) << "PListBox: in destructor" << endl;
+ /*
+ delete widget(); // Delete the frame
+ lb=0; // Set it to 0
+ setWidget(lb); // Now set all widget() calls to 0.
+ */
+}
+
+void PListBox::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_LISTBOX_INSERT:
+ if(!checkWidget())
+ return;
+
+ widget()->insertItem(pm->cArg, pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->count();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LISTBOX_INSERT_SORT:
+ if(!checkWidget())
+ return;
+
+ widget()->insertItem(pm->cArg);
+ widget()->sort();
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->count();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LISTBOX_INSERT_PIXMAP:
+ if(!checkWidget())
+ return;
+
+ widget()->insertItem(QPixmap(pm->cArg), pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->count();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LISTBOX_HIGHLIGHT:
+ if(!checkWidget())
+ return;
+
+ widget()->setCurrentItem(pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->currentItem();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LISTBOX_REMOVE:
+ if(!checkWidget())
+ return;
+
+ widget()->removeItem(pm->iArg);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LISTBOX_GETTEXT:
+ if(!checkWidget())
+ return;
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ if(widget()->text(pm->iArg) != 0x0){
+ pmRet.iArg = 1;
+ pmRet.iTextSize = strlen(widget()->text(pm->iArg));
+ pmRet.cArg = new char[strlen(widget()->text(pm->iArg))+1];
+ strcpy(pmRet.cArg, widget()->text(pm->iArg));
+ emit outputMessage(fd, &pmRet);
+ delete[] pmRet.cArg;
+ }
+ else{
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ break;
+ case PUKE_LISTBOX_SET_SCROLLBAR:
+ widget()->setVScrollBarMode( (bool) pm->iArg ? QListBox::AlwaysOn : QListBox::AlwaysOff );
+ pmRet.iCommand = PUKE_LISTBOX_SET_SCROLLBAR_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LISTBOX_SET_AUTO_SCROLLBAR:
+ widget()->setVScrollBarMode( (bool) pm->iArg ? QListBox::Auto : QListBox::AlwaysOff );
+ pmRet.iCommand = PUKE_LISTBOX_SET_AUTO_SCROLLBAR_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_LISTBOX_CLEAR:
+ widget()->clear();
+ pmRet.iCommand = PUKE_LISTBOX_CLEAR_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ default:
+ PFrame::messageHandler(fd, pm);
+ }
+}
+
+void PListBox::setWidget(QObject *_lb)
+{
+ if(_lb != 0 && _lb->inherits("QListBox") == FALSE)
+ {
+ errorInvalidSet(_lb);
+ return;
+ }
+
+ lb = (QListBox *) _lb;
+ if(lb != 0){
+ connect(lb, SIGNAL(highlighted(int)),
+ this, SLOT(highlighted(int)));
+ connect(lb, SIGNAL(selected(int)),
+ this, SLOT(selected(int)));
+ }
+ PFrame::setWidget(lb);
+
+}
+
+
+QListBox *PListBox::widget()
+{
+ return lb;
+}
+
+
+void PListBox::highlighted(int index) {
+ PukeMessage pmRet;
+
+ kdDebug(5008) << "Got highlight" << endl;
+ pmRet.iCommand = PUKE_LISTBOX_HIGHLIGHTED_ACK;
+ pmRet.iWinId = widgetIden().iWinId;
+ pmRet.iArg = index;
+ if(widget()->text(index) != 0){
+ pmRet.iTextSize = strlen(widget()->text(index));
+ pmRet.cArg = new char[strlen(widget()->text(index)) + 1];
+ strcpy(pmRet.cArg, widget()->text(index));
+ }
+ else
+ pmRet.cArg = 0;
+ emit outputMessage(widgetIden().fd, &pmRet);
+ delete[] pmRet.cArg;
+}
+
+void PListBox::selected(int index) {
+ PukeMessage pmRet;
+
+ kdDebug(5008) << "Got selected" << endl;
+ pmRet.iCommand = PUKE_LISTBOX_SELECTED_ACK;
+ pmRet.iWinId = widgetIden().iWinId;
+ pmRet.iArg = index;
+ if(widget()->text(index) != 0){
+ pmRet.iTextSize = strlen(widget()->text(index));
+ pmRet.cArg = new char[strlen(widget()->text(index)) + 1];
+ strcpy(pmRet.cArg, widget()->text(index));
+ }
+ else
+ pmRet.cArg = 0;
+ emit outputMessage(widgetIden().fd, &pmRet);
+ delete[] pmRet.cArg;
+}
+
+bool PListBox::checkWidget(){
+ if(widget() == 0){
+ kdDebug(5008) << "PListBox: No Widget set" << endl;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#include "plistbox.moc"
+
diff --git a/ksirc/puke/plistbox.h b/ksirc/puke/plistbox.h
new file mode 100644
index 00000000..cad454a8
--- /dev/null
+++ b/ksirc/puke/plistbox.h
@@ -0,0 +1,37 @@
+#ifndef PLISTBOX_H
+#define PLISTBOX_H
+
+class PListBox;
+
+#include <qlistbox.h>
+#include "pmessage.h"
+#include "ptablevw.h"
+#include "controller.h"
+
+class PListBox : public PFrame
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PListBox ( PObject * parent );
+ virtual ~PListBox ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_lb);
+ virtual QListBox *widget();
+
+public slots:
+ void highlighted(int);
+ void selected(int);
+
+protected:
+ bool checkWidget();
+
+private:
+ QListBox *lb;
+
+};
+
+#endif
diff --git a/ksirc/puke/plistbox.pm b/ksirc/puke/plistbox.pm
new file mode 100644
index 00000000..2e7af417
--- /dev/null
+++ b/ksirc/puke/plistbox.pm
@@ -0,0 +1,196 @@
+
+&::PukeSendMessage($::PUKE_WIDGET_LOAD,
+ $::PUKE_CONTROLLER,
+ $::PWIDGET_LISTBOX,
+ "plistbox.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PListBox Load failed!\n";
+ }
+ }
+ );
+
+
+package PListBox;
+@ISA = qw(PTableView);
+use strict;
+
+if($PListBox::usage == undef){
+ $PListBox::usage = 0;
+}
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_LISTBOX;
+
+ if($class eq 'PListBox'){
+ $self->create();
+ }
+
+ $self->{count} = 0;
+ $self->{items} = ();
+
+ $self->installHandler($::PUKE_LISTBOX_SELECTED_ACK, sub{$self->selected(@_)});
+
+ return $self;
+
+}
+
+sub DESTROY {
+ my $self = shift;
+ $self->SUPER::DESTROY(@_);
+ $PListBox::usage--;
+ if($PListBox::usage == 0){
+ &::PukeSendMessage($::PUKE_WIDGET_UNLOAD,
+ 0,
+ $::PWIDGET_LISTBOX,
+ "",
+ sub {}
+ );
+
+ }
+}
+
+sub insertText {
+ my $self = shift;
+
+ my $text = shift;
+ my $index = shift;
+ my $rindex = $index;
+
+ if($index < 0 || $index >= $self->{count}){
+ $rindex = $self->{count};
+ }
+
+ $self->{count} ++;
+
+ # Don't need the ouput since GET_TEXT_ACK will be called and
+ # we'll set it there
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_INSERT,
+ 'iArg' => $rindex,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+sub text {
+ my $self = shift;
+ my $index = shift;
+
+ my %arg = $self->sendMessage('iCommand' => $::PUKE_LISTBOX_GETTEXT,
+ 'iArg' => $index,
+ 'WaitFor' => 1);
+
+ if($arg{'iArg'} != 1){
+ return undef;
+ }
+ $arg{'cArg'} =~ s/\000//g;
+ return $arg{'cArg'};
+}
+
+sub insertPixmap {
+ my $self = shift;
+
+ my $file = shift;
+ my $index = shift;
+ my $rindex = $index;
+
+ if($index < 0 || $index >= $self->{count}){
+ $rindex = $self->{count};
+ }
+ # $self->{items}->[$rindex] = "***PIXMAP***" . $file;
+ $self->{count} ++;
+
+
+ # Don't need the ouput since GET_TEXT_ACK will be called and
+ # we'll set it there
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_INSERT_PIXMAP,
+ 'iArg' => $rindex,
+ 'cArg' => $file,
+ 'CallBack' => sub {});
+
+}
+sub selected {
+ my $self = shift;
+ my %ARGS = %{shift()};
+
+ $self->{current} = $ARGS{'iArg'};
+ $ARGS{'cArg'} =~ s/\000//g;
+ $self->{currentText} = $ARGS{'cArg'};
+}
+
+sub current {
+ my $self = shift;
+ return $self->{current};
+}
+
+sub currentText {
+ my $self = shift;
+ return $self->text($self->{current});
+}
+
+sub setCurrentItem {
+ my $self = shift;
+
+ my $index = shift;
+ my $rindex = $index;
+
+ # Async call be default, no need to wait result
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_HIGHLIGHT,
+ 'iArg' => $index,
+ 'CallBack' => sub {});
+
+
+}
+
+sub removeItem {
+ my $self = shift;
+
+ my $index = shift;
+
+ $self->{count} --;
+
+ # Async call be default, no need to wait result
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_REMOVE,
+ 'iArg' => $index,
+ 'CallBack' => sub {});
+
+
+}
+
+sub setScrollBar {
+ my $self = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_SET_SCROLLBAR,
+ 'iArg' => shift(),
+ 'CallBack' => sub {});
+
+}
+
+sub setAutoScrollBar {
+ my $self = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_SET_AUTO_SCROLLBAR,
+ 'iArg' => shift(),
+ 'CallBack' => sub {});
+
+}
+
+sub clear {
+ my $self = shift;
+
+ $self->{count} = 0;
+ $self->{items} = ();
+
+ $self->sendMessage('iCommand' => $::PUKE_LISTBOX_CLEAR,
+ 'CallBack' => sub {});
+
+}
+
+
+
+package main;
+
+1;
diff --git a/ksirc/puke/pmenudta.cpp b/ksirc/puke/pmenudta.cpp
new file mode 100644
index 00000000..30b375fc
--- /dev/null
+++ b/ksirc/puke/pmenudta.cpp
@@ -0,0 +1,79 @@
+#include "pmenudta.h"
+#include "pobject.h"
+#include <qpopupmenu.h>
+
+
+PMenuData::PMenuData(PObject *_child)
+: PObject()
+{
+ child = _child;
+ connect(this, SIGNAL(outputMessage(int, PukeMessage*)),
+ child, SIGNAL(outputMessage(int, PukeMessage*)));
+}
+
+PMenuData::~PMenuData()
+{
+ // We don't nuke anything since we're kind of abstract and we let the parent take care of it
+}
+
+void PMenuData::messageHandler(int , PukeMessage *)
+{
+ // We don't do anything since we should never ben involked directly
+}
+
+bool PMenuData::menuMessageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ int id = 0;
+ switch(pm->iCommand){
+ case PUKE_MENUDATA_INSERT_TEXT:
+ {
+ QPopupMenu *widget = (QPopupMenu *) child->widget();
+ id = widget->insertItem(pm->cArg);
+ if(pm->iArg > 0){
+ widget->setAccel(pm->iArg, id);
+ }
+
+ pmRet.iCommand = PUKE_MENUDATA_INSERT_TEXT_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = id;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+ case PUKE_MENUDATA_INSERT_PIXMAP:
+ {
+ QPopupMenu *widget = (QPopupMenu *) child->widget();
+ id = widget->insertItem(QPixmap(pm->cArg));
+ if(pm->iArg > 0){
+ widget->setAccel(pm->iArg, id);
+ }
+
+ pmRet.iCommand = PUKE_MENUDATA_INSERT_PIXMAP_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = id;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+ case PUKE_MENUDATA_REMOVE_ITEM:
+ {
+ QPopupMenu *widget = (QPopupMenu *) child->widget();
+ widget->removeItem(pm->iArg);
+
+ pmRet.iCommand = PUKE_MENUDATA_REMOVE_ITEM_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = pm->iArg;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#include "pmenudta.moc"
+
diff --git a/ksirc/puke/pmenudta.h b/ksirc/puke/pmenudta.h
new file mode 100644
index 00000000..0c3bfc6a
--- /dev/null
+++ b/ksirc/puke/pmenudta.h
@@ -0,0 +1,57 @@
+#ifndef PMENUDATA_H
+#define PMENUDATA_H
+
+class PMenuData;
+
+#include <qobject.h>
+#include <qmenudata.h>
+#include "pmessage.h"
+#include "pframe.h"
+#include "pobject.h"
+#include "controller.h"
+
+/**
+ * Little helper class here gives us access to needed info inside
+ * QMenuData
+ */
+
+class PMenuDataHelper : public QMenuData
+{
+public:
+ PMenuDataHelper(QMenuData &qmd) {
+ memcpy(this, &qmd, sizeof(QMenuData));
+ }
+ int active() {
+ return QMenuData::actItem;
+ }
+ int actItem;
+};
+
+/**
+ * We're subclased off QMenuData so we can access it's internal proteted vars
+ * We do not initialize NOR create it!!!!
+ */
+
+class PMenuData : public PObject
+{
+ Q_OBJECT
+public:
+ PMenuData (PObject *_child);
+ virtual ~PMenuData ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+ virtual bool menuMessageHandler(int fd, PukeMessage *pm);
+
+// virtual void setWidget(QMenuData *_qmd);
+ // virtual QMenuData *widget();
+
+ virtual int activeItem()
+ {
+ return PMenuDataHelper(*((QMenuData *) child->widget())).active();
+ }
+
+ private:
+ PObject *child;
+};
+
+#endif
diff --git a/ksirc/puke/pmenudta.pm b/ksirc/puke/pmenudta.pm
new file mode 100644
index 00000000..f98acf91
--- /dev/null
+++ b/ksirc/puke/pmenudta.pm
@@ -0,0 +1,60 @@
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $PUKE_CONTROLLER,
+ $PWIDGET_MENUDATA,
+ "pmenudta.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PMenuData Load failed!\n";
+ }
+ }
+ );
+
+package PMenuData;
+use strict;
+
+#
+# Only methods, constructor must create $self elsewhere and must of PBase type
+#
+
+sub new {
+ print "*E* Can't call new for this class\n";
+}
+
+sub insertText {
+ my $self = shift;
+
+ my $text = shift;
+
+ my %ARG = $self->sendMessage('iCommand' => $::PUKE_MENUDATA_INSERT_TEXT,
+ 'cArg' => $text,
+ 'WaitFor' => 1);
+
+ return $ARG{'iArg'};
+}
+
+sub insertPixmap {
+ my $self = shift;
+
+ my $text = shift;
+
+ my %ARG = $self->sendMessage('iCommand' => $::PUKE_MENUDATA_INSERT_PIXMAP,
+ 'cArg' => $text,
+ 'WaitFor' => 1);
+
+ return $ARG{'iArg'};
+
+}
+
+sub removeItem {
+ my $self = shift;
+
+ my $id = shift;
+
+ my %ARG = $self->sendMessage('iCommand' => $::PUKE_MENUDATA_REMOVE_ITEM,
+ 'iArg' => $id);
+
+}
+
+package main;
+
+1;
diff --git a/ksirc/puke/pmessage.h b/ksirc/puke/pmessage.h
new file mode 100644
index 00000000..5c777b24
--- /dev/null
+++ b/ksirc/puke/pmessage.h
@@ -0,0 +1,38 @@
+#ifndef PUKE_MESSAGE_H
+#define PUKE_MESSAGE_H
+
+typedef struct {
+ unsigned int iHeader; // Filled in durring in PukeController, do not set
+ int iCommand;
+ int iWinId;
+ int iArg;
+ int iTextSize; // Size of the text message that follows
+ char *cArg;
+} PukeMessage;
+
+typedef struct {
+ int fd;
+ int iWinId;
+} widgetId;
+
+const uint iPukeHeader = 42U;
+
+#if 0
+class errorInvalidSet {
+public:
+ errorInvalidSet(QObject *_from, const char *_to)
+ : __from(_from), __to(_to)
+ {
+ }
+
+ QObject *from() { return __from; }
+ const char *to() { return __to; }
+
+private:
+ QObject *__from;
+ const char *__to;
+
+};
+#endif
+
+#endif
diff --git a/ksirc/puke/pobject.cpp b/ksirc/puke/pobject.cpp
new file mode 100644
index 00000000..f2481a04
--- /dev/null
+++ b/ksirc/puke/pobject.cpp
@@ -0,0 +1,138 @@
+#include "pobject.h"
+#include "commands.h"
+
+
+PObject::PObject(QObject *pobject, const char *name)
+ : QObject(pobject, name)
+{
+ // Connect slots as needed
+ obj = 0;
+ setWidget(0);
+ manualTerm = FALSE;
+ deleteAble = TRUE;
+ m_hasError = false;
+}
+
+PObject::~PObject()
+{
+ if(isDeleteAble())
+ delete widget();
+ obj = 0;
+ setWidget(0);
+}
+
+PObject *PObject::createWidget(CreateArgs &ca)
+{
+ PObject *pw = new PObject(ca.parent);
+ QObject *o;
+ if(ca.parent != 0)
+ o = new QObject(ca.parent->widget());
+ else
+ o = new QObject();
+ pw->setWidget(o);
+ pw->setWidgetId(ca.pwI);
+ pw->setPukeController(ca.pc);
+ return pw;
+}
+
+void PObject::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ if(pm->iCommand == PUKE_WIDGET_DELETE){
+ /**
+ * Emit the ack before the delete since we don't exist afterwards.
+ */
+ pmRet.iCommand = PUKE_WIDGET_DELETE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+
+ manTerm();
+ delete this;
+ }
+ if(pm->iCommand == PUKE_RELEASEWIDGET){
+ /**
+ * Emit the ack before the delete since we don't exist afterwards.
+ */
+ pmRet.iCommand = PUKE_RELEASEWIDGET_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+
+ /**
+ * By setting the widget to 0 we loose the pointer and then don't delete it
+ */
+ setWidget(0);
+ manTerm();
+ delete this;
+ }
+ else {
+ qWarning("PObject: Unkown Command: %d", pm->iCommand);
+ pmRet.iCommand = PUKE_INVALID;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+}
+
+void PObject::setWidget(QObject *_o)
+{
+ // Disconnect everything from the object we where listning too
+ // Just in case it fires something off, we don't want to get it
+ if(widget() != 0){
+ disconnect(widget(), SIGNAL(destroyed()),
+ this, SLOT(swidgetDestroyed()));
+ }
+
+ obj = _o;
+ if(obj != 0){
+ connect(widget(), SIGNAL(destroyed()),
+ this, SLOT(swidgetDestroyed()));
+ }
+}
+
+QObject *PObject::widget()
+{
+ // kdDebug(5008) << "PObject widget called" << endl;
+ return obj;
+}
+
+void PObject::setWidgetId(widgetId *pwI)
+{
+ wI = *pwI;
+ // kdDebug(5008) << "PObject: set widget id " << wI.iWinId << endl;
+}
+
+widgetId PObject::widgetIden()
+{
+ // kdDebug(5008) << "PObject: called widget id " << wI.iWinId << endl;
+ return wI;
+}
+
+void PObject::swidgetDestroyed(){
+ setWidget(0x0);
+ if(manualTerm == FALSE){
+ manTerm();
+ delete this;
+ }
+}
+
+PukeController *PObject::controller() {
+
+ return pController;
+}
+
+void PObject::manTerm() {
+ manualTerm = TRUE;
+}
+
+void PObject::errorInvalidSet(QObject *_w)
+{
+ m_error = QString("Tried setting a %1 to %2").arg(_w->className()).arg(className());
+ m_hasError = true;
+}
+#include "pobject.moc"
+
diff --git a/ksirc/puke/pobject.h b/ksirc/puke/pobject.h
new file mode 100644
index 00000000..8e5c7c5a
--- /dev/null
+++ b/ksirc/puke/pobject.h
@@ -0,0 +1,134 @@
+#ifndef POBJECT_H
+#define POBJECT_H
+
+class PObject;
+class PukeController;
+class CreateArgs;
+
+#include <qobject.h>
+#include "pmessage.h"
+
+
+class CreateArgs {
+public:
+ CreateArgs(PukeController *_pc, PukeMessage *_pm, widgetId *_pwI, PObject *_parent){
+ pc = _pc;
+ pwI = _pwI;
+ parent = _parent;
+ pm = _pm;
+ fetchedObj = 0;
+ }
+ PukeController *pc;
+ widgetId *pwI;
+ PObject *parent;
+ PukeMessage *pm;
+
+ /**
+ * name of the widget which was fetched from kSirc, this has to be set explicitly
+ */
+ QObject *fetchedObj;
+};
+
+class PObject : public QObject
+{
+ Q_OBJECT
+ public:
+ PObject(QObject *parent = 0, const char *name = 0);
+ virtual ~PObject();
+
+ /**
+ * Creates a new QObject and returns a PObject
+ */
+ static PObject *createWidget(CreateArgs &ca);
+
+ /**
+ * Handles messages from dsirc
+ * PObject can't get messages so return an error
+ */
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ /**
+ * Sets the current opbect
+ */
+ virtual void setWidget(QObject *w);
+
+ /**
+ * Returns the current object
+ */
+ virtual QObject *widget();
+
+ /**
+ * Sets the window id
+ */
+ virtual void setWidgetId(widgetId *pwI);
+ /**
+ * Returns the current window identifier
+ */
+ virtual widgetId widgetIden();
+
+ /**
+ * Set's the puke controller for the widget
+ */
+ void setPukeController(PukeController *pc){
+ pController = pc;
+ }
+
+ /**
+ * If we cannot delete the widget, check this (ie fetched widgets)
+ */
+ bool isDeleteAble(){
+ return deleteAble;
+ }
+
+ /**
+ * Returns if an error was encountered.
+ */
+ bool hasError() {
+ return m_hasError;
+ }
+
+ /**
+ * Returns error description
+ */
+ QString error() {
+ m_hasError = false;
+ return m_error;
+ }
+
+ /**
+ * Set this for fetched widgets and such that cannot be deleted
+ */
+ void setDeleteAble(bool _d){
+ deleteAble = _d;
+ }
+ /**
+ * Before deleting the widget, call manTerm() to signal manual
+ * termination of the widget
+ */
+ void manTerm();
+
+
+ signals:
+ void outputMessage(int fd, PukeMessage *pm);
+ void widgetDestroyed(widgetId wI);
+
+ protected slots:
+ void swidgetDestroyed();
+
+protected:
+ PukeController *controller();
+ void errorInvalidSet(QObject *_w);
+
+private:
+ QObject *obj;
+ PukeController *pController;
+ widgetId wI;
+
+ bool manualTerm;
+ bool deleteAble;
+ QString m_error;
+ bool m_hasError;
+};
+
+#include "controller.h"
+#endif
diff --git a/ksirc/puke/pobjfinder-cmd.h b/ksirc/puke/pobjfinder-cmd.h
new file mode 100644
index 00000000..4f89cfec
--- /dev/null
+++ b/ksirc/puke/pobjfinder-cmd.h
@@ -0,0 +1,32 @@
+#ifndef POBJFINDER_CMD_H
+#define POBJFINDER_CMD_H
+
+/*
+ * We get 2300
+ */
+
+// Desc: fetchs all object names that kSirc knows about
+// iWinId: widget
+// iArg: not defined
+// cArg: path
+#define PUKE_OBJFINDER_ALLOBJECTS 2300
+
+// Desc: ack for the fetch
+// iWinId: widget
+// iArg: not defined
+// cArg: new line seperated list of widgets className::name
+#define PUKE_OBJFINDER_ALLOBJECTS_ACK -2300
+
+// Desc: signal for creation of a new object, not used, only ack
+// iWinId: not defined
+// iArg: not defined
+// cArg: not defined
+#define PUKE_OBJFINDER_NEWOBJECT 2301
+
+// Desc: signal for new widget created
+// iWinId: widget
+// iArg: not defined
+// cArg: className::name of new object
+#define PUKE_OBJFINDER_NEWOBJECT_ACK -2301
+
+#endif
diff --git a/ksirc/puke/pobjfinder.cpp b/ksirc/puke/pobjfinder.cpp
new file mode 100644
index 00000000..0f510ea4
--- /dev/null
+++ b/ksirc/puke/pobjfinder.cpp
@@ -0,0 +1,86 @@
+#include "pobjfinder.h"
+#include "pobjfinder-cmd.h"
+
+
+PObject *
+PObjFinder::createWidget(CreateArgs &ca)
+{
+ PObjFinder *pw = new PObjFinder(ca.parent);
+ pw->setWidget(0x0);
+ pw->setWidgetId(ca.pwI);
+ pw->setPukeController(ca.pc);
+ return pw;
+}
+
+
+PObjFinder::PObjFinder(PObject *parent)
+ : PObject(parent)
+{
+ // We don't actually encase a widget since all the ObjFinder interface
+ // is static
+ setWidget(0x0);
+ connect(controller(), SIGNAL(inserted(QObject *)),
+ this, SLOT(newObject(QObject *)));
+}
+
+PObjFinder::~PObjFinder()
+{
+}
+
+void PObjFinder::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_OBJFINDER_ALLOBJECTS:
+ {
+ QString qscArg;
+ QStrList allObj = controller()->allObjects();
+ for(uint i = 0; i <= allObj.count(); i++){
+ qscArg += allObj.at(i);
+ qscArg += "\n";
+ }
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = qstrdup(qscArg);
+ pmRet.iTextSize = qscArg.length();
+ emit outputMessage(fd, &pmRet);
+ delete pmRet.cArg;
+ break;
+ }
+ default:
+ PObject::messageHandler(fd, pm);
+ }
+}
+
+void PObjFinder::setWidget(QObject *_obj)
+{
+ PObject::setWidget(_obj);
+}
+
+
+objFinder *PObjFinder::widget()
+{
+ return 0x0;
+}
+
+
+void PObjFinder::newObject(QObject *name){
+ QString info;
+
+ info = name->className();
+ info += "::";
+ info += name->name("unnamed");
+
+ PukeMessage pmRet;
+ pmRet.iCommand = - PUKE_OBJFINDER_NEWOBJECT_ACK;
+ pmRet.iWinId = widgetIden().iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = qstrdup(info);
+ pmRet.iTextSize = info.length();
+ emit outputMessage(widgetIden().fd, &pmRet);
+ delete pmRet.cArg;
+}
+
+#include "pobjfinder.moc"
diff --git a/ksirc/puke/pobjfinder.h b/ksirc/puke/pobjfinder.h
new file mode 100644
index 00000000..9149aa86
--- /dev/null
+++ b/ksirc/puke/pobjfinder.h
@@ -0,0 +1,33 @@
+#ifndef POBJFINDER_H
+#define POBJFINDER_H
+
+#include "pobject.h"
+#include "../objFinder.h"
+#include "pmessage.h"
+#include "controller.h"
+
+
+class PObjFinder : public PObject
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PObjFinder ( PObject * parent );
+ virtual ~PObjFinder ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_obj = 0);
+ virtual objFinder *widget();
+
+public slots:
+ virtual void newObject(QObject *obj);
+
+protected:
+ bool checkWidget();
+
+private:
+};
+
+#endif
diff --git a/ksirc/puke/pobjfinder.pm b/ksirc/puke/pobjfinder.pm
new file mode 100644
index 00000000..6cf6c5bb
--- /dev/null
+++ b/ksirc/puke/pobjfinder.pm
@@ -0,0 +1,89 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $::PUKE_CONTROLLER,
+ $PWIDGET_OBJFINDER,
+ "pobjfinder.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PLabel Load failed!\n";
+ }
+ }
+ );
+
+package PObjFinder;
+@ISA = qw(PBase);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_OBJFINDER;
+
+ if($class eq 'PObjFinder'){
+ $self->create();
+ }
+
+ $self->installHandler($::PUKE_OBJFINDER_NEWOBJECT, sub {$self->newObject(shift())});
+
+ return $self;
+
+}
+
+sub newObject {
+}
+
+sub interAllObjects {
+ my $self = shift;
+ my %REPLY = $self->sendMessage('iCommand' => $::PUKE_OBJFINDER_ALLOBJECTS,
+ 'WaitFor' => 1);
+
+ return $REPLY{'cArg'};
+
+}
+
+sub allObjects {
+ my $self = shift;
+ my $line = $self->interAllObjects();
+
+ $line =~ s/\S+::unnamed//gm;
+
+ return $line;
+
+}
+
+
+sub allObjectsHash {
+ my $self = shift;
+
+ my $line = $self->allObjects();
+
+ my $widget;
+ my %hash;
+
+ foreach $widget (split(/\n/, $line)){
+ $hash{$widget} = 1;
+ }
+
+ return \%hash;
+
+}
+
+sub allObjectsArray {
+ my $self = shift;
+
+ my $line = $self->allObjects();
+
+ my $widget;
+ my @arr;
+
+ foreach $widget (split(/\n/, $line)){
+ next if $widget eq '';
+ $arr[$#arr+1] = $widget;
+ }
+
+ return @arr;
+}
+
+package main;
+
diff --git a/ksirc/puke/ppopmenu.cpp b/ksirc/puke/ppopmenu.cpp
new file mode 100644
index 00000000..4c07d800
--- /dev/null
+++ b/ksirc/puke/ppopmenu.cpp
@@ -0,0 +1,120 @@
+#include <kdebug.h>
+#include <qcursor.h>
+
+#include "ppopmenu.h"
+
+PObject *
+PPopupMenu::createWidget(CreateArgs &ca)
+{
+ PPopupMenu *pm = new PPopupMenu(ca.parent);
+ QPopupMenu *qpm;
+ if(ca.fetchedObj != 0 && ca.fetchedObj->inherits("QPopupMenu") == TRUE){
+ qpm= (QPopupMenu *) ca.fetchedObj;
+ pm->setDeleteAble(FALSE);
+ }
+ else if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ qpm = new QPopupMenu((QWidget *) ca.parent->widget());
+ else
+ qpm = new QPopupMenu();
+ pm->setWidget(qpm);
+ pm->setWidgetId(ca.pwI);
+ return pm;
+}
+
+
+PPopupMenu::PPopupMenu(PObject *parent)
+ : PFrame(parent)
+{
+ // kdDebug(5008) << "PLineEdit PLineEdit called" << endl;
+ menu = 0;
+ setWidget(menu);
+ pmd = new PMenuData(this);
+}
+
+PPopupMenu::~PPopupMenu()
+{
+ // kdDebug(5008) << "PLineEdit: in destructor" << endl;
+/* delete widget(); // Delete the frame
+ menu = 0; // Set it to 0
+ setWidget(menu); // Now set all widget() calls to 0.
+*/
+ delete pmd;
+}
+
+void PPopupMenu::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ /*
+ case PUKE_LINED_SET_MAXLENGTH:
+ if(widget() == 0){
+ kdDebug(5008) << "PLineEdit: No Widget set" << endl;
+ return;
+ }
+ widget()->setMaxLength(pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->maxLength();
+ emit outputMessage(fd, &pmRet);
+ break;
+ */
+ case PUKE_POPUPMENU_POPUP_CURRENT:
+ if(widget() == 0){
+ kdDebug(5008) << "PPopupMenu: No Widget set" << endl;
+ return;
+ }
+
+ widget()->popup(QCursor::pos(), 0);
+
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 1;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+
+ default:
+ if(pmd->menuMessageHandler(fd, pm) == FALSE) // Call pmd's even filter
+ PFrame::messageHandler(fd, pm);
+ }
+}
+
+void PPopupMenu::setWidget(QObject *_menu)
+{
+ if(_menu != 0 && _menu->inherits("QPopupMenu") == FALSE)
+ {
+ errorInvalidSet(_menu);
+ return;
+ }
+
+ menu = (QPopupMenu *) _menu;
+ if(menu != 0x0){
+ connect(menu, SIGNAL(activated(int)),
+ this, SLOT(got_activated(int)));
+ }
+ PFrame::setWidget(menu);
+}
+
+
+QPopupMenu *PPopupMenu::widget()
+{
+ return menu;
+}
+
+void PPopupMenu::got_activated(int itemId){
+ qWarning("Item got activated: %d", itemId);
+
+ widgetId wI;
+ PukeMessage pmRet;
+
+ wI = widgetIden();
+ pmRet.iCommand = PUKE_POPUPMENU_ACTIVATED_ACK;
+ pmRet.iWinId = wI.iWinId;
+ pmRet.iArg = itemId;
+ pmRet.cArg = 0;
+ emit outputMessage(wI.fd, &pmRet);
+
+}
+
+#include "ppopmenu.moc"
+
diff --git a/ksirc/puke/ppopmenu.h b/ksirc/puke/ppopmenu.h
new file mode 100644
index 00000000..9044b935
--- /dev/null
+++ b/ksirc/puke/ppopmenu.h
@@ -0,0 +1,36 @@
+#ifndef PPOPMENU_H
+#define PPOPMENU_H
+
+class PPopupMenu;
+
+#include <qpopupmenu.h>
+#include "pobject.h"
+#include "pmessage.h"
+
+#include "ptablevw.h"
+#include "pmenudta.h"
+
+class PPopupMenu : public PFrame
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PPopupMenu(PObject *child);
+ virtual ~PPopupMenu();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_menu);
+ virtual QPopupMenu *widget();
+
+protected slots:
+ void got_activated ( int itemId );
+
+private:
+ QPopupMenu *menu;
+ PMenuData *pmd;
+
+};
+
+#endif
diff --git a/ksirc/puke/ppopmenu.pm b/ksirc/puke/ppopmenu.pm
new file mode 100644
index 00000000..c1c011fa
--- /dev/null
+++ b/ksirc/puke/ppopmenu.pm
@@ -0,0 +1,65 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $PUKE_CONTROLLER,
+ $PWIDGET_POPMENU,
+ "ppopmenu.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PPopMenu Load failed!\n";
+ }
+ }
+ );
+
+package PPopupMenu;
+@ISA = qw(PTableView PMenuData);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_POPMENU;
+
+ if($class eq 'PPopupMenu'){
+ $self->create();
+ }
+
+ $self->installHandler($::PUKE_POPUPMENU_ACTIVATED_ACK,
+ sub {$self->activated(@_)});
+
+ return $self;
+
+}
+
+sub activated {
+ my $self = shift;
+
+ my %ARG = %{shift()};
+
+ if($self->{'menu_id'}{$ARG{'iArg'}}){
+ &{$self->{'menu_id'}{$ARG{'iArg'}}}(%ARG);
+ }
+ else {
+ # There's not handler, don't make noise, since if we used fetchWidget()
+ # We don't handlers for everything
+ # &::tell("*E* No handler for id: $ARG{iArg}\n");
+ }
+}
+
+sub installMenu {
+ my $self = shift;
+
+ my $id = shift;
+ my $func = shift;
+ $self->{'menu_id'}{$id} = $func;
+}
+
+sub popupAtCurrent {
+ my $self = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_POPUPMENU_POPUP_CURRENT,
+ 'CallBack' => sub {});
+}
+
+
+package main;
diff --git a/ksirc/puke/pprogress.cpp b/ksirc/puke/pprogress.cpp
new file mode 100644
index 00000000..75c7fa4b
--- /dev/null
+++ b/ksirc/puke/pprogress.cpp
@@ -0,0 +1,133 @@
+#include <stdio.h>
+
+
+#include <kdebug.h>
+
+#include "pprogress.h"
+
+PObject *
+PProgress::createWidget(CreateArgs &ca)
+{
+ PProgress *pw = new PProgress(ca.parent);
+ KSProgress *ksp;
+ if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ ksp = new KSProgress((QWidget *) ca.parent->widget());
+ else
+ ksp = new KSProgress();
+ pw->setWidget(ksp);
+ pw->setWidgetId(ca.pwI);
+ return pw;
+}
+
+
+PProgress::PProgress( PObject *parent)
+ : PWidget(parent)
+{
+ // kdDebug(5008) << "PProgress PProgress called" << endl;
+ ksp = 0;
+}
+
+PProgress::~PProgress()
+{
+ // kdDebug(5008) << "PProgress: in destructor" << endl;
+ /*
+ delete widget(); // Delete the frame
+ ksp=0; // Set it to 0
+ setWidget(ksp); // Now set all widget() calls to 0.
+ */
+}
+
+void PProgress::messageHandler(int fd, PukeMessage *pm)
+{
+ // kdDebug(5008) << "PProgress handler called" << endl;
+ PukeMessage pmRet;
+ if(widget() == 0){
+ qWarning("Null widget");
+ return;
+ }
+ switch(pm->iCommand){
+ case PUKE_KSPROGRESS_SET_RANGE:
+ {
+ int start=0, stop=1;
+ int found = sscanf(pm->cArg, "%d\t%d", &start, &stop);
+ if(found != 2)
+ throw(errorCommandFailed(PUKE_INVALID,13));
+ if(start >= stop){
+ stop = start+1;
+ start = 0;
+ }
+
+ widget()->setRange(start, stop);
+ pmRet.iCommand = PUKE_KSPROGRESS_SET_RANGE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+ case PUKE_KSPROGRESS_SET_TOPTEXT:
+ widget()->setTopText(QString(pm->cArg));
+ pmRet.iCommand = PUKE_KSPROGRESS_SET_TOPTEXT;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_KSPROGRESS_SET_BOTTEXT:
+ widget()->setBotText(QString(pm->cArg));
+ pmRet.iCommand = PUKE_KSPROGRESS_SET_BOTTEXT;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_KSPROGRESS_SET_VALUE:
+ widget()->setValue(pm->iArg);
+ pmRet.iCommand = PUKE_KSPROGRESS_SET_VALUE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ default:
+ PWidget::messageHandler(fd, pm);
+ }
+}
+
+void PProgress::cancelPressed(){
+ kdDebug(5008) << "Cancel Pressed" << endl;
+ PukeMessage pmRet;
+ pmRet.iCommand = PUKE_KSPROGRESS_CANCEL_ACK;
+ pmRet.iWinId = widgetIden().iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(widgetIden().fd, &pmRet);
+}
+
+void PProgress::setWidget(QObject *_f)
+{
+ // kdDebug(5008) << "PProgress setWidget called" << endl;
+ if(_f != 0 && _f->inherits("KSProgress") == FALSE)
+ {
+ errorInvalidSet(_f);
+ return;
+ }
+
+ ksp = (KSProgress *) _f;
+ if(widget() != 0){
+ connect(widget(), SIGNAL(cancel()),
+ this, SLOT(cancelPressed()));
+ }
+ PWidget::setWidget(ksp);
+
+}
+
+
+KSProgress *PProgress::widget()
+{
+ // kdDebug(5008) << "PProgress widget called" << endl;
+ return ksp;
+}
+
+#include "pprogress.moc"
+
diff --git a/ksirc/puke/pprogress.h b/ksirc/puke/pprogress.h
new file mode 100644
index 00000000..f81fd976
--- /dev/null
+++ b/ksirc/puke/pprogress.h
@@ -0,0 +1,32 @@
+#ifndef PPROGRESS_H
+#define PPROGRESS_H
+
+class PProgress;
+
+#include "../KSProgress/ksprogress.h"
+#include "pmessage.h"
+//#include "pwidget.h"
+#include "pobject.h"
+#include "controller.h"
+
+class PProgress : public PWidget {
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PProgress ( PObject * parent = 0);
+ virtual ~PProgress ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_f);
+ virtual KSProgress *widget();
+
+protected slots:
+ void cancelPressed();
+
+private:
+ KSProgress *ksp;
+};
+
+#endif
diff --git a/ksirc/puke/pprogress.pm b/ksirc/puke/pprogress.pm
new file mode 100644
index 00000000..b889483e
--- /dev/null
+++ b/ksirc/puke/pprogress.pm
@@ -0,0 +1,86 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $PUKE_CONTROLLER,
+ $PWIDGET_KSPROGRESS,
+ "pprogress.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PProgress Load failed!\n";
+ }
+ }
+ );
+
+package PProgress;
+@ISA = qw(PWidget);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_KSPROGRESS;
+
+ $self->installHandler($::PUKE_KSPROGRESS_CANCEL_ACK,
+ sub {$self->cancelPressed(@_)});
+
+
+ if($class eq 'PProgress'){
+ $self->create();
+ }
+
+ return $self;
+
+}
+
+sub setTopText {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_KSPROGRESS_SET_TOPTEXT,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+sub setBotText {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_KSPROGRESS_SET_BOTTEXT,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+sub setRange {
+ my $self = shift;
+
+ my $lower = shift;
+ my $upper = shift;
+
+ my $carg = "$lower\t$upper";
+
+ $self->sendMessage('iCommand' => $::PUKE_KSPROGRESS_SET_RANGE,
+ 'cArg' => $carg,
+ 'CallBack' => sub {});
+
+}
+
+sub setValue {
+ my $self = shift;
+
+ my $value = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_KSPROGRESS_SET_VALUE,
+ 'iArg' => $value,
+ 'CallBack' => sub {});
+
+}
+
+sub cancelPressed {
+ print "*E* Cancel pressed\n";
+}
+
+package main;
diff --git a/ksirc/puke/ppushbt.cpp b/ksirc/puke/ppushbt.cpp
new file mode 100644
index 00000000..48cf6121
--- /dev/null
+++ b/ksirc/puke/ppushbt.cpp
@@ -0,0 +1,70 @@
+#include "ppushbt.h"
+#include <stdio.h>
+
+
+PObject *
+PPushButton::createWidget(CreateArgs &ca)
+{
+ PPushButton *pb = new PPushButton(ca.parent);
+ QPushButton *qb;
+ if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ qb = new QPushButton((QWidget *) ca.parent->widget());
+ else
+ qb = new QPushButton(0L);
+ pb->setWidget(qb);
+ pb->setWidgetId(ca.pwI);
+ return pb;
+}
+
+
+PPushButton::PPushButton(PObject *parent)
+ : PButton(parent)
+{
+ // kdDebug(5008) << "PLineEdit PLineEdit called" << endl;
+ button = 0;
+ setWidget(button);
+}
+
+PPushButton::~PPushButton()
+{
+ // kdDebug(5008) << "PLineEdit: in destructor" << endl;
+/* delete widget(); // Delete the frame
+ button=0; // Set it to 0
+ setWidget(button); // Now set all widget() calls to 0.
+ */
+}
+
+void PPushButton::messageHandler(int fd, PukeMessage *pm)
+{
+// PukeMessage pmRet;
+ switch(pm->iCommand){
+ default:
+ PButton::messageHandler(fd, pm);
+ }
+}
+
+void PPushButton::setWidget(QObject *_qb)
+{
+ if(_qb != 0 && _qb->inherits("QPushButton") == FALSE)
+ {
+ errorInvalidSet(_qb);
+ return;
+ }
+
+ button = (QPushButton *) _qb;
+ if(_qb != 0){
+ }
+ PButton::setWidget(_qb);
+
+}
+
+
+QPushButton *PPushButton::widget()
+{
+ return button;
+}
+
+
+
+#include "ppushbt.moc"
+
diff --git a/ksirc/puke/ppushbt.h b/ksirc/puke/ppushbt.h
new file mode 100644
index 00000000..87336679
--- /dev/null
+++ b/ksirc/puke/ppushbt.h
@@ -0,0 +1,33 @@
+#ifndef PPUSHBUTTON_H
+#define PPUSHBUTTON_H
+
+class PPushButton;
+
+#include <qpushbutton.h>
+#include "pmessage.h"
+#include "pbutton.h"
+#include "pobject.h"
+#include "controller.h"
+
+class PPushButton : public PButton
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PPushButton ( PObject * parent );
+ virtual ~PPushButton ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_b = 0);
+ virtual QPushButton *widget();
+
+public slots:
+
+private:
+ QPushButton *button;
+
+};
+
+#endif
diff --git a/ksirc/puke/ppushbt.pm b/ksirc/puke/ppushbt.pm
new file mode 100644
index 00000000..c1d00349
--- /dev/null
+++ b/ksirc/puke/ppushbt.pm
@@ -0,0 +1,30 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $PUKE_CONTROLLER,
+ $PWIDGET_PUSHBT,
+ "ppushbt.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PPushButton Load failed!\n";
+ }
+ }
+ );
+
+package PPushButton;
+@ISA = qw(PButton);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_PUSHBT;
+
+ if($class eq 'PPushButton'){
+ $self->create();
+ }
+ return $self;
+
+}
+
+package main;
diff --git a/ksirc/puke/ptabdialog.cpp b/ksirc/puke/ptabdialog.cpp
new file mode 100644
index 00000000..b0e3ba2c
--- /dev/null
+++ b/ksirc/puke/ptabdialog.cpp
@@ -0,0 +1,101 @@
+#include <stdio.h>
+
+
+#include "ptabdialog.h"
+#include "commands.h"
+#include <iostream>
+
+PObject *
+PTabDialog::createWidget(CreateArgs &ca)
+{
+ PTabDialog *ptd = new PTabDialog(ca.parent);
+ QTabDialog *qtd;
+ // Retreive the border and direction information out of the
+ // carg string
+ if(ca.fetchedObj != 0 && ca.fetchedObj->inherits("QTabDialog") == TRUE){
+ qtd = (QTabDialog *) ca.fetchedObj;
+ ptd->setDeleteAble(FALSE);
+ }
+ else if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ qtd = new QTabDialog((QWidget *) ca.parent->widget());
+ else
+ qtd = new QTabDialog();
+ ptd->setWidget(qtd);
+ ptd->setWidgetId(ca.pwI);
+ ptd->setPukeController(ca.pc);
+ return ptd;
+}
+
+PTabDialog::PTabDialog(QObject *)
+ : PWidget()
+{
+ // Connect slots as needed
+ setWidget(0);
+}
+
+PTabDialog::~PTabDialog()
+{
+ // kdDebug(5008) << "PObject: in destructor" << endl;
+ /*
+ delete widget();
+ tab = 0;
+ setWidget(0);
+ */
+}
+
+void PTabDialog::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+
+ if(pm->iCommand == PUKE_TABDIALOG_ADDTAB){
+ if(!(pm->iTextSize > 0)){
+ qWarning("QTabDialog/addtab: incorrent cArg size, bailing out. Needed: >0 got: %d\n", pm->iTextSize);
+ pmRet.iCommand = PUKE_TABDIALOG_ADDTAB_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 1;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ return;
+ }
+ widgetId wiWidget;
+ wiWidget.fd = fd;
+ wiWidget.iWinId = pm->iArg;
+ PWidget *pw = controller()->id2pwidget(&wiWidget);
+ // kdDebug(5008) << "Adding widget with stretch: " << (int) pm->cArg[0] << " and align: " << // (int) pm->cArg[1] << endl;
+ widget()->addTab(pw->widget(), pm->cArg);
+
+ pmRet.iCommand = PUKE_TABDIALOG_ADDTAB_ACK; // ack the add widget
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ else {
+ PWidget::messageHandler(fd, pm);
+ }
+
+}
+
+void PTabDialog::setWidget(QObject *tb)
+{
+ if(tb != 0 && tb->inherits("QTabDialog") == FALSE)
+ {
+ errorInvalidSet(tb);
+ return;
+ }
+
+ tab = (QTabDialog *) tb;
+ if(tab != 0){
+ }
+ PObject::setWidget(tb);
+
+}
+
+QTabDialog *PTabDialog::widget()
+{
+ // kdDebug(5008) << "PObject widget called" << endl;
+ return tab;
+}
+
+#include "ptabdialog.moc"
+
diff --git a/ksirc/puke/ptabdialog.h b/ksirc/puke/ptabdialog.h
new file mode 100644
index 00000000..6e669074
--- /dev/null
+++ b/ksirc/puke/ptabdialog.h
@@ -0,0 +1,41 @@
+#ifndef PTABDIALOG_H
+#define PTABDIALOG_H
+
+class PTabDialog;
+
+#include <qtabdialog.h>
+#include "pmessage.h"
+#include "pwidget.h"
+
+class PTabDialog : public PWidget
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PTabDialog(QObject *parent = 0);
+ virtual ~PTabDialog();
+
+ /**
+ * Handles messages from dsirc
+ * PObject can't get messages so return an error
+ */
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ /**
+ * Sets the current opbect
+ */
+ virtual void setWidget(QObject *tb);
+
+ /**
+ * Returns the current object
+ */
+ virtual QTabDialog *widget();
+
+private:
+
+ QTabDialog *tab;
+
+};
+
+#endif
diff --git a/ksirc/puke/ptabdialog.pm b/ksirc/puke/ptabdialog.pm
new file mode 100644
index 00000000..65435fb9
--- /dev/null
+++ b/ksirc/puke/ptabdialog.pm
@@ -0,0 +1,49 @@
+
+&::PukeSendMessage($PUKE_WIDGET_LOAD,
+ $PUKE_CONTROLLER,
+ $PWIDGET_TABDIALOG,
+ "ptabdialog.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PTabDialog Load failed!\n";
+ }
+ }
+ );
+
+package PTabDialog;
+@ISA = qw(PWidget);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_TABDIALOG;
+
+ if($class eq 'PTabDialog'){
+ $self->create();
+ }
+
+ return $self;
+
+}
+
+sub addTab {
+ my $self = shift;
+
+ my $widget = shift;
+ my $text = shift;
+
+ if($widget->{iWinId} <= 0){
+ print "*E* Trying to add invalid widget " . ref($widget) . "\n";
+ return;
+ }
+
+ $self->sendMessage('iCommand' => $::PUKE_TABDIALOG_ADDTAB,
+ 'iArg' => $widget->{iWinId},
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+package main;
diff --git a/ksirc/puke/ptablevw.cpp b/ksirc/puke/ptablevw.cpp
new file mode 100644
index 00000000..1dba614b
--- /dev/null
+++ b/ksirc/puke/ptablevw.cpp
@@ -0,0 +1,76 @@
+#include "ptablevw.h"
+
+
+PObject *
+PTableView::createWidget(CreateArgs &ca)
+{
+ qWarning("Table View is abstract class, cannot create an object from it!!!");
+ PTableView *pt = new PTableView(ca.parent);
+ pt->setWidget(0);
+ pt->setWidgetId(ca.pwI);
+ return pt;
+}
+
+
+PTableView::PTableView(PObject *parent)
+ : PFrame(parent)
+{
+ // kdDebug(5008) << "PTableView PTableView called" << endl;
+ tbl = 0;
+ setWidget(tbl);
+}
+
+PTableView::~PTableView()
+{
+ // don't delete the widget since none acutally exists.
+ // delete widget(); // Delete the frame
+ // tbl=0; // Set it to 0
+// setWidget(tbl); // Now set all widget() calls to 0.
+}
+
+void PTableView::messageHandler(int fd, PukeMessage *pm)
+{
+// PukeMessage pmRet;
+ switch(pm->iCommand){
+ /*
+ case PUKE_LINED_SET_MAXLENGTH:
+ if(widget() == 0){
+ kdDebug(5008) << "PTableView: No Widget set" << endl;
+ return;
+ }
+ widget()->setMaxLength(pm->iArg);
+ pmRet.iCommand = - pm->iCommand;
+ pmRet.iWinId = - pm->iWinId;
+ pmRet.iArg = widget()->maxLength();
+ emit outputMessage(fd, &pmRet);
+ break;
+ */
+ default:
+ PFrame::messageHandler(fd, pm);
+ }
+}
+
+void PTableView::setWidget(QObject *_tbv)
+{
+ if(_tbv != 0 && _tbv->inherits("QGridView") == FALSE)
+ {
+ errorInvalidSet(_tbv);
+ return;
+ }
+
+ tbl = (QGridView *) _tbv;
+ if(tbl != 0){
+ }
+ PFrame::setWidget(_tbv);
+
+}
+
+
+QGridView *PTableView::widget()
+{
+ return tbl;
+}
+
+
+#include "ptablevw.moc"
+
diff --git a/ksirc/puke/ptablevw.h b/ksirc/puke/ptablevw.h
new file mode 100644
index 00000000..33ba4015
--- /dev/null
+++ b/ksirc/puke/ptablevw.h
@@ -0,0 +1,33 @@
+#ifndef PTABLEVIEW_H
+#define PTABLEVIEW_H
+
+class PTableView;
+
+#include <qgridview.h>
+
+#include "pmessage.h"
+#include "pframe.h"
+#include "controller.h"
+
+// Init and setup code
+class PTableView : public PFrame
+{
+ Q_OBJECT
+public:
+ static PObject *createWidget(CreateArgs &ca);
+
+ PTableView ( PObject * parent );
+ virtual ~PTableView ();
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *_tbl);
+ virtual QGridView *widget();
+
+public slots:
+
+private:
+ QGridView *tbl;
+};
+
+#endif
diff --git a/ksirc/puke/ptablevw.pm b/ksirc/puke/ptablevw.pm
new file mode 100644
index 00000000..297d7b29
--- /dev/null
+++ b/ksirc/puke/ptablevw.pm
@@ -0,0 +1,57 @@
+
+&::PukeSendMessage($::PUKE_WIDGET_LOAD,
+ $::PUKE_CONTROLLER,
+ $::PWIDGET_TABLEVW,
+ "ptablevw.so",
+ sub { my %ARG = %{shift()};
+ if($ARG{'iArg'} == 1){
+ print "*E* PTableView Load failed!\n";
+ }
+ }
+ );
+
+
+package PTableView;
+@ISA = qw(PFrame);
+use strict;
+
+if($PTableView::usage == undef){
+ $PTableView::usage = 0;
+}
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ if($PTableView::usage == 0){
+ }
+ $PTableView::usage++;
+
+ $self->{widgetType} = $::PWIDGET_TABLEVW;
+
+ if($class eq 'PTableView'){
+ $self->create();
+ }
+
+ return $self;
+
+}
+
+sub DESTROY {
+ my $self = shift;
+ $self->SUPER::DESTROY(@_);
+ $PTableView::usage--;
+ if($PTableView::usage == 0){
+ # &::PukeSendMessage($::PUKE_WIDGET_UNLOAD,
+ # 0,
+ # $::PWIDGET_TABLEVW,
+ # "",
+ # sub {}
+ # );
+
+ }
+}
+
+
+package main;
+1;
diff --git a/ksirc/puke/puke.pl b/ksirc/puke/puke.pl
new file mode 100644
index 00000000..f0d2c7fd
--- /dev/null
+++ b/ksirc/puke/puke.pl
@@ -0,0 +1,225 @@
+use Socket;
+use Fcntl;
+
+#
+# Clean up if this is the second load.
+#
+# Don't close anything so we can be loaded twice.
+#
+#if($PUKEFd != undef){
+# &remsel($PUKEFd);
+# close($PUKEFd);
+# sleep(1);
+# $PUKEFd = undef;
+#}
+
+#
+# Puke timeout waiting for messages
+$PUKE_TIMEOUT = 10;
+
+#
+# Setup flag fo syncronous operation
+# 1 for sync
+# 0 for async/fly by the seat of your pants
+#
+$SYNC = 0;
+
+#
+# Setup debugging logger, comment out for production use
+#
+$DEBUG = 0;
+if($DEBUG){
+ open(LOG, ">msg-log") || warn "Failed to open log file: $!\n";
+ select(LOG); $| = 1; select(STDOUT);
+ print LOG "Start time: ". `date`;
+}
+
+
+
+#
+# Multi operation level handler, winId Based.
+#
+# PUKE_HANDLER{Cmd}{winId} = sub();
+
+%PUKE_HANDLER = ();
+
+#
+# Default handler is called if no handler defined
+# Default handlers defined in commands-handler.pl
+# Single level PUKE_DEF_HANDLER{$cmd};
+#
+
+#%PUKE_DEF_HANDLER = ();
+
+#require 'commands-perl.pl';
+&docommand("/load commands-perl.pl");
+#require 'commands-handler.pl';
+&docommand("/load commands-handler.pl");
+
+$PukeHeader = 42; # Alternating 1010 for 32 bits
+$PukePacking = "Iiiiia*"; # 4 ints, followed by any number of of characters
+$PukeMSize = length(pack($PukePacking, $PukeHeader, 0, 0, 0, 0, ""));
+
+if(!$ENV{'PUKE_SOCKET'}) {
+ $sock = $ENV{'HOME'} . "/.ksirc.socket";
+}
+else {
+ $sock = $ENV{'PUKE_SOCKET'};
+}
+
+if($PUKEFd == undef){
+ $PUKEFd = &newfh;
+ $proto = getprotobyname('tcp');
+ socket($PUKEFd, PF_UNIX, SOCK_STREAM, 0) || print "PUKE: Sock failed: $!\n";
+ $sun = sockaddr_un($sock);
+ print "*P* PUKE: Connecting to $sock\n";
+ connect($PUKEFd,$sun) || (die "Puke: Connect failed: $!\n",$PUKEFailed=1);
+ select($PUKEFd); $| = 1; select(STDOUT);
+ #fcntl($PUKEFd, F_SETFL, O_NONBLOCK);
+}
+
+# Arg1: Command
+# Arg2: WinId
+# Arg3: iArg
+# Arg4: cArg
+sub PukeSendMessage {
+ my($cmd, $winid, $iarg, $carg, $handler, $waitfor) = @_;
+ # print("PUKE: cArg message too long $cArg\n") if(length($carg) > 50);
+ $PUKE_HANDLER{$cmd}{$winid} = $handler if $handler != undef;
+ my $msg = pack($PukePacking, $PukeHeader, $cmd, $winid, $iarg, length($carg), $carg);
+ syswrite($PUKEFd, $msg, length($msg));
+ # print STDERR "*** " . $msg . "\n";
+ print LOG kgettimeofday() . " SEND message: CMD: $PUKE_NUM2NAME{$cmd} WIN: $winid IARG: $iarg LEN: " . length($carg) . " CARG: $carg\n" if $DEBUG;
+ if($SYNC == 1 || $waitfor == 1){
+ return &sel_PukeRecvMessage(1, $winid, -$cmd, $carg);
+ }
+ return ();
+}
+
+sub sel_PukeRecvMessage {
+ ($wait, $wait_winid, $wait_cmd, $wait_carg) = @_;
+ my($m);
+ my($cmd, $winid, $iarg, $carg, $junk);
+
+ while(1){
+ my $old_a = $SIG{'alarm'};
+ $SIG{'alarm'} = sub { die "alarm\n"; };
+ my $old_time = alarm($PUKE_TIMEOUT);
+ eval {
+ $len = sysread($PUKEFd, $m, $PukeMSize);
+ };
+ if($@){
+ print "*E* Timeout waiting for data for first sysread\n";
+ $SIG{ALRM} = $old_a;
+ alarm($old_time);
+ return;
+ }
+ $SIG{ALRM} = $old_a;
+ alarm($old_time);
+
+ if($len== 0){
+ &remsel($PUKEFd);
+ close($PUKEFd);
+ return;
+ }
+ # print "Length: $len " . length($m) . "\n";
+ ($header, $cmd, $winid, $iarg, $length, $carg) = unpack($PukePacking, $m);
+ if($header != $PukeHeader){
+ print("*E* Invalid message received! Discarding! Got: $header wanted: $PukeHeader\n");
+ # return;
+ }
+ if($length > 0){
+ my $old_a = $SIG{'alarm'};
+ $SIG{'alarm'} = sub { die "alarm\n"; };
+ my $old_time = alarm($PUKE_TIMEOUT);
+ eval {
+ $clen = sysread($PUKEFd, $m2, $length);
+ };
+ if($@){
+ print "*E* Timeout waiting for cArg data\n";
+ }
+ $SIG{ALRM} = $old_a;
+ alarm($old_time);
+
+ if($length != $clen){
+ print "\n*E* Warning: wanted to read: $length got $clen\n";
+ }
+ $m .= $m2;
+ ($header, $cmd, $winid, $iarg, $length, $carg) = unpack($PukePacking, $m);
+ }
+ # print("PUKE: Got => $PUKE_NUM2NAME{$cmd}/$cmd\n");
+ # print("PUKE: Got: $cmd, $winid, $iarg, $length, $carg\n");
+ # print("\n");
+ if($winid == undef){ $winid = 0; }
+ $blah = $carg;
+ $blah =~ s/\000//g;
+ print LOG kgettimeofday() . " GOT message: CMD: $PUKE_NUM2NAME{$cmd} WIN: $winid IARG: $iarg LEN: $length CARG: $blah\n" if $DEBUG;
+ #
+ # Check both $cmd and the correct reply -$cmd
+ #
+ my(%ARG) = ('iCommand' => $cmd,
+ 'iWinId' => $winid,
+ 'iArg' => $iarg,
+ 'cArg' => $carg);
+
+ # print "*I* Def handler: $PUKE_DEF_HANDLER{$cmd}\n";
+
+ if($wait == 1 && $winid == $wait_winid && $wait_cmd == $cmd){
+ print LOG kgettimeofday() . " WAIT message: CMD: $PUKE_NUM2NAME{$cmd} WIN: $winid IARG: $iarg LEN: $length CARG: $blah\n" if $DEBUG;
+ ($wait, $wait_winid, $wait_cmd, $wait_carg) = ();
+ return %ARG;
+ }
+
+ if($PUKE_HANDLER{-$cmd}{$winid}){ # one shot/command handler
+ &{$PUKE_HANDLER{-$cmd}{$winid}}(\%ARG);
+ } elsif ($PUKE_HANDLER{$cmd}{$winid}){
+ &{$PUKE_HANDLER{$cmd}{$winid}}(\%ARG);
+ } elsif ($PUKE_W_HANDLER{$cmd}{$winid}) { # widget specific handler
+ &{$PUKE_W_HANDLER{$cmd}{$winid}}(\%ARG);
+ } elsif ($PUKE_DEF_HANDLER{"$cmd"}) {# catch all
+ &{$PUKE_DEF_HANDLER{"$cmd"}}(\%ARG);
+ }
+ else {
+ #
+ # If there was no handler this is a widget creation falling throuhg
+ #
+
+ if($wait == 1 && (substr($wait_carg,0,7) eq substr($carg,0,7))){
+ print LOG kgettimeofday() . " WAI2 message: CMD: $PUKE_NUM2NAME{$cmd} WIN: $winid IARG: $iarg LEN: $length CARG: $blah\n" if $DEBUG;
+ ($wait, $wait_winid, $wait_cmd, $wait_carg) = ();
+ return %ARG;
+ }
+ # No handler at all, unkown reply
+ print("*E* PUKE: Got unkown command: $cmd/$PUKE_NUM2NAME{$cmd}\n");
+ # print("PUKE: Got: $cmd, $winid, $iarg, $carg\n");
+ }
+
+ #
+ # If we're not waiting for a message, return
+ #
+ if(!$wait){
+ ($wait, $wait_winid, $wait_cmd, $wait_carg) = ();
+ return ();
+ }
+
+ my($rin, $rout) =('', '');
+ vec($rin,fileno($PUKEFd),1) = 1;
+ $nfound = select($rout=$rin, undef, undef, 1);
+ if($nfound < 1){
+ print "*E* PUKE: Timed out waiting for reply, returning null\n";
+ print LOG kgettimeofday() . " FAIL message: CMD: $PUKE_NUM2NAME{$wait_cmd} WIN: $wait_winid IARG: ### LEN: $length CARG: $wait_carg\n" if $DEBUG;
+ return ();
+ }
+ }
+}
+
+&addsel($PUKEFd, "PukeRecvMessage", 0);
+
+# Basics are up and running, now init Puke/Ksirc Interface.
+
+my(%ARG) = &PukeSendMessage($PUKE_SETUP, $::PUKE_CONTROLLER, 0, $server, undef, 1);
+
+$PukeMSize = $ARG{'iArg'};
+print "*P* Puke: Initial Setup complete\n";
+print "*P* Puke: Communications operational\n";
+
diff --git a/ksirc/puke/pwidget.cpp b/ksirc/puke/pwidget.cpp
new file mode 100644
index 00000000..d254832b
--- /dev/null
+++ b/ksirc/puke/pwidget.cpp
@@ -0,0 +1,492 @@
+#include "pwidget.h"
+#include "commands.h"
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <qpixmap.h>
+
+PWidget::PWidget(PObject *)
+ : PObject()
+{
+ // kdDebug(5008) << "PWidget constructor called" << endl;
+
+ w = 0;
+ setWidget(0);
+
+ eventList[0] = &PWidget::eventNone;
+ eventList[1] = &PWidget::eventTimer;
+ eventList[2] = &PWidget::eventMouse;
+ eventList[3] = &PWidget::eventMouse;
+ eventList[4] = &PWidget::eventMouse;
+ eventList[5] = &PWidget::eventMouse;
+ eventList[6] = &PWidget::eventKey;
+ eventList[7] = &PWidget::eventKey;
+ eventList[8] = &PWidget::eventFocus;
+ eventList[9] = &PWidget::eventFocus;
+ eventList[10] = &PWidget::eventFocus;
+ eventList[11] = &PWidget::eventFocus;
+ eventList[12] = &PWidget::eventPaint;
+ eventList[13] = &PWidget::eventMove;
+ eventList[14] = &PWidget::eventResize;
+ eventList[15] = &PWidget::eventNone;
+ eventList[16] = &PWidget::eventNone;
+ eventList[17] = &PWidget::eventNone;
+ eventList[18] = &PWidget::eventNone;
+ eventList[19] = &PWidget::eventNone;
+
+ // Connect slots as needed
+
+}
+
+PWidget::~PWidget()
+{
+ // kdDebug(5008) << "PWidget: in destructor" << endl;
+ /*
+ delete widget();
+ w = 0;
+ setWidget(0);
+ */
+}
+
+PObject *PWidget::createWidget(CreateArgs &ca)
+{
+ PWidget *pw = new PWidget();
+ QWidget *tw;
+ if(ca.fetchedObj != 0 && ca.fetchedObj->inherits("QWidget") == TRUE){
+ tw = (QWidget *) ca.fetchedObj;
+ pw->setDeleteAble(FALSE);
+ }
+ else if(ca.parent != 0 && ca.parent->widget()->isWidgetType() == TRUE)
+ tw = new QWidget((QWidget *) ca.parent->widget());
+ else
+ tw = new QWidget();
+ pw->setWidget(tw);
+ pw->setWidgetId(ca.pwI);
+ pw->setPukeController(ca.pc);
+ return pw;
+}
+
+void PWidget::messageHandler(int fd, PukeMessage *pm)
+{
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_WIDGET_SHOW:
+ widget()->show();
+ pmRet.iCommand = PUKE_WIDGET_SHOW_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_WIDGET_HIDE:
+ widget()->hide();
+ pmRet.iCommand = PUKE_WIDGET_HIDE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_WIDGET_REPAINT:
+ widget()->repaint(pm->iArg);
+ pmRet.iCommand = PUKE_WIDGET_REPAINT_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_WIDGET_RESIZE:
+ {
+ int x, y;
+ int found = sscanf(pm->cArg, "%d\t%d", &x, &y);
+ if(found != 2)
+ throw(errorCommandFailed(PUKE_INVALID,10));
+
+ widget()->resize(x, y);
+
+ pmRet.iCommand = PUKE_WIDGET_RESIZE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = pm->iArg;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ break;
+ case PUKE_WIDGET_MOVE:
+ {
+ int x, y;
+ int found = sscanf(pm->cArg, "%d\t%d", &x, &y);
+ if(found != 2)
+ throw(errorCommandFailed(PUKE_INVALID,10));
+
+ // kdDebug(5008) << "Moving to: " << pm->iArg << " => " << pos[0] << " " << pos[1] << endl;
+ widget()->move(x, y);
+ pmRet.iCommand = PUKE_WIDGET_MOVE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ break;
+ case PUKE_WIDGET_SETMINSIZE:
+ {
+ int x, y;
+ int found = sscanf(pm->cArg, "%d\t%d", &x, &y);
+ if(found != 2)
+ throw(errorCommandFailed(PUKE_INVALID,11));
+
+ widget()->setMinimumSize(x, y);
+
+ pmRet.iCommand = PUKE_WIDGET_SETMINSIZE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ }
+ break;
+ case PUKE_WIDGET_SETMAXSIZE:
+ {
+ int x, y;
+ int found = sscanf(pm->cArg, "%d\t%d", &x, &y);
+ if(found != 2)
+ throw(errorCommandFailed(PUKE_INVALID,12));
+
+ widget()->setMaximumSize(x, y);
+
+ pmRet.iCommand = -pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = pm->iArg;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+ case PUKE_WIDGET_SETCAPTION:
+ widget()->setCaption(pm->cArg);
+ pmRet.iCommand = PUKE_WIDGET_SETCAPTION_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.iTextSize = strlen(widget()->caption());
+ pmRet.cArg = strdup(widget()->caption());
+ emit outputMessage(fd, &pmRet);
+ free(pmRet.cArg);
+ break;
+ case PUKE_WIDGET_GET_BACKGROUND_COLOUR:
+ {
+ pmRet.cArg = new char[15];
+ pmRet.iTextSize = 15;
+ QColor back = widget()->backgroundColor();
+ sprintf(pmRet.cArg, "%d,%d,%d", back.red(), back.green(), back.blue());
+
+ pmRet.iCommand = -pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ emit outputMessage(fd, &pmRet);
+ delete pmRet.cArg;
+ break;
+ }
+ case PUKE_WIDGET_SET_BACKGROUND_PIXMAP:
+ widget()->setBackgroundPixmap(QPixmap(pm->cArg));
+
+ pmRet.iCommand = -pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_WIDGET_SET_BACKGROUND_MODE:
+ widget()->setBackgroundMode((QWidget::BackgroundMode) pm->iArg);
+
+ pmRet.iCommand = -pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = (int) widget()->backgroundMode();
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+
+ case PUKE_WIDGET_SET_BACKGROUND_COLOUR:
+ {
+ int *pos;
+ pos = (int *) pm->cArg;
+ QColor bg(pos[0], pos[1], pos[2]);
+ QColorGroup cg = QColorGroup(widget()->colorGroup().foreground(),
+ bg,
+ widget()->colorGroup().light(),
+ widget()->colorGroup().dark(),
+ widget()->colorGroup().mid(),
+ widget()->colorGroup().text(),
+ bg);
+ widget()->setPalette(QPalette(cg,cg,cg));
+
+ pmRet.iCommand = -pm->iCommand;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+
+ case PUKE_WIDGET_SET_ENABLED:
+ widget()->setEnabled((bool) pm->iArg);
+ pmRet.iCommand = PUKE_WIDGET_SET_ENABLED_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ case PUKE_WIDGET_RECREATE:
+ {
+ QWidget *nparent = 0x0;
+ if(pm->iArg != 0x0){
+ widgetId wiWidget;
+ wiWidget.fd = fd;
+ wiWidget.iWinId = pm->iArg;
+ nparent = controller()->id2pwidget(&wiWidget)->widget();
+ }
+ if(pm->iTextSize != 3*sizeof(int)){
+ throw(errorCommandFailed(pm->iCommand, pm->iArg));
+ }
+ int *point_show = (int *) pm->cArg;
+
+ qWarning("Recreate: %d %d %d", point_show[0], point_show[1], point_show[3]);
+
+ widget()->reparent(nparent, (WFlags) 0, QPoint(point_show[0], point_show[1]), point_show[3]);
+
+ pmRet.iCommand = PUKE_WIDGET_RECREATE_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = 0;
+ pmRet.cArg = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ }
+ default:
+ PObject::messageHandler(fd, pm);
+ }
+}
+
+void PWidget::setWidget(QObject *_w)
+{
+ if(_w != 0 && _w->inherits("QWidget") == FALSE)
+ {
+ errorInvalidSet(_w);
+ return;
+ }
+
+ w = (QWidget *) _w;
+ if(w != 0){
+ widget()->installEventFilter(this);
+ }
+ PObject::setWidget(_w);
+}
+
+QWidget *PWidget::widget()
+{
+ // kdDebug(5008) << "PWidget widget called" << endl;
+ return w;
+}
+
+// PWidget specific
+bool PWidget::eventFilter(QObject *o, QEvent *e)
+{
+ if(e->type() < 20 && e->type() >= 0){
+ (this->*(eventList[e->type()]))(o,e);
+ }
+ else{
+ PukeMessage pm;
+ widgetId wI;
+
+ wI = widgetIden();
+ pm.iCommand = PUKE_EVENT_UNKOWN;
+ pm.iWinId = wI.iWinId;
+ pm.iArg = e->type();
+ pm.cArg = 0;
+ emit outputMessage(wI.fd, &pm);
+
+ }
+
+ return false;
+}
+
+void PWidget::eventNone(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ // kdDebug(5008) << "PWidget: eventNone" << endl;
+
+ wI = widgetIden();
+ pm.iCommand = - e->type() - 1020; // 1030 offset for events
+ pm.iWinId = wI.iWinId;
+ pm.iArg = 0;
+ pm.cArg = 0;
+
+ emit outputMessage(wI.fd, &pm);
+
+}
+
+void PWidget::eventTimer(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ QTimerEvent *et = (QTimerEvent *)(e);
+
+ wI = widgetIden();
+ pm.iCommand = PUKE_WIDGET_EVENT_TIMER;
+ pm.iWinId = wI.iWinId;
+ pm.iArg = et->timerId();
+ pm.cArg = 0;
+
+ emit outputMessage(wI.fd, &pm);
+
+}
+
+void PWidget::eventMouse(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ QMouseEvent *me = (QMouseEvent *)(e);
+
+ wI = widgetIden();
+ pm.iCommand = - e->type() - 1020; // 1020 offset for events
+ pm.iWinId = wI.iWinId;
+ pm.iArg = 0;
+
+ // special cArg handling
+ pm.iTextSize = 4*sizeof(int);
+ int *icArg = new int[4];
+ icArg[0] = me->x();
+ icArg[1] = me->y();
+ icArg[2] = me->button();
+ icArg[3] = me->state();
+ pm.cArg = (char *) icArg;
+
+ emit outputMessage(wI.fd, &pm);
+
+ delete[] icArg;
+
+}
+
+void PWidget::eventKey(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ QKeyEvent *ke = (QKeyEvent *)(e);
+
+ wI = widgetIden();
+ pm.iCommand = - e->type() - 1020; // 1020 offset for events
+ pm.iWinId = wI.iWinId;
+ pm.iArg = 0;
+
+ // special cArg handling
+ pm.iTextSize = 3*sizeof(int);
+ int *icArg = new int[3];
+ icArg[0] = ke->key();
+ icArg[1] = ke->ascii();
+ icArg[2] = ke->state();
+ pm.cArg = (char *) icArg;
+
+ emit outputMessage(wI.fd, &pm);
+
+ delete[] icArg;
+
+}
+
+void PWidget::eventFocus(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ // kdDebug(5008) << "PWidget: eventFocus" << endl;
+
+ QFocusEvent *fe = (QFocusEvent *)(e);
+
+ wI = widgetIden();
+ pm.iCommand = - e->type() - 1020; // 1020 offset for events
+ pm.iWinId = wI.iWinId;
+ pm.iArg = 0;
+
+ pm.cArg = new char[2];
+ pm.iTextSize = 2*sizeof(char);
+ pm.cArg[0] = fe->gotFocus();
+ pm.cArg[1] = fe->lostFocus();
+
+ emit outputMessage(wI.fd, &pm);
+
+ delete[] pm.cArg;
+}
+
+void PWidget::eventPaint(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ wI = widgetIden();
+ pm.iCommand = - e->type() - 1020; // 1020 offset for events
+ pm.iWinId = wI.iWinId;
+ pm.iArg = 0;
+ pm.cArg = 0;
+
+ emit outputMessage(wI.fd, &pm);
+
+}
+
+void PWidget::eventMove(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ QMoveEvent *me = (QMoveEvent *)(e);
+
+ wI = widgetIden();
+ pm.iCommand = - e->type() - 1020; // 1020 offset for events
+ pm.iWinId = wI.iWinId;
+ pm.iArg = 0;
+
+ // special cArg handling
+ pm.iTextSize = 4*sizeof(int);
+ int *icArg = new int[4];
+ icArg[0] = me->pos().x();
+ icArg[1] = me->pos().y();
+ icArg[2] = me->oldPos().x();
+ icArg[3] = me->oldPos().y();
+ pm.cArg = (char *) icArg;
+
+ emit outputMessage(wI.fd, &pm);
+
+ delete[] icArg;
+
+}
+
+void PWidget::eventResize(QObject *, QEvent *e)
+{
+ PukeMessage pm;
+ widgetId wI;
+
+ QResizeEvent *re = (QResizeEvent *)(e);
+
+ wI = widgetIden();
+ pm.iCommand = - e->type() - 1020; // 1020 offset for events
+ pm.iWinId = wI.iWinId;
+ pm.iArg = 0;
+
+ // special cArg handling
+ pm.iTextSize = 4*sizeof(int);
+ int *icArg = new int[4];
+ icArg[0] = re->size().height();
+ icArg[1] = re->size().width();
+ icArg[2] = re->oldSize().height();
+ icArg[3] = re->oldSize().width();
+ pm.cArg = (char *) icArg;
+
+ emit outputMessage(wI.fd, &pm);
+
+ delete[] icArg;
+
+}
+
+
+#include "pwidget.moc"
+
diff --git a/ksirc/puke/pwidget.h b/ksirc/puke/pwidget.h
new file mode 100644
index 00000000..f7f748fb
--- /dev/null
+++ b/ksirc/puke/pwidget.h
@@ -0,0 +1,45 @@
+#ifndef PWIDGET_H
+#define PWIDGET_H
+
+class PWidget;
+
+#include <qobject.h>
+#include <qwidget.h>
+#include "pobject.h"
+#include "pmessage.h"
+
+class PWidget : public PObject
+{
+ Q_OBJECT
+ public:
+ PWidget(PObject *parent = 0);
+ virtual ~PWidget();
+
+ // Init and setup code
+ static PObject *createWidget(CreateArgs &ca);
+
+ virtual void messageHandler(int fd, PukeMessage *pm);
+
+ virtual void setWidget(QObject *w = 0x0);
+ virtual QWidget *widget();
+
+ protected:
+ bool eventFilter(QObject *o, QEvent *e);
+
+ private:
+ QWidget *w;
+
+ void (PWidget::*eventList[20])(QObject *, QEvent *);
+
+ void eventNone(QObject *, QEvent *);
+ void eventTimer(QObject *, QEvent *);
+ void eventMouse(QObject *, QEvent *);
+ void eventKey(QObject *, QEvent *);
+ void eventFocus(QObject *, QEvent *);
+ void eventPaint(QObject *, QEvent *);
+ void eventMove(QObject *, QEvent *);
+ void eventResize(QObject *, QEvent *);
+
+};
+
+#endif
diff --git a/ksirc/puke/pwidget.pm b/ksirc/puke/pwidget.pm
new file mode 100644
index 00000000..5a73d393
--- /dev/null
+++ b/ksirc/puke/pwidget.pm
@@ -0,0 +1,231 @@
+
+package PWidget;
+@ISA = qw(PBase);
+use strict;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_WIDGET;
+
+ # Default handlers
+ $self->installHandler($::PUKE_WIDGET_EVENT_RESIZE,
+ sub {$self->resizeEvent(@_)});
+ $self->installHandler($::PUKE_WIDGET_EVENT_PAINT,
+ sub {$self->paintEvent(@_)});
+ $self->installHandler($::PUKE_WIDGET_EVENT_MOVE,
+ sub {$self->moveEvent(@_)});
+ $self->installHandler($::PUKE_EVENT_UNKOWN,
+ sub {$self->miscEvent(@_)});
+ # Examplesto listen for mouse events
+ # $self->installHandler($::PUKE_WIDGET_EVENT_MOUSEBUTTONPRESS,
+ # sub {$self->mousePressEvent(@_)});
+ #$self->installHandler($::PUKE_WIDGET_EVENT_MOUSEBUTTONRELEASE,
+ # sub {$self->mouseReleaseEvent(@_)});
+
+
+
+ if($class eq 'PWidget'){
+ $self->create();
+ }
+
+ return $self;
+
+}
+
+sub close {
+ my $self = shift;
+
+ $self->hide();
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_DELETE,
+ 'CallBack' => sub {});
+
+ $self->{DESTROYED} = 1;
+
+}
+
+sub show {
+ my $self = shift;
+
+ # make sure we are runable then show continue.
+ my @ARG = ();
+ # $self->canRun($self, \&PWidget::show, \@ARG) || return;
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SHOW);
+}
+
+sub hide {
+ my $self = shift;
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_HIDE);
+}
+
+sub repaint {
+ my $self = shift;
+
+ my $erase = shift; # 1 for erase and reapint
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_REPAINT,
+ 'iArg' => $erase);
+}
+
+sub resize {
+ my $self = shift;
+
+ my $width = shift;
+ my $height = shift;
+
+ my $carg = "$width\t$height";
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_RESIZE,
+ 'cArg' => $carg);
+
+}
+
+sub move {
+ my $self = shift;
+
+ my $x = shift;
+ my $y = shift;
+
+ my $carg = "$x\t$y";
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_MOVE,
+ 'cArg' => $carg);
+
+}
+
+sub setMinimumSize {
+ my $self = shift;
+
+ my $w = shift;
+ my $h = shift;
+
+ my $carg = "$w\t$h";
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SETMINSIZE,
+ 'cArg' => $carg,
+ 'CallBack' => sub {});
+
+}
+
+sub setMaximumSize {
+ my $self = shift;
+
+ my $w = shift;
+ my $h = shift;
+
+ my $carg = "$w\t$h";
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SETMAXSIZE,
+ 'cArg' => $carg,
+ 'CallBack' => sub {});
+
+}
+
+
+sub setCaption {
+ my $self = shift;
+
+ my $text = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SETCAPTION,
+ 'cArg' => $text,
+ 'CallBack' => sub {});
+
+}
+
+sub resizeEvent {
+ my $self = shift;
+
+ my %ARG = %{shift()};
+
+ my($h, $w, $oh, $ow) = unpack("iiii", $ARG{'cArg'});
+ $self->{'height'} = $h;
+ $self->{'width'} = $w;
+
+}
+
+sub paintEvent {
+}
+
+sub moveEvent {
+ my $self = shift;
+
+ my %ARG = %{shift()};
+
+ my($x, $y, $ox, $oy) = unpack("iiii", $ARG{'cArg'});
+ $self->{'x'} = $x;
+ $self->{'y'} = $y;
+
+}
+
+sub miscEvent {
+}
+
+sub backgroundColor {
+ my $self = shift;
+
+ my %arg = $self->sendMessage('iCommand' => $::PUKE_WIDGET_GET_BACKGROUND_COLOUR,
+ 'WaitFor' => 1);
+
+ # print "Got: " . $arg{'cArg'} . "\n";
+
+ $arg{'cArg'} =~ s/\000//g;
+ my ($r, $g, $b) = split(/,/, $arg{'cArg'});
+
+ return ($r, $g, $b);
+}
+
+sub setBackgroundColor {
+ my $self = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SET_BACKGROUND_COLOUR,
+ 'cArg' => pack("i3", shift(), shift(), shift()),
+ 'CallBack' => sub {});
+
+}
+
+sub setBackgroundPixmap {
+ my $self = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SET_BACKGROUND_PIXMAP,
+ 'cArg' => shift(),
+ 'CallBack' => sub {});
+}
+
+sub setBackgroundMode {
+ my $self = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SET_BACKGROUND_MODE,
+ 'iArg' => shift(),
+ 'CallBack' => sub {});
+}
+
+
+sub setEnabled {
+ my $self = shift;
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_SET_ENABLED,
+ 'iArg' => shift(),
+ 'CallBack' => sub {});
+
+}
+
+sub recreate {
+ my $self = shift;
+
+ my $nparent = shift;
+ my $wflags = shift; # Not used!
+
+ $self->sendMessage('iCommand' => $::PUKE_WIDGET_RECREATE,
+ 'iArg' => $nparent ? $nparent->{'iWinId'} : 0,
+ 'cArg' => pack("iii", shift(), shift(), shift()),
+ 'CallBack' => sub {});
+
+}
+
+package main;
+
+1;
diff --git a/ksirc/puke/small.pl b/ksirc/puke/small.pl
new file mode 100644
index 00000000..7e7b251d
--- /dev/null
+++ b/ksirc/puke/small.pl
@@ -0,0 +1,65 @@
+&docommand("/load pbase.pm");
+&docommand("/load pwidget.pm");
+&docommand("/load pframe.pm");
+&docommand("/load pboxlayout.pm");
+&docommand("/load plined.pm");
+&docommand("/load pbutton.pm");
+&docommand("/load ppushbt.pm");
+&docommand("/load pprogress.pm");
+&docommand("/load ptablevw.pm");
+&docommand("/load plistbox.pm");
+&docommand("/load plabel.pm");
+
+$pw = new PWidget;
+$pw->resize(250,500);
+
+$pf = new PFrame($pw);
+$pf->setFrameStyle($PFrame::Panel|$PFrame::Sunken, 1);
+$pf->move(50,50);
+$pf->resize(150,400);
+$pf->setMinimumSize(50,50);
+
+$pf2 = new PFrame($pw);
+$pf2->setFrameStyle($PFrame::Panel|$PFrame::Raised, 1);
+$pf2->setMinimumSize(50,50);
+
+
+$pl = new PListBox($pw);
+$pl->move(50,50);
+$pl->resize(300, 50);
+$pl->setMinimumSize(50,50);
+
+$label = new PLabel($pw);
+$label->setText("Label");
+$label->setMinimumSize(50,50);
+
+$pb = new PBoxLayout($pw, $PBoxLayout::TopToBottom, 5);
+$pb2 = new PBoxLayout($PBoxLayout::LeftToRight, 5);
+$pb3 = new PBoxLayout($PBoxLayout::TopToBottom, 5);
+$pb->addLayout($pb2);
+$pb->addLayout($pb3);
+$pb->addWidget($pf, 1, $PBoxLayout::AlignCenter);
+$pb2->addWidget($pf2, 10, $PBoxLayout::AlignCenter);
+$pb2->addWidget($pl, 10, $PBoxLayout::AlignCenter);
+$pb2->addWidget($label, 10, $PBoxLayout::AlignCenter);
+
+$pb4 = new PBoxLayout($PBoxLayout::RightToLeft, 1);
+$pb3->addLayout($pb4);
+
+$pb4->addWidget($pf2, 0, $PBoxLayout::AlignCenter);
+
+$pbutton = new PPushButton($pw);
+$pbutton->setText("Hello");
+#$pbutton->setPixmap("/opt/kde/share/icons/ksirc.gif");
+$pbutton->setMaximumSize(50,50);
+$pbutton->setMinimumSize(50,50);
+$pb->addWidget($pbutton, 10, $PBoxLayout::AlignCenter);
+
+$pline = new PLineEdit($pw);
+$pline->setMinimumSize(50, 30);
+$pline->resize(200, 20);
+$pline->setMaximumSize(1000, 30);
+$pline->setText("Hello!");
+$pb->addWidget($pline, 0);
+
+$pw->show; \ No newline at end of file
diff --git a/ksirc/puke/test.pl b/ksirc/puke/test.pl
new file mode 100644
index 00000000..4b4c3169
--- /dev/null
+++ b/ksirc/puke/test.pl
@@ -0,0 +1,63 @@
+&docommand("/load pbase.pm");
+&docommand("/load pwidget.pm");
+&docommand("/load pframe.pm");
+&docommand("/load pboxlayout.pm");
+&docommand("/load plined.pm");
+&docommand("/load pbutton.pm");
+&docommand("/load ppushbt.pm");
+&docommand("/load pprogress.pm");
+&docommand("/load ptablevw.pm");
+&docommand("/load plistbox.pm");
+
+$pw = new PWidget;
+$pw->resize(250,500);
+
+$pf = new PFrame($pw);
+$pf->setFrameStyle($PFrame::Panel|$PFrame::Sunken, 1);
+$pf->move(50,50);
+$pf->resize(150,400);
+
+$pf2 = new PListBox($pw);
+#$pf2->setFrameStyle($PFrame::Box|$PFrame::Raised, 1);
+$pf2->move(50,50);
+$pf2->resize(50,300);
+
+$pb = new PBoxLayout($pw, $PBoxLayout::TopToBottom, 5);
+$pb->addWidget($pf, 10);
+$pb->addWidget($pf2, 5);
+
+$pb2 = new PBoxLayout($PBoxLayout::LeftToRight, 5);
+$pb->addLayout($pb2, 0);
+
+$pl = new PLineEdit($pw);
+$pl->setMinimumSize(30,50);
+$pl->setMaximumSize(30,1000);
+$pl->setText("Blah blah");
+#$pl->resize(50,75);
+$pb2->addWidget($pl, 0, $PBoxLayout::AlignCenter);
+
+$pp = new PPushButton($pw);
+$pp->setMinimumSize(65,65);
+$pp->setMaximumSize(65,65);
+$pp->setPixmap("/opt/kde/share/icons/ksirc.gif");
+$pp->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub
+ {
+ print "*I* Clocked!\n";
+ $pw->close;
+ }
+ );
+$pb2->addWidget($pp, 0, $PBoxLayout::AlignRight);
+
+for(my $i = 0; $i < 100; $i++){
+ $pf2->insertPixmap("/opt/kde/share/icons/ksirc.gif", -1);
+ $pf2->insertText("Test $i", -1);
+}
+
+$pp = new PProgress;
+
+$pw->onNext(sub{$pw->show()});
+$pp->onNext(sub{$pw->show(); $pp->show()});
+#$pw->show();
+#$pf->show();
+#$pf2->show();
+
diff --git a/ksirc/puke/tester.pl b/ksirc/puke/tester.pl
new file mode 100755
index 00000000..d3b25462
--- /dev/null
+++ b/ksirc/puke/tester.pl
@@ -0,0 +1,28 @@
+#!/usr/bin/perl
+
+$sock = $ENV{'HOME'} . "/.ksirc.socket";
+
+use Socket;
+
+$proto = getprotobyname('tcp');
+socket(fd, PF_UNIX, SOCK_STREAM, 0) || die "Sock failed: $!\n";
+$sun = sockaddr_un($sock);
+print "Connecting to $sock\n";
+connect(fd,$sun) || die "Connect failed: $!\n";
+
+select(fd); $| = 1; select(STDOUT);
+
+while(1){
+ print "Command: ";
+ chomp($cmd = <STDIN>);
+ print "WinId: ";
+ chomp($winid = <STDIN>);
+ print "iArg: ";
+ chomp($iarg = <STDIN>);
+ print "cArg: ";
+ chomp($carg = <STDIN>);
+ $m = pack("iiia50xx", $cmd, $winid, $iarg, $carg);
+ print fd $m;
+
+}
+
diff --git a/ksirc/puke/user_monitor.ks b/ksirc/puke/user_monitor.ks
new file mode 100644
index 00000000..a0b2a56a
--- /dev/null
+++ b/ksirc/puke/user_monitor.ks
@@ -0,0 +1,440 @@
+&docommand("/load pbase.pm");
+&docommand("/load pwidget.pm");
+&docommand("/load pframe.pm");
+&docommand("/load ptablevw.pm");
+&docommand("/load plistbox.pm");
+&docommand("/load pboxlayout.pm");
+&docommand("/load plabel.pm");
+&docommand("/load pmenudta.pm");
+&docommand("/load ppopmenu.pm");
+&docommand("/load pbutton.pm");
+&docommand("/load ppushbt.pm");
+&docommand("/load palistbox.pm");
+&docommand("/load plined.pm");
+
+use Net::SMTP;
+
+my $WHO = "$ENV{HOME}/who_online.pl";
+my $INFO = "$ENV{HOME}/mysql_fetch";
+
+my %ALLOW_MULT = ();
+$ALLOW_MULT{'asj'} = 1;
+$ALLOW_MULT{'administrator'} = 1;
+
+@PAGE_PPL = ('andrew', 'lee', 'william', 'seamus', 'gerry', 'jason', 'derik');
+
+$PUKE_DEF_HANDLER{-999} = sub {};
+
+package UserList;
+
+@ISA = qw(PFrame);
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->create();
+
+ my $gm = new PBoxLayout($self, $PBoxLayout::TopToBottom, 5);
+
+ my $list_box = new PListBox($self);
+ $gm->addWidget($list_box, 5);
+
+ my $event_list = new PListBox($self);
+ $event_list->setMaximumSize(110, 2000);
+ $event_list->setMinimumSize(110, 1);
+ # $event_list->setFrameStyle($PFrame::Box|$PFrame::Raised);
+ $event_list->setFrameStyle(0);
+ $event_list->setBackgroundColor($self->backgroundColor());
+ # Turn off the widget so people can't click in it
+ $event_list->setEnabled(0);
+ $event_list->setAutoScrollBar(0);
+ $event_list->setScrollBar(0);
+ $gm->addWidget($event_list, 5);
+
+ my $gm_but = new PBoxLayout($PBoxLayout::LeftToRight, 5);
+ $gm->addLayout($gm_but, 5);
+
+ my $refresh_but = new PPushButton($self);
+ $refresh_but->setMaximumSize(25, 2000);
+ $refresh_but->setMinimumSize(25, 25);
+ $refresh_but->installHandler($::PUKE_BUTTON_PRESSED_ACK, sub { } );
+ $refresh_but->installHandler($::PUKE_BUTTON_RELEASED_ACK, sub { } );
+ $refresh_but->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub { &::docommand("refresh_users"); } );
+ $refresh_but->setText("&Refresh Users");
+ $gm_but->addWidget($refresh_but, 5);
+
+ my $page_dialog = new pageDialog();
+ $page_dialog->resize(265, 250);
+
+ my $page_but = new PPushButton($self);
+ $page_but->setMaximumSize(25, 2000);
+ $page_but->setMinimumSize(25, 25);
+ $page_but->installHandler($::PUKE_BUTTON_PRESSED_ACK, sub { } );
+ $page_but->installHandler($::PUKE_BUTTON_RELEASED_ACK, sub { } );
+ $page_but->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub { $self->{'page_dialog'}->show(); } );
+ $page_but->setText("&Page");
+ $gm_but->addWidget($page_but, 5);
+
+
+ my $user_count = new PLabel($self);
+ $user_count->setMaximumSize(25, 2000);
+ $user_count->setMinimumSize(25, 25);
+ $user_count->setFrameStyle($PFrame::Box|$PFrame::Raised);
+ $gm->addWidget($user_count, 5);
+
+ $user_count->setText($list_box->{count});
+
+ my $menu = new PPopupMenu();
+ my $menu_online = $menu->insertText("Online Time");
+ $menu->installMenu($menu_online, sub { &::say("online " . $self->{'list_box'}->currentText() . "\n"); });
+ my $menu_info = $menu->insertText("User Information");
+ $menu->installMenu($menu_info, sub { my $user = $self->{'list_box'}->currentText(); print `$INFO $user`; });
+ my $menu_info2 = $menu->insertText("Connection Information");
+ $menu->installMenu($menu_info2, sub { my $exec = "$WHO info " . $self->{'list_box'}->currentText(); print `$exec`; });
+
+ my $menu_rem = $menu->insertText("Remove User From List");
+ $menu->installMenu($menu_rem, sub {
+ my $user = $self->{'list_box'}->currentText();
+ my $count = $self->{'list_box'}->current();
+ $self->{'list_box'}->removeItem($count);
+ if($users_online->{$user} > 0){
+ $users_online->{$user}--;
+ }
+ if($users_online->{$user} == 0){
+ delete $users_online->{$user};
+ }
+ });
+ my $menu_kill = $menu->insertText("Disconnect User");
+ $menu->installMenu($menu_kill, sub { my $exec = "$WHO reset " . $self->{'list_box'}->currentText(); print "Running: $exec\n"; system($exec); });
+
+ # Install listner for mouse events
+
+ $list_box->installHandler($::PUKE_WIDGET_EVENT_MOUSEBUTTONPRESS,
+ sub {$self->popupMenu(@_)});
+ $list_box->installHandler($::PUKE_WIDGET_EVENT_MOUSEBUTTONRELEASE,
+ sub {$self->popdownMenu(@_)});
+
+
+ @$self{'gm', 'list_box', 'user_count', 'max', 'event_list', 'menu', 'page_dialog', 'page_but', 'gm_but'} = ($gm, $list_box, $user_count, 0, $event_list, $menu, $page_dialog, $page_but, $gm_but);
+
+ return $self;
+
+}
+
+sub DESTROY {
+ # $self->hide();
+ $self->{'gm'}->DESTROY;
+ delete $self->{'gm'};
+ delete $self->{'gm2'};
+ $self->{'list_box'}->DESTROY;
+ delete $self->{'list_box'};
+ $self->{'use_count'}->DESTROY;
+ delete $self->{'use_count'};
+
+ $self->SUPER::DESTROY();
+}
+
+sub popupMenu {
+ my $self = shift;
+ my $arg = shift;
+
+ my($x, $y, $b, $s) = unpack("i4", $arg->{'cArg'});
+ # print "$x $y $b $s\n";
+
+ # Only popup for button 2
+ $self->{'menu'}->popupAtCurrent() if $b == 2;
+}
+
+sub popdownMenu {
+ my $self = shift;
+
+ $self->{'menu'}->hide();
+}
+
+sub addEvent {
+ my $self = shift;
+
+ my $event_list = $self->{'event_list'};
+
+ while($event_list->{count} >= 10){
+ $event_list->removeItem($event_list->{count});
+ }
+
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+
+ my $text = sprintf("%02d:%02d:%02d " . shift(), $hour, $min, $sec);
+
+ $event_list->insertText($text, 0);
+}
+
+sub insertText {
+ my $self = shift;
+
+ $self->{'list_box'}->insertText(@_);
+
+ if($self->{'list_box'}->{count} > $self->{'max'}){
+ $self->{'max'} = $self->{'list_box'}->{count};
+ }
+
+ $self->{'user_count'}->setText("C: " . $self->{'list_box'}->{count} . " M: " . $self->{'max'});
+}
+
+sub removeItem {
+ my $self = shift;
+
+ $self->{'list_box'}->removeItem(@_);
+
+ $self->{'user_count'}->setText("C: " . $self->{'list_box'}->{count} . " M: " . $self->{'max'});
+}
+
+sub text {
+ my $self = shift;
+
+ return $self->{'list_box'}->text(@_);
+}
+
+sub count {
+ my $self = shift;
+
+ return $self->{'list_box'}->{count};
+}
+
+sub AUTOLOAD {
+ my $self = shift;
+
+ return if $AUTOLOAD =~ /::DESTROY$/;
+
+ $AUTOLOAD =~ /.+::(.+)/;
+ return $self->{'list_box'}->$1(@_);
+}
+
+package pageDialog;
+
+@ISA = qw(PFrame);
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+ $self->create();
+
+ my $gm = new PBoxLayout($self, $PBoxLayout::TopToBottom, 5);
+
+ my $ppl_label = new PLabel($self);
+ $ppl_label->setText("Person to page:");
+ $ppl_label->setMaximumSize(25, 2000);
+ $ppl_label->setMinimumSize(25, 25);
+ $gm->addWidget($ppl_label, 5);
+
+ my $page_ppl = new PListBox($self);
+ $gm->addWidget($page_ppl, 5);
+
+ my $msg_label = new PLabel($self);
+ $msg_label->setText("Message to page:");
+ $msg_label->setMaximumSize(25, 2000);
+ $msg_label->setMinimumSize(25, 25);
+ $gm->addWidget($msg_label, 5);
+
+ my $page_msg = new PLineEdit($self);
+ $page_msg->setMaximumSize(25, 2000);
+ $page_msg->setMinimumSize(25, 25);
+ $page_msg->setMaxLength(49);
+ $page_msg->installHandler($::PUKE_EVENT_UNKOWN, sub {});
+ $gm->addWidget($page_msg, 5);
+
+ my $send_but = new PPushButton($self);
+ $send_but->setMaximumSize(25, 2000);
+ $send_but->setMinimumSize(25, 25);
+ $send_but->installHandler($::PUKE_BUTTON_PRESSED_ACK, sub { } );
+ $send_but->installHandler($::PUKE_BUTTON_RELEASED_ACK, sub { } );
+ $send_but->installHandler($::PUKE_BUTTON_CLICKED_ACK, sub { &::docommand("msg #polarcom page " . $self->{'page_ppl'}->currentText() . " " . $self->{'page_msg'}->text()); $self->hide() } );
+ $send_but->setText("&Send");
+ $gm->addWidget($send_but, 5);
+
+ $self->setCaption("Page User");
+
+ @$self{'gm', 'page_ppl', 'page_msg', 'send_but', 'msg_label', 'ppl_label'} =
+ ($gm, $page_ppl, $page_msg, $send_but, $msg_label, $ppl_label);
+
+ return $self;
+
+}
+
+sub show {
+ my $self = shift;
+ my $page_ppl = $self->{'page_ppl'};
+
+ $self->hide();
+
+ my $c = $page_ppl->current();
+
+ $page_ppl->clear();
+ my $person;
+ foreach $person (@main::PAGE_PPL) {
+ $page_ppl->insertText($person, -1);
+ }
+ $page_ppl->setCurrentItem($c);
+
+ $self->resize(265, 250);
+ $self->recreate(0, 0, 265, 250, 1);
+
+# $self->SUPER::show();
+#
+# $self->resize(265,250);
+# $self->move(400,270);
+
+}
+
+
+package main;
+
+
+if($online == undef){
+ $online = new UserList();
+ $online->setCaption("Users Online");
+ $online->show();
+ $online->resize(196,740);
+ $online->move(823,0);
+
+ eval {
+ $main::polar = new PWidget();
+ $main::polar->fetchWidget("199.247.156.200_toplevel");
+ $main::polar->move(0,0);
+ $main::polar->resize(816, 740);
+ };
+ if($@) {
+ eval {
+ $main::polar = new PWidget();
+ $main::polar->fetchWidget("199.247.156.200_#polarcom_toplevel");
+ $main::polar->move(0,0);
+ $main::polar->resize(816, 740);
+ };
+ }
+ $users_online = {};
+}
+
+sub hook_online_mon {
+ my $channel = shift;
+ my $msg = shift;
+ return unless $channel eq '#polarcom';
+ return unless $msg =~ /Login|Logoff/;
+ return if $msg =~ /administrator/;
+
+ if($msg =~ /ice: Login (\S+)/){
+ my $nick = $1;
+ #return if $nick =~ /administrator/;
+ $nick =~ s/(\S+)\@\S+/$1/g;
+ $online->addEvent("On: $nick");
+ if($users_online->{$nick} > 0){
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+ my $date;
+ chomp($date = `date`);
+ my $times = $users_online->{$nick} + 1;
+ &say("$date Duplicate login for $nick, logged on $times times") if (($main::nick eq 'action') || ($nick eq 'administrator'));
+ $online->addEvent("Duplicate: $nick");
+ if($ALLOW_MULT{$nick} != 1){
+ my $exec = "$WHO reset " . $nick;
+ print "*I* Running: $exec\n";
+ system($exec);
+ my $smtp = new Net::SMTP->new;
+ $smtp->mail("sysadmin\@polarcom.com");
+ $smtp->to("$nick\@polarcom.com", "sysadmin\@polarcom.com");
+ $smtp->data();
+ $smtp->datasend("To: $nick\@polarcom.com\n");
+ $smtp->datasend("From: Polarcom System Admin <sysadmin\@polarcom.com>\n");
+ $smtp->datasend("Subject: Security Alert\n\n\n");
+ $smtp->datasend("To: $nick\n");
+ $smtp->datasend("Your account was simultaneously access by 2 or more users.\n");
+ $smtp->datasend("The second user was automatically terminated.\n\n");
+ $smtp->datasend("If you have any question, please email sysadmin\@polarcom.com\n");
+ $smtp->datasend("-- Security Monitor\n");
+ $smtp->datasend();
+ $smtp->quit();
+ }
+ else {
+ print "*I* $nick not being removed, in exclude list\n";
+ }
+ }
+ # Make the list sorted
+ my $i = 0;
+ SEARCH: while($online->text($i) ne undef){
+
+ if(($online->text($i) cmp $nick) >= 0){
+ last SEARCH;
+ }
+ $i++;
+ }
+ $online->insertText($nick, $i);
+ $users_online->{$nick}++;
+ }
+ elsif($msg =~ /ice: Logoff (\S+)/){
+ my $i = 0;
+ my $nick = $1;
+ $nick =~ s/(\S+)\@\S+/$1/g;
+ # print "Trying to logoff: $nick\n";
+ $online->addEvent("Off: $nick");
+ if($users_online->{$nick} > 0){
+ # print "$nick in list\n";
+ $users_online->{$nick}--;
+ if($users_online->{$nick} == 0){
+ delete $users_online->{$nick};
+ }
+ while($online->text($i) ne undef){
+ if($online->text($i) eq $nick){
+ # print "Removing $i for $nick which is really: " . $online->text($i) . "\n";
+ $online->removeItem($i);
+ return;
+ }
+ $i++;
+ }
+ }
+ }
+}
+
+&addhook("public", "online_mon");
+
+sub hook_get_users {
+ my $mesg = shift;
+
+ if($mesg =~ /^send users online/){
+ my $reply = 'Online: ';
+ for($i = 0; $i <= $online->count(); $i++){
+ $reply .= $online->text($i) . " ";
+ }
+ &msg($who, $reply);
+ }
+ if($mesg = /Online: (.+)\s+$/){
+ &tell("*I* Updating user list from $who");
+ $online->addEvent("Update user list: $who");
+ my $users = $1;
+ while($online->count() > 0){
+ $online->removeItem(0);
+ }
+ $users_online = {};
+ foreach $user (split(/\s+/, $users)){
+ $users_online->{$user}++;
+ $online->insertText($user, -1);
+ }
+ }
+}
+
+&addhook("msg", "get_users");
+
+sub cmd_refresh_users {
+ $online->clear();
+ $users_online = {};
+ my $output = `$WHO list`;
+ my @users = split(/\n/, $output);
+ # while($online->count() > 0){
+ # $online->removeItem(0);
+ #}
+ foreach $user (@users){
+ $user =~ s/(\S+)\@\S+/$1/g;
+ next if $user eq '';
+ next if $user =~ /administrator/;
+ $users_online->{$user}++;
+ $online->insertText($user, -1);
+ }
+}
+
+&addcmd("refresh_users");
diff --git a/ksirc/puke/widgethdlr.h b/ksirc/puke/widgethdlr.h
new file mode 100644
index 00000000..6c3e93c7
--- /dev/null
+++ b/ksirc/puke/widgethdlr.h
@@ -0,0 +1,3 @@
+void hdlrCreateWidget(int fd, PukeMessage *pm);
+void hdlrShowWidget(int fd, PukeMessage *pm);
+
diff --git a/ksirc/relnotes b/ksirc/relnotes
new file mode 100644
index 00000000..6207f2f9
--- /dev/null
+++ b/ksirc/relnotes
@@ -0,0 +1,107 @@
+~b~12,4 kSirc Release Notes for 981220
+
+Work over the past month or so has concentrated in 2 majour areas,
+memory consumption and Puke. There's also been some minor features
+etc.
+
+~2Misc Features:
+
+~4~b*~C If you bring up a menu, ctrl+letter generates an on the fly accelerator
+~4~b*~C Scroll back size if setable through the Prefrences
+~4~b*~C Setable background pixmap, it ~b~ureally~b~u sucks
+~4~b*~C New icons for the server controller/docking. Thanks mosfet
+
+~2Memory:
+
+~4~b*~C The last few release kSirc has had a gradual memory leak, fixed.
+~4~b*~C Created KPlunger a generic memory debugger and leak tracker for C++.
+~4~b*~C Fixed a bunch of bufffer problems which caused kSirc die on non-intel
+~4~b*~C Reduced memory footprint, and effeciency.
+
+~2Puke:
+~4~b*~C Reduced endian dependance
+~4~b*~C Lots to come soon
+
+~b~12,4 kSirc Release Notes for 981107
+
+This release is mostly a bug fix release.
+
+Bugs Fixed:
+
+~4~b*~C ~3Title Bar now works with not umode set, away, etc
+~4~b*~C ~3Puke now works on most machines I can find. This means you can stop whinning about dcc being broken.
+~4~b*~C ~3Puke's now pretty much portable.
+~4~b*~C ~3Lots of little bugs all over the place.
+
+~b~12,4 kSirc Release Notes for 981025
+
+~2New Features:
+
+~4~b*~C ~3Mini Web Server
+~4~b*~C ~3MDI Mode (very experimental)
+~4~b*~C ~3Better Caption support with optional Topic
+~4~b*~C ~3New Server Picker, thanks Atko
+~4~b*~C ~3Selecting windows in SC brings them to foreground
+~4~b*~C ~3Release notes are displayed to the screen on first run
+~4~b*~C ~3Improved online help with /help
+
+
+~b~12,4 Web Server Notes
+
+Credit: Thanks to Roberto for the PWS config dialog,
+99.9% of the work is his.
+
+The web server setup is a graphical configuration
+for the freely available web server called
+mathopd. It's run/controlled via kSirc and
+I've some fun running it.
+
+Couple notes to remember, you cannot use ports
+< 1024. I'm not going to run anything as root,
+since running a web server is dangerous enough,
+much less giving potential root access away.
+
+/url command will show you a valid url
+for you sure. Replace <port> with the port(s)
+that the web server is running on.
+
+~b~12,4 MDI Mode
+
+Credit: Timothy Whitfield, ported the MDI interface
+from kEirc into a generic MDI interface for KDE.
+
+Now, if you want to use it, here's a bunch of
+problems I've already seen:
+
+1. Acelerator keys are all messed up. pgup/dn
+is a good example. It just doesn't work.
+
+2. If you minimize something, you have to
+double click on the channel name in the server
+controller to bring it back.
+
+3. You cannot minimize the server controller.
+
+4. You can drag windows off the screen in never
+never land.
+
+I'm personally not a big fan of the MDI interface
+but I'll work on making it work right as time permits.
+
+~b~12,4 OTHER Stuff
+
+There's been a bunch of bug fixes everywhere.
+
+Cut & paste now cleans up correctly most of the time now.
+
+New release notes box, I think it's useful. What do
+you think?
+
+Caption should be more useful now. I think this is the
+best way to display the topic on the screen.
+
+Server controller is in and needs some more work. Basic
+idea works well though.
+
+/help now displayes all possible functions, instead of just
+built in ones. Shows all kSirc commands as well.
diff --git a/ksirc/servercontroller.cpp b/ksirc/servercontroller.cpp
new file mode 100644
index 00000000..0b03d1ab
--- /dev/null
+++ b/ksirc/servercontroller.cpp
@@ -0,0 +1,978 @@
+ /**********************************************************************
+
+ Server Controller
+
+ $$Id$$
+
+ Main Server Controller. Displays server connection window, and makes
+ new server connection on demand.
+
+ Signals: NONE
+
+ Slots:
+
+ new_connection(): Creates popup asking for new connection
+
+ new_ksircprocess(QString):
+ Args:
+ QString: new server name or IP to connect to.
+ Action:
+ Creates a new sirc process and window !default connected to the
+ server. Does nothing if a server connection already exists.
+
+ add_toplevel(QString parent, QString child):
+ Args:
+ parent: the server name that the new channel is being joined on
+ child: the new channel name
+ Action:
+ Adds "child" to the list of joined channles in the main
+ window. Always call this on new window creation!
+
+ delete_toplevel(QString parent, QString child):
+ Args:
+ parent: the server name of which channel is closing
+ child: the channle that is closing. IFF Emtpy, parent is
+ deleted.
+ Action:
+ Deletes the "child" window from the list of connections. If
+ the child is Empty the whole tree is removed since it is assumed
+ the parent has disconnected and is closing.
+
+ new_channel: Creates popup asking for new channel name
+
+ new_toplevel(QString str):
+ Args:
+ str: name of the new channel to be created
+ Action:
+ Sends a signal to the currently selected server in the tree
+ list and join the requested channel. Does nothing if nothing
+ is selected in the tree list.
+
+ recvChangeChanel(QString parent, QString old, QString new):
+ Args:
+ parent: parent server connection
+ old: the old name for the window
+ new: the new name for the window
+ Action:
+ Changes the old window name to the new window name in the tree
+ list box. Call for all name change!
+
+ *********************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "servercontroller.h"
+#include "KSOpenkSirc/open_ksirc.h"
+#include "NewWindowDialog.h"
+#include "ksopts.h"
+#include "control_message.h"
+#include "FilterRuleEditor.h"
+#include "../config.h"
+#include "version.h"
+#include "KSPrefs/ksprefs.h"
+#include "toplevel.h"
+#include "ksircserver.h"
+#include "nickColourMaker.h"
+
+#include <stdlib.h>
+
+#include "objFinder.h"
+#include <qlabel.h>
+#include <qregexp.h>
+
+#include <kmenubar.h>
+#include <kconfig.h>
+#include <kfontdialog.h>
+#include <kiconloader.h>
+#include <kwin.h>
+#include <kdebug.h>
+#include <kstdaccel.h>
+#include <kstandarddirs.h>
+#include <khelpmenu.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <knotifydialog.h>
+#include <netwm.h>
+#include <kpassivepopup.h>
+#include <kglobalaccel.h>
+#include <kstdguiitem.h>
+
+#include <qfile.h>
+
+#include "displayMgrSDI.h"
+#include "displayMgrMDI.h"
+
+#include "dockservercontroller.h"
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <klocale.h>
+#include <kapplication.h>
+#include <kpopupmenu.h>
+
+DisplayMgr *displayMgr;
+
+servercontroller *servercontroller::s_self = 0;
+
+servercontroller::servercontroller( QWidget*, const char* name )
+ : KMainWindow( 0, name )
+{
+ we_are_exiting = false;
+ m_notificationCount = 0;
+
+ m_ncm = new nickColourMaker();
+
+ MenuBar = menuBar();
+ KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
+
+ s_self = this;
+
+ switch (ksopts->displayMode)
+ {
+ case KSOptions::SDI:
+ displayMgr = new DisplayMgrSDI();
+ break;
+ case KSOptions::MDI:
+ displayMgr = new DisplayMgrMDI();
+ break;
+ }
+
+ sci = new scInside(this, QCString(name) + "_mainview");
+ setCentralWidget(sci);
+
+ sci->setFrameStyle(QFrame::Box | QFrame::Raised);
+ ConnectionTree = sci->ConnectionTree;
+
+ connect(ConnectionTree, SIGNAL(clicked( QListViewItem * )),
+ this, SLOT(WindowSelected(QListViewItem *)));
+
+ setFrameBorderWidth(5);
+
+ QPopupMenu *file = new QPopupMenu(this, QCString(name) + "_menu_file");
+ KStdAction::quit(this, SLOT(endksirc()), actionCollection())->plug(file);
+#ifndef NDEBUG
+ file->insertItem(i18n("Dump Object Tree"), this, SLOT(dump_obj()));
+ file->insertItem(i18n("Server Debug Window"), this, SLOT(server_debug()));
+#endif
+ MenuBar->insertItem(i18n("&File"), file);
+
+ connections = new QPopupMenu(this, QCString(name) + "_menu_connections");
+
+ server_id = connections->insertItem(i18n("&New Server..."), this, SLOT(new_connection()), Key_F2 );
+ join_id = connections->insertItem(i18n("&Join Channel..."), this, SLOT(new_channel()), Key_F3 );
+ connections->insertSeparator();
+ connections->insertItem(i18n("&Do Autoconnect..."), this, SLOT(start_autoconnect_check()));
+ connections->setItemEnabled(join_id, FALSE);
+ MenuBar->insertItem(i18n("&Connections"), connections);
+
+ options = new QPopupMenu(this, QCString(name) + "_menu_options");
+ options->setCheckable(TRUE);
+
+ options->insertItem(SmallIcon( "filter" ), i18n("&Filter Rule Editor..."),
+ this, SLOT(filter_rule_editor()));
+ options->insertSeparator();
+ KStdAction::configureNotifications(this, SLOT(notification_prefs()), actionCollection())->plug(options);
+
+ KStdAction::preferences(this, SLOT(general_prefs()), actionCollection())->plug(options);
+
+ MenuBar->insertItem(i18n("&Settings"), options);
+
+ KHelpMenu *help = new KHelpMenu( this, kapp->aboutData() );
+ MenuBar->insertItem( KStdGuiItem::help().text(), help->menu() );
+
+ m_kga = new KGlobalAccel(this, "globalAccess");
+ m_kga->insert("New Server", i18n("New Server"),
+ i18n("This action allows you to open a new server more easily "
+ "when in docked mode, since you don't need to click on the "
+ "dock icon."),
+ ALT+CTRL+Key_C, KKey::QtWIN+CTRL+Key_C, this,
+ SLOT(new_connection()));
+
+ open_toplevels = 0;
+
+ pic_server = UserIcon("server");
+ pic_gf = UserIcon("ksirc_a");
+ pic_run = UserIcon("mini-run");
+ pic_ppl = UserIcon("channels");
+ pic_icon = UserIcon("ksirc_b");
+
+ setCaption( i18n("Server Control") );
+ KWin::setIcons(winId(), pic_icon, pic_server);
+
+ resize( 450,200 );
+
+ dockWidget = new dockServerController(this, 0x0, "servercontroller_dock");
+ KWin::setSystemTrayWindowFor( dockWidget->winId(), winId() );
+
+ m_kga->readSettings();
+ m_kga->updateConnections();
+
+ checkDocking();
+}
+
+
+servercontroller::~servercontroller()
+{
+ kdDebug(5008) << "~servercontroller in" << endl;
+ s_self = 0;
+ delete m_ncm;
+ kdDebug(5008) << "~servercontroller out" << endl;
+}
+
+void servercontroller::checkDocking()
+{
+ if(ksopts->runDocked == true){
+ dockWidget->show();
+ hide();
+ m_kga->setEnabled(true);
+ }
+ else {
+ dockWidget->hide();
+ show();
+ m_kga->setEnabled(false);
+ }
+
+}
+
+void servercontroller::new_connection()
+{
+ open_ksirc *w = new open_ksirc(); // Create new ksirc popup
+ connect(w, SIGNAL(open_ksircprocess(KSircServer &)), // connected ok to process
+ this, SLOT(new_ksircprocess(KSircServer &))); // start
+ w->exec(); // show the sucker!
+ delete w;
+}
+
+void servercontroller::new_ksircprocess(KSircServer &kss)
+{
+ QString server_id;
+ int id = 1;
+ if(kss.server().isEmpty()) // nothing entered, nothing done
+ return;
+ server_id = kss.server();
+ while(proc_list[server_id]){ // if it already exists, quit
+ server_id = QString("%1 %2").arg(kss.server()).arg(id++);
+ }
+
+ // Insert new base
+ QListViewItem *rootItem = new QListViewItem( ConnectionTree, server_id );
+ rootItem->setPixmap( 0, pic_server );
+ rootItem->setOpen( true );
+
+ // We do no_channel here since proc emits the signal in the
+ // constructor, and we can't connect to before then, so we have to
+ // do the dirty work here.
+ ProcMessage(server_id, ProcCommand::addTopLevel, QString("no_channel"));
+
+ KSircProcess *proc = new KSircProcess(server_id, kss, 0, (QString(name()) + "_" + server_id + "_ksp").ascii() ); // Create proc
+ //this->insertChild(proc); // Add it to out inheritance tree so we can retreive child widgets from it.
+ objFinder::insert(proc);
+ proc_list.insert(server_id, proc); // Add proc to hash
+ connect(proc, SIGNAL(ProcMessage(QString, int, QString)),
+ this, SLOT(ProcMessage(QString, int, QString)));
+ connect(this, SIGNAL(ServMessage(QString, int, QString)),
+ proc, SLOT(ServMessage(QString, int, QString)));
+
+ if(!ConnectionTree->currentItem()){ // If nothing's highlighted
+ ConnectionTree->setCurrentItem(rootItem); // highlight it.
+ }
+
+ connections->setItemEnabled(join_id, TRUE);
+
+ dockWidget->serverOpen(server_id);
+}
+
+void servercontroller::new_channel()
+{
+ QString server;
+ QListViewItem *citem = ConnectionTree->currentItem(); // get item
+ if(citem){ // if it exist, ie something is highlighted, continue
+ if(proc_list[citem->text(0)]){ // If it's a match with a server, ok
+ server = citem->text(0);
+ }
+ // Otherwise, check the parent to see it's perhaps a server.
+ else if ( citem->parent() ) {
+ if(proc_list[citem->parent()->text(0)]){
+ server = citem->parent()->text(0);
+ }
+ }
+ }
+
+ if(server.isEmpty())
+ return;
+
+ KSircChannel ci(server, QString::null);
+ NewWindowDialog w(ci);
+ connect(&w, SIGNAL(openTopLevel(const KSircChannel &)),
+ this, SLOT(new_toplevel(const KSircChannel &)));
+ w.exec();
+}
+
+void servercontroller::new_toplevel(const KSircChannel &channelInfo)
+{
+ new_toplevel(channelInfo, false);
+}
+
+void servercontroller::new_toplevel(const KSircChannel &channelInfo, bool safe)
+{
+ if(proc_list[channelInfo.server()]){ // If it's a match with a server, ok
+ proc_list[channelInfo.server()]->new_toplevel(channelInfo, safe);
+ }
+}
+
+void servercontroller::ToggleAutoCreate()
+{
+ ksopts->autoCreateWin = !ksopts->autoCreateWin;
+}
+
+void servercontroller::general_prefs()
+{
+ KSPrefs *kp = new KSPrefs();
+ connect(kp, SIGNAL(update(int)),
+ this, SLOT(configChange()));
+ kp->resize(550, 450);
+ kp->show();
+}
+
+void servercontroller::notification_prefs()
+{
+ KNotifyDialog::configure(this, "Notification Configuration Dialog");
+}
+
+void servercontroller::dump_obj()
+{
+
+ objFinder::dumpTree();
+
+}
+void servercontroller::server_debug()
+{
+ QListViewItem *citem = ConnectionTree->currentItem(); // get item
+ if(citem){ // if it exist, ie something is highlighted, continue
+ QString server;
+ if(proc_list[citem->text(0)]){ // If it's a match with a server, ok
+ server = citem->text(0);
+ }
+ else if ( citem->parent() ) {
+ if(proc_list[citem->parent()->text(0)]){
+ server = citem->parent()->text(0);
+ }
+ }
+
+ if( !server.isNull() ){
+ bool sh = proc_list[server]->getIOController()->isDebugTraffic();
+ proc_list[server]->getIOController()->showDebugTraffic(!sh);
+ }
+ }
+
+
+}
+
+void servercontroller::filter_rule_editor()
+{
+ FilterRuleEditor *fe = new FilterRuleEditor();
+ connect(fe, SIGNAL(destroyed()),
+ this, SLOT(slot_filters_update()));
+ fe->show();
+}
+
+void servercontroller::font_update(const QFont &font)
+{
+ ksopts->defaultFont = font;
+/* configChange(); */
+
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("GlobalOptions");
+ kConfig->sync();
+ QApplication::setFont( font, true, "KSirc::TextView" );
+}
+
+void servercontroller::configChange()
+{
+ QDictIterator<KSircProcess> it( proc_list );
+ while(it.current()){
+ it.current()->filters_update();
+ it.current()->getWindowList()["!all"]->control_message(REREAD_CONFIG, "");
+ ++it;
+ }
+ m_kga->readSettings();
+ m_kga->updateConnections();
+}
+
+void servercontroller::ProcMessage(QString server, int command, QString args)
+{
+ QListViewItem *serverItem = 0L;
+ QListViewItem *item = ConnectionTree->firstChild();
+ while ( item ) {
+ if ( !item->parent() && item->text(0) == server ) {
+ serverItem = item;
+ break;
+ }
+ item = item->nextSibling();
+ }
+
+ if ( !serverItem ) {
+ kdDebug(5008) << "* ProcMessage for non-existant server?! - " << server<< endl;
+ return;
+ }
+
+
+ switch(command){
+
+
+ // Nick offline and online both remove the nick first.
+ // We remove the nick in case of an online so that we don't get
+ // duplicates.
+ // Args == nick comming on/offline.
+ case ProcCommand::nickOffline:
+ {
+ QListViewItem *online_item = findChild(serverItem, i18n("Online"));
+ if(online_item){
+ item = findChild(online_item, args);
+ delete item;
+ if(online_item->childCount() == 0)
+ delete online_item;
+ if(ksopts->runDocked && ksopts->dockPopups)
+ KPassivePopup::message(i18n("%1 just went offline on %2").arg(args).arg(server), dockWidget);
+ }
+ dockWidget->nickOffline(server, args);
+ break;
+ }
+ case ProcCommand::nickOnline:
+ {
+ QListViewItem *online_item = findChild(serverItem, i18n("Online"));
+ if(!online_item){
+ online_item = new QListViewItem(serverItem, i18n("Online"));
+ online_item->setPixmap( 0, pic_gf );
+ online_item->setOpen( true );
+ }
+ else {
+ item = findChild(online_item, args);
+ if( item ){
+ delete item;
+ }
+ }
+ item = new QListViewItem(online_item, args);
+ item->setPixmap( 0, pic_run );
+ if(ksopts->runDocked && ksopts->dockPopups)
+ KPassivePopup::message(i18n("%1 just came online on %2").arg(args).arg(server), dockWidget);
+ dockWidget->nickOnline(server, args);
+ break;
+ }
+ /*
+ // Add new channel, first add the parent to the path
+ path.push(&server);
+ path.push(&online);
+ path.push(&args);
+ // Remove old one if it's there
+ ConnectionTree->removeItem(&path); // Remove the item
+ path.pop();
+ // add a new child item with parent as its parent
+ ConnectionTree->addChildItem(args, pic_run, &path);
+ if (kSircConfig->BeepNotify) {
+ KNotifyClient::beep();
+ }
+ break;
+ */
+
+ /**
+ * Args:
+ * parent: the server name that the new channel is being joined on
+ * child: the new channel name
+ * Action:
+ * Adds "child" to the list of joined channles in the main
+ * window. Always call this on new window creation!
+ */
+ case ProcCommand::addTopLevel:
+ // Add new channel
+ if(args[0] == '!')
+ args.remove(0, 1); // If the first char is !, it's control, remove it
+ // add a new child item with parent as it's parent
+ item = new QListViewItem( serverItem, args );
+ item->setPixmap( 0, pic_ppl );
+
+ open_toplevels++;
+ break;
+ /**
+ * Args:
+ * parent: the server name of which channel is closing
+ * child: the channle that is closing. IFF Emtpy, parent is
+ * deleted.
+ * Action:
+ * Deletes the "child" window from the list of connections. If
+ * the child is Empty the whole tree is removed since it is assumed
+ * the parent has disconnected and is closing.
+ */
+ case ProcCommand::deleteTopLevel:
+ // If the child is emtpy, delete the whole tree, otherwise just the child
+ if(args[0] == '!')
+ args.remove(0, 1); // If the first char is !, it's control, remove it
+
+ item = findChild( serverItem, args );
+ delete item;
+ if ( serverItem->childCount() == 0 )
+ delete serverItem;
+
+ open_toplevels--;
+ break;
+
+ /**
+ * Args:
+ * parent: parent server connection
+ * old: the old name for the window
+ * new: the new name for the window
+ * Action:
+ * Changes the old window name to the new window name in the tree
+ * list box. Call for all name change!
+ */
+ case ProcCommand::changeChannel:
+ {
+ char *new_s, *old_s;
+ new_s = new char[args.length()+1];
+ old_s = new char[args.length()+1];
+ sscanf(args.ascii(), "%s %s", old_s, new_s);
+ // If the channel has a !, it's a control channel, remove the !
+ if(old_s[0] == '!')
+ // Even though, we want strlen() -1 characters, strlen doesn't
+ // include the \0, so we need to copy one more. -1 + 1 = 0.
+ memmove(old_s, old_s+1, strlen(old_s));
+ if(new_s[0] == '!')
+ memmove(new_s, new_s+1, strlen(new_s)); // See above for strlen()
+
+ item = findChild( serverItem, old_s );
+ delete item;
+ item = new QListViewItem( serverItem, new_s );
+ item->setPixmap( 0, pic_ppl );
+
+ delete[] new_s;
+ delete[] old_s;
+ }
+ break;
+ case ProcCommand::procClose:
+ dockWidget->serverClose(server);
+ delete serverItem;
+ proc_list.remove(server); // Remove process entry while we are at it
+ if(proc_list.count() == 0){
+ ConnectionTree->clear();
+ connections->setItemEnabled(join_id, FALSE);
+ }
+ break;
+ case ProcCommand::turnOffAutoCreate:
+ if (ksopts->autoCreateWin) {
+ ToggleAutoCreate();
+ }
+ break;
+ case ProcCommand::turnOnAutoCreate:
+ if (!ksopts->autoCreateWin) {
+ ToggleAutoCreate();
+ }
+ break;
+ default:
+ kdDebug(5008) << "Unkown command: [" << command << "] from "
+ << server
+ << " " << args << endl;
+ }
+}
+
+void servercontroller::slot_filters_update()
+{
+ emit ServMessage(QString(), ServCommand::updateFilters, QString());
+}
+
+void servercontroller::saveGlobalProperties(KConfig *ksc)
+{
+ // ksc hos the K Session config
+ // ksp == current KSircProcess
+ // ksm == current KSircMessageReceiver
+
+ // Ignore all !<name> windows
+
+ QString group = ksc->group();
+
+ ksc->setGroup( "KSircSession" );
+ SessionConfigMap::ConstIterator it = m_sessionConfig.begin();
+ for (; it != m_sessionConfig.end(); ++it ) {
+
+ ChannelSessionInfoList infoList = *it;
+
+ QStringList channels;
+ QString port = "6667";
+ QStringList desktops;
+
+ for ( ChannelSessionInfoList::ConstIterator sessionInfoIt = infoList.begin();
+ sessionInfoIt != infoList.end(); ++sessionInfoIt ) {
+ channels << ( *sessionInfoIt ).name;
+ port = ( *sessionInfoIt ).port;
+ desktops << QString::number( ( *sessionInfoIt ).desktop );
+ }
+
+ KConfigGroup( ksc, "KSircSession" ).writeEntry( it.key(), channels );
+ KConfigGroup( ksc, "KSircSessionPort" ).writeEntry( it.key(), port );
+ KConfigGroup( ksc, "KSircSessionDesktopNumbers" ).writeEntry( it.key(), desktops );
+ }
+
+ ksc->setGroup("ServerController");
+// ksc->writeEntry("Docked", !isVisible());
+ ksc->writeEntry("Size", geometry());
+ ksc->setGroup(group);
+}
+
+void servercontroller::readGlobalProperties(KConfig *ksc)
+{
+ QString group = ksc->group();
+
+ // ksc == K Session Config
+
+ // KMainWindow silently disables our menubar, when we quit in a docked
+ // state, so we have to force showing it here.
+ menuBar()->show();
+
+ // commented in for testing...
+ ksc->setGroup( "KSircSession" );
+ QMap<QString,QString> keyMap = ksc->entryMap( ksc->group() );
+ QMap<QString,QString>::Iterator it = keyMap.begin();
+
+ while(it != keyMap.end()) {
+ QString server = it.key();
+ QString port = KConfigGroup( ksc, "KSircSessionPort" ).readEntry( server );
+ // debug("%s", it.key().latin1());
+ KSircServer kss(server, port);
+ new_ksircprocess( kss ); // sets up proc_list
+ QStringList channels = ksc->readListEntry( server );
+
+ QStringList desktops = KConfigGroup( ksc, "KSircSessionDesktopNumbers" ).readListEntry( server );
+
+ for(uint i = 0; i < channels.count(); i++){
+
+ QString channel = channels[ i ];
+
+ proc_list[ server ]->new_toplevel( KSircChannel(server, channel), true );
+
+ KSircTopLevel *topLevel = dynamic_cast<KSircTopLevel *>( proc_list[ server ]->getWindowList()[ channel ] );
+ if ( !topLevel || !topLevel->isTopLevel() )
+ continue;
+
+ QStringList::ConstIterator desktopNumberIt = desktops.at( i );
+ if ( desktopNumberIt == desktops.end() )
+ continue;
+
+ int desktop = ( *desktopNumberIt ).toInt();
+ if ( desktop == -1 )
+ continue;
+#ifdef Q_WS_X11
+ NETWinInfo winInfo( qt_xdisplay(), topLevel->winId(), qt_xrootwin(), NET::WMDesktop );
+ winInfo.setDesktop( desktop );
+#endif
+ }
+ ++it;
+ }
+
+ QRect geom;
+
+// ksc->setGroup("ServerController");
+// bool docked = ksc->readBoolEntry("Docked", FALSE);
+// if ( !docked )
+ // show();
+ if(ksopts->runDocked == false)
+ show();
+
+ geom = ksc->readRectEntry("Size");
+ if(! geom.isEmpty())
+ setGeometry(geom);
+
+ ksc->setGroup(group);
+}
+
+void servercontroller::saveSessionConfig()
+{
+ QDictIterator<KSircProcess> ksp(proc_list);
+ for (; ksp.current(); ++ksp ) {
+ ChannelSessionInfoList channels;
+
+ QDictIterator<KSircMessageReceiver> ksm(ksp.current()->getWindowList());
+ for (; ksm.current(); ++ksm )
+ if(ksm.currentKey()[0] != '!') { // Ignore !ksm's (system created)
+ ChannelSessionInfo sessionInfo;
+
+ sessionInfo.name = ksm.currentKey();
+ sessionInfo.port = ksp.current()->serverPort();
+ KSircTopLevel *topLev = dynamic_cast<KSircTopLevel *>( ksm.current() );
+ if ( topLev && topLev->isTopLevel() ) {
+#ifdef Q_WS_X11
+ NETWinInfo winInfo( qt_xdisplay(), topLev->winId(), qt_xrootwin(), NET::WMDesktop );
+ sessionInfo.desktop = winInfo.desktop();
+#endif
+ }
+
+ channels << sessionInfo;
+ }
+
+ if ( !channels.isEmpty() )
+ m_sessionConfig[ ksp.currentKey() ] = channels;
+ }
+}
+
+void servercontroller::showEvent( QShowEvent *e )
+{
+ QWidget::showEvent( e );
+ if ( !e->spontaneous() )
+ saveDockingStatus();
+}
+
+void servercontroller::hideEvent( QHideEvent * )
+{
+ /*
+ QWidget::hideEvent( e );
+ if ( !e->spontaneous() )
+ saveDockingStatus();
+ if(QWidget::isMinimized()){
+ hide();
+ KWin::setState(winId(), NET::SkipTaskbar);
+ }
+ */
+}
+
+void servercontroller::saveDockingStatus()
+{
+ if ( we_are_exiting ) // we are hidden by closeEvent
+ return;
+
+// KConfig *kConfig = kapp->config();
+// KConfigGroupSaver s( kConfig, "ServerController" );
+// kConfig->writeEntry("Docked", !isVisible());
+// kConfig->sync();
+}
+
+void servercontroller::endksirc(){
+ kapp->config()->sync();
+ exit(0);
+}
+
+void servercontroller::closeEvent( QCloseEvent *e )
+{
+ we_are_exiting = true;
+ saveSessionConfig();
+ KMainWindow::closeEvent( e );
+}
+
+void servercontroller::WindowSelected(QListViewItem *item)
+{
+ if ( !item )
+ return;
+
+ QListViewItem *parent_server = item->parent();
+ if(!parent_server)
+ return;
+
+ QString txt = QString(parent_server->text(0)) + "_" + item->text(0) + "_toplevel";
+ QWidget *obj = dynamic_cast<QWidget *>( objFinder::find(txt.utf8(), "KSircTopLevel"));
+ if(obj == 0x0){
+ txt =QString(parent_server->text(0)) + "_!" + item->text(0) + "_toplevel";
+ obj = dynamic_cast<QWidget *>( objFinder::find(txt.utf8(), "KSircTopLevel"));
+ }
+
+ if(obj != 0x0){
+ displayMgr->raise(obj);
+ }
+ else {
+ kdWarning() << "Did not find widget ptr to raise it" << endl;
+ }
+}
+
+
+QListViewItem * servercontroller::findChild( QListViewItem *parent,
+ const QString& text )
+{
+ if ( !parent || parent->childCount() == 0 ) {
+ return 0L;
+ }
+
+ QListViewItem *item = parent->firstChild();
+ while ( item ) {
+ if ( item->text(0) == text ) {
+ return item;
+ }
+ item = item->nextSibling();
+ }
+
+ return 0L;
+}
+
+void servercontroller::increaseNotificationCount(const QString& reason, const QString& text)
+{
+ dockWidget->startBlink(reason, text);
+ m_notificationCount++;
+}
+
+void servercontroller::decreaseNotificationCount(QString reason)
+{
+ m_notificationCount--;
+ if ( m_notificationCount == 0 )
+ {
+ dockWidget->stopBlink(reason, true);
+ }
+ else {
+ dockWidget->stopBlink(reason, false);
+ }
+}
+
+void servercontroller::resetNotification()
+{
+ m_notificationCount = 0;
+ dockWidget->stopBlink(QString::null, true);
+ QDictIterator<KSircProcess> it( proc_list );
+ while(it.current()){
+ it.current()->filters_update();
+ it.current()->getWindowList()["!all"]->control_message(RESET_NOTIF, "");
+ ++it;
+ }
+}
+
+void servercontroller::do_autoconnect()
+{
+ static int stime = 0;
+ static int ctime = 0;
+ int loop;
+
+ kdDebug(5008) << "Doing AUTOCONNECT" << endl;
+
+ KConfig *conf = kapp->config();
+ conf->setGroup("AutoConnect");
+ QStringList servers = conf->readListEntry("Servers");
+ servers.sort();
+ QStringList::ConstIterator ser = servers.begin();
+
+ loop = 0;
+
+ for( ; ser != servers.end(); ser++){
+ if(loop++ == stime){
+ stime++;
+ QString server = *ser;
+ QString port = "6667";
+ bool usessl = false;
+ QString pass = QString::null;
+
+ QRegExp rx("(.+) \\(SSL\\)(.*)");
+ if(rx.search(server) >= 0){
+ server = rx.cap(1) + rx.cap(3);
+ usessl = true;
+ }
+ rx.setPattern("(.+) \\(pass: (\\S+)\\)(.*)");
+ if(rx.search(server) >= 0){
+ server = rx.cap(1) + rx.cap(3);
+ pass = rx.cap(2);
+ }
+ rx.setPattern("([^: ]+):(\\d+)");
+ if(rx.search(server) >= 0){
+ server = rx.cap(1);
+ port = rx.cap(2);
+ }
+ kdDebug(5008) << server << ": Done " << port << " " << usessl << " " << pass << endl;
+ KSircServer kss(server, port, "", pass, usessl);
+ new_ksircprocess(kss);
+ return;
+ }
+ }
+
+ loop = 0;
+
+ ser = servers.begin();
+ for( ; ser != servers.end(); ser++){
+ QStringList channels = conf->readListEntry(*ser);
+ if(channels.empty() == FALSE){
+ channels.sort();
+ QStringList::ConstIterator chan = channels.begin();
+ for(; chan != channels.end(); chan++){
+ if(loop++ == ctime){
+ ctime++;
+ QString channel = *chan;
+ QString key = QString::null;
+ QRegExp crx("(.+) \\(key: (\\S+)\\)");
+ if(crx.search(channel) >= 0){
+ channel = crx.cap(1);
+ key = crx.cap(2);
+ }
+ QString server = *ser;
+
+ QRegExp rx("^([^ :]+)");
+ if(rx.search(server) >= 0){
+ server = rx.cap(1);
+ }
+ kdDebug(5008) << server << ": Channed: " << channel << " key: " << key << endl;
+ new_toplevel(KSircChannel(server, channel, key), true);
+ return;
+ }
+ }
+ }
+ }
+
+ ctime = 0;
+ stime = 0;
+ at->stop();
+ delete at;
+
+}
+
+void servercontroller::start_autoconnect() {
+ at = new QTimer(this);
+ connect(at, SIGNAL(timeout()), this, SLOT(do_autoconnect()));
+ at->start(250, FALSE);
+}
+
+void servercontroller::start_autoconnect_check() {
+
+ KConfig *conf = kapp->config();
+ conf->setGroup("AutoConnect");
+ QStringList servers = conf->readListEntry("Servers");
+
+ if(servers.count() == 0){
+ KSPrefs *kp = new KSPrefs();
+ connect(kp, SIGNAL(update(int)),
+ this, SLOT(configChange()));
+ kp->resize(550, 450);
+ kp->showPage(7); /* Show auto connect page */
+ kp->show();
+ }
+ else {
+ at = new QTimer(this);
+ connect(at, SIGNAL(timeout()), this, SLOT(do_autoconnect()));
+ at->start(250, FALSE);
+ }
+
+}
+
+
+scInside::scInside ( QWidget * parent, const char * name, WFlags
+ f )
+ : QFrame(parent, name, f)
+{
+ ASConn = new QLabel(i18n("Active server connections:"), this, "servercontroller_label");
+ QFont asfont = ASConn->font();
+ asfont.setBold(TRUE);
+ ASConn->setFont(asfont);
+
+ ConnectionTree = new KListView(this, "connectiontree");
+ ConnectionTree->addColumn(QString::null);
+ ConnectionTree->setRootIsDecorated( true );
+ ConnectionTree->setSorting( 0 );
+ ConnectionTree->header()->hide();
+}
+
+scInside::~scInside()
+{
+ delete ASConn;
+ delete ConnectionTree;
+}
+
+void scInside::resizeEvent ( QResizeEvent *e )
+{
+ QFrame::resizeEvent(e);
+ ASConn->setGeometry(10,10, width() - 20,
+ ASConn->fontMetrics().height()+5);
+ ConnectionTree->setGeometry(10, 10 + ASConn->height(),
+ width() - 20, height() - 20 - ASConn->height());
+}
+
+#include "servercontroller.moc"
diff --git a/ksirc/servercontroller.dlg b/ksirc/servercontroller.dlg
new file mode 100644
index 00000000..7e515bdc
--- /dev/null
+++ b/ksirc/servercontroller.dlg
@@ -0,0 +1,33 @@
+DlgEdit:v2.0:Dialog:
+Dialog {
+ ClassHeader {servercontroller.h}
+ ClassSource {servercontroller.cpp}
+ ClassName {servercontroller}
+ DataHeader {servercontrollerData.h}
+ DataSource {servercontrollerData.cpp}
+ DataName {servercontrollerData}
+ WindowBaseClass {Custom}
+ CustomBase {KSircControl}
+ CustomBaseHeader {control.h}
+ WindowCaption {Server Control}
+ WindowFlags {233472}
+}
+WidgetLayout {
+InitialPos {-1 -1}
+Size {410 200}
+MinSize {0 0}
+MaxSize {32767 32767}
+Grid {10}
+
+User {
+ UserClassHeader {kmenubar.h}
+ UserClassName {KMenuBar}
+ Rect {0 0 410 30}
+ Name {User_2}
+ Variable {MenuBar}
+ LayoutStatus {NoLayout}
+ MinimumSize {10 10}
+ MaximumSize {32767 32767}
+}
+Layout {None}
+}
diff --git a/ksirc/servercontroller.h b/ksirc/servercontroller.h
new file mode 100644
index 00000000..54d0292c
--- /dev/null
+++ b/ksirc/servercontroller.h
@@ -0,0 +1,267 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: servercontroller.h
+ Last generated: Sat Nov 29 08:50:19 1997
+
+ Now Under CVS control.
+
+ $$Id$$
+
+ *********************************************************************/
+
+#ifndef servercontroller_included
+#define servercontroller_included
+
+class servercontroller;
+class dockServerController;
+class ServMessage;
+class ProcCommand;
+
+#include <qdict.h>
+#include <qpixmap.h>
+#include <qheader.h>
+#include <qtimer.h>
+
+#include <klistview.h>
+#include <kmainwindow.h>
+
+#include "ksircprocess.h"
+#include "ksircchannel.h"
+
+//#include "puke/controller.h"
+class QLabel;
+class KMenuBar;
+class KSircServer;
+class KGlobalAccel;
+class nickColourMaker;
+class dockServerController;
+
+class ProcCommand // ServerController message
+{
+ public:
+ static enum {
+ addTopLevel,
+ deleteTopLevel,
+ procClose,
+ newChannel,
+ changeChannel,
+ nickOnline,
+ nickOffline,
+ turnOffAutoCreate,
+ turnOnAutoCreate
+ } command;
+};
+
+
+class ServCommand // ServerController message
+{
+ public:
+ static enum {
+ updateFilters,
+ updatePrefs
+ } command;
+};
+
+class scInside : QFrame
+{
+ Q_OBJECT
+ friend class servercontroller;
+ public:
+ scInside ( QWidget *parent = 0L, const char * name = 0, WFlags f=0 );
+ ~scInside();
+
+ protected:
+ virtual void resizeEvent ( QResizeEvent * );
+
+ private:
+ KListView *ConnectionTree;
+ QLabel *ASConn;
+
+};
+
+class servercontroller : public KMainWindow
+{
+ Q_OBJECT
+ friend class dockServerController;
+public:
+
+ servercontroller ( QWidget* parent = 0L, const char* name = NULL );
+ virtual ~servercontroller();
+
+ const QDict<KSircProcess> &processes() const { return proc_list; }
+
+ static servercontroller *self() { return s_self; }
+
+ /**
+ * Someone is talking to the user (blue icon), notify him (using the docked icon).
+ */
+ void increaseNotificationCount(const QString& reason = QString::null, const QString& text = QString::null);
+
+ /**
+ * The channel in which the user was talked to, has been read.
+ * -> decrease count of blue icons.
+ */
+ void decreaseNotificationCount(QString reason = QString::null);
+
+ /**
+ * This resets all notificaiton counts and allows new ones
+ * this is used if we don't want to give the window
+ * focus to reset focus
+ */
+ void resetNotification();
+
+ void checkDocking();
+
+ KGlobalAccel *getGlobalAccel(){ return m_kga; }
+
+signals:
+ /**
+ * Filter rules have changed, need to re-read and update.
+ */
+ virtual void filters_update();
+
+ void ServMessage(QString server, int command, QString args);
+
+public slots:
+ // All slots are described in servercontroll.cpp file
+ /**
+ * Does auto-joins on start up
+ */
+ virtual void do_autoconnect();
+ /**
+ * Creates popup asking for new connection
+ */
+ virtual void new_connection();
+ /**
+ * Args:
+ * QString: new server name or IP to connect to.
+ * Action:
+ * Creates a new sirc process and window !default connected to the
+ * server. Does nothing if a server connection already exists.
+ */
+ // virtual void new_ksircprocess(QString);
+ virtual void new_ksircprocess(KSircServer &);
+ /**
+ * Creates popup asking for new channel name
+ */
+ virtual void new_channel();
+ /**
+ * Args:
+ * str: name of the new channel to be created
+ * server: name of the server channel is created on
+ * Action:
+ * opens a new toplevel on the requested channel and server
+ */
+ virtual void new_toplevel(const KSircChannel &channel);
+ virtual void new_toplevel(const KSircChannel &channel, bool safe);
+ /**
+ * Action:
+ * Notify all ksircprocess' to update filters
+ */
+ virtual void slot_filters_update();
+ virtual void ToggleAutoCreate();
+
+ /**
+ * Action: Popup a general preferences window which allows various
+ * settings, etc.
+ */
+ virtual void general_prefs();
+ /**
+ * Opens the dialog that lets the user configure system notifications
+ */
+ virtual void notification_prefs();
+ virtual void font_update(const QFont&);
+ virtual void filter_rule_editor();
+ virtual void configChange();
+
+ virtual void ProcMessage(QString server, int command, QString args);
+ /**
+ * On quit we sync the config to disk and exit
+ */
+ virtual void endksirc();
+ /**
+ * Start auto-connect
+ */
+ void start_autoconnect();
+ /**
+ * Start auto-connect with check
+ */
+ void start_autoconnect_check();
+
+
+ QListViewItem * findChild( QListViewItem *parent, const QString& text );
+
+protected slots:
+ void WindowSelected(QListViewItem *);
+
+ void dump_obj();
+ void server_debug();
+
+protected:
+
+ virtual void showEvent( QShowEvent *e );
+ virtual void hideEvent( QHideEvent *e );
+ virtual void closeEvent( QCloseEvent * );
+ void saveDockingStatus();
+
+ void saveGlobalProperties(KConfig *);
+ void readGlobalProperties(KConfig *);
+
+private:
+ void saveSessionConfig();
+
+ // La raison d'etre. We don't run ConnectionTree ourselves, but
+ // we get it from our helper class scInside.
+ KListView *ConnectionTree;
+
+ scInside *sci;
+
+ // Menubar for the top.
+ KMenuBar *MenuBar;
+
+ // Hold a list of all KSircProcess's for access latter. Index by server
+ // name
+ QDict<KSircProcess> proc_list;
+ QPopupMenu *options, *connections;
+ int join_id, server_id;
+
+ KGlobalAccel *m_kga;
+
+ int open_toplevels;
+
+ QPixmap pic_icon;
+ QPixmap pic_server;
+ QPixmap pic_gf;
+ QPixmap pic_run;
+ QPixmap pic_ppl;
+
+// PukeController *PukeC;
+
+ // Holds dockable widget
+ dockServerController *dockWidget;
+ bool we_are_exiting;
+
+ // Docked icon notification
+ int m_notificationCount;
+ struct ChannelSessionInfo
+ {
+ ChannelSessionInfo()
+ : desktop( -1 ) {}
+ QString name;
+ QString port;
+ int desktop;
+ };
+ typedef QValueList<ChannelSessionInfo> ChannelSessionInfoList;
+
+ typedef QMap<QString, ChannelSessionInfoList> SessionConfigMap;
+ SessionConfigMap m_sessionConfig;
+
+ static servercontroller *s_self;
+
+ QTimer *at;
+
+ nickColourMaker *m_ncm;
+};
+#endif // servercontroller_included
diff --git a/ksirc/sirc.help.gz b/ksirc/sirc.help.gz
new file mode 100644
index 00000000..fb5bce09
--- /dev/null
+++ b/ksirc/sirc.help.gz
Binary files differ
diff --git a/ksirc/ssfeprompt.cpp b/ksirc/ssfeprompt.cpp
new file mode 100644
index 00000000..46e68909
--- /dev/null
+++ b/ksirc/ssfeprompt.cpp
@@ -0,0 +1,54 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: ssfeprompt.cpp
+ Last generated: Thu Jan 15 20:49:56 1998
+
+ *********************************************************************/
+
+#include "ssfeprompt.h"
+#include <klocale.h>
+
+#undef Inherited
+#define Inherited ssfepromptdata
+
+ssfePrompt::ssfePrompt
+(
+ QString prompttext,
+ QWidget* parent,
+ const char* name
+)
+ :
+ Inherited( parent, name )
+{
+ setCaption( i18n("Prompt") );
+ prompt->setText(prompttext);
+ SLine->setFocus();
+}
+
+
+ssfePrompt::~ssfePrompt()
+{
+}
+
+void ssfePrompt::terminate()
+{
+ done(0);
+}
+
+QString ssfePrompt::text()
+{
+ QString text;
+ text = SLine->text();
+ return text;
+}
+
+void ssfePrompt::setPassword(bool pass)
+{
+ if(pass == TRUE)
+ SLine->setEchoMode(QLineEdit::Password);
+ else
+ SLine->setEchoMode(QLineEdit::Normal);
+}
+#include "ssfeprompt.moc"
diff --git a/ksirc/ssfeprompt.h b/ksirc/ssfeprompt.h
new file mode 100644
index 00000000..ff777912
--- /dev/null
+++ b/ksirc/ssfeprompt.h
@@ -0,0 +1,37 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: ssfeprompt.h
+ Last generated: Thu Jan 15 20:49:55 1998
+
+ *********************************************************************/
+
+#ifndef ssfePrompt_included
+#define ssfePrompt_included
+
+#include "ssfepromptdata.h"
+
+class ssfePrompt : public ssfepromptdata
+{
+ Q_OBJECT
+
+public:
+
+ ssfePrompt
+ (
+ QString prompttext,
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~ssfePrompt();
+
+ QString text();
+ void setPassword(bool);
+
+protected slots:
+ virtual void terminate();
+
+};
+#endif // ssfePrompt_included
diff --git a/ksirc/ssfepromptdata.cpp b/ksirc/ssfepromptdata.cpp
new file mode 100644
index 00000000..ce1dc368
--- /dev/null
+++ b/ksirc/ssfepromptdata.cpp
@@ -0,0 +1,68 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: ssfepromptdata.cpp
+ Last generated: Thu Jan 15 21:21:29 1998
+
+ DO NOT EDIT!!! This file will be automatically
+ regenerated by qtarch. All changes will be lost.
+
+ *********************************************************************/
+
+#include "ssfepromptdata.h"
+
+#undef Inherited
+#define Inherited QDialog
+
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+ssfepromptdata::ssfepromptdata
+(
+ QWidget* parent,
+ const char* name
+)
+ :
+ Inherited( parent, name, TRUE, 20480 )
+{
+ prompt = new QLabel( this, "Label_1" );
+ prompt->setGeometry( 10, 10, 220, 30 );
+ prompt->setMinimumSize( 10, 10 );
+ prompt->setMaximumSize( 32767, 32767 );
+ prompt->setText( "" );
+ prompt->setAlignment( 289 );
+ prompt->setMargin( -1 );
+
+ SLine = new QLineEdit( this, "LineEdit_1" );
+ SLine->setGeometry( 240, 10, 100, 30 );
+ SLine->setMinimumSize( 10, 10 );
+ SLine->setMaximumSize( 32767, 32767 );
+ connect( SLine, SIGNAL(returnPressed()), SLOT(terminate()) );
+ SLine->setText( "" );
+ SLine->setMaxLength( 32767 );
+ SLine->setEchoMode( QLineEdit::Normal );
+ SLine->setFrame( TRUE );
+
+ QPushButton* dlgedit_PushButton_1;
+ dlgedit_PushButton_1 = new KPushButton( KStdGuiItem::ok(), this, "PushButton_1" );
+ dlgedit_PushButton_1->setGeometry( 240, 50, 100, 30 );
+ dlgedit_PushButton_1->setMinimumSize( 10, 10 );
+ dlgedit_PushButton_1->setMaximumSize( 32767, 32767 );
+ connect( dlgedit_PushButton_1, SIGNAL(clicked()), SLOT(terminate()) );
+ dlgedit_PushButton_1->setAutoRepeat( FALSE );
+ dlgedit_PushButton_1->setAutoDefault( TRUE );
+
+ resize( 350,90 );
+ setMinimumSize( 350, 90 );
+ setMaximumSize( 350, 90 );
+}
+
+
+ssfepromptdata::~ssfepromptdata()
+{
+}
+void ssfepromptdata::terminate()
+{
+}
+#include "ssfepromptdata.moc"
diff --git a/ksirc/ssfepromptdata.h b/ksirc/ssfepromptdata.h
new file mode 100644
index 00000000..c4b6a4e6
--- /dev/null
+++ b/ksirc/ssfepromptdata.h
@@ -0,0 +1,47 @@
+/**********************************************************************
+
+ --- Qt Architect generated file ---
+
+ File: ssfepromptdata.h
+ Last generated: Thu Jan 15 21:21:29 1998
+
+ DO NOT EDIT!!! This file will be automatically
+ regenerated by qtarch. All changes will be lost.
+
+ *********************************************************************/
+
+#ifndef ssfepromptdata_included
+#define ssfepromptdata_included
+
+#include <qdialog.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+
+class ssfepromptdata : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ ssfepromptdata
+ (
+ QWidget* parent = NULL,
+ const char* name = NULL
+ );
+
+ virtual ~ssfepromptdata();
+
+public slots:
+
+
+protected slots:
+
+ virtual void terminate();
+
+protected:
+ QLabel* prompt;
+ QLineEdit* SLine;
+
+};
+
+#endif // ssfepromptdata_included
diff --git a/ksirc/stringparserstate.h b/ksirc/stringparserstate.h
new file mode 100644
index 00000000..cd9220a4
--- /dev/null
+++ b/ksirc/stringparserstate.h
@@ -0,0 +1,71 @@
+#ifndef __stringparserstate_h__
+#define __stringparserstate_h__
+
+// ### optimize me: it's stupid to do a linear search for each
+// atEnd() invocation. This should be done once in the ctor and
+// end() should be set appropriately
+template <typename CharType, typename _SizeType = size_t>
+class StringParserState
+{
+public:
+ typedef CharType ValueType;
+ typedef const CharType * ConstIterator;
+ typedef _SizeType SizeType;
+ typedef QValueList<ValueType> ValueList;
+
+ StringParserState( ConstIterator start, SizeType maxSteps,
+ const ValueList &optionalEndItems = ValueList() )
+ {
+ m_begin = start;
+ m_current = start;
+ m_end = start + maxSteps;
+ m_endItems = optionalEndItems;
+ }
+
+ void operator++() { ++m_current; }
+
+ bool atBegin() const
+ {
+ return m_current == m_begin;
+ }
+
+ bool atEnd() const
+ {
+ if ( m_current >= m_end )
+ return true;
+ return m_endItems.findIndex( currentValue() ) != -1;
+ }
+
+ ConstIterator current() const { return m_current; }
+ ValueType currentValue() const { return *current(); }
+
+ ConstIterator begin() const { return m_begin; }
+ ConstIterator end() const { return m_end; }
+
+ SizeType stepsLeft() const { return m_end - m_current; }
+
+ SizeType advanceTo( ValueType val )
+ {
+ ConstIterator start = m_current;
+ while ( !atEnd() && currentValue() != val )
+ ++m_current;
+ return m_current - start;
+ }
+
+ SizeType skip( ValueType valueToIgnore )
+ {
+ ConstIterator start = m_current;
+ while ( !atEnd() && currentValue() == valueToIgnore )
+ ++m_current;
+ return m_current - start;
+ }
+
+private:
+ ConstIterator m_begin;
+ ConstIterator m_current;
+ ConstIterator m_end;
+ ValueList m_endItems;
+};
+
+#endif
+
diff --git a/ksirc/test/nicklist.pl b/ksirc/test/nicklist.pl
new file mode 100644
index 00000000..948429eb
--- /dev/null
+++ b/ksirc/test/nicklist.pl
@@ -0,0 +1,77 @@
+sub rndchr {
+ my $string = "";
+ for(my $i = 0; $i < 8; $i++){
+ $string .= chr(int(rand(26)) + 97); # More or less the alpahbet
+ }
+ return $string;
+}
+
+srand(time());
+
+&timer(1, "&next_one", 1);
+
+$state = 0;
+$max_nicks = 100;
+$min_nicks = 5;
+$num_nicks = 0;
+%list_nicks = ();
+$repeat = 100000;
+$count = 0;
+
+@state = (\&join, \&part);
+
+$line = "~#test~*#* Users on #test:";
+for($i = 0; $i < $max_nicks; $i++){
+ my($mynick) = rndchr();
+ $list_nicks{$mynick} = 1;
+ $is_op = rand(100);
+ if($is_op > 50){
+ $mynick = "@" . $mynick;
+ }
+ $line .= " " . $mynick;
+ $num_nicks ++;
+}
+print "$line\n";
+
+sub next_one {
+ for(my($i) = 0; $i < 200; $i++){
+ $goto_state = int(rand($#state+1));
+ &{$state[$goto_state]};
+ }
+ if($count++ < $repeat){
+ &timer(1, "&next_one", 1);
+ }
+}
+
+sub join{
+ return if $num_nicks > $max_nicks;
+ my($mynick) = rndchr();
+ $list_nicks{$mynick} = 1;
+ print("~#test~*>* $mynick (blah\@blah) has joined channel #test\n");
+ $is_op = rand(100);
+ if($is_op > 75){
+ print "~#test~*+* Mode change \"+o $mynick\" on channel #test by ChanServ\n";
+ }
+ $is_voice = rand(100);
+ if($is_voice > 40){
+ print "~#test~*+* Mode change \"+v $mynick\" on channel #test by ChanServ\n";
+ }
+ $num_nicks ++;
+}
+
+sub part{
+ return if $num_nicks < $min_nicks;
+ AGAIN: {
+ my($times) = int(rand($num_nicks));
+ for($i = 0; $i<= $times; $i++){
+ ($mynick, $value) = each(%list_nicks);
+ }
+ return if $mynick eq '';
+ }
+ next AGAIN if $value != 1;
+ $list_nicks{$mynick} = 0;
+ print("~#test~*<* $mynick has left channel #test\n");
+
+ delete $list_nicks{$mynick};
+ $num_nicks --;
+}
diff --git a/ksirc/test/tester.pl b/ksirc/test/tester.pl
new file mode 100644
index 00000000..2815a3a1
--- /dev/null
+++ b/ksirc/test/tester.pl
@@ -0,0 +1,65 @@
+sub rndchr {
+ my $string = "";
+ for(my $i = 0; $i < 8; $i++){
+ $string .= chr(int(rand(26)) + 97); # More or less the alpahbet
+ }
+ return $string;
+}
+
+srand(time());
+
+&timer(1, "&next_one", 1);
+
+$state = 0;
+$max_win = 5;
+$win_open = 0;
+%wins = {};
+$repeat = 1000;
+$count = 0;
+
+
+sub next_one {
+ #
+ # State 0 is open window
+ #
+ if($state == 0){
+ $winnum = int(rand($max_win));
+ $winname = "#" . rndchr();
+ $wins{$winname} = 1;
+ print("~$winname~*>* You have joined channel $winname\n");
+ &docommand("/join $winname");
+ $state = 1;
+ $win_open ++;
+ }
+ #
+ # State 1 is print stuff to channel
+ #
+ elsif($state == 1){
+ while(($winname, $value) = each(%wins)){
+ &msg("$winname", rndchr());
+ &notice("$winname", rndchr());
+ }
+ $state = 2;
+ }
+ #
+ # State 2 is close window
+ #
+ elsif($state == 2){
+ if($win_open > $max_win){
+ $times = int(rand($win_open-1));
+ for($i = 0; $i<= $times; $i++){
+ ($winname, $value) = each(%wins);
+ }
+ print("~#test~ <boren> leaving $winname\n");
+ delete($wins{$winname});
+ print("~!all~*<* You have left channel $winname\n");
+ &docommand("/part $winname");
+ $win_open --;
+ }
+ $state = 0;
+ }
+
+ if($count++ < $repeat){
+ &timer(5, "&next_one", 1);
+ }
+} \ No newline at end of file
diff --git a/ksirc/topic.cpp b/ksirc/topic.cpp
new file mode 100644
index 00000000..9e0d8f3e
--- /dev/null
+++ b/ksirc/topic.cpp
@@ -0,0 +1,245 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Artistic License.
+*/
+
+
+#include "topic.h"
+
+#include <qapplication.h>
+#include <qtimer.h>
+#include <qregexp.h>
+#include <qlayout.h>
+#include <qtextedit.h>
+#include <qtooltip.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <krun.h>
+#include <kpopupmenu.h>
+#include <kstringhandler.h>
+#include <kfiledialog.h>
+#include <kio/job.h>
+
+#include "ksopts.h"
+#include "ksparser.h"
+
+
+KSircTopic::KSircTopic( QWidget *parent, const char *name )
+ : KActiveLabel( parent, name )
+{
+ m_editor = 0;
+ m_doEdit = false;
+ m_height = 0;
+// setBackgroundColor( colorGroup().light() );
+ setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
+ setTextFormat( RichText );
+ setWordWrap(QTextEdit::NoWrap);
+ doResize();
+// setAlignment( alignment() | WordBreak );
+}
+
+void KSircTopic::setText( const QString &_text)
+{
+ m_text = _text; /* save a raw copy for us */
+ QString text = _text;
+
+ QString richText( "<font color=\"%1\">" );
+ richText = richText.arg( ksopts->textColor.name() );
+
+ text.replace('&', "&amp;");
+ text.replace('<', "&lt;");
+ text.replace('>', "&gt;");
+
+ text.replace('~', "~~");
+
+ // ### a bit of a hack: turn '&lt;nick&gt; message' into
+ // <span>&lt;nick&gt;<span> message' . span itself isn't supported but it
+ // enforces the creation of separate item objects and hence separate
+ // drawing of '<nick>' and 'message' , which is needed for BiDi users,
+ // according to UV Kochavi <uv1st@yahoo.com> , to prevent output like
+ // '<nick message<' , which is supposedly a bug in Qt's reordering. The
+ // same is done for [nick] and >nick< to catch queries.
+ QRegExp bidiRe( "^(&lt;\\S+&gt;)(.+)$" );
+ text.replace( bidiRe, QString::fromLatin1( "<span>\\1</span>\\2" ) );
+ QRegExp bidiRe2( "^(\\[\\S+\\])(.+)$" );
+ text.replace( bidiRe2, QString::fromLatin1( "<span>\\1</span>\\2" ) );
+ QRegExp bidiRe3( "^(&gt;\\S+&lt;)(.+)$" );
+ text.replace( bidiRe3, QString::fromLatin1( "<span>\\1</span>\\2" ) );
+
+ KSParser parser;
+ richText += parser.parse( text );
+ richText += "</font>";
+
+ richText = KStringHandler::tagURLs( richText );
+ KActiveLabel::setText(richText);
+
+ doResize();
+
+}
+
+void KSircTopic::contentsMouseDoubleClickEvent( QMouseEvent * )
+{
+ m_doEdit = true;
+}
+
+void KSircTopic::contentsMouseReleaseEvent( QMouseEvent *e )
+{
+ if ( m_doEdit ) {
+ m_doEdit = false;
+
+ if ( m_editor )
+ return;
+
+ doResize();
+
+ m_editor = new KSircTopicEditor( this );
+
+ connect( m_editor, SIGNAL( returnPressed() ),
+ this, SLOT( setNewTopic() ) );
+ connect( m_editor, SIGNAL( resized() ),
+ this, SLOT( slotEditResized() ) );
+ connect( m_editor, SIGNAL( destroyed() ),
+ this, SLOT( doResize() ) );
+
+ /*
+ * If you don't do this order
+ * the size really breaks and you get
+ * a huge widget
+ */
+ m_editor->setGeometry( geometry() );
+ m_editor->setFocus();
+ m_editor->show();
+
+ m_editor->setText( m_text );
+ QToolTip::remove(this);
+
+ }
+ KActiveLabel::contentsMouseReleaseEvent(e);
+}
+
+void KSircTopic::setNewTopic()
+{
+ QString topic = m_editor->text().stripWhiteSpace();
+
+ /*
+ * don't change the channel display
+ * test since if it is set we'll get it
+ * from the server. If we can't set the topic
+ * don't make it look like it was set
+ */
+ QTimer::singleShot( 0, m_editor, SLOT( close() ) );
+ disconnect( m_editor, SIGNAL( resized() ),
+ this, SLOT( slotEditResized() ) );
+ doResize();
+ emit topicChange( topic );
+}
+
+void KSircTopic::slotEditResized( )
+{
+ setFixedHeight( m_editor->height() );
+}
+
+
+void KSircTopic::doResize()
+{
+
+ int h;
+ QFontMetrics metrics( currentFont() );
+
+ h = metrics.lineSpacing()+8;
+ m_height = h;
+ setFixedHeight( h );
+
+
+ QToolTip::remove(this);
+ QStringList sep = QStringList::split(" ", m_text);
+ int len = 0;
+ QString brok;
+ QStringList::Iterator it = sep.begin();
+ for(; it != sep.end(); ++it) {
+ brok += *it + " ";
+ len += (*it).length();
+ if(len >= 50){
+ brok += "\n";
+ len = 0;
+ }
+ }
+
+ QToolTip::add(this, brok);
+
+}
+
+void KSircTopic::fontChange(QFont &f)
+{
+ KActiveLabel::fontChange(f);
+ doResize();
+}
+
+KSircTopicEditor::KSircTopicEditor( QWidget *parent, const char *name )
+ : QTextEdit( parent, name )
+{
+ setWFlags( WDestructiveClose );
+ setFocusPolicy( QWidget::ClickFocus );
+ connect( this, SIGNAL( textChanged () ), this, SLOT( slotMaybeResize() ) );
+}
+
+void KSircTopicEditor::keyPressEvent( QKeyEvent *ev )
+{
+ if ( ev->key() == Key_Escape )
+ {
+ ev->accept();
+ QTimer::singleShot( 0, this, SLOT( close() ) );
+ return;
+ }
+ else if ( ev->key() == Key_Return )
+ {
+ ev->accept();
+ emit returnPressed();
+ return;
+ }
+ QTextEdit::keyPressEvent( ev );
+}
+
+void KSircTopicEditor::focusOutEvent( QFocusEvent * )
+{
+ // we don't want to quit editing when someone brings up QLE's popup
+ // menu
+ if ( QFocusEvent::reason() == QFocusEvent::Popup )
+ {
+ QWidget *focusw = qApp->focusWidget();
+ if ( focusw && m_popup && focusw == m_popup )
+ return;
+ }
+
+ QTimer::singleShot( 0, this, SLOT( close() ) );
+}
+
+QPopupMenu *KSircTopicEditor::createPopupMenu( const QPoint &pos )
+{
+ QPopupMenu *popup = QTextEdit::createPopupMenu( pos );
+ m_popup = popup;
+ return popup;
+}
+
+void KSircTopicEditor::slotMaybeResize()
+{
+ if(text().contains("\n")){
+ QString s = text();
+ s.replace('\n', " ");
+ setText(s);
+ setCursorPosition(0, s.length());
+ }
+
+ QFontMetrics metrics( currentFont() );
+
+ int h = metrics.lineSpacing() * lines()+8;
+ setFixedHeight( h );
+ emit resized();
+}
+
+#include "topic.moc"
diff --git a/ksirc/topic.h b/ksirc/topic.h
new file mode 100644
index 00000000..73191128
--- /dev/null
+++ b/ksirc/topic.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Artistic License.
+*/
+#ifndef __topic_h__
+#define __topic_h__
+
+#include <kactivelabel.h>
+#include <qtextedit.h>
+#include <qlineedit.h>
+#include <qpopupmenu.h>
+#include <qguardedptr.h>
+
+class KSircTopicEditor;
+
+class KSircTopic : public KActiveLabel
+{
+ Q_OBJECT
+public:
+ KSircTopic( QWidget *parent, const char *name = 0 );
+
+public slots:
+ virtual void setText( const QString &);
+
+signals:
+ void topicChange( const QString &newTopic );
+
+protected:
+ virtual void contentsMouseDoubleClickEvent( QMouseEvent * );
+ virtual void contentsMouseReleaseEvent( QMouseEvent * );
+ virtual void fontChange(QFont &);
+
+private slots:
+ void setNewTopic();
+ void slotEditResized();
+ void doResize();
+
+private:
+
+
+ QGuardedPtr<KSircTopicEditor> m_editor;
+ bool m_doEdit;
+ int m_height;
+ QString m_text;
+};
+
+class KSircTopicEditor : public QTextEdit
+{
+ Q_OBJECT
+public:
+ KSircTopicEditor( QWidget *parent, const char *name = 0 );
+
+signals:
+ void resized();
+
+public slots:
+ virtual void slotMaybeResize();
+
+protected:
+ virtual void keyPressEvent( QKeyEvent *ev );
+ virtual void focusOutEvent( QFocusEvent * );
+ virtual QPopupMenu *createPopupMenu( const QPoint &pos );
+
+private:
+ QGuardedPtr<QPopupMenu> m_popup;
+};
+
+#endif
diff --git a/ksirc/toplevel.cpp b/ksirc/toplevel.cpp
new file mode 100644
index 00000000..f064a291
--- /dev/null
+++ b/ksirc/toplevel.cpp
@@ -0,0 +1,1848 @@
+/**********************************************************************
+
+ TopLevel IRC Channel/query Window
+
+ $$Id$$
+
+ This is the main window with which the user interacts. It handles
+ both normal channel conversations and private conversations.
+
+ 2 classes are defined, the UserControlMenu and KSircToplevel. The
+ user control menu is used as a list of user defineable menus used by
+ KSircToplevel.
+
+ KSircTopLevel:
+
+ Signals:
+
+ outputLine(QString &):
+ output_toplevel(QString):
+
+ closing(KSircTopLevel *, QString channel):
+
+ changeChannel(QString old, QString new):
+
+ currentWindow(KSircTopLevel *):
+
+ Slots:
+
+
+
+ *********************************************************************/
+
+#include "toplevel.h"
+#include "alistbox.h"
+#include "chanparser.h"
+#include "ksopts.h"
+#include "control_message.h"
+#include "displayMgr.h"
+#include "NewWindowDialog.h"
+#include "usercontrolmenu.h"
+#include "topic.h"
+#include "charSelector.h"
+#include "ksview.h"
+#include "logfile.h"
+#include "servercontroller.h"
+#include "ioDCC.h"
+
+#include "KSTicker/ksticker.h"
+
+#include <stdlib.h>
+
+#include <qaccel.h>
+#include <qclipboard.h>
+#include <qregexp.h>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qlayout.h>
+#include <qtextcodec.h>
+#include <qvbox.h>
+#include <qlabel.h>
+
+#include <kmenubar.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kwin.h>
+#include <knotifyclient.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kcharsets.h>
+#include <kglobalsettings.h>
+#include <kstdguiitem.h>
+
+extern DisplayMgr *displayMgr;
+//QPopupMenu *KSircTopLevel::user_controls = 0L;
+QPtrList<UserControlMenu> *KSircTopLevel::user_menu = 0L;
+QStringList KSircTopLevel::cmd_menu;
+
+void
+KSircTopLevel::initColors()
+{
+ QColorGroup cg_mainw = kapp->palette().active();
+ cg_mainw.setColor(QColorGroup::Base, ksopts->backgroundColor);
+ cg_mainw.setColor(QColorGroup::Text, ksopts->textColor);
+ cg_mainw.setColor(QColorGroup::Link, ksopts->linkColor);
+ cg_mainw.setColor(QColorGroup::Highlight, ksopts->selBackgroundColor);
+ cg_mainw.setColor(QColorGroup::HighlightedText, ksopts->selForegroundColor);
+ mainw->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw));
+ nicks->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw));
+ linee->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw));
+ lag->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw));
+ cg_mainw.setColor(QColorGroup::Background, ksopts->backgroundColor);
+ cg_mainw.setColor(QColorGroup::Foreground, ksopts->textColor);
+ ksTopic->setPalette(QPalette(cg_mainw,cg_mainw, cg_mainw));
+ selector->setFont( ksopts->defaultFont.family() );
+ mainw->setFont( ksopts->defaultFont );
+ nicks->setFont( ksopts->defaultFont );
+ linee->setFont( ksopts->defaultFont );
+ ksTopic->setFont( ksopts->defaultFont );
+
+}
+
+KSircTopLevel::KSircTopLevel(KSircProcess *_proc, const KSircChannel &channelInfo, const char * name)
+ : KMainWindow(0, name, 0/*no WDestructiveClose !*/),
+ UnicodeMessageReceiver(_proc),
+ lastBeep( QTime::currentTime() ),
+ m_channelInfo(channelInfo)
+
+{
+ // prevent us from being quitted when closing a channel-window. Only
+ // closing the servercontroller shall quit.
+ // KMainWindow will deref() us in closeEvent
+ kapp->ref();
+
+
+ m_topic = QString::null;
+
+ QCString kstl_name = QCString(QObject::name()) + "_" + "toplevel";
+ setName(kstl_name);
+
+ if(!m_channelInfo.channel().isEmpty()) {
+ setCaption(m_channelInfo.channel());
+ caption = m_channelInfo.channel();
+ }
+ else
+ {
+ caption = QString::null;
+ }
+
+ Buffer = FALSE;
+
+ have_focus = 0;
+ tab_pressed = -1; // Tab (nick completion not pressed yet)
+ tab_start = -1;
+ tab_end = -1;
+
+ m_gotMsgWithoutFocus = false;
+
+ KickWinOpen = false;
+ current_size = size();
+
+ ksopts->channelSetup(ksircProcess()->serverName(), m_channelInfo.channel());
+ m_channelInfo.setEncoding(ksopts->chan(m_channelInfo).encoding);
+
+ selector = new charSelector();
+ connect(selector, SIGNAL(clicked()), this, SLOT(insertText()));
+ selector->setFont(ksopts->defaultFont.family());
+
+ file = new QPopupMenu(this, QCString(QObject::name()) + "_popup_file");
+ file->setCheckable(true);
+
+ KAction *act = KStdAction::openNew( this, SLOT( newWindow() ), actionCollection() );
+ act->plug( file );
+ file->insertItem(i18n("New Ser&ver..."), servercontroller::self(), SLOT(new_connection()), Key_F2);
+ file->insertSeparator();
+ file->insertItem(i18n("&DCC Manager..."), this, SLOT(showDCCMgr()));
+ file->insertItem(i18n("&Save to Logfile..."), this, SLOT(saveCurrLog()), CTRL + Key_S);
+
+ tsitem = file->insertItem(i18n("Time St&amp"), this, SLOT(toggleTimestamp()), CTRL + Key_T);
+ file->setItemChecked(tsitem, ksopts->chan(m_channelInfo).timeStamp);
+
+ fjpitem = file->insertItem(i18n("Hide Join/Part Messages"), this, SLOT(toggleFilterJoinPart()));
+ file->setItemChecked(fjpitem, ksopts->chan(m_channelInfo).filterJoinPart);
+
+ file->insertItem(i18n("Character &Table"), selector, SLOT(show()), CTRL + Key_H);
+ beepitem = file->insertItem(i18n("N&otify on Change"), this, SLOT(toggleBeep()), CTRL + Key_P);
+ file->setItemChecked(beepitem, ksopts->chan(m_channelInfo).beepOnMsg);
+
+ encodingAction = new KSelectAction( i18n( "&Encoding" ), 0, this );
+ connect( encodingAction, SIGNAL( activated() ), this, SLOT( setEncoding() ) );
+ QStringList encodings = KGlobal::charsets()->descriptiveEncodingNames();
+
+ topicitem = file->insertItem(i18n("S&how Topic"), this, SLOT(toggleTopic()), CTRL + Key_O);
+ if (isPrivateChat() || m_channelInfo.channel().startsWith("!no_channel")) {
+ file->setItemEnabled(topicitem, false);
+ }
+ else {
+ file->setItemChecked(topicitem, ksopts->chan(m_channelInfo).topicShow);
+ }
+
+ tickeritem = file->insertItem(i18n("Ticker &Mode"), this, SLOT(toggleTicker()));
+
+ // remove utf16/ucs2 as it just doesn't work for IRC
+ QStringList::Iterator encodingIt = encodings.begin();
+ while ( encodingIt != encodings.end() ) {
+ if ( ( *encodingIt ).find( "utf16" ) != -1 ||
+ ( *encodingIt ).find( "iso-10646" ) != -1 )
+ encodingIt = encodings.remove( encodingIt );
+ else
+ ++encodingIt;
+ }
+ encodings.prepend( i18n( "Default" ) );
+
+ encodingAction->setItems( encodings );
+ encodingAction->plug( file );
+
+ int eindex = encodings.findIndex(ksopts->chan(m_channelInfo).encoding);
+ if(eindex == -1)
+ encodingAction->setCurrentItem( 0 );
+ else
+ encodingAction->setCurrentItem(eindex);
+ setEncoding();
+
+ file->insertSeparator();
+ act = KStdAction::close( this, SLOT( terminate() ), actionCollection() );
+ act->plug( file );
+
+ kmenu = menuBar();
+ kmenu->insertItem(i18n("&Channel"), file, KST_CHANNEL_ID, -1);
+ kmenu->setAccel(Key_F, KST_CHANNEL_ID);
+
+ /*
+ * Ok, let's look at the basic widget "layout"
+ * Everything belongs to q QFrame F, this is use so we
+ * can give the KApplication a single main client widget, which is needs.
+ *
+ * A QVbox and a QHbox is used to ctronl the 3 sub widget
+ * The Modified QListBox is then added side by side with the User list box.
+ * The SLE is then fit bello.
+ */
+
+ // kstInside does not setup fonts, etc, it simply handles sizing
+
+ top = new QVBox( this );
+
+ ksTopic = new KSircTopic( top );
+ ksTopic->setFont(ksopts->defaultFont);
+ connect( ksTopic, SIGNAL( topicChange( const QString & ) ),
+ this, SLOT( setTopicIntern( const QString & ) ) );
+
+ QCString kstn = QCString(QObject::name()) + "_";
+
+ pan = new QSplitter(QSplitter::Horizontal, top, kstn + "splitter");
+#if KDE_IS_VERSION(3,1,92)
+ pan->setOpaqueResize( KGlobalSettings::opaqueResize() );
+#else
+ pan->setOpaqueResize( true );
+#endif
+
+ mainw = new KSircView(ksircProcess(), pan, kstn + "KSircView" );
+ mainw->setFocusPolicy(QWidget::NoFocus);
+
+ nicks_box = new QVBox(pan);
+
+ channelButtons = new chanButtons(ksircProcess(), nicks_box);
+ connect(channelButtons, SIGNAL(mode(QString, int, QString)),
+ this, SLOT(setMode(QString, int, QString)));
+
+ nicks = new aListBox(nicks_box, kstn + "aListBox");
+ nicks->setFocusPolicy(QWidget::NoFocus);
+ //nicks->hide(); // default = only the main widget
+
+ lag = new QLabel(nicks_box);
+ lag->setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ lag->setAlignment(Qt::AlignCenter | Qt::SingleLine);
+ lag->setText(i18n("Lag: Wait"));
+
+
+ QValueList<int> sizes;
+ sizes << int(width()*0.85) << int(width()*0.15);
+ pan->setSizes(sizes);
+ pan->setResizeMode( mainw, QSplitter::Stretch );
+ pan->setResizeMode( nicks_box, QSplitter::Stretch );
+
+// f = new kstInside(top, QString(QObject::name()) + "_" + "kstIFrame");
+ top->setStretchFactor(pan, 1);
+
+ setCentralWidget(top); // Tell the KApplication what the main widget is.
+
+ logFile = 0;
+ if ( ksopts->chan(m_channelInfo).logging && (m_channelInfo.channel() != "!no_channel" ))
+ {
+ logFile = new LogFile( m_channelInfo.channel(), m_channelInfo.server() );
+ logFile->open();
+ }
+
+ // get basic variable
+
+// mainw = f->mainw;
+// nicks = f->nicks;
+ // pan = f->pan;
+
+ clearWindow();
+
+ if(isPrivateChat()){
+ KConfig conf("ksirc/winlog/" + channelInfo.server() + "-" + channelInfo.channel(),
+ false, false, "data");
+ QString group = "Message-History";
+
+ if(conf.hasGroup( group )){
+ conf.setGroup( group );
+
+ QStringList strlist = conf.readListEntry("History");
+ if(strlist.count() > 0){
+ mainw->enableTimeStamps(true);
+ for ( QStringList::Iterator it = strlist.begin();
+ it != strlist.end();
+ ++it ) {
+ mainw->addRichText(*it);
+ }
+ }
+ strlist.clear();
+ }
+ }
+
+ mainw->enableTimeStamps(ksopts->chan(m_channelInfo).timeStamp);
+
+ edit = new QPopupMenu(this);
+ act = KStdAction::copy( mainw, SLOT( copy() ), actionCollection() );
+ act->plug( edit );
+ act = KStdAction::paste( this, SLOT( pasteToWindow() ), actionCollection() );
+ act->plug( edit );
+ edit->insertItem(i18n("C&lear Window"), this, SLOT(clearWindow()), CTRL + Key_L);
+ kmenu->insertItem(i18n("&Edit"), edit, -1, -1);
+
+ linee = new aHistLineEdit(top, "");
+
+ initColors();
+
+ // ksb_main->addWidget(linee, mainw->width());
+// ksb_main->insertItem(, KSB_MAIN_LAG, true);
+
+ // don't show the nick lists in a private chat or the default window
+ if (isPrivateChat() || m_channelInfo.channel().startsWith("!no_channel"))
+ {
+ nicks_box->hide();
+ ksTopic->hide();
+ // nicks->hide();
+ // lag->hide();
+ // channelButtons->hide();
+ }
+ else
+ {
+ nicks_box->show();
+
+ if(file->isItemChecked(topicitem)){
+ ksTopic->show();
+// channelButtons->show();
+ }
+ else{
+ ksTopic->hide();
+ // channelButtons->hide();
+ }
+ // channelButtons->show();
+ // lag->show();
+ // nicks->show();
+ }
+
+
+ connect(mainw, SIGNAL(pasteReq( const QString& )),
+ this, SLOT( slotTextDropped( const QString& )));
+
+ nicks->setFont(ksopts->defaultFont);
+
+ // setup line editor
+
+ linee->setFocusPolicy(QWidget::StrongFocus);
+ linee->setFont(ksopts->defaultFont);
+
+ if(ksopts->oneLineEntry == true) {
+ linee->setWordWrap(QTextEdit::NoWrap);
+ }
+ else {
+ linee->setWordWrap(QTextEdit::WidgetWidth);
+ }
+
+ connect(linee, SIGNAL(gotFocus()),
+ this, SLOT(gotFocus()));
+ connect(linee, SIGNAL(lostFocus()),
+ this, SLOT(lostFocus()));
+ connect(linee, SIGNAL(pasteText(const QString&)),
+ this, SLOT(slotTextDropped(const QString&)));
+ connect(linee, SIGNAL(notTab()),
+ this, SLOT(lineeNotTab()));
+
+ connect( linee, SIGNAL( gotReturnPressed() ),
+ this, SLOT( returnPressed() ) );
+
+ linee->setFocus(); // Give SLE focus
+ linee->slotMaybeResize();
+
+ lines = 0; // Set internal line counter to 0
+
+ ticker = 0x0;
+
+ /*
+ * Set generic run time variables
+ *
+ */
+
+ opami = FALSE;
+ continued_line = FALSE;
+// on_root = FALSE;
+
+ /*
+ * Load basic pics and images
+ * This should use on of the KDE finder commands
+ */
+
+ KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon());
+
+ /*
+ * Create our basic parser object
+ */
+
+ ChanParser = new ChannelParser(this);
+
+
+ /*
+ * Create the user Controls popup menu, and connect it with the
+ * nicks list on the lefthand side (highlighted()).
+ *
+ */
+
+ if(user_menu == 0)
+ user_menu = UserControlMenu::parseKConfig();
+
+ user_controls = new QPopupMenu(this);
+ kmenu->insertItem(i18n("&Users"), user_controls);
+
+ command = new QPopupMenu(this);
+
+ setupCommandMenu();
+
+ int i = 0;
+ QDict<QPopupMenu> cml;
+ for(QStringList::Iterator it = cmd_menu.begin();
+ it != cmd_menu.end();
+ ++it){
+ QString top, item;
+ top = (*it).section('/', 0, 0);
+ item = (*it).section('/', 1, 1);
+ if(!cml[top]) {
+ cml.insert(top, new QPopupMenu(this));
+ command->insertItem(top, cml[top]);
+ }
+ cml[top]->insertItem(item, this, SLOT(cmd_process(int)), 0, i);
+
+ i++;
+ }
+
+ kmenu->insertItem(i18n("C&ommand"), command);
+
+ kmenu->insertItem( KStdGuiItem::help().text(), helpMenu( QString::null, false ));
+
+ connect(user_controls, SIGNAL(activated(int)),
+ this, SLOT(UserParseMenu(int)));
+
+ connect(nicks, SIGNAL(contextMenuRequested(int)), this,
+ SLOT(UserSelected(int)));
+ connect(nicks, SIGNAL(selectedNick(const QString &)),
+ this, SLOT(openQueryFromNick(const QString &)));
+ connect(nicks, SIGNAL(mouseButtonClicked ( int, QListBoxItem *, const QPoint &)),
+ this, SLOT(pasteToNickList(int, QListBoxItem *, const QPoint &)));
+ connect(nicks, SIGNAL(textDropped( const QListBoxItem *, const QString& )),
+ this, SLOT(dndTextToNickList(const QListBoxItem *, const QString&)));
+
+ UserUpdateMenu(); // Must call to update Popup.
+
+ accel = new QAccel(this, "accel");
+
+ accel->connectItem(accel->insertItem(SHIFT + Key_PageUp),
+ this,
+ SLOT(AccelScrollUpPage()));
+ accel->connectItem(accel->insertItem(SHIFT + Key_PageDown),
+ this,
+ SLOT(AccelScrollDownPage()));
+
+ /*
+ * Pageup/dn
+ * Added for stupid wheel mice
+ */
+
+ accel->connectItem(accel->insertItem(Key_PageUp),
+ this,
+ SLOT(AccelScrollUpPage()));
+ accel->connectItem(accel->insertItem(Key_PageDown),
+ this,
+ SLOT(AccelScrollDownPage()));
+
+ /*
+ * These are not presently implemented, so let's not fill the logs.
+ accel->connectItem(accel->insertItem(CTRL + Key_Return),
+ this,
+ SLOT(AccelPriorMsgNick()));
+
+ accel->connectItem(accel->insertItem(CTRL + SHIFT + Key_Return),
+ this,
+ SLOT(AccelNextMsgNick()));
+ */
+
+ accel->connectItem(accel->insertItem(Key_Tab), // adds TAB accelerator
+ this, // connected to the main
+ SLOT(TabNickCompletionNormal())); // TabNickCompletion() slot
+ accel->connectItem(accel->insertItem(SHIFT+Key_Tab), // adds TAB accelerator
+ this, // connected to the main
+ SLOT(TabNickCompletionShift())); // TabNickCompletion() slot
+ accel->connectItem(accel->insertItem(CTRL + Key_N),
+ this, SLOT(newWindow()));
+// accel->connectItem(accel->insertItem(CTRL + Key_S),
+// this, SLOT(toggleTimestamp()));
+
+ // Drag & Drop
+ connect( mainw, SIGNAL( textDropped(const QString&) ),
+ SLOT( slotTextDropped(const QString&) ));
+ connect( mainw, SIGNAL( urlsDropped(const QStringList&) ),
+ SLOT( slotDropURLs(const QStringList&) ));
+ connect( nicks, SIGNAL( urlsDropped( const QStringList&, const QString& )),
+ SLOT( slotDccURLs( const QStringList&, const QString& )));
+ connect( this, SIGNAL( changed(bool, QString) ), this, SLOT( doChange(bool, QString) ));
+
+ mainw->setAcceptFiles( isPrivateChat() );
+ resize(600, 360);
+
+}
+
+KSircTopLevel::~KSircTopLevel()
+{
+ // Cleanup and shutdown
+ // if(this == ksircProcess()->getWindowList()["default"])
+ // write(sirc_stdin, "/quit\n", 7); // tell dsirc to close
+ //
+ // if(ksircProcess()->getWindowList()[m_channelInfo.channel()])
+ // ksircProcess()->getWindowList().remove(m_channelInfo.channel());
+
+ // if((m_channelInfo.channel()[0] == '#') || (m_channelInfo.channel()[0] == '&')){
+ // QString str = QString("/part ") + m_channelInfo.channel() + "\n";
+ // emit outputLine(str);
+ // }
+
+ kdDebug(5008) << "~KSircTopLevel in" << endl;
+ if ( ksopts->autoSaveHistory )
+ {
+ if ( isPublicChat() ) {
+ kdDebug(5008) << "*** parting channel: " << m_channelInfo.channel() << endl;
+ QString str = QString("/part ") + m_channelInfo.channel() + "\n";
+ emit outputUnicodeLine(str);
+ }
+ else {
+ QStringList strlist;
+
+ mainw->addLine("user|X", ksopts->channelColor, " Saved log of previous messages");
+
+ mainw->enableTimeStamps(true);
+
+ for(KSirc::TextParagIterator ksit = mainw->firstParag();
+ ksit.atEnd() == 0;
+ ++ksit) {
+ QString rt = ksit.richText();
+ if(rt.contains("<img src=\"user|servinfo\">"))
+ continue;
+
+ kdDebug(5008) << rt << endl;
+
+ strlist += rt;
+
+ }
+
+ KConfig conf("ksirc/winlog/" + channelInfo().server() +
+ "-" + channelInfo().channel(),
+ false, false, "data");
+ QString group = "Message-History";
+
+ conf.setGroup( group );
+
+ conf.writeEntry("History", strlist);
+ conf.sync();
+
+ }
+ }
+ delete ticker;
+ delete user_controls;
+ delete ChanParser;
+ delete selector;
+ delete channelButtons;
+ delete logFile;
+ kdDebug(5008) << "~KSircToplevel out" << endl;
+}
+
+void KSircTopLevel::setMode(QString mode, int mode_type, QString currentNick)
+{
+ QString command;
+ if (mode_type == 0)
+ command = QString::fromLatin1("/mode %1 %2\n").arg(m_channelInfo.channel()).arg(mode);
+ else
+ command = QString::fromLatin1("/mode %1 %2\n").arg(currentNick).arg(mode);
+ sirc_write(command);
+ linee->setFocus();
+}
+
+void KSircTopLevel::setEncoding()
+{
+ int index = encodingAction->currentItem();
+ if ( index == 0 ) {// default (locale) encoding
+ ksopts->chan(m_channelInfo).encoding = QString::null;
+ UnicodeMessageReceiver::setEncoding( QString::null );
+ }
+ else {
+ ksopts->chan(m_channelInfo).encoding = encodingAction->currentText();
+ UnicodeMessageReceiver::setEncoding( KGlobal::charsets()->encodingForName( encodingAction->currentText() ) );
+ }
+ ksopts->save(KSOptions::Channels);
+}
+
+void KSircTopLevel::setupCommandMenu()
+{
+ if(cmd_menu.empty() == true){
+ cmd_menu.append(i18n("Help") + "/" + "help");
+ cmd_menu.append(i18n("Client") + "/" + "alias");
+ cmd_menu.append(i18n("User") + "/" + "away");
+ cmd_menu.append(i18n("Client") + "/" + "bye");
+ cmd_menu.append(i18n("Client") + "/" + "cd");
+ cmd_menu.append(i18n("Basic") + "/" + "ctcp");
+ cmd_menu.append(i18n("Basic") + "/" + "dcc");
+ cmd_menu.append(i18n("Operator") + "/" + "deop");
+ cmd_menu.append(i18n("User") + "/" + "describe");
+ cmd_menu.append(i18n("Client") + "/" + "eval");
+ cmd_menu.append(i18n("Client") + "/" + "exit");
+ cmd_menu.append(i18n("Client") + "/" + "hop");
+ cmd_menu.append(i18n("Basic") + "/" + "ignore");
+ cmd_menu.append(i18n("Server") + "/" + "info");
+ cmd_menu.append(i18n("Channel") + "/" + "invite" + "/" + "*chan*");
+ cmd_menu.append(i18n("Basic") + "/" + "join");
+ cmd_menu.append(i18n("Operator") + "/" + "kick");
+ cmd_menu.append(i18n("Oper") + "/" + "kill");
+ cmd_menu.append(i18n("Basic") + "/" + "leave");
+ cmd_menu.append(i18n("Server") + "/" + "links");
+ cmd_menu.append(i18n("Basic") + "/" + "list");
+ cmd_menu.append(i18n("Basic") + "/" + "ll");
+ cmd_menu.append(i18n("Client") + "/" + "load");
+ cmd_menu.append(i18n("Server") + "/" + "lusers");
+ cmd_menu.append(i18n("Server") + "/" + "map");
+ cmd_menu.append(i18n("Basic") + "/" + "me");
+ cmd_menu.append(i18n("Channel") + "/" + "mode" + "/" + "*chan*");
+ cmd_menu.append(i18n("Server") + "/" + "motd");
+ cmd_menu.append(i18n("Basic") + "/" + "msg");
+ cmd_menu.append(i18n("Basic") + "/" + "nick");
+ cmd_menu.append(i18n("Basic") + "/" + "notice");
+ cmd_menu.append(i18n("Basic") + "/" + "notify");
+ cmd_menu.append(i18n("Operator") + "/" + "op");
+ cmd_menu.append(i18n("Oper") + "/" + "oper");
+ cmd_menu.append(i18n("Basic") + "/" + "query");
+ cmd_menu.append(i18n("Channel") + "/" + "part"+ "/" + "*chan*");
+ cmd_menu.append(i18n("Basic") + "/" + "ping");
+ cmd_menu.append(i18n("Client") + "/" + "quit");
+ cmd_menu.append(i18n("Server") + "/" + "quote");
+ cmd_menu.append(i18n("Oper") + "/" + "rping");
+ cmd_menu.append(i18n("Oper") + "/" + "rehash");
+ cmd_menu.append(i18n("Basic") + "/" + "say");
+ cmd_menu.append(i18n("Server") + "/" + "stats");
+ cmd_menu.append(i18n("Client") + "/" + "system");
+ cmd_menu.append(i18n("Server") + "/" + "time");
+ cmd_menu.append(i18n("Channel") + "/" + "topic" + "/" + "*chan*");
+ cmd_menu.append(i18n("Client") + "/" + "version");
+ cmd_menu.append(i18n("Oper") + "/" + "wallops");
+ cmd_menu.append(i18n("Channel") + "/" + "who" + "/" + "*chan*");
+ cmd_menu.append(i18n("Basic") + "/" + "whois");
+ cmd_menu.append(i18n("Basic") + "/" + "whowas");
+ cmd_menu.append(i18n("Basic") + "/" + "wi");
+ cmd_menu.append(i18n("Help") + "/" + "newuser");
+ cmd_menu.append(i18n("Channel") + "/" + "ban");
+ cmd_menu.append(i18n("Channel") + "/" + "unban");
+ cmd_menu.append(i18n("Channel") + "/" + "clrban" + "/" + "*chan*");
+ cmd_menu.append(i18n("Channel") + "/" + "banlist" + "/" + "*chan*");
+ cmd_menu.append(i18n("Basic") + "/" + "pig");
+ cmd_menu.append(i18n("Channel") + "/" + "wallop");
+ cmd_menu.append(i18n("Client") + "/" + "exec");
+ cmd_menu.append(i18n("Basic") + "/" + "url");
+ cmd_menu.sort();
+ }
+}
+
+void KSircTopLevel::insertText()
+{
+ linee->insert(selector->currentText());
+}
+
+void KSircTopLevel::show()
+{
+ KMainWindow::show();
+ linee->setFocus();
+ mainw->scrollToBottom(true);
+}
+
+enum {
+ KSTUp = 1,
+ KSTDown = 2
+};
+
+void KSircTopLevel::TabNickCompletionShift()
+{
+ TabNickCompletion(KSTDown);
+}
+
+void KSircTopLevel::TabNickCompletionNormal()
+{
+ TabNickCompletion(KSTUp);
+}
+
+void KSircTopLevel::TabNickCompletion(int dir)
+{
+ /*
+ * Gets current text from lined find the last item and try and perform
+ * a nick completion, then return and reset the line.
+ */
+
+ int start, end;
+ int extra = 0;
+ bool first = false;
+ QString s;
+
+ if(tab_pressed == -1){
+ s = linee->text();
+ tab_saved = s;
+ end = linee->cursorPosition() - 1;
+ start = s.findRev(" ", end, FALSE);
+ tab_start = start;
+ tab_end = end;
+ first = true;
+ }
+ else{
+ s = tab_saved;
+ start = tab_start;
+ end = tab_end;
+ }
+
+ if(dir == KSTDown){
+ if(tab_pressed > 0)
+ tab_pressed -= 1;
+ }
+ else {
+ tab_pressed += 1;
+ }
+
+
+ if(s.length() == 0){
+ if(tab_nick.isEmpty()) {
+ KNotifyClient::beep();
+ lineeNotTab();
+ return;
+ }
+ QString line = tab_nick + ": "; // tab_nick holds the last night since we haven't overritten it yet.
+ linee->setText(line);
+ linee->setCursorPosition(line.length());
+ connect(linee, SIGNAL(notTab()),
+ this, SLOT(lineeNotTab()));
+ return;
+ }
+
+ if (start == -1) {
+ tab_nick = findNick(s.mid(0, end+1), tab_pressed);
+
+ if(first && (tab_nick.isNull() == TRUE)){
+ KNotifyClient::beep();
+ lineeNotTab();
+ return;
+ }
+ else if(tab_nick.isNull() == TRUE){
+ tab_pressed -= 1;
+ tab_nick = findNick(s.mid(0, end+1), tab_pressed);
+ }
+ s.replace(0, end + 1, "");
+ if(s[0] == ':')
+ s.replace(0, 2, "");
+ s.prepend(tab_nick + ": ");
+ extra = 2;
+ }
+ else {
+ tab_nick = findNick(s.mid(start + 1, end - start), tab_pressed);
+ if(first && (tab_nick.isNull() == TRUE)){
+ KNotifyClient::beep();
+ lineeNotTab();
+ return;
+ }
+ else if(tab_nick.isNull() == TRUE){
+ tab_pressed -= 1;
+ tab_nick = findNick(s.mid(start + 1, end - start), tab_pressed);
+ }
+
+ if((uint) end == s.length() - 1){ /* if we're at the end add a space */
+ s.replace(start + 1, end - start, tab_nick + " ");
+ extra = 1;
+ }
+ else {
+ s.replace(start + 1, end - start, tab_nick);
+ extra = 0;
+ }
+ }
+
+ int tab = tab_pressed;
+
+ linee->setText(s);
+ linee->setCursorPosition(start + tab_nick.length() + 1 + extra);
+
+ tab_pressed = tab; // setText causes lineeTextChanged to get called and erase tab_pressed
+
+ connect(linee, SIGNAL(notTab()),
+ this, SLOT(lineeNotTab()));
+
+}
+
+void KSircTopLevel::sirc_receive(QString str, bool broadcast)
+{
+
+ /*
+ * read and parse output from dsirc.
+ * call reader, split the read input into lines, parse the lines
+ * then print line by line into the main text area.
+ *
+ * PROBLEMS: if a line terminates in mid line, it will get borken oddly
+ *
+ */
+
+ if(!Buffer){
+ if( !str.isEmpty() ){
+ LineBuffer.append( BufferedLine( str, broadcast ) );
+ }
+
+ bool addressed = false;
+ BufferedLine line;
+
+ // be careful not to use a QValueList iterator here, as it is possible
+ // that we enter a local event loop (think of the ssfeprompt dialog!)
+ // which might trigger a socketnotifier activation which in turn
+ // might result in the execution of code that modifies the LineBuffer,
+ // which would invalidate iterators (Simon)
+ while ( LineBuffer.begin() != LineBuffer.end() )
+ {
+ QString plainText("");
+ line = *LineBuffer.begin();
+ LineBuffer.remove( LineBuffer.begin() );
+
+ // Get the need list box item, with colour, etc all set
+ if (parse_input(line.message, plainText))
+ {
+ // If we should add anything, add it.
+ // Don't announce server messages as they are
+ // spread through all channels anyway
+
+ bool addressedLine = false;
+
+ if(line.message.contains( ">~o")){ /* highlighted with our nick */
+ addressedLine = true;
+ }
+
+ // detect /msg's -- needed when auto-create-window is off
+ if ( line.message.find( QRegExp( "^\\[~b.+~b\\].+$" ) ) == 0 )
+ addressedLine = true;
+
+ if ( addressedLine == true && line.message.startsWith("* " + ksircProcess()->getNick()))
+ addressedLine = false;
+
+ if ( addressedLine )
+ addressed = true;
+
+ if ( !line.wasBroadcast ) {
+ // This line is addressed to me if it contains my nick, or is in a private chat
+ emit changed( addressedLine || isPrivateChat(), plainText );
+ }
+ }
+ }
+ LineBuffer.clear(); // Clear it since it's been added
+ }
+ else{
+ LineBuffer.append( BufferedLine( str, broadcast ) );
+ }
+
+ QValueList<int> list;
+ QValueList<int>::iterator it;
+ QString values;
+ list = pan->sizes();
+ it = list.begin();
+ while( it != list.end()){
+ values += QString("%1 ").arg(*it);
+ ++it;
+ }
+}
+void KSircTopLevel::sirc_line_return(const QString &text)
+{
+
+ /* Take line from SLE, and output if to dsirc */
+
+ QString s = text;
+
+ if(s.length() == 0)
+ return;
+
+ tab_pressed = -1; // new line, zero the counter.
+ s += '\n'; // Append a need carriage return :)
+
+ sirc_write(s);
+
+ linee->setText("");
+ linee->slotMaybeResize();
+
+}
+
+void KSircTopLevel::sirc_write(const QString &str)
+{
+ /*
+ * Parse line forcommand we handle
+ */
+ QString command = str, plain = str.lower().simplifyWhiteSpace();
+ if(plain.startsWith("/join ") ||
+ plain.startsWith("/j ") ||
+ plain.startsWith("/query ")) {
+
+ QString s = plain.mid(plain.find(' ')+1);
+
+ QStringList channels = QStringList::split(",", s);
+ QStringList::ConstIterator it = channels.begin();
+
+ for( ; it != channels.end(); ++it){
+ QString name = *it;
+ //kdDebug(5008) << "Doing " << name << endl;
+ QRegExp rx("(\\S+)\\s*(\\S*)");
+ rx.search(name);
+ KSircChannel ci(m_channelInfo.server(),
+ rx.cap(1), // channel
+ rx.cap(2)); // optional key
+ linee->setText(QString::null);
+ emit open_toplevel(ci);
+/* if(name[0] != '#'){
+ emit open_toplevel(name);
+ linee->setText(QString::null);
+ }
+ else {
+ emit outputUnicodeLine(plain + "\n");
+ emit open_toplevel(encoder()->fromUnicode(name));
+ }
+*/
+ }
+ // Finish sending /join
+ return;
+ }
+ else if(plain.startsWith("/server ")) {
+ plain.simplifyWhiteSpace();
+ QRegExp rx("/server (\\S+) *(\\S*) *(\\S*)");
+ if(rx.search(str) >= 0){
+ QString server = rx.cap(1);
+ QString port = rx.cap(2);
+ QString pass = rx.cap(3);
+
+ bool ssl = false;
+ if(server.startsWith("+")){
+ server.replace(0, 1, "");
+ ssl = true;
+ }
+
+ KSircServer serv(server, port, QString::null, pass, ssl);
+ servercontroller::self()->new_ksircprocess(serv);
+
+ return;
+ }
+ }
+ else if(plain.startsWith("/part") ||
+ plain.startsWith("/leave") ||
+ plain.startsWith("/hop")) {
+ QApplication::postEvent(this, new QCloseEvent()); // WE'RE DEAD
+ linee->setText(QString::null);
+ return;
+ }
+ else if( plain.startsWith( "/bye" ) ||
+ plain.startsWith( "/exit" ) ||
+ plain.startsWith( "/quit" )) {
+ linee->setText( QString::null );
+ emit requestQuit( command.ascii() );
+ return;
+ }
+ else if ( plain.startsWith( "/away" ) ) {
+ QString awayEvalCommand = QString::fromLatin1( "/eval $publicAway = %1\n" ).arg( ksopts->publicAway ? '1' : '0' );
+ emit outputUnicodeLine( awayEvalCommand );
+ }
+
+ //
+ // Look at the command, if we're assigned a channel name, default
+ // messages, etc to the right place. This include /me, etc
+ //
+
+ if(!isSpecialWindow()) { // channel or private chat
+ if(plain[0].latin1() != '/'){
+ command.prepend(QString::fromLatin1("/msg %1 ").arg(m_channelInfo.channel()));
+ }
+ else if(plain.startsWith("/me ")) {
+ command.remove(0, 3);
+ command.prepend(QString("/de ") + m_channelInfo.channel());
+ }
+ }
+
+ // Write out line
+
+ emit outputUnicodeLine(command);
+ /*
+ * as opposed to what some might think
+ * it doesn't matter when you call stb
+ */
+ mainw->scrollToBottom(true);
+}
+
+bool KSircTopLevel::parse_input(const QString &string, QString &plainText)
+{
+ /*
+ * Parsing routines are broken into 3 majour sections
+ *
+ * 1. Search and replace evil characters. The string is searched for
+ * each character in turn (evil[i]), and the character string in
+ * evil_rep[i] is replaced.
+ *
+ * 2. Parse control messages, add pixmaps, and colourize required
+ * lines. Caption is also set as required.
+ *
+ * 3. Create and return the ircListItem.
+ *
+ */
+
+ /*
+ * No-output get's set to 1 if we should ignore the line
+ */
+
+ /*
+ * This is the second generation parsing code.
+ * Each line type is determined by the first 3 characters on it.
+ * Each line type is then sent to a parsing function.
+ */
+ parseResult *pResult = ChanParser->parse(string);
+
+ parseSucc *item = dynamic_cast<parseSucc *>(pResult);
+ parseError *err = dynamic_cast<parseError *>(pResult);
+
+ QString logString;
+
+ if(item)
+ {
+ parseJoinPart *jp = dynamic_cast<parseJoinPart *>(pResult);
+ if(jp &&
+ ksopts->chan(m_channelInfo).filterJoinPart){
+ delete pResult;
+ return true;
+ }
+ else if (!item->string.isEmpty()) {
+ logString = mainw->
+ addLine( item->pm, item->colour, item->string );
+ if(ticker != NULL){
+ ticker->mergeString(item->string, item->colour);
+ }
+ } else {
+ delete pResult;
+ return false;
+ }
+ }
+ else if (err)
+ {
+ if(err->err.isEmpty() == FALSE)
+ {
+ kdWarning() << err->err << ": " << string << endl;
+ delete pResult;
+ return false;
+ }
+ if (!err->str.isEmpty()) {
+ logString = mainw->addLine( "user|error", ksopts->errorColor, err->str );
+ }
+
+ }
+ else
+ {
+ logString = mainw->addLine( QString::null, ksopts->textColor, string );
+ if(ticker != NULL){
+ ticker->mergeString(string);
+ }
+ // If it contains our nick, move the speaker to the top
+ // of the nick completion list
+ if(string.contains("~o")){
+ QRegExp rx("<(\\S+)>");
+ if ( (rx.search(logString) >= 0) &&
+ (rx.cap(1) != ksircProcess()->getNick()) ) {
+ //kdDebug(5008) << "addCompleteNick: " << rx.cap(1) << endl;
+ addCompleteNick( rx.cap(1) );
+ }
+ }
+
+ }
+ delete pResult;
+
+ if ( !logString.isEmpty() && logFile )
+ logFile->log( logString );
+
+ if(!plainText.isNull())
+ plainText = logString;
+
+ return true;
+}
+
+void KSircTopLevel::returnPressed()
+{
+
+ QString s = linee->text();
+
+ uint i;
+ QChar c;
+ for(i = 0; (c = s[i]); i++){
+ switch(c.unicode()){
+ case 0336:
+ s[i] = 002;
+ break;
+ case 0327:
+ s[i] = 037;
+ break;
+ case 0237:
+ s[i] = 026;
+ break;
+ case 0252:
+ s[i] = 003;
+ break;
+ }
+ }
+
+ while(s.length() > IRC_SAFE_MAX_LINE){
+ int wrap = s.findRev(' ', IRC_SAFE_MAX_LINE);
+ if(wrap == -1)
+ wrap = IRC_SAFE_MAX_LINE;
+ sirc_line_return(s.left(wrap));
+ s = s.mid(wrap + 1);
+ }
+ if(!s.stripWhiteSpace().isEmpty())
+ sirc_line_return(s);
+ else {
+ linee->setText("");
+ linee->slotMaybeResize();
+ }
+}
+
+void KSircTopLevel::UserSelected(int index)
+{
+ if(index >= 0)
+ user_controls->popup(this->cursor().pos());
+}
+
+void KSircTopLevel::UserParseMenu(int id)
+{
+ if(nicks->currentItem() < 0)
+ return;
+
+ QString s;
+ s = QString("/eval $dest_nick='%1';\n").arg(nicks->text(nicks->currentItem()));
+ sirc_write(s);
+ // set $$dest_chan variable
+ s = QString("/eval $dest_chan='%1';\n").arg(m_channelInfo.channel());
+ sirc_write(s);
+ QString action = user_menu->at(id)->action;
+ if (action.length() && action[0] == '/')
+ action.remove(0, 1);
+ s = QString("/eval &docommand(eval{\"%1\"});\n").arg(action);
+ s.replace(QRegExp("\\$\\$"), "$");
+ sirc_write(s);
+}
+
+void KSircTopLevel::UserUpdateMenu()
+{
+ int i = 0;
+ UserControlMenu *ucm;
+
+ user_controls->clear();
+ for(ucm = user_menu->first(); ucm != 0; ucm = user_menu->next(), i++){
+ if(ucm->type == UserControlMenu::Seperator){
+ user_controls->insertSeparator();
+ }
+ else{
+ user_controls->insertItem(ucm->title, i);
+ if(ucm->accel)
+ user_controls->setAccel(i, ucm->accel);
+ if((ucm->op_only == TRUE) && (opami == FALSE))
+ user_controls->setItemEnabled(i, FALSE);
+ }
+ }
+}
+
+void KSircTopLevel::AccelScrollDownPage()
+{
+ mainw->verticalScrollBar()->addPage();
+}
+
+void KSircTopLevel::AccelScrollUpPage()
+{
+ mainw->verticalScrollBar()->subtractPage();
+}
+
+void KSircTopLevel::newWindow()
+{
+ NewWindowDialog w(KSircChannel(m_channelInfo.server(), QString::null));
+ connect(&w, SIGNAL(openTopLevel(const KSircChannel &)), SIGNAL(open_toplevel(const KSircChannel &)));
+ w.exec();
+}
+
+void KSircTopLevel::closeEvent(QCloseEvent *e)
+{
+ KMainWindow::closeEvent( e );
+ e->accept();
+
+ //Let's not part the channel till we are acutally delete.
+ // We should always get a close event, *BUT* we will always be deleted.
+ // if( isPublicChat() ) {
+ // QString str = QString("/part ") + m_channelInfo.channel() + "\n";
+ // emit outputLine(str);
+ // }
+
+ // Hide ourselves until we finally die
+ hide();
+ qApp->flushX();
+ // Let's say we're closing
+ kdDebug(5008) << "Toplevel closing: " << m_channelInfo.channel() << endl;
+ emit closing(this, m_channelInfo.channel());
+}
+
+void KSircTopLevel::focusChange(QWidget *w)
+{
+ QWidget *me = this;
+ if(w == me){
+ gotFocus();
+ }
+ else {
+ lostFocus();
+ }
+}
+
+void KSircTopLevel::gotFocus()
+{
+ if(isVisible() == TRUE){
+ if(have_focus == 0){
+ if(m_channelInfo.channel()[0] != '!' ){
+ QString str = QString("/join %1").arg(m_channelInfo.channel());
+ if(m_channelInfo.key().length() > 0){
+ str.append(" " + m_channelInfo.key());
+ }
+ kdDebug(5008) << "Doing join: " << str << " / " << m_channelInfo.channel() << endl;
+ str.append("\n");
+ emit outputUnicodeLine(str);
+ }
+ have_focus = 1;
+ emit currentWindow(this);
+ }
+ }
+ if(m_gotMsgWithoutFocus == true){
+ m_gotMsgWithoutFocus = false;
+ servercontroller::self()->decreaseNotificationCount(QString("%1 -> %2 got message").arg(ksircProcess()->serverID()).arg(m_channelInfo.channel()));
+ }
+
+}
+
+void KSircTopLevel::lostFocus()
+{
+ if(have_focus == 1){
+ have_focus = 0;
+ }
+}
+
+void KSircTopLevel::control_message(int command, QString str)
+{
+ switch(command){
+ case CHANGE_CHANNEL: // 001 is defined as changeChannel
+ {
+ KSircChannel ci(m_channelInfo.server(), QString::null);
+ QRegExp rx("([^!]+)!+([^!]+)!*([^!]*)");
+ if(rx.search(str) < 0){
+ ci.setChannel(str);
+ }
+ else{
+ ci.setChannel(rx.cap(2));
+ ci.setKey(rx.cap(3));
+ }
+ //kdDebug(5008) << "CHANGE NAME: " << ci.channel() << " key: " << ci.key() << endl;
+ emit changeChannel(m_channelInfo.channel(), ci.channel());
+ ksopts->channelSetup(m_channelInfo.server(), m_channelInfo.channel());
+ m_channelInfo.setChannel(ci.channel());
+ m_channelInfo.setKey(ci.key());
+ m_channelInfo.setEncoding(ksopts->chan(m_channelInfo).encoding);
+ if ( !logFile && ksopts->chan(m_channelInfo).logging )
+ {
+ logFile = new LogFile( m_channelInfo.channel(), ksircProcess()->serverName() );
+ logFile->open();
+ }
+ setName(m_channelInfo.server().utf8() + "_" + m_channelInfo.channel().utf8() + "_" + "toplevel");
+ pan->setName(QCString(QObject::name()) + "_" + "QSplitter");
+ kmenu->setName(QCString(QObject::name()) + "_ktoolframe");
+ linee->setName(QCString(QObject::name()) + "_" + "LineEnter");
+ kmenu->show();
+ setCaption(m_channelInfo.channel());
+ emit currentWindow(this);
+
+ if(m_channelInfo.channel()[0] == '#' || m_channelInfo.channel()[0] == '&'){
+ QString str = QString("/join %1 %2\n").arg(m_channelInfo.channel()).arg(m_channelInfo.key());
+ kdDebug(5008) << "Doing /join " << m_channelInfo.channel() << " :" << str << endl;
+ emit outputUnicodeLine(str);
+ emit outputLine("/eval $query=''\n");
+ }
+ else if (m_channelInfo.channel()[0] != '!')
+ {
+ emit outputUnicodeLine(QString("/eval $query='%1'\n").arg(m_channelInfo.channel()));
+ }
+
+ bool isPrivate = isPrivateChat();
+
+ mainw->setAcceptFiles( isPrivate );
+
+ if ( isPrivate )
+ {
+ nicks_box->hide();
+ ksTopic->hide();
+ file->setItemEnabled(topicitem, false);
+ }
+ else
+ {
+ file->setItemEnabled(topicitem, true);
+ file->setItemChecked(topicitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow);
+ if(file->isItemChecked(topicitem)){
+ ksTopic->show();
+ // channelButtons->show();
+ }
+ nicks_box->show();
+ pan->show();
+// channelButtons->show();
+// nicks->show();
+// lag->show();
+ }
+ if(layout()) {
+ //kdDebug(5008) << "Redoeing layout" << endl;
+ layout()->invalidate();
+ layout()->activate();
+ }
+ else {
+ //kdDebug(5008) << "No layout" << endl;
+ }
+ pan->refresh();
+
+ ksopts->channelSetup(m_channelInfo.server(), m_channelInfo.channel());
+ file->setItemChecked(topicitem, ksopts->chan(m_channelInfo).topicShow);
+ file->setItemChecked(beepitem, ksopts->chan(m_channelInfo).beepOnMsg);
+ file->setItemChecked(tsitem, ksopts->chan(m_channelInfo).timeStamp);
+ file->setItemChecked(fjpitem, ksopts->chan(m_channelInfo).filterJoinPart);
+ int eindex = encodingAction->items().findIndex(ksopts->chan(m_channelInfo).encoding);
+ //kdDebug(5008) << "in change channel we want: " << ksopts->chan(m_channelInfo).encoding << " eindex: " << eindex << endl;
+ encodingAction->setCurrentItem(eindex < 0 ? 0 : eindex);
+ setEncoding();
+ mainw->enableTimeStamps(ksopts->chan(m_channelInfo).timeStamp);
+
+ break;
+ }
+ case STOP_UPDATES:
+ Buffer = TRUE;
+ break;
+ case RESUME_UPDATES:
+ Buffer = FALSE;
+ if(LineBuffer.isEmpty() == FALSE)
+ sirc_receive(QString::null);
+ break;
+ case REREAD_CONFIG:
+ emit freezeUpdates(TRUE); // Stop the list boxes update
+ selector->setFont( ksopts->defaultFont.family() );
+ mainw->setFont( ksopts->defaultFont );
+ nicks->setFont( ksopts->defaultFont );
+ linee->setFont( ksopts->defaultFont );
+ ksTopic->setFont( ksopts->defaultFont );
+ UserUpdateMenu(); // Must call to update Popup.
+ emit freezeUpdates(FALSE); // Stop the list boxes update
+ initColors();
+ ksopts->channelSetup(m_channelInfo.server(), m_channelInfo.channel());
+ file->setItemChecked(topicitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow);
+ file->setItemChecked(beepitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg);
+ file->setItemChecked(tsitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp);
+ {
+ int eindex = encodingAction->items().findIndex(ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].encoding);
+ //kdDebug(5008) << "in re-readconfig we want: " << ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].encoding << " eindex: " << eindex << endl;
+ encodingAction->setCurrentItem(eindex < 0 ? 0 : eindex);
+ setEncoding();
+ }
+ mainw->enableTimeStamps(ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp);
+ if(ksopts->oneLineEntry == true) {
+ linee->setWordWrap(QTextEdit::NoWrap);
+ }
+ else {
+ linee->setWordWrap(QTextEdit::WidgetWidth);
+ }
+ mainw->scrollToBottom(true);
+ update();
+ break;
+ case SET_LAG:
+ if(str.isNull() == FALSE){
+ bool ok = TRUE;
+
+ str.truncate(6);
+ double lag = str.toDouble(&ok);
+ if(ok == TRUE){
+ lag -= (lag*100.0 - int(lag*100.0))/100.0;
+ QString s_lag;
+ s_lag.sprintf("Lag: %.2f", lag);
+ this->lag->setText(s_lag);
+ }
+ else{
+ this->lag->setText(str);
+ }
+ }
+ break;
+ case RESET_NOTIF:
+ m_gotMsgWithoutFocus = 0;
+ break;
+ default:
+ kdDebug(5008) << "Unkown control message: " << str << endl;
+ }
+}
+
+void KSircTopLevel::setTopic( const QString &topic )
+{
+ m_topic = topic;
+ ksTopic->setText( topic );
+}
+
+void KSircTopLevel::toggleTimestamp()
+{
+ ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp = !ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp;
+ ksopts->save(KSOptions::Channels);
+ mainw->enableTimeStamps( ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp );
+ file->setItemChecked( tsitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].timeStamp );
+}
+
+void KSircTopLevel::toggleFilterJoinPart()
+{
+ ksopts->chan(m_channelInfo).filterJoinPart = !ksopts->chan(m_channelInfo).filterJoinPart;
+ ksopts->save(KSOptions::Channels);
+ file->setItemChecked( fjpitem, ksopts->chan(m_channelInfo).filterJoinPart );
+}
+
+QString KSircTopLevel::findNick(QString part, uint which)
+{
+ QStringList matches;
+
+ for (QStringList::ConstIterator it = completeNicks.begin();
+ it != completeNicks.end();
+ ++it)
+ {
+ if ((*it).left(part.length()).lower() == part.lower() && nicks->findNick(*it) >= 0) {
+ matches.append(*it);
+ }
+ }
+
+ for(uint i=0; i < nicks->count(); i++){
+ if (matches.contains(nicks->text(i)))
+ continue;
+ if(nicks->text(i).length() >= part.length()){
+ if(nicks->text(i).lower().startsWith( part.lower())){
+ if(nicks->text(i) != ksircProcess()->getNick() ){ // Don't match your own nick
+ matches.append(nicks->text(i));
+ }
+ }
+ }
+ }
+ if(matches.count() > 0){
+ if(which < matches.count())
+ return *(matches.at(which));
+ else
+ return QString::null;
+ }
+ return QString::null;
+
+}
+
+void KSircTopLevel::removeCompleteNick(const QString &nick)
+{
+ QStringList::Iterator it = completeNicks.find(nick);
+ if (it != completeNicks.end())
+ completeNicks.remove(it);
+}
+
+void KSircTopLevel::addCompleteNick(const QString &nick)
+{
+ removeCompleteNick(nick);
+ completeNicks.prepend(nick);
+}
+
+void KSircTopLevel::changeCompleteNick(const QString &oldNick, const QString &newNick)
+{
+ QStringList::Iterator it = completeNicks.find(oldNick);
+ if (it != completeNicks.end())
+ *it = newNick;
+}
+
+void KSircTopLevel::openQueryFromNick(const QString &nick)
+{
+ KSircChannel ci(m_channelInfo.server(), nick.lower());
+ emit open_toplevel(ci);
+}
+
+void KSircTopLevel::pasteToWindow()
+{
+ // Ctrl-V
+ //kdDebug(5008) << "Going to paste: " << KApplication::clipboard()->text( QClipboard::Clipboard ) << endl;
+ slotTextDropped(KApplication::clipboard()->text( QClipboard::Clipboard ) );
+}
+
+void KSircTopLevel::pasteToNickList(int button,
+ QListBoxItem *item,
+ const QPoint &)
+{
+ if(button == Qt::MidButton && item){
+ KSircChannel ci(m_channelInfo.server(), item->text().lower());
+ emit open_toplevel(ci);
+
+ QStringList lines = QStringList::split( '\n',
+ KApplication::clipboard()->text( QClipboard::Selection ),
+ true );
+ QStringList::ConstIterator it = lines.begin();
+ QStringList::ConstIterator end = lines.end();
+ for (; it != end; ++it )
+ {
+ if ((*it).isEmpty())
+ continue;
+
+ QString str =
+ QString("/msg ") + item->text().lower() + " " +
+ *it + "\n";
+ emit outputUnicodeLine(str);
+
+ }
+ }
+
+}
+
+void KSircTopLevel::dndTextToNickList(const QListBoxItem *item,
+ const QString& text)
+{
+ if(item){
+ KSircChannel ci(m_channelInfo.server(), item->text().lower());
+ emit open_toplevel(ci);
+
+ QStringList lines = QStringList::split( '\n',
+ text,
+ true );
+ QStringList::ConstIterator it = lines.begin();
+ QStringList::ConstIterator end = lines.end();
+ for (; it != end; ++it )
+ {
+ if ((*it).isEmpty())
+ continue;
+
+ QString str =
+ QString("/msg ") + item->text().lower() + " " +
+ *it + "\n";
+ emit outputUnicodeLine(str);
+
+ }
+ }
+
+}
+
+enum KSircTopLevelCommands{ Ask, Parse, Escape };
+void KSircTopLevel::slotTextDropped( const QString& _text )
+{
+ if (_text.isEmpty())
+ return;
+ QString text = linee->text();
+ int curPos = linee->cursorPosition();
+
+ text = text.mid( 0, curPos ) + _text + text.mid( curPos );
+
+ if (text[text.length()-1] != '\n')
+ text += "\n";
+ int lines = text.contains("\n");
+ int approx_lines = text.length() / 75;
+ if ( lines > approx_lines )
+ approx_lines = lines;
+ if (lines > 4) {
+ int result = KMessageBox::warningContinueCancel(this,
+ i18n("You are about to send %1 lines of text.\nDo you really want to send that much?").arg(approx_lines),
+ QString::null, i18n("Send"));
+ if (result != KMessageBox::Continue)
+ {
+// linee->setText("");
+ return;
+ }
+ }
+
+ tab_pressed = -1;
+ if(lines > 1){
+ linee->setUpdatesEnabled(FALSE);
+
+ QStringList lines = QStringList::split( '\n', text, true );
+ QStringList::ConstIterator it = lines.begin();
+ QStringList::ConstIterator end = lines.end();
+ KSircTopLevelCommands commands = Ask;
+ for (; it != end; ++it )
+ {
+ if ((*it).isEmpty())
+ continue;
+ QString line = *it;
+ if ( line[0].latin1() == '/' )
+ {
+ if ( commands == Ask )
+ switch ( KMessageBox::questionYesNo( this, i18n(
+ "The text you pasted contains lines that start with /.\n"
+ "Should they be interpreted as IRC commands?" ), QString::null, i18n("Interpret"), i18n("Do Not Interpret") ) )
+ {
+ case KMessageBox::Yes:
+ commands = Parse;
+ break;
+ case KMessageBox::No:
+ commands = Escape;
+ break;
+ }
+ if ( commands == Escape )
+ line.prepend( "/say " );
+ }
+ linee->setText( line );
+ sirc_line_return(line);
+ }
+
+ linee->setText("");
+ linee->setUpdatesEnabled(TRUE);
+ linee->update();
+ }
+ else{
+ text.replace(QRegExp("\n"), "");
+ linee->setText(text);
+ linee->setCursorPosition( curPos + _text.length() );
+ }
+}
+
+void KSircTopLevel::clearWindow()
+{
+ kdDebug(5008) << "Doing clear on main window" << endl;
+ mainw->clear();
+}
+
+void KSircTopLevel::lineeNotTab()
+{
+ tab_pressed = -1;
+ disconnect(linee, SIGNAL(notTab()),
+ this, SLOT(lineeNotTab()));
+ addCompleteNick(tab_nick);
+}
+
+void KSircTopLevel::toggleRootWindow()
+{
+}
+
+bool KSircTopLevel::event( QEvent *e)
+{
+ if(e->type() == QEvent::ApplicationPaletteChange ||
+ e->type() == QEvent::ApplicationFontChange)
+ {
+ QTimer::singleShot(750, this, SLOT(initColors()));
+ initColors();
+ }
+ return KMainWindow::event(e);
+}
+
+void KSircTopLevel::saveCurrLog()
+{
+ KURL url = KURL( KFileDialog::getSaveFileName(QString::null,
+ "*.log", 0L,
+ i18n("Save Chat/Query Logfile")));
+ if( url.isEmpty())
+ return;
+
+ KTempFile temp;
+ QTextStream *str = temp.textStream();
+
+ *str << mainw->plainText();
+
+ temp.close();
+#if KDE_IS_VERSION(3,1,92)
+ KIO::NetAccess::upload(temp.name(), url, this);
+#else
+ KIO::NetAccess::upload(temp.name(), url);
+#endif
+}
+
+
+void KSircTopLevel::slotDropURLs( const QStringList& urls )
+{
+ if ( !isPrivateChat() )
+ return;
+
+ slotDccURLs( urls, m_channelInfo.channel() );
+}
+
+// sends the list of urls to $dest_nick
+void KSircTopLevel::slotDccURLs( const QStringList& urls, const QString& nick )
+{
+ if ( urls.isEmpty() || nick.isEmpty() )
+ return;
+
+ QStringList::ConstIterator it = urls.begin();
+ // QString s("/eval &docommand(eval{\"dcc send " + nick + " %1\"});\n");
+ QString s("/dcc send " + nick + " %1\n");
+ for ( ; it != urls.end(); ++it ) {
+ QString file( *it );
+ kdDebug(5008) << "........ " << file << endl;
+ if ( !file.isEmpty() )
+ sirc_write(s.arg( file ));
+ }
+}
+
+bool KSircTopLevel::isPrivateChat() const
+{
+ return ((m_channelInfo.channel()[0] != '!') && (m_channelInfo.channel()[0] != '&') &&
+ (m_channelInfo.channel()[0] != '#'));
+}
+
+bool KSircTopLevel::isPublicChat() const
+{
+ return ((m_channelInfo.channel()[0] == '#') || (m_channelInfo.channel()[0] == '&'));
+}
+
+bool KSircTopLevel::isSpecialWindow() const
+{
+ return (m_channelInfo.channel()[0] == '!');
+}
+
+void KSircTopLevel::outputUnicodeLine( const QString &message )
+{
+ emit outputLine( encoder()->fromUnicode( message ) );
+}
+
+void KSircTopLevel::setTopicIntern( const QString &topic )
+{
+ QString command = QString::fromLatin1( "/topic %1 %2\n" ).arg( m_channelInfo.channel() ).arg( topic );
+ sirc_write( command );
+ linee->setFocus();
+}
+
+void KSircTopLevel::doChange(bool pers, QString text)
+{
+ QTime ctime = QTime::currentTime();
+ if (ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg) {
+ // beep only every 2 seconds otherwise it'll get very noisy in the room ;)
+ if ( QABS( lastBeep.secsTo( ctime ) ) > 1 ) {
+ if ( pers ) {
+ int winId = !ticker ? topLevelWidget()->winId() : ticker->winId();
+ KNotifyClient::event(winId,
+ QString::fromLatin1("ChannelPersonal"),
+ i18n("Your nick appeared on channel %1").arg(m_channelInfo.channel()));
+ } else {
+ int winId = !ticker ? topLevelWidget()->winId() : ticker->winId();
+ KNotifyClient::event(winId,
+ QString::fromLatin1("ChannelChanged"),
+ i18n("Channel %1 changed").arg(m_channelInfo.channel()));
+ }
+ lastBeep = ctime;
+ }
+ }
+
+ if(have_focus == 0 && pers == true && m_gotMsgWithoutFocus == false){
+ m_gotMsgWithoutFocus = true;
+ servercontroller::self()->increaseNotificationCount(QString("%1 -> %2").arg(ksircProcess()->serverID()).arg(m_channelInfo.channel()), text);
+ }
+}
+
+void KSircTopLevel::toggleBeep()
+{
+ ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg = !ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg;
+ ksopts->save(KSOptions::Channels);
+ file->setItemChecked(beepitem, ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].beepOnMsg);
+}
+
+void KSircTopLevel::toggleTopic()
+{
+ if(file->isItemChecked(topicitem)){
+ ksTopic->hide();
+// channelButtons->hide();
+ ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow = false;
+ }
+ else {
+ ksTopic->show();
+// channelButtons->show();
+ ksopts->channel[m_channelInfo.server()][m_channelInfo.channel()].topicShow = true;
+ }
+ file->setItemChecked(topicitem, !file->isItemChecked(topicitem));
+ ksopts->save(KSOptions::Channels);
+}
+
+void KSircTopLevel::toggleTicker()
+{
+ //kdDebug(5008) << "Got toggle ticker" << endl;
+ if(ticker){
+ show();
+ displayMgr->show(this);
+ linee->setFocus(); // Give focus back to the linee, someone takes it away on new create
+ tickerpoint = ticker->pos();
+ tickersize = ticker->size();
+ delete ticker;
+ ticker = 0x0;
+ }
+ else {
+ ticker = new KSTicker(0x0, m_channelInfo.channel().utf8() + "_ticker");
+ ticker->setCaption(m_channelInfo.channel());
+ if(tickerpoint.isNull() == false)
+ ticker->move(tickerpoint);
+ if(tickersize.isEmpty() == false)
+ ticker->resize(tickersize);
+ ticker->show();
+ displayMgr->hide(this);
+
+ connect(ticker, SIGNAL(doubleClick()), this, SLOT(toggleTicker()));
+ }
+}
+
+bool KSircTopLevel::atBottom()
+{
+ return mainw->verticalScrollBar()->maxValue() - mainw->verticalScrollBar()->value() < 20;
+}
+
+void KSircTopLevel::cmd_process(int id)
+{
+ if(cmd_menu.at(id) != cmd_menu.end()) {
+ QString item, arg, out;
+ item = cmd_menu[id].section('/', 1, 1);
+ arg = cmd_menu[id].section('/', 2, 2);
+
+ out = "/" + item;
+
+ if(arg == "*chan*")
+ out.append(" " + m_channelInfo.channel());
+
+ out.append(" ");
+
+ linee->insertAt(out, 0, 0);
+ linee->setCursorPosition(linee->cursorPosition() + out.length());
+ }
+}
+
+void KSircTopLevel::showDCCMgr()
+{
+ KSircMessageReceiver *kmr = ksircProcess()->mrList().find("!dcc");
+ if(kmr){
+ KSircIODCC *dcc = static_cast<KSircIODCC *>(kmr);
+ if(dcc){
+ dcc->showMgr();
+ }
+ }
+}
+
+#include "toplevel.moc"
+
+// vim: ts=2 sw=2 et
diff --git a/ksirc/toplevel.h b/ksirc/toplevel.h
new file mode 100644
index 00000000..ef8d4a57
--- /dev/null
+++ b/ksirc/toplevel.h
@@ -0,0 +1,535 @@
+#ifndef KSIRCTOPLEVEL_H
+#define KSIRCTOPLEVEL_H
+
+#include <qdatetime.h>
+#include <kmainwindow.h>
+
+#include "ahistlineedit.h"
+#include "messageReceiver.h"
+#include "chanButtons.h"
+#include "KSTicker/ksticker.h"
+#include "ksircchannel.h"
+
+#define KST_CHANNEL_ID 2
+
+class KSircTopic;
+class QSplitter;
+class KSircView;
+class aListBox;
+class UserControlMenu;
+class ChannelParser;
+class charSelector;
+class LogFile;
+class KSelectAction;
+class QLabel;
+class QVBox;
+class QListBoxItem;
+
+class QPopupMenu;
+
+class KSircTopLevel : public KMainWindow,
+ public UnicodeMessageReceiver
+{
+ Q_OBJECT
+ friend class ChannelParser;
+public:
+ /**
+ * Constructor, needs the controlling ksircprocess passed to it, so
+ * we can make the ksircmessage receiver happy.
+ */
+ KSircTopLevel(KSircProcess *_proc, const KSircChannel &channelInfo, const char *
+ name=0);
+ /**
+ * Destructor, destroys itself.
+ */
+ ~KSircTopLevel();
+
+ /**
+ * Reimplement show() to popup the menu bars and toolbar items
+ */
+ virtual void show();
+
+ /**
+ * Line recieved that should be printed on the screen. Unparsed, and
+ * ready processing. This is a single line, and it NOT \n
+ * terminated.
+ */
+ virtual void sirc_receive(QString str, bool broadcast = false);
+
+ /**
+ * Reimplement the ksircmessagereceiver control messages. These
+ * are parsed and dealt with quickly.
+ */
+ virtual void control_message(int, QString);
+
+ QWidget *lineEdit() const { return linee; }
+
+ void setTopic( const QString &topic );
+ QString topic() const { return m_topic; }
+
+ /**
+ * This returns the current channel information for a toplevel
+ */
+ const KSircChannel &channelInfo() const { return m_channelInfo; }
+
+signals:
+ /**
+ * signals thats the toplevel widget wishes to
+ * output a new line. The line is correctly
+ * linefeed terminated, etc.
+ */
+ void outputLine(QCString);
+ /**
+ * open a new toplevel widget with for the
+ * channel/user QString.
+ */
+ void open_toplevel(const KSircChannel &);
+ /**
+ * emittedon shutdown, indicating that
+ * this window is closing. Refrence to outselves
+ * is include.
+ */
+ void closing(KSircTopLevel *, QString channel);
+ /**
+ * emitted when the user typed /quit, will disconnect from this
+ * server and close all toplevels belonging to it.
+ */
+ void requestQuit( const QCString& command );
+ /**
+ * emitted when we change channel name
+ * on the fly. old is the old channel name, new
+ * is the new one.
+ */
+ void changeChannel(const QString &oldName, const QString &newName);
+ /**
+ * emitted to say that KSircTopLevel
+ * (this) is now the window with focus. Used by
+ * servercontroller to set the !default window.
+ */
+ void currentWindow(KSircTopLevel *);
+ /**
+ * Stop updating list item sizes, majour changes comming through
+ *
+ */
+ void freezeUpdates(bool);
+ /**
+ * Emitted when a new message appeared in the irc window
+ */
+ void changed(bool, QString);
+
+public slots:
+ /**
+ * When enter is pressed, we read the SLE and output the results
+ * after processing via emitting outputLine.
+ */
+ virtual void sirc_line_return(const QString &s);
+
+ /**
+ * Clears the message window
+ */
+ void clearWindow();
+
+ /**
+ * If the focus shifts this should get called with
+ * the widget that just got focus. Used in MDI modes
+ * where the toplevel doesn't get focus in/out events.
+ */
+ void focusChange(QWidget *w);
+
+protected slots:
+ /**
+ * When the rightMouse button is pressed in the nick list, popup
+ * the User popup menu at his cursor location.
+ */
+ void UserSelected(int index);
+ /**
+ * Menu items was selected, now read the UserControlMenu and
+ * reupdate the required menus.
+ */
+ void UserParseMenu(int id);
+ /**
+ * Page down accel key. Tells the mainw to scroll down 1 page.
+ */
+ void AccelScrollDownPage();
+ /**
+ * Page Up accell key. Tells the mainw to scroll down 1 page.
+ */
+ void AccelScrollUpPage();
+ /**
+ * Slot to termiate (close) the window.
+ */
+ void terminate() { close( true /*alsoDelete*/ ); }
+ /**
+ * Called when the user menu is finished and the popup menu needs
+ * to be updated.
+ */
+ void UserUpdateMenu();
+ /**
+ * Open the new channel/window selector.
+ */
+ void newWindow();
+ /**
+ * We've received focus, let's make us the default, and issue a
+ * /join such that we default to the right channel.
+ */
+ void gotFocus();
+ /**
+ * We've lost focus, set ourselves as loosing focus.
+ */
+ void lostFocus();
+ /**
+ * Create and popup the ticker. Make sure to restore it to the
+ * last position is was at.
+ */
+// void showTicker();
+ /**
+ * toggle the timestamp from the channel window menu (and with keyaccel)
+ */
+ void toggleTimestamp();
+ /**
+ * toggle the filtering of join/part message
+ */
+ void toggleFilterJoinPart();
+
+ /**
+ * toggle the beep from the channel window menu (and with keyaccel)
+ */
+ void toggleBeep();
+
+ /**
+ * show the dcc manager
+ */
+ void showDCCMgr();
+
+ /**
+ * Delete the ticker and ppoup the main window
+ */
+// void unHide();
+ /**
+ * On a TAB key press we call TabNickCompletion which
+ * reads the last thing in linee matches it with a nick and
+ * puts it back into the line.
+ */
+ void TabNickCompletionShift();
+ /**
+ * On a TAB key press we call TabNickCompletion which
+ * reads the last thing in linee matches it with a nick and
+ * puts it back into the line.
+ */
+ void TabNickCompletionNormal();
+
+ /**
+ * Signals a Line Change in linee
+ */
+ void lineeNotTab();
+ /**
+ * Move the display to or from the root window
+ *
+ */
+ void toggleRootWindow();
+ /**
+ * On a middle mouse button press we call pasteToWindow which
+ * reads the clip board and pastes into the main listbox.
+ */
+ void pasteToWindow();
+ /**
+ * On a midle mouse button press to the nick list we open
+ * a query window and paste the text there
+ */
+ void pasteToNickList(int button, QListBoxItem *item, const QPoint &pos);
+ /**
+ * dnd paste to nick list
+ */
+ void dndTextToNickList(const QListBoxItem *itom, const QString& text);
+ /**
+ * open a toplevel on double click
+ */
+ void openQueryFromNick(const QString &);
+
+ /**
+ * Some text was dropped on the listbox
+ */
+ void slotTextDropped(const QString&);
+
+ /**
+ * Calls slotDccURLs with the current nick we're talking to
+ */
+ void slotDropURLs(const QStringList& urls);
+
+ /**
+ * Sends the list of urls to nick
+ */
+ void slotDccURLs(const QStringList& urls, const QString& nick );
+
+ /**
+ * Re-apply color settings.
+ */
+ void initColors();
+
+ /**
+ * Dumps current content of mainw into a logfile
+ */
+ void saveCurrLog();
+
+ /**
+ * Makes a beep when a change happens (if the user has this on)
+ * the bool is TRUE if changed line contained user's nick
+ */
+ void doChange(bool, QString);
+
+ /**
+ * show the ticker window
+ */
+ void toggleTicker();
+
+ /**
+ * ksirc command menu clicked on
+ */
+ void cmd_process(int id);
+
+protected:
+ /**
+ * On a TAB key press we call TabNickCompletion which
+ * reads the last thing in linee matches it with a nick and
+ * puts it back into the line.
+ */
+ void TabNickCompletion(int dir);
+
+ /**
+ * Make sure to update colors correctly.
+ */
+ virtual bool event( QEvent *e);
+
+ /**
+ * Redfine closeEvent to emit closing and delete itself.
+ */
+ virtual void closeEvent(QCloseEvent *);
+ /**
+ * Searches through the nick list and finds the nick with the best match.
+ * which, arg2, selects nicks other than the first shouldarg1 match more
+ * than 1 nick.
+ */
+ virtual QString findNick(QString, uint which = 0);
+ /**
+ * remove a nick from the prefered in nick completion list
+ */
+ virtual void removeCompleteNick(const QString &);
+ /**
+ * Adds a nick to the list of nicks to prefer in nick completion
+ * or moves it to the top of the list if it was already there
+ */
+ virtual void addCompleteNick(const QString &);
+ /**
+ * Changes a nick in the completion list if it has been listed,
+ * otherwise does nothing
+ */
+ virtual void changeCompleteNick(const QString &, const QString &);
+
+ virtual void setupCommandMenu();
+
+ /**
+ * Returns true if this window is a private conversation (query or dcc chat)
+ *, instead of a public chat in a channel or a special window.
+ */
+ bool isPrivateChat() const;
+
+ /**
+ * Returns true if this is a public channel window
+ */
+ bool isPublicChat() const;
+
+ /**
+ * Returns true if this is a special window
+ */
+ bool isSpecialWindow() const;
+
+private slots:
+ void setTopicIntern( const QString &topic );
+ void insertText();
+ void setMode(QString, int, QString currentNick=0);
+ void setEncoding();
+ void returnPressed();
+ void toggleTopic();
+
+private:
+
+ void outputUnicodeLine( const QString &message );
+
+ bool atBottom();
+
+ bool continued_line;
+ charSelector *selector;
+ chanButtons *channelButtons;
+ QSplitter *pan;
+ QVBox *nicks_box;
+ QVBox *top;
+ KMenuBar *kmenu;
+ QLabel *lag;
+ enum {PING = 10, TOPIC = 20};
+ KSircView *mainw;
+ aHistLineEdit *linee;
+ aListBox *nicks;
+
+ //QString m_currentNick;
+
+ //KSircProcess *proc;
+
+ int lines;
+
+ struct BufferedLine
+ {
+ BufferedLine() { wasBroadcast = false; }
+ BufferedLine( const QString &msg, bool broadc )
+ { message = msg; wasBroadcast = broadc; }
+ bool operator==( const BufferedLine &other )
+ { return message == other.message &&
+ wasBroadcast == other.wasBroadcast; }
+
+ QString message;
+ bool wasBroadcast;
+ };
+
+ bool Buffer;
+ QValueList<BufferedLine> LineBuffer;
+
+ // QPopupMenu's used for the menubar
+ QPopupMenu *file, *edit, *command;
+
+ bool parse_input(const QString &string, QString &plainText);
+ void sirc_write(const QString &str);
+
+ QPopupMenu *user_controls;
+ static QPtrList<UserControlMenu> *user_menu;
+ int opami;
+
+ QAccel *accel;
+
+ /**
+ * The channel name that we belong too.
+ */
+ //QString channel_name;
+
+ /**
+ * Caption at the top of the window.
+ */
+ QString caption;
+ /**
+ * Current topic for the channel
+ */
+ QString m_topic;
+
+ /**
+ * Does the window have focus? 1 when yes, 0 when no.
+ */
+ int have_focus;
+
+ /**
+ * Number of time tab has been pressed. Each time it's pressed
+ * roll through the list of matching nicks.
+ */
+ int tab_pressed;
+ /**
+ * When tabs pressed save the line for use at a latter date.
+ * tab_nick holds the last nick found so when a blank tab is pressed
+ * we pop the last niick and ": " up.
+ */
+ QString tab_saved, tab_nick;
+ int tab_start, tab_end;
+
+ // Ticker specific variables.
+
+ /**
+ * Main pointer to ksticker. Caution, it doesn't always exist!
+ * Set to 0 ifwhen you delete it.
+ */
+ KSTicker *ticker;
+ /**
+ * Size and position of the main window. Main window is returns this
+ * this position when it reappears.
+ */
+ QRect myrect;
+ /**
+ * Position of the main window
+ */
+ QPoint mypoint;
+ /**
+ * Ticker's size and geometry
+ */
+ QRect tickerrect;
+ /**
+ * Tickers position
+ */
+ QPoint tickerpoint;
+ QSize tickersize;
+ /**
+ * Do we have a kick window open?
+ * Remember not to open 2
+ */
+ bool KickWinOpen;
+
+ /**
+ * Hold an internal parser object which does all our parsing for us.
+ * Since parsing an intergral part of TopLevel, it's also a friend
+ * of ours
+ */
+ ChannelParser *ChanParser;
+
+ /**
+ * QSize maintains size information in case it changes somehow
+ */
+ QSize current_size;
+
+ /**
+ * ID of the timestamp menu item, to use in (un)checking it from slot
+ */
+ int tsitem;
+
+ /**
+ * ID of the filter join/part menu item, to use in (un)checking it from slot
+ */
+ int fjpitem;
+
+ /**
+ * ID of the beep menu item, to use in (un)checking it from slot
+ */
+ int beepitem;
+
+ /**
+ * ID of the toggle topic menu item, to use in (un)checking it from slot
+ */
+ int topicitem;
+
+ /**
+ * ID of the show/hide ticker menu item
+ */
+ int tickeritem;
+
+ /**
+ * List of nicks already used in nick completion to give them
+ * higher priority
+ */
+ QStringList completeNicks;
+
+ /**
+ * The time of the last beep to prevent your soundcard from detonating
+ * in high traffic channels
+ */
+ QTime lastBeep;
+
+ KSircTopic *ksTopic;
+
+ LogFile *logFile;
+
+ KSelectAction *encodingAction;
+
+ static QStringList cmd_menu;
+
+ bool m_gotMsgWithoutFocus;
+
+ KSircChannel m_channelInfo;
+
+};
+
+#endif
+
+// vim: ts=2 sw=2 et
diff --git a/ksirc/usercontrolmenu.cpp b/ksirc/usercontrolmenu.cpp
new file mode 100644
index 00000000..ca35e094
--- /dev/null
+++ b/ksirc/usercontrolmenu.cpp
@@ -0,0 +1,167 @@
+#include "usercontrolmenu.h"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+
+QPtrList<UserControlMenu> UserControlMenu::UserMenu;
+
+UserControlMenu::UserControlMenu(const QString& _title,
+ const QString& _action,
+ int _accel,
+ int _type,
+ bool _op_only)
+{
+ title = _title;
+ action = _action;
+ accel = _accel;
+ type = (itype) _type;
+ op_only = _op_only;
+}
+
+UserControlMenu::~UserControlMenu()
+{
+}
+
+QPtrList<UserControlMenu> *UserControlMenu::parseKConfig()
+{
+
+ // Reset the UserMenu to nothing before we start.
+
+ UserMenu.clear();
+
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("UserMenu");
+ int items = kConfig->readNumEntry("Number");
+ if(items == 0){
+
+ // We found nothing, so let's use some defaults.
+
+ UserMenu.setAutoDelete(TRUE);
+ UserMenu.append(new UserControlMenu(i18n("&Refresh Nicks"),
+ "refresh",
+ 0, UserControlMenu::Text));
+ UserMenu.append(new UserControlMenu);
+ UserMenu.append(new UserControlMenu(i18n("&Follow"),
+ "follow $$dest_nick",
+ 0, UserControlMenu::Text));
+ UserMenu.append(new UserControlMenu(i18n("&UnFollow"),
+ "unfollow $$dest_nick",
+ 0, UserControlMenu::Text));
+ UserMenu.append(new UserControlMenu); // Defaults to a separator
+ UserMenu.append(new UserControlMenu(i18n("&Whois"),
+ "/whois $$dest_nick",
+ 0, UserControlMenu::Text));
+ UserMenu.append(new UserControlMenu(i18n("&Ping"),
+ "/ping $$dest_nick",
+ 0, UserControlMenu::Text));
+ UserMenu.append(new UserControlMenu(i18n("V&ersion"),
+ "/ctcp $$dest_nick VERSION",
+ 0, UserControlMenu::Text));
+ UserMenu.append(new UserControlMenu); // Defaults to a separator
+ UserMenu.append(new UserControlMenu(i18n("&Abuse"),
+ "/me slaps $$dest_nick around with a small 50lb Unix Manual",
+ 0, UserControlMenu::Text));
+ UserMenu.append(new UserControlMenu); // Defaults to a separator
+ UserMenu.append(new UserControlMenu(i18n("&Kick"),
+ "/kick $$dest_nick",
+ 0,
+ UserControlMenu::Text,
+ TRUE));
+ UserMenu.append(new UserControlMenu(i18n("&Ban"),
+ "/ban $$dest_nick",
+ 0,
+ UserControlMenu::Text,
+ TRUE));
+ UserMenu.append(new UserControlMenu(i18n("U&nBan"),
+ "/unban $$dest_nick",
+ 0,
+ UserControlMenu::Text,
+ TRUE));
+ UserMenu.append(new UserControlMenu());
+ UserMenu.append(new UserControlMenu(i18n("&Op"),
+ "/op $$dest_nick",
+ 0,
+ UserControlMenu::Text,
+ TRUE));
+ UserMenu.append(new UserControlMenu(i18n("&Deop"),
+ "/deop $$dest_nick",
+ 0,
+ UserControlMenu::Text,
+ TRUE));
+ UserMenu.append(new UserControlMenu());
+ UserMenu.append(new UserControlMenu(i18n("&Voice"),
+ "/mode $$dest_chan +v $$dest_nick",
+ 0,
+ UserControlMenu::Text,
+ TRUE));
+ UserMenu.append(new UserControlMenu(i18n("Devo&ice"),
+ "/mode $$dest_chan -v $$dest_nick",
+ 0,
+ UserControlMenu::Text,
+ TRUE));
+ }
+ else{
+ QString key, cindex, title, action;
+ int accel, type, oponly;
+ for(int i = 0; i < items; i++){
+ cindex.sprintf("%d", i);
+ key = "MenuType-" + cindex;
+ type = kConfig->readNumEntry(key);
+ if(type == UserControlMenu::Seperator)
+ UserMenu.append(new UserControlMenu());
+ else if(type == UserControlMenu::Text){
+ key = "MenuTitle-" + cindex;
+ title = kConfig->readEntry(key);
+ key = "MenuAction-" + cindex;
+ action = kConfig->readEntry(key);
+ key = "MenuAccel-" + cindex;
+ accel = kConfig->readNumEntry(key);
+ key = "MenuOpOnly-" + cindex;
+ oponly = kConfig->readNumEntry(key);
+
+ UserMenu.append(new UserControlMenu(title, action, accel, type, (bool) oponly));
+ }
+ }
+ }
+
+ return &UserMenu;
+
+}
+
+void UserControlMenu::writeKConfig()
+{
+ KConfig *kConfig = kapp->config();
+ kConfig->setGroup("UserMenu");
+
+ int items = (int) UserMenu.count();
+
+ kConfig->writeEntry("Number", items);
+
+ QString key;
+ QString cindex;
+ UserControlMenu *ucm;
+ int type;
+
+ for(int i = 0; i < items; i++){
+ ucm = UserMenu.at(i);
+ cindex.sprintf("%d", i);
+ key = "MenuType-" + cindex;
+ type = ucm->type;
+ kConfig->writeEntry(key, (int) type);
+ // Do nothing for a seperator since it defaults across
+ if(type == UserControlMenu::Text){
+ key = "MenuTitle-" + cindex;
+ kConfig->writeEntry(key, ucm->title);
+ key = "MenuAction-" + cindex;
+ kConfig->writeEntry(key, ucm->action);
+ key = "MenuAccel-" + cindex;
+ kConfig->writeEntry(key, (int) ucm->accel);
+ key = "MenuOpOnly-" + cindex;
+ kConfig->writeEntry(key, (int) ucm->op_only);
+ }
+ }
+ kConfig->sync();
+
+}
+
diff --git a/ksirc/usercontrolmenu.h b/ksirc/usercontrolmenu.h
new file mode 100644
index 00000000..1f7a983a
--- /dev/null
+++ b/ksirc/usercontrolmenu.h
@@ -0,0 +1,52 @@
+#ifndef USERCONTROLLERMENU_H
+#define USERCONTROLLERMENU_H
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+class UserControlMenu {
+ public:
+ /**
+ Basic constructor, everything defaults to a Seperator. All data
+ is public so there is no problems changing it in the future.
+ Data is copied internally and deleted when finished.
+ */
+ UserControlMenu(const QString& _title = 0,
+ const QString& _action = 0,
+ int _accel = 0,
+ int _type = 0,
+ bool _op_only = FALSE);
+
+ ~UserControlMenu();
+
+ static QPtrList<UserControlMenu> UserMenu;
+
+ static QPtrList<UserControlMenu> *parseKConfig();
+ static void writeKConfig();
+
+ /**
+ * title in the popup menu
+ */
+ QString title;
+ /**
+ * Action to preform, must be of the format "blah lbah %s blah"
+ * where %s will be expanded into the selected nick.
+ */
+ QString action;
+
+ /**
+ * Accelerator key, currently does nothing.
+ */
+ int accel;
+ /**
+ * is this function only available to ops?
+ */
+ bool op_only;
+ /**
+ * What type of menu item is this? a Seperator of Text?
+ */
+ enum itype { Seperator, Text } type;
+};
+
+
+#endif
diff --git a/ksirc/version.h b/ksirc/version.h
new file mode 100644
index 00000000..7f49130c
--- /dev/null
+++ b/ksirc/version.h
@@ -0,0 +1,6 @@
+#ifndef KSIRC_VERSION_H
+#define KSIRC_VERSION_H
+
+#define KSIRC_VERSION "1.3.12"
+
+#endif