summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rw-r--r--COPYING346
-rw-r--r--COPYING-DOCS397
-rw-r--r--INSTALL176
-rw-r--r--Makefile.am.in7
-rw-r--r--Makefile.cvs15
-rw-r--r--README79
-rw-r--r--configure.in.in10
-rw-r--r--doc/Makefile.am5
-rw-r--r--doc/kcron/Makefile.am2
-rw-r--r--doc/kcron/index.docbook900
-rw-r--r--doc/kcron/kcron.pngbin0 -> 12848 bytes
-rw-r--r--doc/kcron/kcronstart.pngbin0 -> 11164 bytes
-rw-r--r--doc/kcron/newtask.pngbin0 -> 27943 bytes
-rw-r--r--doc/kcron/newvariable.pngbin0 -> 8271 bytes
-rw-r--r--doc/kcron/print.pngbin0 -> 19911 bytes
-rw-r--r--doc/kdat/Makefile.am4
-rw-r--r--doc/kdat/index.docbook833
-rw-r--r--doc/knetworkconf/01.pngbin0 -> 19174 bytes
-rw-r--r--doc/knetworkconf/02.pngbin0 -> 11535 bytes
-rw-r--r--doc/knetworkconf/03.pngbin0 -> 34941 bytes
-rw-r--r--doc/knetworkconf/04.pngbin0 -> 17281 bytes
-rw-r--r--doc/knetworkconf/05.pngbin0 -> 23226 bytes
-rw-r--r--doc/knetworkconf/06.pngbin0 -> 20572 bytes
-rw-r--r--doc/knetworkconf/07.pngbin0 -> 38636 bytes
-rw-r--r--doc/knetworkconf/08.pngbin0 -> 38582 bytes
-rw-r--r--doc/knetworkconf/09.pngbin0 -> 14696 bytes
-rw-r--r--doc/knetworkconf/11.pngbin0 -> 88408 bytes
-rw-r--r--doc/knetworkconf/Makefile.am4
-rw-r--r--doc/knetworkconf/about1.pngbin0 -> 25159 bytes
-rw-r--r--doc/knetworkconf/index.docbook1117
-rw-r--r--doc/kpackage/Makefile.am4
-rw-r--r--doc/kpackage/bsdloc.pngbin0 -> 13152 bytes
-rw-r--r--doc/kpackage/debaptloc.pngbin0 -> 20365 bytes
-rw-r--r--doc/kpackage/debloc.pngbin0 -> 28484 bytes
-rw-r--r--doc/kpackage/handle.pngbin0 -> 25717 bytes
-rw-r--r--doc/kpackage/index.docbook1229
-rw-r--r--doc/kpackage/install.pngbin0 -> 57287 bytes
-rw-r--r--doc/kpackage/left.pngbin0 -> 87127 bytes
-rw-r--r--doc/kpackage/right-change.pngbin0 -> 37157 bytes
-rw-r--r--doc/kpackage/right-files.pngbin0 -> 25459 bytes
-rw-r--r--doc/kpackage/right-prop.pngbin0 -> 31602 bytes
-rw-r--r--doc/kpackage/root-prompt.pngbin0 -> 13526 bytes
-rw-r--r--doc/kpackage/rpmloc.pngbin0 -> 26686 bytes
-rw-r--r--doc/kpackage/search.pngbin0 -> 12484 bytes
-rw-r--r--doc/kpackage/searchf.pngbin0 -> 45882 bytes
-rw-r--r--doc/kpackage/searchl.pngbin0 -> 5851 bytes
-rw-r--r--doc/kpackage/slackloc.pngbin0 -> 19097 bytes
-rw-r--r--doc/kpackage/uninstall.pngbin0 -> 24775 bytes
-rw-r--r--doc/ksysv/Makefile.am4
-rw-r--r--doc/ksysv/index.docbook1117
-rw-r--r--doc/kuser/Makefile.am4
-rw-r--r--doc/kuser/index.docbook273
-rw-r--r--doc/kuser/kuser.pngbin0 -> 15170 bytes
-rw-r--r--doc/lilo-config/Makefile.am4
-rw-r--r--doc/lilo-config/index.docbook177
-rw-r--r--kcron/AUTHORS2
-rw-r--r--kcron/COPYING340
-rw-r--r--kcron/ChangeLog66
-rw-r--r--kcron/Makefile.am111
-rw-r--r--kcron/README12
-rw-r--r--kcron/README.hacking8
-rw-r--r--kcron/README.translators109
-rw-r--r--kcron/TODO7
-rw-r--r--kcron/configure.in.in4
-rw-r--r--kcron/ctcron.cpp333
-rw-r--r--kcron/ctcron.h154
-rw-r--r--kcron/ctdom.cpp73
-rw-r--r--kcron/ctdom.h62
-rw-r--r--kcron/ctdow.cpp99
-rw-r--r--kcron/ctdow.h70
-rw-r--r--kcron/cthost.cpp117
-rw-r--r--kcron/cthost.h118
-rw-r--r--kcron/cthour.h50
-rw-r--r--kcron/cti18n.h27
-rw-r--r--kcron/ctminute.h50
-rw-r--r--kcron/ctmonth.cpp62
-rw-r--r--kcron/ctmonth.h63
-rw-r--r--kcron/cttask.cpp361
-rw-r--r--kcron/cttask.h104
-rw-r--r--kcron/ctunit.cpp319
-rw-r--r--kcron/ctunit.h158
-rw-r--r--kcron/ctvariable.cpp101
-rw-r--r--kcron/ctvariable.h82
-rw-r--r--kcron/hi16-app-kcron.pngbin0 -> 578 bytes
-rw-r--r--kcron/hi22-app-kcron.pngbin0 -> 1285 bytes
-rw-r--r--kcron/hi32-app-kcron.pngbin0 -> 880 bytes
-rw-r--r--kcron/kcron.desktop94
-rw-r--r--kcron/kcron.lsm14
-rw-r--r--kcron/kcronui.rc54
-rw-r--r--kcron/ktapp.cpp463
-rw-r--r--kcron/ktapp.h267
-rw-r--r--kcron/kticon.cpp115
-rw-r--r--kcron/kticon.h43
-rw-r--r--kcron/ktlistcron.cpp69
-rw-r--r--kcron/ktlistcron.h55
-rw-r--r--kcron/ktlistitem.cpp46
-rw-r--r--kcron/ktlistitem.h81
-rw-r--r--kcron/ktlisttask.cpp70
-rw-r--r--kcron/ktlisttask.h63
-rw-r--r--kcron/ktlisttasks.cpp99
-rw-r--r--kcron/ktlisttasks.h62
-rw-r--r--kcron/ktlistvar.cpp80
-rw-r--r--kcron/ktlistvar.h63
-rw-r--r--kcron/ktlistvars.cpp99
-rw-r--r--kcron/ktlistvars.h63
-rw-r--r--kcron/ktprint.cpp188
-rw-r--r--kcron/ktprint.h216
-rw-r--r--kcron/ktprintopt.cpp68
-rw-r--r--kcron/ktprintopt.h52
-rw-r--r--kcron/kttask.cpp900
-rw-r--r--kcron/kttask.h184
-rw-r--r--kcron/ktvariable.cpp152
-rw-r--r--kcron/ktvariable.h84
-rw-r--r--kcron/ktview.cpp576
-rw-r--r--kcron/ktview.h215
-rw-r--r--kcron/main.cpp47
-rw-r--r--kdat/Archive.cpp389
-rw-r--r--kdat/Archive.h184
-rw-r--r--kdat/ArchiveInfoWidget.cpp145
-rw-r--r--kdat/ArchiveInfoWidget.h62
-rw-r--r--kdat/BackupDlg.cpp432
-rw-r--r--kdat/BackupDlg.h108
-rw-r--r--kdat/BackupOptDlg.cpp100
-rw-r--r--kdat/BackupOptDlg.h99
-rw-r--r--kdat/BackupProfile.cpp293
-rw-r--r--kdat/BackupProfile.h198
-rw-r--r--kdat/BackupProfileInfoWidget.cpp209
-rw-r--r--kdat/BackupProfileInfoWidget.h62
-rw-r--r--kdat/BackupProfileManager.cpp112
-rw-r--r--kdat/BackupProfileManager.h120
-rw-r--r--kdat/BackupProfileWidget.cpp259
-rw-r--r--kdat/BackupProfileWidget.h148
-rw-r--r--kdat/CREDITS45
-rw-r--r--kdat/ErrorHandler.cpp114
-rw-r--r--kdat/File.cpp287
-rw-r--r--kdat/File.h201
-rw-r--r--kdat/FileInfoWidget.cpp173
-rw-r--r--kdat/FileInfoWidget.h58
-rw-r--r--kdat/FormatOptDlg.cpp142
-rw-r--r--kdat/FormatOptDlg.h70
-rw-r--r--kdat/ImageCache.cpp137
-rw-r--r--kdat/ImageCache.h150
-rw-r--r--kdat/IndexDlg.cpp355
-rw-r--r--kdat/IndexDlg.h92
-rw-r--r--kdat/InfoShellWidget.cpp43
-rw-r--r--kdat/InfoShellWidget.h49
-rw-r--r--kdat/KDat.kdoc643
-rw-r--r--kdat/KDatMainWindow.cpp1381
-rw-r--r--kdat/KDatMainWindow.h285
-rw-r--r--kdat/LoggerWidget.cpp79
-rw-r--r--kdat/LoggerWidget.h62
-rw-r--r--kdat/Makefile.am110
-rw-r--r--kdat/Node.cpp1585
-rw-r--r--kdat/Node.h1051
-rw-r--r--kdat/Options.cpp165
-rw-r--r--kdat/Options.h211
-rw-r--r--kdat/OptionsDlg.cpp126
-rw-r--r--kdat/OptionsDlg.h56
-rw-r--r--kdat/OptionsDlgWidget.ui385
-rw-r--r--kdat/OptionsDlgWidget.ui.h48
-rw-r--r--kdat/RELEASE_NOTES76
-rw-r--r--kdat/Range.cpp132
-rw-r--r--kdat/Range.h107
-rw-r--r--kdat/TODO225
-rw-r--r--kdat/Tape.cpp933
-rw-r--r--kdat/Tape.h156
-rw-r--r--kdat/TapeDrive.cpp642
-rw-r--r--kdat/TapeDrive.h247
-rw-r--r--kdat/TapeFileInfoWidget.cpp133
-rw-r--r--kdat/TapeFileInfoWidget.h59
-rw-r--r--kdat/TapeInfoWidget.cpp275
-rw-r--r--kdat/TapeInfoWidget.h71
-rw-r--r--kdat/TapeManager.cpp151
-rw-r--r--kdat/TapeManager.h154
-rw-r--r--kdat/TarParser.cpp117
-rw-r--r--kdat/TarParser.h207
-rw-r--r--kdat/Util.cpp71
-rw-r--r--kdat/Util.h47
-rw-r--r--kdat/VerifyDlg.cpp415
-rw-r--r--kdat/VerifyDlg.h94
-rw-r--r--kdat/VerifyOptDlg.cpp129
-rw-r--r--kdat/VerifyOptDlg.h66
-rw-r--r--kdat/configure.in.in10
-rw-r--r--kdat/kdat.desktop92
-rw-r--r--kdat/kdat.h42
-rw-r--r--kdat/ktreeview.cpp2074
-rw-r--r--kdat/ktreeview.h899
-rw-r--r--kdat/large-kdat.pngbin0 -> 1376 bytes
-rw-r--r--kdat/main.cpp97
-rw-r--r--kdat/pics/Makefile.am3
-rw-r--r--kdat/pics/cr16-app-kdat_archive.pngbin0 -> 325 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_backup.pngbin0 -> 525 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_eject.pngbin0 -> 373 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_mounted.pngbin0 -> 319 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_restore.pngbin0 -> 503 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_select_all.pngbin0 -> 219 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_select_none.pngbin0 -> 219 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_select_some.pngbin0 -> 443 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_unmounted.pngbin0 -> 279 bytes
-rw-r--r--kdat/pics/cr16-app-kdat_verify.pngbin0 -> 505 bytes
-rw-r--r--kdat/pics/cr32-app-kdat_backup.pngbin0 -> 1422 bytes
-rw-r--r--kdat/pics/cr32-app-kdat_restore.pngbin0 -> 1488 bytes
-rw-r--r--kdat/pics/cr32-app-kdat_verify.pngbin0 -> 1484 bytes
-rw-r--r--kdat/pics/hi16-app-kdat.pngbin0 -> 334 bytes
-rw-r--r--kdat/pics/hi22-app-kdat.pngbin0 -> 1054 bytes
-rw-r--r--kdat/pics/hi32-app-kdat.pngbin0 -> 1575 bytes
-rw-r--r--kdat/pics/hi48-app-kdat.pngbin0 -> 1376 bytes
-rw-r--r--kdat/pics/lo16-app-kdat.pngbin0 -> 334 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_archive.pngbin0 -> 325 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_backup.pngbin0 -> 525 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_eject.pngbin0 -> 373 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_mounted.pngbin0 -> 319 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_restore.pngbin0 -> 503 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_select_all.pngbin0 -> 219 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_select_none.pngbin0 -> 219 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_select_some.pngbin0 -> 443 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_unmounted.pngbin0 -> 279 bytes
-rw-r--r--kdat/pics/lo16-app-kdat_verify.pngbin0 -> 505 bytes
-rw-r--r--kdat/pics/lo32-app-kdat.pngbin0 -> 474 bytes
-rw-r--r--kdeadmin.lsm11
-rw-r--r--kfile-plugins/Makefile.am1
-rw-r--r--kfile-plugins/deb/Makefile.am22
-rw-r--r--kfile-plugins/deb/kfile_deb.cpp130
-rw-r--r--kfile-plugins/deb/kfile_deb.desktop69
-rw-r--r--kfile-plugins/deb/kfile_deb.h38
-rw-r--r--kfile-plugins/rpm/Makefile.am22
-rw-r--r--kfile-plugins/rpm/kfile_rpm.cpp152
-rw-r--r--kfile-plugins/rpm/kfile_rpm.desktop69
-rw-r--r--kfile-plugins/rpm/kfile_rpm.h53
-rw-r--r--knetworkconf/AUTHORS1
-rw-r--r--knetworkconf/COPYING340
-rw-r--r--knetworkconf/ChangeLog54
-rw-r--r--knetworkconf/Doxyfile232
-rw-r--r--knetworkconf/INSTALL167
-rw-r--r--knetworkconf/LEAME83
-rw-r--r--knetworkconf/Makefile.am1
-rw-r--r--knetworkconf/README74
-rw-r--r--knetworkconf/TODO5
-rw-r--r--knetworkconf/backends/AUTHORS5
-rw-r--r--knetworkconf/backends/Makefile.am29
-rw-r--r--knetworkconf/backends/NEWS325
-rw-r--r--knetworkconf/backends/README9
-rw-r--r--knetworkconf/backends/README.NEW_PLATFORMS5
-rw-r--r--knetworkconf/backends/configure.in.in15
-rw-r--r--knetworkconf/backends/debug.pl.in222
-rw-r--r--knetworkconf/backends/file.pl.in934
-rw-r--r--knetworkconf/backends/general.pl.in644
-rwxr-xr-xknetworkconf/backends/guess_system.sh1121
-rwxr-xr-xknetworkconf/backends/mkinstalldirs111
-rwxr-xr-xknetworkconf/backends/network-conf.in639
-rw-r--r--knetworkconf/backends/network.pl.in6605
-rw-r--r--knetworkconf/backends/parse.pl.in1828
-rw-r--r--knetworkconf/backends/platform.pl.in685
-rw-r--r--knetworkconf/backends/process.pl.in54
-rw-r--r--knetworkconf/backends/replace.pl.in1770
-rw-r--r--knetworkconf/backends/report.pl.in366
-rw-r--r--knetworkconf/backends/service-list.pl.in337
-rw-r--r--knetworkconf/backends/service.pl.in2119
-rw-r--r--knetworkconf/backends/system-tools-backends.pc.in14
-rwxr-xr-xknetworkconf/backends/type1inst1387
-rw-r--r--knetworkconf/backends/util.pl.in463
-rw-r--r--knetworkconf/backends/xml.pl.in1012
-rw-r--r--knetworkconf/config.h.in204
-rw-r--r--knetworkconf/knetworkconf-mdk.spec159
-rw-r--r--knetworkconf/knetworkconf.lsm14
-rw-r--r--knetworkconf/knetworkconf.spec110
-rw-r--r--knetworkconf/knetworkconf/Makefile.am41
-rw-r--r--knetworkconf/knetworkconf/hi16-app-knetworkconf.pngbin0 -> 883 bytes
-rw-r--r--knetworkconf/knetworkconf/hi22-app-knetworkconf.pngbin0 -> 1058 bytes
-rw-r--r--knetworkconf/knetworkconf/hi32-app-knetworkconf.pngbin0 -> 2535 bytes
-rw-r--r--knetworkconf/knetworkconf/kadddevicecontainer.cpp205
-rw-r--r--knetworkconf/knetworkconf/kadddevicecontainer.h83
-rw-r--r--knetworkconf/knetworkconf/kadddevicedlg.ui411
-rw-r--r--knetworkconf/knetworkconf/kadddevicedlg.ui.h13
-rw-r--r--knetworkconf/knetworkconf/kadddevicedlgextension.ui156
-rw-r--r--knetworkconf/knetworkconf/kadddevicedlgextension.ui.h18
-rw-r--r--knetworkconf/knetworkconf/kadddevicewifiext.ui96
-rw-r--r--knetworkconf/knetworkconf/kadddnsserverdlg.ui166
-rw-r--r--knetworkconf/knetworkconf/kadddnsserverdlg.ui.h64
-rw-r--r--knetworkconf/knetworkconf/kaddknownhostdlg.ui303
-rw-r--r--knetworkconf/knetworkconf/kaddknownhostdlg.ui.h102
-rw-r--r--knetworkconf/knetworkconf/kaddressvalidator.cpp240
-rw-r--r--knetworkconf/knetworkconf/kaddressvalidator.h116
-rw-r--r--knetworkconf/knetworkconf/kcm_knetworkconfmodule1
-rw-r--r--knetworkconf/knetworkconf/kcm_knetworkconfmodule.desktop178
-rw-r--r--knetworkconf/knetworkconf/kdetectdistrodlg.ui73
-rw-r--r--knetworkconf/knetworkconf/kdnsinfo.cpp61
-rw-r--r--knetworkconf/knetworkconf/kdnsinfo.h55
-rw-r--r--knetworkconf/knetworkconf/kinterfaceupdowndlg.ui104
-rw-r--r--knetworkconf/knetworkconf/kinterfaceupdowndlg.ui.h16
-rw-r--r--knetworkconf/knetworkconf/kknownhostinfo.cpp42
-rw-r--r--knetworkconf/knetworkconf/kknownhostinfo.h44
-rw-r--r--knetworkconf/knetworkconf/knetworkconf.cpp1186
-rw-r--r--knetworkconf/knetworkconf/knetworkconf.desktop128
-rw-r--r--knetworkconf/knetworkconf/knetworkconf.h211
-rw-r--r--knetworkconf/knetworkconf/knetworkconfdlg.ui1101
-rw-r--r--knetworkconf/knetworkconf/knetworkconfdlg.ui.h168
-rw-r--r--knetworkconf/knetworkconf/knetworkconfiface.h34
-rw-r--r--knetworkconf/knetworkconf/knetworkconfigparser.cpp1239
-rw-r--r--knetworkconf/knetworkconf/knetworkconfigparser.h181
-rw-r--r--knetworkconf/knetworkconf/knetworkconfmodule.cpp118
-rw-r--r--knetworkconf/knetworkconf/knetworkconfmodule.h49
-rw-r--r--knetworkconf/knetworkconf/knetworkinfo.cpp76
-rw-r--r--knetworkconf/knetworkconf/knetworkinfo.h68
-rw-r--r--knetworkconf/knetworkconf/knetworkinterface.cpp104
-rw-r--r--knetworkconf/knetworkconf/knetworkinterface.h83
-rw-r--r--knetworkconf/knetworkconf/kprofileslistviewtooltip.cpp16
-rw-r--r--knetworkconf/knetworkconf/kprofileslistviewtooltip.h139
-rw-r--r--knetworkconf/knetworkconf/kreloadnetworkdlg.ui137
-rw-r--r--knetworkconf/knetworkconf/kroutinginfo.cpp60
-rw-r--r--knetworkconf/knetworkconf/kroutinginfo.h58
-rw-r--r--knetworkconf/knetworkconf/kselectdistrodlg.ui142
-rw-r--r--knetworkconf/knetworkconf/kwirelessinterface.cpp55
-rw-r--r--knetworkconf/knetworkconf/kwirelessinterface.h48
-rw-r--r--knetworkconf/knetworkconf/main.cpp49
-rw-r--r--knetworkconf/knetworkconf/version.h6
-rw-r--r--knetworkconf/pasosRelease.txt14
-rw-r--r--knetworkconf/pixmaps/Makefile.am7
-rw-r--r--knetworkconf/pixmaps/ark.pngbin0 -> 802 bytes
-rw-r--r--knetworkconf/pixmaps/blackpanther.pngbin0 -> 944 bytes
-rw-r--r--knetworkconf/pixmaps/conectiva.pngbin0 -> 1161 bytes
-rw-r--r--knetworkconf/pixmaps/debian.pngbin0 -> 608 bytes
-rw-r--r--knetworkconf/pixmaps/fedora.pngbin0 -> 698 bytes
-rw-r--r--knetworkconf/pixmaps/freebsd.pngbin0 -> 1106 bytes
-rw-r--r--knetworkconf/pixmaps/gentoo.pngbin0 -> 1116 bytes
-rw-r--r--knetworkconf/pixmaps/hi22-action-network_connected_lan_knc.pngbin0 -> 850 bytes
-rw-r--r--knetworkconf/pixmaps/hi22-action-network_disconnected_lan.pngbin0 -> 746 bytes
-rw-r--r--knetworkconf/pixmaps/hi22-action-network_disconnected_wlan.pngbin0 -> 473 bytes
-rw-r--r--knetworkconf/pixmaps/hi22-action-network_traffic_wlan.pngbin0 -> 1153 bytes
-rw-r--r--knetworkconf/pixmaps/kubuntu.pngbin0 -> 765 bytes
-rw-r--r--knetworkconf/pixmaps/mandriva.pngbin0 -> 853 bytes
-rw-r--r--knetworkconf/pixmaps/openna.pngbin0 -> 743 bytes
-rw-r--r--knetworkconf/pixmaps/pld.pngbin0 -> 682 bytes
-rw-r--r--knetworkconf/pixmaps/redhat.pngbin0 -> 443 bytes
-rw-r--r--knetworkconf/pixmaps/rpath.pngbin0 -> 1170 bytes
-rw-r--r--knetworkconf/pixmaps/slackware.pngbin0 -> 1062 bytes
-rw-r--r--knetworkconf/pixmaps/suse.pngbin0 -> 793 bytes
-rw-r--r--knetworkconf/pixmaps/turbolinux.pngbin0 -> 749 bytes
-rw-r--r--knetworkconf/pixmaps/vine.pngbin0 -> 944 bytes
-rw-r--r--knetworkconf/pixmaps/yoper.pngbin0 -> 1159 bytes
-rwxr-xr-xknetworkconf/update_backends.sh42
-rw-r--r--kpackage/CHANGES282
-rw-r--r--kpackage/Makefile.am36
-rw-r--r--kpackage/README11
-rw-r--r--kpackage/cache.cpp229
-rw-r--r--kpackage/cache.h114
-rw-r--r--kpackage/debAptInterface.cpp535
-rw-r--r--kpackage/debAptInterface.h84
-rw-r--r--kpackage/debDpkgInterface.cpp164
-rw-r--r--kpackage/debDpkgInterface.h65
-rw-r--r--kpackage/debInterface.cpp596
-rw-r--r--kpackage/debInterface.h112
-rw-r--r--kpackage/fbsdInterface.cpp641
-rw-r--r--kpackage/fbsdInterface.h158
-rw-r--r--kpackage/findf.cpp228
-rw-r--r--kpackage/findf.h91
-rw-r--r--kpackage/gentooInterface.cpp466
-rw-r--r--kpackage/gentooInterface.h68
-rw-r--r--kpackage/icon/Makefile.am1
-rw-r--r--kpackage/icon/hi128-app-kpackage.pngbin0 -> 16495 bytes
-rw-r--r--kpackage/icon/hi16-app-kpackage.pngbin0 -> 885 bytes
-rw-r--r--kpackage/icon/hi22-app-kpackage.pngbin0 -> 1545 bytes
-rw-r--r--kpackage/icon/hi32-app-kpackage.pngbin0 -> 2547 bytes
-rw-r--r--kpackage/icon/hi48-app-kpackage.pngbin0 -> 4630 bytes
-rw-r--r--kpackage/icon/hi64-app-kpackage.pngbin0 -> 6757 bytes
-rw-r--r--kpackage/kio.cpp124
-rw-r--r--kpackage/kio.h75
-rw-r--r--kpackage/kissInterface.cpp422
-rw-r--r--kpackage/kissInterface.h87
-rw-r--r--kpackage/kpPty.cpp446
-rw-r--r--kpackage/kpPty.h106
-rw-r--r--kpackage/kpTerm.cpp234
-rw-r--r--kpackage/kpTerm.h90
-rw-r--r--kpackage/kpackage.cpp759
-rw-r--r--kpackage/kpackage.desktop101
-rw-r--r--kpackage/kpackage.h336
-rw-r--r--kpackage/kpackageui.rc60
-rw-r--r--kpackage/kplview.cpp667
-rw-r--r--kpackage/kplview.h191
-rw-r--r--kpackage/main.cpp159
-rw-r--r--kpackage/managementWidget.cpp699
-rw-r--r--kpackage/managementWidget.h227
-rw-r--r--kpackage/mini-icon/cr16-mime-debfile.pngbin0 -> 594 bytes
-rw-r--r--kpackage/mini-icon/cr16-mime-rpmfile.pngbin0 -> 567 bytes
-rw-r--r--kpackage/options.cpp469
-rw-r--r--kpackage/options.h181
-rw-r--r--kpackage/packageDisplay.cpp439
-rw-r--r--kpackage/packageDisplay.h164
-rw-r--r--kpackage/packageInfo.cpp635
-rw-r--r--kpackage/packageInfo.h165
-rw-r--r--kpackage/packageProperties.cpp278
-rw-r--r--kpackage/packageProperties.h103
-rw-r--r--kpackage/pics/Makefile.am6
-rw-r--r--kpackage/pics/bnew.pngbin0 -> 174 bytes
-rw-r--r--kpackage/pics/bsd.pngbin0 -> 241 bytes
-rw-r--r--kpackage/pics/bupdated.pngbin0 -> 154 bytes
-rw-r--r--kpackage/pics/cross.pngbin0 -> 817 bytes
-rw-r--r--kpackage/pics/dbad.pngbin0 -> 162 bytes
-rw-r--r--kpackage/pics/deb.pngbin0 -> 358 bytes
-rw-r--r--kpackage/pics/dnew.pngbin0 -> 176 bytes
-rw-r--r--kpackage/pics/dupdated.pngbin0 -> 159 bytes
-rw-r--r--kpackage/pics/kiss.pngbin0 -> 379 bytes
-rw-r--r--kpackage/pics/knew.pngbin0 -> 183 bytes
-rw-r--r--kpackage/pics/kupdated.pngbin0 -> 165 bytes
-rw-r--r--kpackage/pics/noball.pngbin0 -> 126 bytes
-rw-r--r--kpackage/pics/ptick.pngbin0 -> 578 bytes
-rw-r--r--kpackage/pics/question.pngbin0 -> 165 bytes
-rw-r--r--kpackage/pics/rnew.pngbin0 -> 173 bytes
-rw-r--r--kpackage/pics/rpm.pngbin0 -> 325 bytes
-rw-r--r--kpackage/pics/rupdated.pngbin0 -> 160 bytes
-rw-r--r--kpackage/pics/slack.pngbin0 -> 301 bytes
-rw-r--r--kpackage/pics/snew.pngbin0 -> 171 bytes
-rw-r--r--kpackage/pics/supdated.pngbin0 -> 154 bytes
-rw-r--r--kpackage/pics/tick.pngbin0 -> 578 bytes
-rw-r--r--kpackage/pkgInterface.cpp435
-rw-r--r--kpackage/pkgInterface.h220
-rw-r--r--kpackage/pkgOptions.cpp372
-rw-r--r--kpackage/pkgOptions.h151
-rw-r--r--kpackage/procbuf.cpp165
-rw-r--r--kpackage/procbuf.h68
-rw-r--r--kpackage/rpmInterface.cpp631
-rw-r--r--kpackage/rpmInterface.h111
-rw-r--r--kpackage/search.cpp115
-rw-r--r--kpackage/search.h69
-rw-r--r--kpackage/slackInterface.cpp691
-rw-r--r--kpackage/slackInterface.h92
-rw-r--r--kpackage/toolbar/Makefile.am2
-rw-r--r--kpackage/toolbar/ftin.xpm24
-rw-r--r--kpackage/toolbar/ftout.xpm24
-rw-r--r--kpackage/updateLoc.cpp761
-rw-r--r--kpackage/updateLoc.h326
-rw-r--r--kpackage/utils.cpp63
-rw-r--r--kpackage/utils.h39
-rw-r--r--ksysv/AUTHORS17
-rw-r--r--ksysv/ActionList.cpp217
-rw-r--r--ksysv/ActionList.h131
-rw-r--r--ksysv/Data.cpp190
-rw-r--r--ksysv/Data.h79
-rw-r--r--ksysv/IOCore.cpp291
-rw-r--r--ksysv/IOCore.h64
-rw-r--r--ksysv/Makefile.am84
-rw-r--r--ksysv/OldView.cpp1150
-rw-r--r--ksysv/OldView.h179
-rw-r--r--ksysv/PreferencesDialog.cpp291
-rw-r--r--ksysv/PreferencesDialog.h68
-rw-r--r--ksysv/Properties.cpp209
-rw-r--r--ksysv/Properties.h110
-rw-r--r--ksysv/README33
-rw-r--r--ksysv/RunlevelAuthIcon.cpp149
-rw-r--r--ksysv/RunlevelAuthIcon.h49
-rw-r--r--ksysv/ServiceDlg.cpp123
-rw-r--r--ksysv/ServiceDlg.h56
-rw-r--r--ksysv/SpinBox.cpp87
-rw-r--r--ksysv/SpinBox.h32
-rw-r--r--ksysv/TODO7
-rw-r--r--ksysv/TopWidget.cpp1109
-rw-r--r--ksysv/TopWidget.h153
-rw-r--r--ksysv/configure.in.in11
-rw-r--r--ksysv/configwizard.ui626
-rwxr-xr-xksysv/genui.sh25
-rw-r--r--ksysv/hi16-app-ksysv.pngbin0 -> 663 bytes
-rw-r--r--ksysv/hi22-app-ksysv.pngbin0 -> 1033 bytes
-rw-r--r--ksysv/hi32-app-ksysv.pngbin0 -> 1542 bytes
-rw-r--r--ksysv/hi48-app-ksysv.pngbin0 -> 2614 bytes
-rw-r--r--ksysv/kbusymanager.cpp94
-rw-r--r--ksysv/kbusymanager.h49
-rw-r--r--ksysv/kdltooltip.cpp95
-rw-r--r--ksysv/kdltooltip.h43
-rw-r--r--ksysv/kscroller.cpp191
-rw-r--r--ksysv/kscroller.h150
-rw-r--r--ksysv/ksv_conf.cpp224
-rw-r--r--ksysv/ksv_conf.h143
-rw-r--r--ksysv/ksv_core.cpp186
-rw-r--r--ksysv/ksv_core.h58
-rw-r--r--ksysv/ksv_service.cpp76
-rw-r--r--ksysv/ksv_service.h99
-rw-r--r--ksysv/ksvapplication.cpp20
-rw-r--r--ksysv/ksvapplication.h19
-rw-r--r--ksysv/ksvconfigwizard.cpp150
-rw-r--r--ksysv/ksvconfigwizard.h66
-rw-r--r--ksysv/ksvdrag.cpp102
-rw-r--r--ksysv/ksvdrag.h36
-rw-r--r--ksysv/ksvdraglist.cpp802
-rw-r--r--ksysv/ksvdraglist.h277
-rw-r--r--ksysv/ksvlookandfeel.cpp93
-rw-r--r--ksysv/ksvlookandfeel.h39
-rw-r--r--ksysv/ksvmiscconfig.cpp64
-rw-r--r--ksysv/ksvmiscconfig.h47
-rw-r--r--ksysv/ksvpathconfig.cpp75
-rw-r--r--ksysv/ksvpathconfig.h49
-rw-r--r--ksysv/ksysv.desktop72
-rw-r--r--ksysv/ksysvui.rc96
-rw-r--r--ksysv/leveldb.c353
-rw-r--r--ksysv/leveldb.h50
-rw-r--r--ksysv/lookandfeelconfig.ui500
-rw-r--r--ksysv/main.cpp103
-rw-r--r--ksysv/miscconfig.ui186
-rw-r--r--ksysv/pathconfig.ui294
-rw-r--r--ksysv/pics/Makefile.am7
-rw-r--r--ksysv/pics/ksysv_locked.pngbin0 -> 928 bytes
-rw-r--r--ksysv/pics/ksysv_restart.pngbin0 -> 157 bytes
-rw-r--r--ksysv/pics/ksysv_start.pngbin0 -> 213 bytes
-rw-r--r--ksysv/pics/ksysv_stop.pngbin0 -> 216 bytes
-rw-r--r--ksysv/pics/ksysv_unlocked.pngbin0 -> 1009 bytes
-rw-r--r--ksysv/pics/stop.pngbin0 -> 821 bytes
-rw-r--r--ksysv/toolbar/Makefile.am1
-rw-r--r--ksysv/toolbar/cr16-action-toggle_log.pngbin0 -> 1111 bytes
-rw-r--r--ksysv/trash.cpp141
-rw-r--r--ksysv/trash.h66
-rw-r--r--ksysv/version.h32
-rw-r--r--ksysv/x-ksysv-log.desktop68
-rw-r--r--ksysv/x-ksysv.desktop78
-rw-r--r--kuser/AUTHORS2
-rw-r--r--kuser/ChangeLog47
-rw-r--r--kuser/Makefile.am60
-rw-r--r--kuser/README19
-rw-r--r--kuser/THANKS20
-rw-r--r--kuser/TODO29
-rw-r--r--kuser/addUser.cpp158
-rw-r--r--kuser/addUser.h51
-rw-r--r--kuser/configure.in.in64
-rw-r--r--kuser/delUser.cpp41
-rw-r--r--kuser/delUser.h45
-rw-r--r--kuser/editDefaults.cpp183
-rw-r--r--kuser/editDefaults.h59
-rw-r--r--kuser/editGroup.cpp329
-rw-r--r--kuser/editGroup.h70
-rw-r--r--kuser/filessettings.ui225
-rw-r--r--kuser/generalsettings.ui240
-rw-r--r--kuser/globals.h66
-rw-r--r--kuser/icon/Makefile.am3
-rw-r--r--kuser/icon/hi128-app-kuser.pngbin0 -> 15977 bytes
-rw-r--r--kuser/icon/hi16-app-kuser.pngbin0 -> 868 bytes
-rw-r--r--kuser/icon/hi22-app-kuser.pngbin0 -> 1413 bytes
-rw-r--r--kuser/icon/hi32-app-kuser.pngbin0 -> 2280 bytes
-rw-r--r--kuser/icon/hi48-app-kuser.pngbin0 -> 4151 bytes
-rw-r--r--kuser/icon/hi64-app-kuser.pngbin0 -> 6154 bytes
-rw-r--r--kuser/kglobal.cpp86
-rw-r--r--kuser/kglobal_.h48
-rw-r--r--kuser/kgroup.cpp328
-rw-r--r--kuser/kgroup.h150
-rw-r--r--kuser/kgroupfiles.cpp402
-rw-r--r--kuser/kgroupfiles.h53
-rw-r--r--kuser/kgroupldap.cpp322
-rw-r--r--kuser/kgroupldap.h66
-rw-r--r--kuser/kgroupsystem.cpp70
-rw-r--r--kuser/kgroupsystem.h42
-rw-r--r--kuser/kgroupvw.cpp145
-rw-r--r--kuser/kgroupvw.h57
-rw-r--r--kuser/kuser.cpp1053
-rw-r--r--kuser/kuser.desktop104
-rw-r--r--kuser/kuser.h309
-rw-r--r--kuser/kuser.kcfg318
-rw-r--r--kuser/kuserfiles.cpp620
-rw-r--r--kuser/kuserfiles.h61
-rw-r--r--kuser/kuserldap.cpp660
-rw-r--r--kuser/kuserldap.h67
-rw-r--r--kuser/kuserprefs.kcfgc20
-rw-r--r--kuser/kusersystem.cpp143
-rw-r--r--kuser/kusersystem.h46
-rw-r--r--kuser/kuserui.rc36
-rw-r--r--kuser/kuservw.cpp145
-rw-r--r--kuser/kuservw.h58
-rw-r--r--kuser/ldapsamba.ui366
-rw-r--r--kuser/ldapsettings.ui278
-rw-r--r--kuser/main.cpp69
-rw-r--r--kuser/mainView.cpp526
-rw-r--r--kuser/mainView.h80
-rw-r--r--kuser/mainWidget.cpp201
-rw-r--r--kuser/mainWidget.h56
-rw-r--r--kuser/misc.cpp172
-rw-r--r--kuser/misc.h45
-rw-r--r--kuser/passwordpolicy.ui244
-rw-r--r--kuser/pic/Makefile.am9
-rw-r--r--kuser/pic/group.pngbin0 -> 481 bytes
-rw-r--r--kuser/pic/user.pngbin0 -> 359 bytes
-rw-r--r--kuser/propdlg.cpp991
-rw-r--r--kuser/propdlg.h151
-rw-r--r--kuser/pwddlg.cpp88
-rw-r--r--kuser/pwddlg.h44
-rw-r--r--kuser/selectconn.cpp153
-rw-r--r--kuser/selectconn.h43
-rw-r--r--kuser/sha1.cpp179
-rw-r--r--kuser/sha1.h36
-rw-r--r--kuser/sid.cpp123
-rw-r--r--kuser/sid.h54
-rw-r--r--kuser/stamp-h.in1
-rw-r--r--kuser/toolbar/Makefile.am2
-rw-r--r--kuser/toolbar/cr22-action-add_group.pngbin0 -> 533 bytes
-rw-r--r--kuser/toolbar/cr22-action-add_user.pngbin0 -> 467 bytes
-rw-r--r--kuser/toolbar/cr22-action-delete_group.pngbin0 -> 531 bytes
-rw-r--r--kuser/toolbar/cr22-action-delete_user.pngbin0 -> 481 bytes
-rw-r--r--kuser/toolbar/cr22-action-edit_group.pngbin0 -> 542 bytes
-rw-r--r--kuser/toolbar/cr22-action-edit_user.pngbin0 -> 425 bytes
-rw-r--r--lilo-config/COPYING346
-rw-r--r--lilo-config/Makefile.am5
-rw-r--r--lilo-config/README9
-rw-r--r--lilo-config/common/Config.cc66
-rw-r--r--lilo-config/common/Config.h40
-rw-r--r--lilo-config/common/Disks.cc294
-rw-r--r--lilo-config/common/Disks.h49
-rw-r--r--lilo-config/common/Files.cc70
-rw-r--r--lilo-config/common/Files.h47
-rw-r--r--lilo-config/common/Makefile.am11
-rw-r--r--lilo-config/common/String.cc437
-rw-r--r--lilo-config/common/String.h96
-rw-r--r--lilo-config/common/lilo.cc585
-rw-r--r--lilo-config/common/lilo.h77
-rw-r--r--lilo-config/common/tests/Makefile.am9
-rw-r--r--lilo-config/common/tests/String.cc77
-rw-r--r--lilo-config/configure.in.in5
-rw-r--r--lilo-config/kde-qt-common/EditWidget.cpp81
-rw-r--r--lilo-config/kde-qt-common/EditWidget.h92
-rw-r--r--lilo-config/kde-qt-common/Makefile.am14
-rw-r--r--lilo-config/kde-qt-common/expert.cpp63
-rw-r--r--lilo-config/kde-qt-common/expert.h53
-rw-r--r--lilo-config/kde-qt-common/general.cpp229
-rw-r--r--lilo-config/kde-qt-common/general.h62
-rw-r--r--lilo-config/kde-qt-common/images.cpp334
-rw-r--r--lilo-config/kde-qt-common/images.h82
-rw-r--r--lilo-config/kde-qt-common/mainwidget.cpp107
-rw-r--r--lilo-config/kde-qt-common/mainwidget.h60
-rw-r--r--lilo-config/kde-qt-common/ui.h77
-rw-r--r--lilo-config/kde/Details.cpp134
-rw-r--r--lilo-config/kde/Details.h61
-rw-r--r--lilo-config/kde/InputBox.cpp43
-rw-r--r--lilo-config/kde/InputBox.h50
-rw-r--r--lilo-config/kde/Makefile.am13
-rw-r--r--lilo-config/kde/kcontrol.cpp87
-rw-r--r--lilo-config/kde/kcontrol.h54
-rw-r--r--lilo-config/kde/lilo.desktop212
-rw-r--r--lilo-config/qt/Details.cpp144
-rw-r--r--lilo-config/qt/Details.h61
-rw-r--r--lilo-config/qt/InputBox.cpp56
-rw-r--r--lilo-config/qt/InputBox.h49
-rw-r--r--lilo-config/qt/Makefile.am21
-rw-r--r--lilo-config/qt/configure.in.in4
-rw-r--r--lilo-config/qt/standalone.cpp126
-rw-r--r--lilo-config/qt/standalone.h64
-rw-r--r--secpolicy/Makefile.am14
-rw-r--r--secpolicy/main.cpp50
-rw-r--r--secpolicy/pamview.cpp113
-rw-r--r--secpolicy/pamview.h49
-rw-r--r--secpolicy/ppitem.cpp44
-rw-r--r--secpolicy/ppitem.h40
-rw-r--r--secpolicy/secpolicywin.cpp64
-rw-r--r--secpolicy/secpolicywin.h45
648 files changed, 106322 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..369e989
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+
+Look in the subdirs to get info about the authors.
+
+The package is maintained by Bernhard Rosenkraenzer <bero@redhat.de>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5185fd3
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,346 @@
+NOTE! The GPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to (the kde programs) are copyrighted
+by the authors who actually wrote it.
+
+---------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYING-DOCS b/COPYING-DOCS
new file mode 100644
index 0000000..4a0fe1c
--- /dev/null
+++ b/COPYING-DOCS
@@ -0,0 +1,397 @@
+ GNU Free Documentation License
+ Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject. (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..f8bad0c
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,176 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/kde/bin', `/usr/local/kde/lib', etc. You can specify an
+installation prefix other than `/usr/local/kde' by giving `configure'
+the option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/Makefile.am.in b/Makefile.am.in
new file mode 100644
index 0000000..d84a4b6
--- /dev/null
+++ b/Makefile.am.in
@@ -0,0 +1,7 @@
+AUTOMAKE_OPTIONS = foreign 1.6.1
+DISTCLEANFILES = inst-apps
+
+MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 SUBDIRS
+
+include admin/deps.am
+
diff --git a/Makefile.cvs b/Makefile.cvs
new file mode 100644
index 0000000..d5c4a7b
--- /dev/null
+++ b/Makefile.cvs
@@ -0,0 +1,15 @@
+
+all:
+ @echo "This Makefile is only for the CVS repository"
+ @echo "This will be deleted before making the distribution"
+ @echo ""
+ @if test ! -d admin; then \
+ echo "Please recheckout this module!" ;\
+ echo "for cvs: use checkout once and after that update again" ;\
+ echo "for cvsup: checkout kde-common from cvsup and" ;\
+ echo " link kde-common/admin to ./admin" ;\
+ exit 1 ;\
+ fi
+ $(MAKE) -f admin/Makefile.common cvs
+
+.SILENT:
diff --git a/README b/README
new file mode 100644
index 0000000..d0f858a
--- /dev/null
+++ b/README
@@ -0,0 +1,79 @@
+In this file:
+
+* About kdeadmin
+* Common Mistakes
+* Debugging
+* More Info
+
+About kdeadmin
+--------------
+The kdeadmin package contains packages that usually only a system
+administrator might need:
+
+* debian
+ Files needed to create Debian packages.
+
+* doc
+ XML based documentation for the programs
+
+* kcmlinuz
+ Linux Kernel configurator
+
+* kcron
+ Editor for the cron command scheduler.
+
+* kdat
+ Tape backup tool.
+
+* kfile-plugins
+ Make Konquerer display additional info on about *.dep and *.rpm files.
+
+* kpackage
+ Manager for DEB, RPM and similar software packages.
+
+* ksysv
+ An editor for System V startup schemes.
+
+* kuser
+ An user manager.
+
+* kwuftpd
+ Front end to the wu-ftpd FTP daemon.
+
+* kxconfig
+ Configure X-Windows display properties.
+
+* lilo-config
+ A plugin for KControl to manage the Linux boot loader LILO.
+
+* secpolicy
+ A program to display PAM security policies.
+
+
+Common Mistakes
+---------------
+If configure claims Qt cannot be found, have a look at ftp://ftp.trolltech.com
+and download the latest Qt 3.3.x release.
+
+
+Debugging
+---------
+You can use --enable-debug with the configure script, if you want to have
+debug code in your KDE apps and libs. I recommend to do this, since this
+is alpha software and this makes debugging things a whole lot easier.
+
+
+More Info
+---------
+You can use --without-shadow, if you do not want to have shadow support.
+
+You can use --without-quota, if you do not want to have quota support.
+
+Please direct any bug reports to our bug list by visiting
+http://bugs.kde.org.
+
+If you have problems compiling and installing this package, contact
+me at bero@redhat.de
+
+General KDE discussions should go to the KDE mailing list (kde@kde.org).
+
diff --git a/configure.in.in b/configure.in.in
new file mode 100644
index 0000000..34e9d1d
--- /dev/null
+++ b/configure.in.in
@@ -0,0 +1,10 @@
+#MIN_CONFIG
+KDE_ENABLE_HIDDEN_VISIBILITY
+AC_CHECK_SETENV
+AC_CHECK_UNSETENV
+
+CXXFLAGS="$CXXFLAGS $KDE_DEFAULT_CXXFLAGS"
+
+AC_CHECK_HEADERS(sys/stropts.h stropts.h)
+AC_CHECK_HEADERS(sys/time.h)
+AC_HEADER_TIME
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..6812bd2
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,5 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+SUBDIRS = $(AUTODIRS)
+
diff --git a/doc/kcron/Makefile.am b/doc/kcron/Makefile.am
new file mode 100644
index 0000000..1a8064c
--- /dev/null
+++ b/doc/kcron/Makefile.am
@@ -0,0 +1,2 @@
+KDE_LANG = en
+KDE_DOCS = AUTO
diff --git a/doc/kcron/index.docbook b/doc/kcron/index.docbook
new file mode 100644
index 0000000..5ff2e14
--- /dev/null
+++ b/doc/kcron/index.docbook
@@ -0,0 +1,900 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN"
+"dtd/kdex.dtd" [
+ <!ENTITY kappname "&kcron;">
+ <!ENTITY package "kdeadmin">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+ <!ENTITY % addindex "IGNORE">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+
+<title>The &kcron; Handbook</title>
+
+<authorgroup>
+
+<author>
+<firstname>Morgan</firstname>
+<othername>N.</othername>
+<surname>Sandquist</surname>
+<affiliation><address><email>morgan@pipeline.com</email></address>
+</affiliation>
+</author>
+
+<othercredit role="developer">
+<firstname>Gary</firstname>
+<surname>Meyer</surname>
+<affiliation><address><email>gary@meyer.net</email></address>
+</affiliation>
+<contrib>Developer</contrib>
+</othercredit>
+
+<othercredit role="reviewer">
+<firstname>Lauri</firstname>
+<surname>Watts</surname>
+<affiliation><address><email>lauri@kde.org</email></address>
+</affiliation>
+<contrib>Reviewer</contrib>
+</othercredit>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>2000</year>
+<holder>Morgan N. Sandquist</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2003-09-16</date>
+<releaseinfo>3.1.91</releaseinfo>
+
+<abstract><para>&kcron; is an application that schedules programs to be
+run.</para></abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kdeadmin</keyword>
+<keyword>KCron</keyword>
+<keyword>cron</keyword>
+<keyword>crontab</keyword>
+<keyword>scheduler</keyword>
+</keywordset>
+
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&kcron; is an application for scheduling programs to run in the
+background. It is a graphical user interface to <command>cron</command>,
+the &UNIX; system scheduler.</para>
+
+</chapter>
+
+<chapter id="using-kcron">
+<title>Using &kcron;</title>
+
+<important><para>Don't forget to tell your system to start the
+<filename>crond</filename> cron daemon first, or &kcron; won't
+work.</para></important>
+
+<sect1 id="kcron-start-up">
+<title>&kcron; Start Up</title>
+
+<para>When &kcron; starts you will see a summarized view of existing
+scheduled tasks and associated environment variables. If you are running
+as the root user, you will see these items for all users on the computer
+as well as the system scheduled tasks. Each of the folders can be
+expanded and contracted.</para>
+
+<screenshot>
+<screeninfo>&kcron; at start up.</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="kcronstart.png" format="PNG"/></imageobject>
+<textobject><phrase>&kcron; at start up.</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<sect2>
+<title>Scheduled Tasks</title>
+
+<para>Scheduled tasks appear under a <guilabel>Tasks</guilabel>
+folder. For each scheduled task, the following are displayed:</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Name</guilabel></term>
+<listitem><para>Name to identify the scheduled task.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Value</guilabel></term>
+<listitem><para>Program file and parameters.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Description</guilabel></term>
+<listitem><para>Natural language description of scheduled
+task.</para></listitem>
+</varlistentry>
+</variablelist>
+
+<para>If a task has been disabled, no program file and parameters will
+appear, and the description will be disabled.</para>
+
+</sect2>
+
+<sect2>
+<title>Environment Variables</title>
+
+<para>Environment variables appear under a
+<guilabel>Variables</guilabel> folder. For each environment variable,
+the following are displayed: </para>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Name</guilabel></term>
+<listitem><para>Variable name.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Value</guilabel></term>
+<listitem><para>Variable value.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Description</guilabel></term>
+<listitem><para>Natural language description of variable.</para></listitem>
+</varlistentry>
+</variablelist>
+
+<para>Environment variables appearing here will override any existing
+environment variable for all scheduled tasks. If an environment variable
+has been disabled, no value will appear and the description will be
+disabled.</para>
+
+<screenshot>
+<screeninfo>&kcron; main window</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="kcron.png" format="PNG"/></imageobject>
+<textobject><phrase>&kcron; main window</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+</sect2>
+</sect1>
+
+<sect1 id="new-task">
+<title>Adding Scheduled Tasks</title>
+
+<para>To create a new scheduled task, first select the
+<guilabel>Tasks</guilabel> folder. Then select
+<menuchoice><guimenu>Edit</guimenu> <guimenuitem>New...</guimenuitem>
+</menuchoice>. Alternatively, you can use the
+<mousebutton>right</mousebutton> mouse button menu and choose
+<menuchoice><guimenuitem>New...</guimenuitem></menuchoice>, or simply
+press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>N</keycap></keycombo>.</para>
+
+<sect2>
+<title>The <guilabel>Edit Task</guilabel> Dialog</title>
+
+<screenshot>
+<screeninfo><guilabel>Edit Task</guilabel> dialog.</screeninfo>
+<mediaobject>
+<imageobject><imagedata fileref="newtask.png" format="PNG"/></imageobject>
+<textobject><phrase><guilabel>Edit Task</guilabel> dialog</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Comment</guilabel></term>
+<listitem><para>Enter a description of the task to schedule.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Program</guilabel></term>
+<listitem><para>Enter the name of the program. You can specify either a
+relative path or absolute path. If you want to look up the program, click
+<guibutton>Browse...</guibutton>.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Enabled</guibutton></term>
+<listitem><para>To enable or disable the task, select or de-select
+<guilabel>Enabled</guilabel>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Silent</guilabel></term>
+<listitem>
+<para>
+Turns off logging of the command and the output from the command.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Months</guilabel></term>
+<listitem><para>Select the months during which the task is to be
+scheduled.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Days of the Month</guilabel></term>
+<listitem><para>Select the days of the month on which the task is to be
+scheduled.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Days of the Week</guilabel></term>
+<listitem><para>Select the days of the week on which the task is to be
+scheduled.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Daily</guilabel></term>
+<listitem><para>If you want to schedule the task to run daily, select
+<guibutton>Run every day</guibutton>.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Hours</guilabel></term>
+<listitem><para>Select the hours on which the task is to be
+scheduled.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Minutes</guilabel></term>
+<listitem><para>Select the minute at which the task is to be scheduled. &kcron;
+does not support scheduling tasks at smaller than five minute intervals.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>OK</guibutton></term>
+<listitem><para>Completes the creation of this task.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Cancel</guibutton></term>
+<listitem><para>Cancels the creation of this task.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<para>If you select both days of the month, and days of the week, the
+task will run when either condition is met. For instance, if you select
+the 1st and 15th, and select Sunday, the program will be run every 1st
+and 15th of the selected months (regardless of day of week) as well as
+every Sunday of the selected months (regardless of day of the
+month).</para>
+
+<para>The scheduled task is not actually set up until the
+<filename>crontab</filename> has been saved.</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="manage-tasks">
+<title>Managing Scheduled Tasks</title>
+
+<para>As with creating new tasks, changes to tasks will not actually be
+made until the <filename>crontab</filename> is saved.</para>
+
+<sect2>
+<title>Cutting Scheduled Tasks</title>
+
+<para>To cut a scheduled task, first select the task to be cut. Then
+select <menuchoice><guimenu>Edit</guimenu>
+<guimenuitem>Cut</guimenuitem></menuchoice>.</para> <para>Alternatively,
+you can use the <mousebutton>right</mousebutton> mouse button menu and
+choose <menuchoice><guimenuitem>Cut</guimenuitem></menuchoice>, or
+simply press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>X</keycap></keycombo>.</para>
+
+</sect2>
+
+<sect2>
+<title>Copying Scheduled Tasks</title>
+
+<para>To copy a scheduled task, first select the task to be copied. Then
+select
+<menuchoice><guimenu>Edit</guimenu><guimenuitem>Copy</guimenuitem></menuchoice>
+.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton> mouse
+button menu and choose <menuchoice><guimenuitem>Copy</guimenuitem></menuchoice>,
+or simply press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>C</keycap></keycombo>.</para>
+
+</sect2>
+
+<sect2>
+<title>Pasting Scheduled Tasks</title>
+
+<para>To paste a scheduled task, first a scheduled task must have
+already been cut or copied to the clipboard. Once a scheduled task has
+been cut or copied, paste will be enabled. Then select the
+<guilabel>Tasks</guilabel> folder. Finally, select <menuchoice>
+<guimenu>Edit</guimenu> <guimenuitem>Paste</guimenuitem>
+</menuchoice>.</para>
+
+<para> Alternatively, you can use the <mousebutton>right</mousebutton> mouse
+button menu and choose
+<menuchoice><guimenuitem>Paste</guimenuitem></menuchoice>, or simply press
+<keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>V</keycap></keycombo>.</para>
+
+</sect2>
+
+<sect2>
+<title>Modifying Scheduled Tasks</title>
+
+<para>To modify a scheduled task, first select the task to be
+modified. Then select
+<menuchoice>
+<guimenu>Edit</guimenu> <guimenuitem>Modify...</guimenuitem>
+</menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose
+<menuchoice><guimenuitem>Modify...</guimenuitem></menuchoice>, or simply
+press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>O</keycap></keycombo>. You
+will see the <guilabel>Edit Task</guilabel> dialog, with which you would
+modify the task as described <link linkend="new-task">above</link>.</para>
+
+</sect2>
+
+<sect2>
+<title>Deleting Scheduled Tasks</title>
+
+<para>To delete a scheduled task, first select the task to be
+deleted. Then select <menuchoice> <guimenu>Edit</guimenu>
+<guimenuitem>Delete</guimenuitem> </menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose <guimenuitem>Delete</guimenuitem>.</para>
+
+</sect2>
+
+<sect2>
+<title>Enabling/Disabling Scheduled Tasks</title>
+
+<para>To enable or disable a scheduled task, first select the disabled
+task. Disabled tasks will have <guilabel>Disabled</guilabel> in their
+descriptions. Then select <menuchoice> <guimenu>Edit</guimenu>
+<guimenuitem>Enabled</guimenuitem> </menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose
+<menuchoice><guimenuitem>Enabled</guimenuitem></menuchoice>. Confirm
+that the scheduled task's program name, parameters, and description are
+correctly displayed.</para>
+
+</sect2>
+
+<sect2>
+<title>Running Scheduled Tasks</title>
+
+<para>To run a scheduled task immediately, first select the task. Then
+select <menuchoice> <guimenu>Edit</guimenu> <guimenuitem>Run
+Now</guimenuitem> </menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose <menuchoice><guimenuitem>Run
+Now</guimenuitem></menuchoice>.</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="new-variable">
+<title>Adding Environment Variables</title>
+
+<para>To create a new environment variable, first select the
+<guilabel>Variables</guilabel> folder. Then select <menuchoice>
+<guimenu>Edit</guimenu><guimenuitem>New...</guimenuitem>
+</menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose
+<menuchoice><guimenuitem>New...</guimenuitem></menuchoice>, or simply
+press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>N</keycap></keycombo>.</para>
+
+<sect2>
+<title>The <guilabel>Edit Variable</guilabel> dialog</title>
+
+<screenshot>
+<screeninfo><guilabel>Edit Variable</guilabel> dialog.</screeninfo>
+<mediaobject>
+<imageobject><imagedata fileref="newvariable.png" format="PNG"/></imageobject>
+<textobject><phrase><guilabel>Edit Variable</guilabel>
+dialog.</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Variable</guilabel></term>
+<listitem><para>Enter the environment variable name. You can use the drop-down
+list box to select from the most common environment variables used by scheduled
+tasks. Those include:</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guimenuitem>HOME</guimenuitem></term>
+<listitem><para>To be used instead of the default user's home
+folder.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenuitem>MAILTO</guimenuitem></term>
+<listitem><para>To send email output to an email address other than the user's
+default email address.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenuitem>PATH</guimenuitem></term>
+<listitem><para>To be used to search folders for program
+files.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenuitem>SHELL</guimenuitem></term>
+<listitem><para>To be used instead of the user's default
+value.</para></listitem>
+</varlistentry>
+</variablelist>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Value</guilabel></term>
+<listitem><para>Enter the environment variable value.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Comment</guilabel></term>
+<listitem><para>Enter a description for the environment variable, such as its
+purpose.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Enabled</guilabel></term>
+<listitem>
+<para>To enable or disable the variable, select or de-select
+<guibutton>Enabled</guibutton>.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>OK</guibutton></term>
+<listitem>
+<para>Completes the setting of this variable.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Cancel</guibutton></term>
+<listitem>
+<para>Cancels the setting of this variable.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<para>The environment variable is not actually set up until the
+<filename>crontab</filename> has been saved.</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="manage-variables">
+<title>Managing Environment Variables</title>
+
+<note><para>As with creating new variables, changes to variables will
+not actually be made until the <filename>crontab</filename> is
+saved.</para></note>
+
+<sect2>
+<title>Cutting Environment Variables</title>
+
+<para>To cut an environment variable, first select the variable to be
+cut. Then select <menuchoice><guimenu>Edit</guimenu>
+<guimenuitem>Cut</guimenuitem> </menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose
+<menuchoice><guimenuitem>Cut</guimenuitem></menuchoice>, or simply press
+<keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>X</keycap></keycombo>.</para>
+
+</sect2>
+
+<sect2>
+<title>Copying Environment Variables</title>
+
+<para>To copy an environment variable, first select the variable to be
+copied. Then select <menuchoice> <guimenu>Edit</guimenu>
+<guimenuitem>Copy</guimenuitem> </menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose <guimenuitem>Copy</guimenuitem>, or simply
+press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>C</keycap></keycombo>.</para>
+
+</sect2>
+
+<sect2>
+<title>Pasting Environment Variables</title>
+
+<para>To paste an environment variable, first an environment variable
+must have already been cut or copied to the clipboard. Once an
+environment variable has been cut or copied, paste will be enabled. Then
+select the <guilabel>Variables</guilabel> folder. Finally, select
+<menuchoice><guimenu>Edit</guimenu> <guimenuitem>Paste</guimenuitem>
+</menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose
+<menuchoice><guimenuitem>Paste</guimenuitem></menuchoice>, or simply
+press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>V</keycap></keycombo>.</para>
+</sect2>
+
+<sect2>
+<title>Modifying Environment Variables</title>
+
+<para>To modify an environment variable, first select the variable to be
+modified. Then select <menuchoice> <guimenu>Edit</guimenu>
+<guimenuitem>Modify...</guimenuitem> </menuchoice>. Alternatively, you
+can use the <mousebutton>right</mousebutton> mouse button menu and
+choose <guimenuitem>Modify...</guimenuitem>, or simply press <keycombo
+action="simul"><keycap>Ctrl</keycap><keycap>O</keycap></keycombo>. You
+will see the <guilabel>Edit Variable</guilabel> dialog, in which you would
+modify the variable as described <link linkend="new-variable">above</link>.</para>
+
+</sect2>
+
+<sect2>
+<title>Deleting Environment Variables</title>
+
+<para>To delete an environment variable, first select the variable to be
+deleted. Then select
+<menuchoice><guimenu>Edit</guimenu><guimenuitem>Delete</guimenuitem>
+</menuchoice></para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton> mouse
+button menu and choose <guimenuitem>Delete</guimenuitem>.</para>
+
+</sect2>
+
+<sect2>
+<title>Enabling/Disabling Environment Variables</title>
+
+<para>To enable or disabled an environment variable, first select the
+disabled variable. Disabled variables will have
+<guilabel>Disabled</guilabel> in their descriptions. Then select
+<menuchoice>
+<guimenu>Edit</guimenu> <guimenuitem>Enabled</guimenuitem> </menuchoice>.</para>
+
+<para>Alternatively, you can use the <mousebutton>right</mousebutton>
+mouse button menu and choose
+<menuchoice><guimenuitem>Enabled</guimenuitem></menuchoice>. Confirm
+that the environment variable's name and value are correctly
+displayed.</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="saving-crontab">
+<title>Saving the <filename>crontab</filename></title>
+
+<para>Once all scheduled tasks and environment variables have been
+created and/or properly modified, save the <filename>crontab</filename>
+by selecting
+<menuchoice>
+<guimenu>File</guimenu> <guimenuitem>Save</guimenuitem> </menuchoice>.</para>
+
+<para>Alternatively, you can simply press <keycombo
+action="simul">&Ctrl;<keycap>S</keycap></keycombo>. Additions or changes
+will not actually be made until this is done.</para>
+
+</sect1>
+
+<sect1 id="printing-crontab">
+<title>Printing the <filename>crontab</filename></title>
+
+<para>To print the <filename>crontab</filename> as it has been saved,
+select <menuchoice> <guimenu>File</guimenu>
+<guimenuitem>Print</guimenuitem> </menuchoice>.</para>
+
+
+<!-- FIXME: New screenshot of expanded print dialog -->
+
+<screenshot>
+<screeninfo>Printing the <filename>crontab</filename>.</screeninfo>
+<mediaobject>
+<imageobject><imagedata fileref="print.png" format="PNG"/></imageobject>
+<textobject><phrase>Printing the
+<filename>crontab</filename>.</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>The standard &kde; printer dialog will display. If you select
+<guilabel>Expand</guilabel> you will see that there are two extra
+&kcron; specific options in the Print Dialog box.</para>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Print Crontab</guilabel></term>
+<listitem>
+<para>Prints the <filename>crontab</filename> for the current user.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Print All Users</guilabel></term>
+<listitem>
+<para>Prints the <filename>crontab</filename>s for all users. This option is
+enabled only for users with super-user privileges.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+</chapter>
+
+<chapter id="commands">
+<title>Command Reference</title>
+
+<sect1 id="kcron-mainwindow">
+<title>The main &kcron; window</title>
+
+<sect2>
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>S</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Save</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Saves changes</action> to the <filename>crontab</filename>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo
+action="simul">&Ctrl;<keycap>P</keycap></keycombo></shortcut>
+<guimenu>File</guimenu> <guimenuitem>Print...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Prints</action> the <filename>crontab</filename>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Quits</action> &kcron;.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+<sect2>
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>X</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Cut</guimenuitem> </menuchoice></term>
+<listitem><para><action>Cut the selected task or
+variable.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>C</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Copy</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Copy the selected task or
+variable.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>V</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Paste</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Paste a task or variable that has been cut or
+copied.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>New...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Create a new task or
+variable.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Modify...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Modify the selected task or
+variable.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Delete</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Delete the selected task or
+variable.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Enabled</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Enable/disable the selected task or variable.</action></para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Run Now</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Run the selected task now.</action></para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2>
+<title>The <guimenu>Settings</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Toolbar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays toolbar.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Statusbar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays statusbar.</action></para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2>
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+
+</sect2>
+</sect1>
+</chapter>
+
+<chapter id="faq">
+<title>Questions and Answers</title>
+
+<qandaset id="questions-and-answers">
+<qandaentry>
+<question>
+<para>Why aren't the changes I'm making to scheduled tasks and/or environment
+variables taking effect?</para>
+</question>
+<answer><para>Additions or changes to scheduled tasks do not actually happen until the
+<filename>crontab</filename> has been <link
+linkend="saving-crontab">saved</link>.</para>
+</answer>
+</qandaentry>
+</qandaset>
+</chapter>
+
+<chapter id="credits">
+
+<title>Credits and License</title>
+
+<para>&kcron;</para>
+
+<para>Program copyright 2000 Gary Meyer <email>gary@meyer.net</email></para>
+
+<para>Documentation copyright 2000 Morgan N. Sandquist
+<email>morgan@pipeline.com</email></para>
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+
+&underGPL;
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<sect1 id="getting-kcron">
+<title>How to obtain &kcron;</title>
+
+&install.intro.documentation;
+
+</sect1>
+
+<sect1 id="requirements">
+<title>Requirements</title>
+
+<para>In order to successfully compile &kcron;, you need the following
+libraries:</para>
+
+<itemizedlist>
+<listitem><para><command>cron</command>, such as
+<command>vixie-cron</command>. &kcron; uses the
+<filename>crontab</filename> command to modify user's scheduled
+tasks.</para></listitem>
+<listitem><para>POSIX-compliant &UNIX;, such as provided by
+glibc. &kcron; uses some standard &UNIX; system calls for localization of
+dates and times</para></listitem>
+</itemizedlist>
+
+</sect1>
+
+<sect1 id="compilation">
+<title>Compilation and Installation</title>
+
+&install.compile.documentation;
+
+</sect1>
+
+</appendix>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+-->
diff --git a/doc/kcron/kcron.png b/doc/kcron/kcron.png
new file mode 100644
index 0000000..b800ebf
--- /dev/null
+++ b/doc/kcron/kcron.png
Binary files differ
diff --git a/doc/kcron/kcronstart.png b/doc/kcron/kcronstart.png
new file mode 100644
index 0000000..fd4c21b
--- /dev/null
+++ b/doc/kcron/kcronstart.png
Binary files differ
diff --git a/doc/kcron/newtask.png b/doc/kcron/newtask.png
new file mode 100644
index 0000000..86da56c
--- /dev/null
+++ b/doc/kcron/newtask.png
Binary files differ
diff --git a/doc/kcron/newvariable.png b/doc/kcron/newvariable.png
new file mode 100644
index 0000000..2334952
--- /dev/null
+++ b/doc/kcron/newvariable.png
Binary files differ
diff --git a/doc/kcron/print.png b/doc/kcron/print.png
new file mode 100644
index 0000000..c622f26
--- /dev/null
+++ b/doc/kcron/print.png
Binary files differ
diff --git a/doc/kdat/Makefile.am b/doc/kdat/Makefile.am
new file mode 100644
index 0000000..085981d
--- /dev/null
+++ b/doc/kdat/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kdat/index.docbook b/doc/kdat/index.docbook
new file mode 100644
index 0000000..b5fb94e
--- /dev/null
+++ b/doc/kdat/index.docbook
@@ -0,0 +1,833 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN"
+"dtd/kdex.dtd" [
+ <!ENTITY kappname "&kdat;">
+ <!ENTITY package "kdeadmin">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+<bookinfo>
+<title>&kdat; Documentation</title>
+
+<authorgroup>
+
+<author>
+<firstname>Sean</firstname>
+<surname>Vyain</surname>
+<affiliation><address><email>svyain@mail.tds.net</email></address></affiliation>
+</author>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>2000</year>
+<holder>Sean Vyain</holder>
+</copyright>
+
+<date>2000-10-03</date>
+<releaseinfo>2.00.00</releaseinfo>
+
+<abstract><para>This documentation describes &kdat;
+2.0</para></abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KDat</keyword>
+<keyword>tape</keyword>
+<keyword>tape management</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="Introduction">
+<title>Introduction</title>
+
+<para>&kdat; is a tar-based tape archiver. It is designed to work with
+multiple archives on a single tape. &kdat; was inspired by two separate
+goals.
+The first, was to provide a nice, <abbrev>GUI</abbrev> front-end to tar
+that
+supported the fast selective extraction features of the
+<application>dds2tar</application> program. The second goal was to
+answer my wife's
+question, <quote>How much longer is it going to be backing
+up?!?</quote></para>
+
+<!-- //////// -->
+<sect1 id="features">
+<title>Features</title>
+
+<itemizedlist>
+<listitem><para>Simple graphical interface to local filesystem and tape
+contents.</para>
+</listitem>
+<listitem><para>Multiple archives on the same physical tape.</para>
+</listitem>
+<listitem><para>Complete index of archives and files is stored on local
+hard
+disk.</para>
+</listitem>
+<listitem><para>Selective restore of files from an archive.</para>
+</listitem>
+<listitem><para>Backup profiles for frequently used backups.</para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+</chapter>
+
+<chapter id="using-kdat">
+<title>Using &kdat;</title>
+
+<sect1 id="mount">
+<title>Mounting/unmounting a tape</title>
+
+<para>Before a tape can be used, it must be mounted by &kdat;. There are
+
+
+
+
+three
+ways to mount a tape:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Mount Tape</guimenuitem> from the
+<guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>Click on the <guiicon>tape drive</guiicon> icon on the
+toolbar.</para>
+</listitem>
+<listitem><para>&RMB; click on the tape drive tree node, and select
+<guimenuitem>Mount Tape</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+<para>&kdat; will rewind the tape, and read the header information from
+the tape. If &kdat; does not recognize the header on the tape, you will
+be prompted to <link linkend="formatting">format</link> the tape.</para>
+
+<para>If &kdat; recognizes the header it will look for the corresponding
+tape index on your local disk. If the tape index cannot be found you
+will be prompted to <link linkend="indexing">recreate the index from
+tape</link>.</para>
+
+<para>If all goes well, the tape drive icon will change to indicate that
+the tape has been mounted, and a message will appear in the status bar.
+The contents of the tape can be explored under the tape drive tree
+node.</para>
+
+<para>Before ejecting a tape, you must unmount the tape. There are three
+ways to unmount the tape:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Unmount Tape</guimenuitem> from the
+<guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>Click on the <guiicon>tape drive</guiicon> icon on the
+toolbar.</para>
+</listitem>
+<listitem><para>&RMB; click on the tape drive tree node, and select
+<guimenuitem>Unmount Tape</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+<para>&kdat; will acknowledge that the tape has been unmounted by
+changing the
+tape drive icon, and displaying a message in the status bar. The tape
+may now
+be safely ejected.</para>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="formatting">
+<title>Formatting a tape</title>
+
+<para>Before a tape can be used by &kdat;, it must be formatted by
+&kdat;.</para>
+
+<para>Some types of tapes must be formatted before they can be used to
+store data. <emphasis>This is not what &kdat; does when formatting a
+tape.</emphasis> If your tape drive requires that the tapes be formatted
+
+
+
+
+before
+using them, then they must be formatted before they can be
+<quote>formatted</quote>
+by &kdat;. Typically floppy tape drives require that their media be
+formatted, but
+DAT drives do not.</para>
+
+<para>There are two ways to format a tape:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Format Tape...</guimenuitem> from
+the
+<guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>&RMB; click on the tape drive tree node, and select
+<guimenuitem>Format Tape...</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+<para>You will be prompted for a name for the tape, and the stated
+capacity of the tape. Both of these parameters can be changed
+after the tape has been formatted. The tape name is only used
+to identify the tape to the user; it is not used to identify the
+tape index associated with the tape. Instead, a unique tape
+identifier is automatically generated and written to the tape.
+The stated capacity of the tape is used by &kdat; to warn the user
+if there will not be enough space to complete a backup.</para>
+
+<para>After entering the tape name and capacity, &kdat; will proceed to
+format the tape. <emphasis>ALL DATA ON THE TAPE WILL BE LOST</emphasis>.
+Once &kdat; has finished formatting the tape, the tape will be
+automatically
+mounted and is ready for use.</para>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="backing-up">
+<title>Backing up files to tape</title>
+
+<para>Before initiating a backup, you must select some files to archive.
+
+
+
+
+There
+are three ways to select files for backup:</para>
+
+<orderedlist>
+<listitem><para>Highlight a file or folder in the local file tree.
+Only the
+selected file or subfolder will be archived.</para>
+</listitem>
+<listitem><para>Highlight a <link linkend="profile">backup
+profile</link> in the
+tree. Only the files in the backup profile will be archived.</para>
+</listitem>
+<listitem><para>Checkmark selected files in the local file tree. Only
+the
+checked files and/or subfolders will be archived.</para>
+</listitem>
+</orderedlist>
+
+<para>There are four ways to initiate a backup:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Backup...</guimenuitem> from the
+<guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>Click on the <guiicon>backup</guiicon> icon in the
+toolbar.</para>
+</listitem>
+<listitem><para>&RMB; click on a file or folder in the local file
+tree, and
+select <guimenuitem>Backup...</guimenuitem>.</para>
+</listitem>
+<listitem><para>&RMB; click on a <link linkend="profile">backup
+profile</link>,
+and select <guimenuitem>Backup...</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+<para>Once the backup has been initiated, the <guilabel>Backup
+Options</guilabel> dialog will appear. This dialog gives you a chance to
+review the selected files, and change the backup options.</para>
+
+<para>After accepting the backup options, the
+<guilabel>Backup</guilabel>
+dialog will appear. This dialog shows the progress of the backup
+including
+throughput and time remaining.</para>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="verifying">
+<title>Verifying tape files against local files</title>
+
+<para>Before initiating a verify, you must select some files to
+verify.</para>
+
+<para>There are two ways to select files for verification:</para>
+
+<orderedlist>
+<listitem><para>Highlight a file or folder in one of the archives
+under the
+tape drive tree node. Only the selected file or subfolder will be
+verified.</para>
+</listitem>
+<listitem><para>Checkmark selected files in one of the archives under
+the tape
+drive tree node. Only the checked files and/or subfolders will be
+verified.</para>
+</listitem>
+</orderedlist>
+
+<para>There are three ways to initiate a verify:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Verify...</guimenuitem> from the
+<guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>Click on the <guiicon>verify</guiicon> icon in the
+toolbar.</para>
+</listitem>
+<listitem><para>&RMB; click on a file or folder in one of the
+archives, and select <guimenuitem>Verify...</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+
+<para>Once the verify has been initiated, the <guilabel>Verify
+Options</guilabel> dialog will appear. This dialog gives you a chance to
+review the selected files, and change the working folder for the
+verification.</para>
+
+<para>After accepting the verify options, the
+<guilabel>Verify</guilabel>
+dialog will appear. This dialog shows the progress of the verification
+including throughput and time remaining.</para>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="restoring">
+<title>Restoring files from tape</title>
+
+<para>Before initiating a restore, you must select some files to
+restore. There are two ways to select files for restoring:</para>
+
+<orderedlist>
+<listitem><para>Highlight a file or folder in one of the archives
+under the
+tape drive tree node. Only the selected file or subfolder will be
+restored.</para>
+</listitem>
+<listitem><para>Checkmark selected files in one of the archives under
+the tape
+drive tree node. Only the checked files and/or subfolders will be
+restored.</para>
+</listitem>
+</orderedlist>
+
+<para>There are three ways to initiate a restore:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Restore...</guimenuitem> from the
+<guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>Click on the <guiicon>restore</guiicon> icon in the
+toolbar.</para>
+</listitem>
+<listitem><para>&RMB; click on a file or folder in one of the
+archives, and select
+<guimenuitem>Restore...</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+<para>Once the restore has been initiated, the <guilabel>Restore
+Options</guilabel> dialog will appear. This dialog gives you a chance to
+review the selected files, and change the working folder for the
+restore.</para>
+
+<para>After accepting the restore options, the
+<guilabel>Restore</guilabel>
+dialog will appear. This dialog shows the progress of the restore
+including
+throughput and time remaining.</para>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="indexing">
+<title>Recreating an index from tape</title>
+
+<para>Sometimes it may be necessary to recreate the tape index file from
+
+
+
+
+the tape
+contents. <emphasis>This process will overwrite any existing index
+file for the tape</emphasis>. There are two way to recreate an index
+from
+tape:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Recreate Tape Index</guimenuitem>
+from the
+<guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>&RMB; click on the tape drive tree node, and select
+<guimenuitem>Recreate Tape Index</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+<para>The <guilabel>Index</guilabel> dialog will appear. This dialog
+shows
+&kdat;'s progress as it creates the index file.</para>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="profile">
+<title>Creating a backup profile</title>
+
+<para>There are two ways to create a backup profile:</para>
+
+<orderedlist>
+<listitem><para>Select <guimenuitem>Create Backup Profile</guimenuitem>
+from
+the <guimenu>File</guimenu> menu.</para>
+</listitem>
+<listitem><para>&RMB; click on the <guilabel>Backup Profiles</guilabel>
+tree node, and select <guimenuitem>Create Backup
+Profile</guimenuitem>.</para>
+</listitem>
+</orderedlist>
+
+<para>This should create a new backup profile using the currently
+checked files
+and the default backup options. The following options can be set for the
+
+
+
+
+backup
+profile:</para>
+
+<variablelist>
+
+<varlistentry>
+<term>Archive name</term>
+<listitem><para>The symbolic name for the archive. It can be changed
+later.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term>Working folder</term>
+<listitem><para>The current working folder to perform the backup in.
+The
+list of files to backup is automatically updated to reflect the selected
+
+
+
+
+working
+folder.</para> </listitem>
+</varlistentry>
+<varlistentry>
+<term>Stay on one filesystem</term>
+<listitem><para>For each folder that is listed under
+<guilabel>Backup files</guilabel>, only the files under that folder
+that are
+on the same filesystem as the folder will be archived. Folders on
+
+
+
+
+different
+filesystems can be listed under <guilabel>Backup files</guilabel>, and
+each will
+be treated independently of the others, by tar.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>GNU listed incremental</term>
+<listitem><para>Perform an incremental backup. A snapshot file is used
+to
+determine which files have changed since the last incremental backup.
+Only the
+files that have changed will be archived.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term>Snapshot file</term>
+<listitem><para>The name of the file that is used to determine which
+files have
+changed since the last incremental backup.</para> </listitem>
+</varlistentry>
+<varlistentry>
+<term>Remove snapshot file before backup.</term>
+<listitem><para>Remove the snapshot file before invoking
+<application>tar</application>. This has the effect of backing up all of
+
+
+
+
+the
+files, and creating the snapshot file for use next time.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<note><para>The <guibutton>Files &gt;&gt;</guibutton> and
+<guibutton>&lt;&lt;
+Files</guibutton> buttons were not fully implemented at the time this
+documentation was
+written...</para></note>
+
+<para>You must press the <guibutton>Apply</guibutton> button to commit
+any
+changes made to the backup profile.</para>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="prefs">
+<title>Configuring user preferences</title>
+
+<para>User preferences can be configured by selecting
+<guimenuitem>Preferences...</guimenuitem> from the
+<guimenu>Edit</guimenu>
+menu. The following preferences can be configured:</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Default tape size</guilabel>
+</term>
+<listitem><para>This value will be used as the default tape size when
+formatting
+a tape.</para> </listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Tape block size</guilabel>
+</term>
+<listitem><para>The hardware block size for the tape drive. For floppy
+tape
+drives this value should be 10240 bytes.</para> </listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Tape device</guilabel>
+</term>
+<listitem><para>The full path to your tape device (usually
+<filename>/dev/tape</filename>).
+This path must point to the <emphasis>non-rewind</emphasis> version of
+your tape device.
+</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Tar command</guilabel>
+</term>
+<listitem><para>The full path to the <command>tar</command> command on
+your
+system.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Load tape on mount</guilabel>
+</term>
+<listitem><para>If enabled, before trying to mount a tape &kdat; will
+issue an
+<userinput><command>mt<option>load</option></command></userinput>
+command to the
+tape drive. Some drives may require this before reading and writing the
+tape.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Lock tape drive on mount</guilabel>
+</term>
+<listitem><para>If enabled, whenever a tape is mounted by &kdat;, the
+tape drive
+will be asked to disable the eject button. This option may not work with
+
+
+
+
+all
+tape drives.</para> </listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Eject tape on unmount</guilabel>
+</term>
+<listitem><para>If enabled, whenever a tape is unmounted by &kdat;, the
+tape
+will automatically be ejected from the drive. Do not use this option
+with floppy tape
+drives.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Variable block size</guilabel>
+</term>
+<listitem><para>If enabled, &kdat; will attempt to change the hardware
+block
+size used by the tape drive. Not all drives support variable block size.
+Whether this feature is enabled or not, you must tell &kdat; the block
+size that
+your tape drive uses (&ie; 10240 for ftape users).</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<!-- //////// -->
+<sect1 id="tapeformat">
+<title>&kdat; tape format</title>
+
+<para>When &kdat; formats a tape it writes a single file at the
+beginning of the
+tape. This file should only occupy a single tape block. The contents of
+the
+file are:</para>
+
+<itemizedlist>
+<listitem><para>(9 bytes) The string literal
+<literal>KDatMAGIC</literal></para>
+</listitem>
+<listitem><para>(4 bytes) The file format version number (currently
+1).</para>
+</listitem>
+<listitem><para>(4 bytes) The length in bytes of the tape ID
+string.</para>
+</listitem>
+<listitem><para>(n bytes) The tape ID string. The format of this string
+is
+<replaceable>hostname</replaceable>:<replaceable>seconds</replaceable>,
+where
+<replaceable>hostname</replaceable> is the full name of the machine that
+
+
+
+
+the tape was
+formatted on and <replaceable>seconds</replaceable> is the number of
+seconds since
+the epoch when the tape was formatted.</para>
+</listitem>
+</itemizedlist>
+
+<para>The tape ID is used to locate a file, with the same name, in the
+<filename>$<envar>HOME</envar>/.kdat</filename> folder.</para>
+
+<para>Each of the remaining files on the tape are plain-old
+<application>tar</application> archives. You should be able to
+manipulate them
+directly with <acronym>GNU</acronym> <application>tar</application>.
+Even
+non-<acronym>GNU</acronym> <application>tar</application> should work
+for
+non-incremental backups.</para>
+
+</sect1>
+</chapter>
+
+<!--
+**********************************************************************
+-->
+<chapter id="menu-reference">
+<title>Menu and Toolbar Reference</title>
+
+<sect1 id="menus">
+<title>&kdat; menus</title>
+
+<para>&kdat; has three menus:
+<link linkend="menu-file"><guimenu>File</guimenu></link>,
+<link linkend="menu-edit"><guimenu>Edit</guimenu></link>, and
+<link linkend="menu-help"><guimenu>Help</guimenu></link>.</para>
+
+<!-- //////// -->
+<sect2 id="menu-file">
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Backup</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Begin a backup.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Restore</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Restore a backup from
+tape.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Verify</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Verify a backup.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Mount Tape</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Mount a tape.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Recreate Tape Index</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Recreate an index on the currently mounted
+tape.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Create Backup Profile</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens the dialog box that allows you to create a
+
+
+
+
+Backup
+Profile.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Delete Archive</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Delete an archive from the
+tape.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Delete Index</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Delete the &kdat; index from a
+tape.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Delete Backup Profile</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Delete a Backup
+Profile.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu><guimenuitem>Format Tape</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Format a tape for use with
+&kdat;.</action></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;<keycap>Q</keycap>
+</keycombo></shortcut><guimenu>File</guimenu><guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Exit &kdat;.</action></para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<!-- //////// -->
+<sect2 id="menu-edit">
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu><guimenuitem>Preferences</guimenuitem>
+</menuchoice></term>
+<listitem><para>Opens the <guilabel>Preferences</guilabel> dialog, where
+you can configure &kdat; for your needs.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<!-- //////// -->
+<sect2 id="menu-help">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+
+</sect2>
+
+<!-- //////// -->
+<sect2 id="icon-reference">
+<title>The &kdat; toolbar</title>
+
+<para>The &kdat; toolbar contains 6 icons, as follows:</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guiicon>Mount/unmount Tape</guiicon>
+</term>
+<listitem><para>Mount or unmount a tape.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guiicon>Backup</guiicon>
+</term>
+<listitem><para>Begin a backup. This item is unavailable unless a tape
+is
+mounted.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guiicon>Restore</guiicon>
+</term>
+<listitem><para>Restore a backup from tape. This item is unavailable
+unless a
+tape is mounted.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guiicon>Verify</guiicon>
+</term>
+<listitem><para>Verify the contents of a backup tape. This item is
+unavailable unless
+a tape is mounted.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guiicon>Help</guiicon>
+</term>
+<listitem><para>Opens the &kdat; help files (this
+document)</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guiicon>Quit</guiicon>
+</term>
+<listitem><para>Quits &kdat;</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+</sect1>
+
+</chapter>
+
+<!--
+***********************************************************************
+-->
+<chapter id="Copyright">
+<title>Copyright</title>
+<para>&kdat;</para>
+
+<para>Program and Documentation copyright 1998-2000 Sean
+Vyain<email>svyain@mail.tds.net</email></para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+End:
+-->
diff --git a/doc/knetworkconf/01.png b/doc/knetworkconf/01.png
new file mode 100644
index 0000000..0e6bd6f
--- /dev/null
+++ b/doc/knetworkconf/01.png
Binary files differ
diff --git a/doc/knetworkconf/02.png b/doc/knetworkconf/02.png
new file mode 100644
index 0000000..2d41e65
--- /dev/null
+++ b/doc/knetworkconf/02.png
Binary files differ
diff --git a/doc/knetworkconf/03.png b/doc/knetworkconf/03.png
new file mode 100644
index 0000000..89dbf86
--- /dev/null
+++ b/doc/knetworkconf/03.png
Binary files differ
diff --git a/doc/knetworkconf/04.png b/doc/knetworkconf/04.png
new file mode 100644
index 0000000..9a80161
--- /dev/null
+++ b/doc/knetworkconf/04.png
Binary files differ
diff --git a/doc/knetworkconf/05.png b/doc/knetworkconf/05.png
new file mode 100644
index 0000000..c10457c
--- /dev/null
+++ b/doc/knetworkconf/05.png
Binary files differ
diff --git a/doc/knetworkconf/06.png b/doc/knetworkconf/06.png
new file mode 100644
index 0000000..1dc2096
--- /dev/null
+++ b/doc/knetworkconf/06.png
Binary files differ
diff --git a/doc/knetworkconf/07.png b/doc/knetworkconf/07.png
new file mode 100644
index 0000000..fee712e
--- /dev/null
+++ b/doc/knetworkconf/07.png
Binary files differ
diff --git a/doc/knetworkconf/08.png b/doc/knetworkconf/08.png
new file mode 100644
index 0000000..fc56293
--- /dev/null
+++ b/doc/knetworkconf/08.png
Binary files differ
diff --git a/doc/knetworkconf/09.png b/doc/knetworkconf/09.png
new file mode 100644
index 0000000..3c834a8
--- /dev/null
+++ b/doc/knetworkconf/09.png
Binary files differ
diff --git a/doc/knetworkconf/11.png b/doc/knetworkconf/11.png
new file mode 100644
index 0000000..3ebffaf
--- /dev/null
+++ b/doc/knetworkconf/11.png
Binary files differ
diff --git a/doc/knetworkconf/Makefile.am b/doc/knetworkconf/Makefile.am
new file mode 100644
index 0000000..01c1911
--- /dev/null
+++ b/doc/knetworkconf/Makefile.am
@@ -0,0 +1,4 @@
+KDE_LANG = en
+KDE_DOCS = knetworkconf
+
+
diff --git a/doc/knetworkconf/about1.png b/doc/knetworkconf/about1.png
new file mode 100644
index 0000000..f602d20
--- /dev/null
+++ b/doc/knetworkconf/about1.png
Binary files differ
diff --git a/doc/knetworkconf/index.docbook b/doc/knetworkconf/index.docbook
new file mode 100644
index 0000000..929e413
--- /dev/null
+++ b/doc/knetworkconf/index.docbook
@@ -0,0 +1,1117 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY knetworkconf "<application>KNetworkConf</application>">
+ <!ENTITY kappname "&knetworkconf;">
+ <!ENTITY package "kdeadmin">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+<bookinfo>
+<title>&kde; Network Configuration</title>
+
+<authorgroup>
+<author>
+<firstname>Sean</firstname>
+<surname>Wheller</surname>
+<affiliation><orgname>
+<ulink url="http://www.inwords.co.za">In Words Techdoc
+Solutions</ulink>
+</orgname>
+<address><email>sean@inwords.co.za</email></address>
+</affiliation>
+</author>
+<author>
+<firstname>Christoph</firstname>
+<surname>Eckert</surname>
+<affiliation>
+<address><email>ce.at.christeck.de</email></address>
+</affiliation>
+</author>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>2005</year>
+<holder>
+<ulink url="http://www.inwords.co.za">In Words Techdoc
+Solutions</ulink>
+</holder>
+<holder>Christoph Eckert</holder>
+</copyright>
+<legalnotice>&FDLNotice;</legalnotice>
+<!-- FIXME: Revhistory is not used in KDE docs, we have revision control to -->
+<!-- handle this retaining this for the first commit, to maintain history, -->
+<!-- but it should be removed on the next edit -->
+<!-- <revhistory>
+<revision>
+<revnumber>0.1</revnumber>
+<date>March 18, 2005</date>
+<revremark>Documented using 0.6.1-3ubuntu1 under Kubuntu. At
+time of writing this version was not a release and was
+therefore in &apos;Universe.&apos;</revremark>
+</revision>
+<revision>
+<revnumber>0.2</revnumber>
+<date>March 23, 2005</date>
+<revremark>Merge upstream work by Christoph from r1.16 into
+document.</revremark>
+</revision>
+</revhistory> -->
+
+<date>2005-03-24</date>
+<releaseinfo>1.0</releaseinfo>
+
+<abstract>
+<para>This manual explains how to install and use &knetworkconf;, a module for
+&kcontrolcenter; that enables management of Network Interfaces, Routing and DNS
+properties.</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kdeadmin</keyword>
+<keyword>network</keyword>
+<keyword>ethernet</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+<para>The &kcontrolcenter; provides users with a single
+integrated interface from which to manage a wide variety of system and
+desktop settings and preferences. &kcontrolcenter; can be started by selecting
+<menuchoice><guimenu>K Menu</guimenu><guimenuitem>&kcontrolcenter;</guimenuitem></menuchoice>.</para>
+
+<para>The &knetworkconf; package was developed to enable users to manage TCP/IP
+networking settings in the same way they manage other system settings from
+&kcontrolcenter;. Tasks enabled by &knetworkconf; provide users with a simple
+interface from which to perform the following tasks:</para>
+
+<itemizedlist>
+<listitem>
+<para>Apply IP addresses to interfaces </para>
+</listitem>
+<listitem>
+<para>Apply netmasks to interfaces </para>
+</listitem>
+<listitem>
+<para>Start and stop interface activities </para>
+</listitem>
+<listitem>
+<para>Configure Routing </para>
+</listitem>
+<listitem>
+<para>Configure Host- and Domain Name </para>
+</listitem>
+<listitem>
+<para>Configure Resolving </para>
+</listitem>
+<listitem>
+<para>Manage known hosts </para>
+</listitem>
+</itemizedlist>
+
+<para>Once installed a new module called <guimenuitem>Network
+Settings</guimenuitem> is displayed in the &kcontrolcenter;.
+To start the <application>Network Settings</application> (&knetworkconf;) module select <menuchoice>
+<guimenuitem>&kcontrolcenter;</guimenuitem> <guimenuitem>Internet &amp; Network</guimenuitem>
+<guimenuitem>Network Settings</guimenuitem> </menuchoice> in the &kmenu;.</para>
+
+<mediaobject>
+<imageobject>
+<imagedata fileref="11.png" format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>&knetworkconf; in user mode</phrase>
+</textobject>
+</mediaobject>
+
+<para>It is important to understand that &knetworkconf; cannot install
+networking hardware. As such physical devices and their drivers must be
+properly installed and configured in order for &knetworkconf; to display the
+device and enable management of networking properties.</para>
+
+<para>In most cases drivers for networking hardware and other devices are
+installed and configured while installing &Linux;. If you add networking
+hardware after installation, you will have to define the drivers to be
+loaded by editing one of the following files depending on your kernel
+version:</para>
+
+<variablelist>
+<varlistentry>
+<term>&Linux; Kernel 2.4 and lower</term>
+<listitem>
+<para>
+<filename class="devicefile"
+>/etc/modules.conf</filename>
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>&Linux; Kernel 2.6 and higher</term>
+<listitem>
+<para>
+<filename class="devicefile"
+>/etc/modprobe.conf</filename>
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</chapter>
+
+<chapter id="using-the-module">
+<title>Using the Network Settings Module</title>
+
+<para>The <application>Network Settings</application> module is loaded when
+the <guibutton>Network Settings</guibutton> option is selected in the
+&kcontrolcenter; index. When started the <application>Network
+Settings</application> module attempts to automatically detect the platform
+running on the system.</para>
+
+<screenshot>
+<screeninfo>Detecting the platform</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="02.png"
+format="PNG"/>
+</imageobject>
+</mediaobject>
+</screenshot>
+
+<para>When the platform is not a recognized you will be prompted to manually
+select the platform. Select a platform from the list that most closely
+corresponds to your distro and its release. Check the <guibutton>Don't ask
+again</guibutton> option to make this choice permanent. Next time
+<guibutton>Network Settings</guibutton> is started the system will
+automatically default to the selected platform option.</para>
+
+<!--FIXME: several screenshots that were linked in this doc are missing-->
+<!--screenshot>
+<screeninfo>Selecting a platform</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="figures/knetwork-conf-select-platform.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Selecting a platform</phrase>
+</textobject>
+</mediaobject>
+</screenshot-->
+
+<para>To manage the system network settings you must enter
+<quote>administrator mode.</quote> Prior to this all options will be
+<quote>grayed,</quote> meaning you can only navigate the interface and view
+properties. Editing is disabled. To enter <quote>administrator mode</quote>
+click the <guibutton>Administrator Mode</guibutton> button located bottom
+left of the module. Enter your password when prompted.</para>
+
+<screenshot>
+<screeninfo>&knetworkconf; in administrator mode</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="01.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>&knetworkconf; in administrator mode</phrase>
+</textobject>
+</mediaobject>
+</screenshot>
+
+<para>Once in <quote>administrator mode</quote> all the modules
+functionality is enable. Functionality is organized into three tabs:</para>
+
+<itemizedlist>
+<listitem>
+<para>
+<xref linkend="network-interfaces"/>
+</para>
+</listitem>
+<listitem>
+<para>
+<xref linkend="route"/>
+</para>
+</listitem>
+<listitem>
+<para>
+<xref linkend="dns"/>
+</para>
+</listitem>
+</itemizedlist>
+
+<sect1 id="network-interfaces">
+<title>Managing Network Interfaces</title>
+
+<para>The <guibutton>Network Interfaces</guibutton> tab is used to manage
+the network communications devices installed on the system. All available
+networking devices are listed. From the <guibutton>Network
+Interfaces</guibutton> tab the following tasks can be accomplished:</para>
+
+<itemizedlist>
+<listitem>
+<para>
+<xref linkend="configure-interface"/>
+</para>
+</listitem>
+<listitem>
+<para>
+<xref linkend="enable-interface"/>
+</para>
+</listitem>
+<listitem>
+<para>
+<xref linkend="disable-interface"/>
+</para>
+</listitem>
+</itemizedlist>
+
+<mediaobject>
+<imageobject>
+<imagedata
+fileref="03.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>The &knetworkconf; interface</phrase>
+</textobject>
+</mediaobject>
+
+<para>For each network device the following properties can be
+viewed:</para>
+
+<variablelist>
+<varlistentry>
+<!-- FIXME: Check punctuation of the GUI against the styleguide, and then -->
+<!-- make sure the doc matches precisely, to aid translation -->
+<term><guilabel>Interface</guilabel></term>
+<listitem>
+<para>Shows the name of the network interfaces. For example, eth0, eth1,
+wlan0.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>IP Address</guilabel></term>
+<listitem>
+<para>Shows the currently assigned IP address.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Protocol</guilabel></term>
+<listitem>
+<para>Shows the boot protocol.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>State</guilabel></term>
+<listitem>
+<para>Shows the current state (up or down).</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Comment</guilabel></term>
+<listitem>
+<para>Shows the (freely assignable) comment.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<sect2 id="configure-interface">
+<title>Configuring a Networking Device</title>
+
+<para>The properties of listed network devices can be configured by
+selecting the required device from the list then <action>clicking</action>
+the <guibutton>Configure Interface...</guibutton> button to display the
+<interface>Configure Device</interface> dialog.</para>
+
+<screenshot>
+<screeninfo>Configuring a networking device</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata
+fileref="04.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Configuring a networking device</phrase>
+</textobject>
+</mediaobject>
+</screenshot>
+
+<para>By default only basic TCP/IP settings are available. Click
+the <guibutton>Advanced Settings</guibutton> button to
+expand the dialog to include advanced properties.</para>
+
+<mediaobject>
+<imageobject>
+<imagedata fileref="05.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Advanced device configuration</phrase>
+</textobject>
+</mediaobject>
+
+<para>Complete the dialog values are as follows:</para>
+<variablelist>
+<varlistentry>
+<term>
+<emphasis role="bold">Automatic</emphasis>
+</term>
+<listitem>
+
+<para>Select the <guibutton>Automatic</guibutton> radio button when the
+TCP/IP settings are obtained from a DHCP server or BOOTP server node. In
+automatic mode the TCP/IP settings for the system are configured when the
+system services are started. The DHCP or BOOTP server sends all the required
+TCP/IP information each time the system is started, there is no need to
+configure any other settings. Use the drop-list to select
+<option>DHCP</option> or <option>BOOTP</option> according to your
+system.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Manual</guilabel></term>
+<listitem>
+<para>Select the <guibutton>Manual</guibutton> radio button when you do not
+use DHCP or BOOTP for TCP/IP configuration. In the <guibutton>IP
+address</guibutton> field enter the TCP/IP address of the host. In the
+<guibutton>Netmask</guibutton> field enter the subnetwork address.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Activate when the computer starts</guilabel></term>
+<listitem>
+<para>When checked this option will cause the system to initialize this
+network interface while the system is booting. If you do not want the device
+initialized leave this option unchecked.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<guilabel>Description</guilabel>
+</term>
+<listitem>
+<para>Enter a descriptive name.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<guilabel>Broadcast</guilabel>
+</term>
+<listitem>
+<para>Enter the <quote>broadcast address</quote> used to communicate with
+all hosts on the subnetwork.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<para>The values entered in this dialog will be displayed as the properties
+of the device in the device list.</para>
+
+<caution>
+<para>Make certain that the IP-address entered is not already in use on the
+network. Entering an IP-address that is already on the network will result
+in a TCP/IP conflict. Use <application>ping</application> from &konsole; to
+check if the address you want to enter is in use or not. If you are not sure
+how to complete this dialog, consult your network administrator.</para>
+</caution>
+
+</sect2>
+
+<sect2 id="enable-interface">
+<title>Enabling a Network Device</title>
+
+<para>Network devices may be enabled or disabled depending on system
+requirements. To enable a disabled network device select the device from the
+list then click <guibutton>Enable Interface</guibutton>.</para>
+
+</sect2>
+
+<sect2 id="disable-interface">
+<title>Disabling Network Devices</title>
+
+<para>Network devices may be enabled or disabled depending on system
+requirements. To disable an enabled network device select the device from
+the list then click <guibutton>Disable Interface</guibutton>.</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="route">
+<title>Managing System Routing</title>
+
+<para>The <guibutton>Routes</guibutton> tab enables management of
+the system routing configuration.</para>
+
+<mediaobject>
+<imageobject>
+<imagedata fileref="06.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Advanced device configuration</phrase>
+</textobject>
+</mediaobject>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Default Gateway</guilabel></term>
+<listitem>
+<para>This specifies the IP address of the host on the local subnetwork that
+provides the physical connection to remote networks, and is used by default
+when TCP/IP needs to communicate with computers on other subnetworks.</para>
+<para>Select a device from the drop list to edit the <guibutton>Default
+Gateway</guibutton> value.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<note>
+<para>If your computer offers more than one network interface, select the
+interface connected to network on which the gateway computer resides.</para>
+</note>
+
+</sect1>
+
+<sect1 id="dns">
+<title>Managing DNS Settings</title>
+
+<para>The <guibutton>Domain Name System</guibutton> tab enables management
+of the system DNS configuration.</para>
+
+<mediaobject>
+<imageobject>
+<imagedata fileref="07.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Advanced device configuration</phrase>
+</textobject>
+</mediaobject>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Host name</guilabel></term>
+<listitem>
+<para>The name by which the host will be known on the subnetwork.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Domain name</guilabel></term>
+<listitem>
+<para>The network domain in which the host resides.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Domain Name Servers</guilabel></term>
+<listitem>
+<para>A list of DNS servers in order of preference (see <xref
+linkend="manage-dns"/>).</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Static Hosts</guilabel></term>
+<listitem>
+<para>A list of known hosts on the subnetwork system (see <xref
+linkend="manage-hosts"/>).</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<sect2 id="manage-dns">
+<title>Managing DNS Servers</title>
+
+<para>A computer running DNS matches up a fully qualified domain with a
+proper IP address. This is necessary because computers only understand the
+IP addresses. When a computer requests http://www.somedomain.com the DNS
+resolves this name to an IP-address such as 123.45.678.90.</para>
+
+<para>The <guilabel>Domain Name Servers</guilabel> part of the
+<guibutton>Domain Name System</guibutton> tab enables easy management of the
+list. Server properties can be added, removed and edited. DNS records can be
+arranged in order of preference by selecting a record and promoting or
+demoting the record in the list using the <guibutton>Move Up</guibutton> or
+<guibutton>Move Down</guibutton> buttons as required.</para>
+
+<procedure>
+<!-- Buggy. cant add alias but alias is required -->
+<title>Adding a DNS server</title>
+<step>
+<para>From the <guilabel>Domain Name Servers</guilabel> group click the
+<guibutton>Add...</guibutton> button. The <guilabel>Add New DNS Server</guilabel>
+dialog is displayed.</para>
+<!--mediaobject>
+<imageobject>
+<imagedata
+fileref="knetwork-conf-kcontrol-add-dns.png"
+format="PNG"/>
+</imageobject>
+<textobject><phrase>Adding a DNS server</phrase></textobject>
+</mediaobject-->
+</step>
+
+<step>
+<para>Enter the IP-address of the DNS server then click
+<guibutton>Add</guibutton>. The record is added to the DNS list.</para>
+</step>
+</procedure>
+
+<procedure>
+<!-- Buggy. no alias cant edit but alias is required -->
+<title>Editing a DNS server record</title>
+<step>
+<para>From the <guilabel>Domain Name Servers</guilabel> group select a DNS
+record then click the <guibutton>Edit...</guibutton> button. The
+<guilabel>Edit Server</guilabel> dialog is displayed.</para>
+<mediaobject>
+<imageobject>
+<imagedata
+fileref="09.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Editing a DNS server record</phrase>
+</textobject>
+</mediaobject>
+</step>
+<step>
+<para>Modify the IP-address then click <guibutton>OK</guibutton>. The record
+is updated to the DNS list.</para>
+</step>
+</procedure>
+</sect2>
+
+<sect2 id="manage-hosts">
+<title>Managing Static (Known) Hosts</title>
+
+<para>The <guilabel>Static Hosts</guilabel> list describes a number of
+hostname-to-address mappings for the TCP/IP subsystem. It is mostly used at
+boot time, when no name servers are running. On small, closed network
+systems, it can be used instead of Domain Name Servers.</para>
+
+<para>By default, the <guilabel>Static Hosts</guilabel> list contains some
+records describing the &apos;localhost&apos; and a handful of special
+records for hosts that support IPv6. This still-experimental version of IP
+is destined to replace version 4.</para>
+
+<procedure>
+<title>Adding Static Hosts</title>
+<step>
+<para>Click the <guibutton>Add...</guibutton> button. The <guilabel>Add New
+Static Host</guilabel> dialog is displayed.</para>
+<!--mediaobject>
+<imageobject>
+<imagedata
+fileref="figures/knetwork-conf-kcontrol-statichost.png"
+format="PNG"/>
+</imageobject>
+<textobject><phrase>Adding static hosts</phrase></textobject>
+</mediaobject-->
+</step>
+<step>
+<para>Enter the IP-address of the known host then click
+<guibutton>Add...</guibutton>. The <guilabel>Add New Alias</guilabel> dialog is
+displayed.</para>
+<!--mediaobject>
+<imageobject>
+<imagedata
+fileref="knetwork-conf-kcontrol-statichost-add.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Adding a static host</phrase>
+</textobject>
+</mediaobject-->
+</step>
+<step>
+<para>Enter the name of the known host then click the
+<guibutton>Add</guibutton> button. If the known host has multiple aliases
+click the <guibutton>Add</guibutton> button again and enter another
+alias.</para>
+</step>
+<step>
+<para>When finished click <guibutton>OK</guibutton> to update the Static
+Hosts list.</para>
+</step>
+</procedure>
+
+<procedure>
+<title>Editing Static Hosts</title>
+<step>
+<para>Select a static host record from the list, then click the
+<guibutton>Edit...</guibutton> button. The <guilabel>Edit Static
+Host</guilabel> dialog is displayed.</para>
+<!--mediaobject>
+<imageobject>
+<imagedata
+fileref="figures/knetwork-conf-kcontrol-statichost-record-edit.png"
+format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Editing static hosts</phrase>
+</textobject>
+</mediaobject-->
+</step>
+<step>
+<para>Perform any of the following tasks, then click
+<guibutton>OK</guibutton> to update the Static Hosts list.</para>
+<itemizedlist>
+<listitem>
+<para>To change the IP-address, enter a new IP-address, then click
+<guibutton>OK</guibutton>.</para>
+</listitem>
+<listitem>
+<para>To add a new alias, click the <guibutton>Add...</guibutton>
+button.</para>
+</listitem>
+<listitem>
+<para>To change an alias value, select the alias record, then click
+<guibutton>Edit...</guibutton>.</para>
+</listitem>
+<listitem>
+<para>To remove an alias, select an alias record then click
+<guibutton>Remove</guibutton>.</para>
+</listitem>
+</itemizedlist>
+</step>
+</procedure>
+</sect2>
+</sect1>
+</chapter>
+
+<chapter id="applying-changes">
+<title>Applying Changes</title>
+
+<para>Changes made via the <application>Network Settings</application>
+module are not automatically applied to the system environment. To apply the
+changes made, start &konsole; and execute the
+following command.</para>
+
+<screen>
+<userinput><command>/etc/init.d/networking</command> restart</userinput>
+</screen>
+
+</chapter>
+
+<chapter id="installation">
+<title>Installation</title>
+
+<sect1 id="requirements">
+<title>Requirements</title>
+
+<para>You need &kde; 3.x and QT 3.x installed to use knetwork-conf. </para>
+<para>knetwork-conf can be used with the following platforms: </para>
+
+<itemizedlist>
+<listitem>
+<para>&kubuntu;</para>
+</listitem>
+<listitem>
+<para>Conectiva</para>
+</listitem>
+<listitem>
+<para>Debian</para>
+</listitem>
+<listitem>
+<para>Fedora Core</para>
+</listitem>
+<listitem>
+<para>FreeBSD</para>
+</listitem>
+<listitem>
+<para>Gentoo</para>
+</listitem>
+<listitem>
+<para>&Mandrake;</para>
+</listitem>
+<listitem>
+<para>PLD</para>
+</listitem>
+<listitem>
+<para>OpenNA</para>
+</listitem>
+<listitem>
+<para>&RedHat;</para>
+</listitem>
+<listitem>
+<para>&SuSE;</para>
+</listitem>
+</itemizedlist>
+</sect1>
+
+<sect1 id="how-to-obtain-knetwork-conf">
+<title>How to obtain knetwork-conf</title>
+
+<para>knetwork-conf's home page is at <ulink
+url="http://knetworkconf.sourceforge.net"
+>http://knetworkconf.sourceforge.net</ulink> where you at least can download
+source packages. </para>
+</sect1>
+
+<sect1 id="installing-binaries">
+<title>Installing binaries</title>
+
+<para>When using the binary distributions (most often rpm packages), it is
+enough to have the &kde; and QT binaries installed. </para> <para>Installing
+binaries is recommended for less experienced users. Simply download the rpm
+packages. Install them from &konsole; using
+<application>RPM</application> as follows:</para>
+
+<para>
+<command>rpm -i knetwork-conf-versionnumber.rpm</command>
+</para>
+
+<para>Alternatively, use a graphical front end like
+ <application>kpackage</application> or the installation
+ tool of your distribution. </para>
+</sect1>
+
+<sect1 id="compilation-and-installation">
+<title>Compilation and Installation</title>
+
+<para>In this case, it is not enough to have the binaries of QT and &kde;
+installed; you also need the development packages which include libraries
+and other stuff. </para>
+
+<para>Recommended for advanced users only. Otherwise, compiling &knetworkconf;
+is not difficult. The following commands should do it.</para>
+
+<screen>
+./configure --prefix=$(kde-config --prefix)
+make
+make install
+</screen>
+
+<note>
+<para>The command <command>make install</command> must be run as
+root.</para>
+</note>
+<para>That should do it. Should you run into any problems, please
+let us know.</para>
+</sect1>
+</chapter>
+
+<chapter id="system-engineering">
+<title>Technical Information</title>
+
+<para>In the first section of this chapter, you'll find some valuable
+information about networking basics. In the second, all configuration files
+on your disk which can be changed by &knetworkconf; will be discussed. </para>
+
+<sect1 id="networking-overview">
+<title>IPv4 Networking</title>
+
+<para>This section cannot be a replacement for further lecture of
+IP-Networking. In this appendix, you'll only find the basic informations to
+get you started integrating your machine into a small (home)
+network. </para>
+
+<para>Currently, IP-networking is done using TCP/IP version 4 (IPv4). IPv5
+has never been used much. IPv6 is expected to get spread in the near
+future. So, this manual is based on the currently most spread IPv4. </para>
+
+<para>One of the most important informations for setting up an interface is
+the IP-address which you have to assign to the interface. In foreign
+networks, &eg; your office, you have to ask the network administrator to
+tell you a valid IP-address, or you can use DHCP if this is available. In
+any case, you are not allowed to simply choose any IP-address! </para>
+
+<para>If you want to set up a small (home) network of your own, you should
+use IP-addresses from a range which has especially reserved for this purpose
+to prevent IP-address-conflicts with the global (Internet) network. The
+addresses from the table shown below are not routed in the Internet, so it
+is save to use them as you like. </para>
+
+<para>Of course these machines can later be configured for Internet access
+by using a gateway machine. </para>
+
+<para>You can freely use the following addresses: </para>
+
+<table id="private-ip-addresses">
+<title>IP-Addresses for private networks</title>
+<tgroup cols="2" align="char">
+<thead>
+<row>
+<entry>Class</entry>
+<entry>Range</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry>A</entry>
+<entry>10.0.0.0 to 10.255.255.255</entry>
+</row>
+<row>
+<entry>B</entry>
+<entry>172.16.0.0 to 172.31.0.0</entry>
+</row>
+<row>
+<entry>C</entry>
+<entry>192.168.0.0 to 192.168.255.0</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<para>For smaller networks, the most often used addresses are these in the
+range of 192.168.1.1 to 192.168.1.254. This is enough for networks up to
+over 250 computers. </para>
+
+<para>Furthermore, the netmask is most often set to 255.255.255.0, so that
+all of these machines are members of the same subnet. </para>
+
+<para>Some addresses are reserved for special things, &eg; 0.0.0.0 and
+127.0.0.1. The first one is the so called default route, the second the
+loopback address. The default route is needed by IP routing. </para>
+
+<para>The network 127.0.0.1 is reserved for the IP-traffic which works on
+the local machine only. Usually, the address 127.0.0.1 is assigned to a
+special device, the so called loopback interface, which works like a closed
+circle. </para>
+
+<para>A default gateway is a computer which connects two different
+networks. If you have configured a small network of your own, it is most
+likely that you want all (or some) of your machines to grant Internet
+access. But this is not possible directly, because these machines use local
+private IP-addresses, which are not routed in the Internet. The solution is
+a computer which translates between the two different networks. This
+computer uses at least two interfaces. One of them, maybe an Ethernet card,
+points to the local network, the other one, maybe an ISDN card, points to
+the Internet. In this case, both interfaces use different IP-addresses. This
+computer performs a so called network address translation (NAT, aka
+IP-forwarding). To enable a local machine the Internet access, you have only
+to tell them the default gateway, the local IP-address of the
+gateway-computer. </para>
+
+</sect1>
+
+<sect1 id="list-of-configuration-files">
+<title>Configuration files</title>
+
+<para>In this section you'll find the configuration files which are touched
+by &knetworkconf; and where they reside in the file system of the different
+distributions. </para>
+
+<sect2 id="resolv.conf">
+<title>resolv.conf</title>
+<para>In this file, the list of name servers is stored. </para>
+<table id="resolv.conf-table">
+<title>Where to find resolv.conf</title>
+<tgroup cols="3">
+<thead>
+<row>
+<entry>Platform</entry>
+<entry>Release number</entry>
+<entry>Location</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry>Conectiva</entry>
+<entry>9.2</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>Debian</entry>
+<entry>3.0</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>Fedora Core</entry>
+<entry>1</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>FreeBSD</entry>
+<entry>5</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>Gentoo</entry>
+<entry>2005.0</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>&Mandrake;</entry>
+<entry>9.2</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>PLD</entry>
+<entry>2.0</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>OpenNA</entry>
+<entry>1.0</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>&RedHat;</entry>
+<entry>9.0</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+<row>
+<entry>&SuSE;</entry>
+<entry>9.0</entry>
+<entry>/etc/resolv.conf</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<para>This file is sometimes dynamically changed by DSL-connections, so do
+not wonder if the file doesn't contain what you have put there when a DSL
+connection is established. </para>
+</sect2>
+
+<sect2 id="hosts">
+<title>hosts</title>
+<para>In this file, the list of known hosts is stored. </para>
+
+<table id="hosts-table">
+<title>Where to find the file hosts</title>
+<tgroup cols="3">
+<thead>
+<row>
+<entry>Distribution</entry>
+<entry>Releasenumber</entry>
+<entry>Location</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry>Conectiva</entry>
+<entry>9.0</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>Debian</entry>
+<entry>3.0</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>Fedora Core</entry>
+<entry>1</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>FreeBSD</entry>
+<entry>5</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>Gentoo</entry>
+<entry>&nbsp;</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>&Mandrake;</entry>
+<entry>9.2</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>PLD</entry>
+<entry>2.0</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>OpenNA</entry>
+<entry>1</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>&RedHat;</entry>
+<entry>9.0</entry>
+<entry>/etc/hosts</entry>
+</row>
+<row>
+<entry>&SuSE;</entry>
+<entry>9.0</entry>
+<entry>/etc/hosts</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<para>On &SuSE; it is known that this file gets occasionally resorted by the
+script SuSEconfig. So do not wonder if you do not find in a state you have
+expected. </para>
+</sect2>
+</sect1>
+</chapter>
+
+<chapter id="credits-licence">
+<title>Credits and license</title>
+<sect1 id="credits">
+<title>Credits</title>
+
+<para>Thanks to all who have worked on &kappname;:</para>
+
+<itemizedlist>
+<title>Developers</title>
+<listitem>
+<para>Juan Luis Baptiste
+<email>juan.baptiste@kdemail.net</email></para>
+</listitem>
+<listitem>
+<para>David Sansome <email>me@davidsansome.com</email></para>
+</listitem>
+<listitem>
+<para>Carlos Garnacho <email>garnacho@tuxerver.net</email></para>
+</listitem>
+<listitem>
+<para>Simon Edwards <email>simon@simonzone.com</email></para>
+</listitem>
+<listitem><para>Pedro Jurado Maquedo
+<email>pjmelenas@biwemail.com</email></para>
+</listitem>
+<listitem>
+<para>Florian Fernandez <email>florian.fernandez2@wanadoo.fr</email></para>
+</listitem>
+<listitem>
+<para>Unai Garro <email>Unai.Garro@ee.ed.ac.uk</email></para>
+</listitem>
+<listitem>
+<para>Christoph Eckert <email>mchristoph.eckert@t-online.de</email></para>
+</listitem>
+<listitem>
+<para>Jaime Torres <email>jtorres@telecorp.net</email></para>
+</listitem>
+<listitem>
+<para>All the others which I have forgotten to list here - you know who
+you are <email>you@foo.tld</email></para>
+</listitem>
+</itemizedlist>
+
+<itemizedlist>
+<title>Authors</title>
+<listitem>
+<para>Christoph Eckert:
+<email>mchristoph.eckert@t-online.de</email></para>
+</listitem>
+<listitem>
+<para>Sean Wheller: <email>sean@inwords.co.za</email></para>
+</listitem>
+</itemizedlist>
+</sect1>
+
+<sect1 id="licence">
+<title>License</title>
+
+<para>The Copyright on &kappname;, at least for the years 2003 and 2004, is
+owned by Juan Luis Baptiste:
+(<email>juan.baptiste@kdemail.net</email>). </para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+</sect1>
+</chapter>
+</book>
diff --git a/doc/kpackage/Makefile.am b/doc/kpackage/Makefile.am
new file mode 100644
index 0000000..085981d
--- /dev/null
+++ b/doc/kpackage/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kpackage/bsdloc.png b/doc/kpackage/bsdloc.png
new file mode 100644
index 0000000..b498b7f
--- /dev/null
+++ b/doc/kpackage/bsdloc.png
Binary files differ
diff --git a/doc/kpackage/debaptloc.png b/doc/kpackage/debaptloc.png
new file mode 100644
index 0000000..965b2ef
--- /dev/null
+++ b/doc/kpackage/debaptloc.png
Binary files differ
diff --git a/doc/kpackage/debloc.png b/doc/kpackage/debloc.png
new file mode 100644
index 0000000..bcc96d0
--- /dev/null
+++ b/doc/kpackage/debloc.png
Binary files differ
diff --git a/doc/kpackage/handle.png b/doc/kpackage/handle.png
new file mode 100644
index 0000000..58caf2d
--- /dev/null
+++ b/doc/kpackage/handle.png
Binary files differ
diff --git a/doc/kpackage/index.docbook b/doc/kpackage/index.docbook
new file mode 100644
index 0000000..2112411
--- /dev/null
+++ b/doc/kpackage/index.docbook
@@ -0,0 +1,1229 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN"
+"dtd/kdex.dtd" [
+ <!ENTITY kappname "&kpackage;">
+ <!ENTITY package "kdeadmin">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+<bookinfo>
+<title>The &kpackage; Handbook</title>
+<authorgroup>
+<author>
+<firstname>Toivo</firstname>
+<surname>Pedaste</surname>
+<affiliation>
+<address><email>toivo@ucs.uwa.edu.au</email></address>
+</affiliation>
+</author>
+
+<othercredit role="reviewer">
+<firstname>Lauri</firstname>
+<surname>Watts</surname>
+<affiliation>
+<address><email>lauri@kde.org</email></address>
+</affiliation>
+<contrib>Reviewer</contrib>
+</othercredit>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>2000</year>
+<holder>Toivo Pedaste</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2006-12-04</date>
+<releaseinfo>3.5.5</releaseinfo>
+
+<abstract><para>&kpackage; is a &GUI; interface to the
+<acronym>RPM</acronym>, Debian, Slackware and BSD package
+managers.</para></abstract>
+
+<keywordset>
+<keyword>kpackage</keyword>
+<keyword>package</keyword>
+<keyword>package manager</keyword>
+<keyword>RPM</keyword>
+<keyword>deb</keyword>
+</keywordset>
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&kpackage; is a &GUI; interface to the <acronym>RPM</acronym>,
+Debian, Slackware and <acronym>BSD</acronym> package managers. &kpackage; is part of the K Desktop
+Environment and, as a result, it is designed to integrate with the &kde;
+file manager. </para>
+
+</chapter>
+
+<chapter id="onscreen-fundamentals">
+
+<title>Onscreen Fundamentals</title>
+
+<para>&kpackage; has two panels. The left panel displays a tree of the
+installed and available packages, the right panel displays information
+on the packages.</para>
+
+
+<sect1 id="the-main-window-left">
+<title>The Main Window - Package Tree</title>
+
+<para>When &kpackage; is started normally (that is it has not been
+invoked via drag and drop and has not been given any parameters) it
+displays two panels with the package tree on the left, this tree shows
+installed packages and optionally new and updated packages as
+well.</para>
+
+<screenshot>
+<screeninfo>&kpackage; Left Panel</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="left.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Left Panel - Package Tree</phrase>
+</textobject>
+<caption>
+<para>Left Panel - Package Tree</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para>The left panel displays the list of packages, the tabs along
+the top determines which packages are displayed:</para>
+
+<itemizedlist>
+
+<listitem><para><guilabel>Installed</guilabel> - Show installed packages</para></listitem>
+
+<listitem><para><guilabel>Updated</guilabel> - Show packages for which newer versions are available</para></listitem>
+
+<listitem><para><guilabel>New</guilabel> - Show uninstalled packages</para></listitem>
+
+<listitem><para><guilabel>All</guilabel> - All packages</para></listitem>
+
+</itemizedlist>
+<para>Below the tabs is the <guilabel>Search</guilabel> line, this filters the package tree so that only those packages whose name or summary contains the search string are displayed.</para>
+
+<para>The package tree is based on the sections of the distribution
+and shows summary information about the packages:</para>
+<itemizedlist>
+
+<listitem><para><guilabel>Package</guilabel> - Name of the package</para></listitem>
+<listitem><para><guilabel>Mark</guilabel> - Shows a tick if the package has
+been marked. Marking allows multiple packages to be installed or
+uninstalled at once using the buttons located below the package tree.</para></listitem>
+<listitem><para><guilabel>Summary</guilabel>- A short description of the package.</para></listitem>
+<listitem><para><guilabel>Size</guilabel>- The package size</para></listitem>
+<listitem><para><guilabel>Version</guilabel> - The package version</para></listitem>
+<listitem><para><guilabel>Old Version</guilabel> - If the package updates an installed package, the
+version of the old package</para></listitem>
+
+</itemizedlist>
+
+<para>The packages have graphical labels to indicate their state, an
+image representing the package type means an installed package, a
+<guilabel>N</guilabel> indicates an available package and a <guilabel>U</guilabel>
+means a package that can upgrade an installed package.</para>
+
+<para>A single package is selected by clicking on the name. Clicking on
+the dot in the <guilabel>Mark</guilabel> column marks the package with a
+tick, a second click unmarks it, while <keycombo
+action="simul">&Shift;<mousebutton>left</mousebutton></keycombo> click
+can be used to mark a range of packages and <keycombo
+action="simul">&Ctrl;<mousebutton>left</mousebutton></keycombo> click
+can be used to add and remove marks on packages.</para>
+
+<para>Selecting a package from the tree displays information about it in
+the right panel.</para>
+
+</sect1>
+
+<sect1 id="package-information-panel">
+<title>The Main Window - Package Information Panel</title>
+
+<para>The right panel has tabs for displaying three different types of
+information about selected packages </para>
+
+<itemizedlist>
+<listitem>
+<screenshot>
+<screeninfo>&kpackage; Right Panel - Properties</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="right-prop.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Right Panel - Package Properties</phrase>
+</textobject>
+<caption>
+<para>The <guilabel>Properties</guilabel> tab which displays
+information on the selected package. In the dependency information there are
+hyper-links to the packages listed, installed packages are in standard font,
+uninstalled but available packages are in italic and dependencies that aren't
+available are normal text.</para>
+</caption>
+</mediaobject>
+</screenshot>
+</listitem>
+
+<listitem>
+
+<screenshot>
+<screeninfo>&kpackage; Right Panel - Properties</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="right-files.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Right Panel - The Files in the Package</phrase>
+</textobject>
+<caption>
+<para>The <guilabel>File List</guilabel> tab shows the files in the
+package and for installed packages (provided the information is
+available) shows the state of the
+files. Files that exist are marked with a tick, those that are
+missing are marked with a cross.</para>
+
+</caption>
+</mediaobject>
+</screenshot>
+
+</listitem>
+
+<listitem>
+<screenshot>
+<screeninfo>&kpackage; Right Panel - Properties</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="right-change.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Right Panel - The Files in the Package</phrase>
+</textobject>
+<caption>
+<para>The <guilabel>Change Log</guilabel> tab shows the change log
+for the package.</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+</listitem>
+
+</itemizedlist>
+
+</sect1>
+
+<sect1 id="installing-packages">
+<title>Installing Packages</title>
+
+<para>To install a package you can</para>
+<itemizedlist>
+<listitem>
+<para>locate the package you wish to install in &konqueror;, drag it
+onto a running copy of &kpackage;</para>
+</listitem>
+<listitem>
+<para>click on a package file in &konqueror; and start a new copy of
+&kpackage;</para>
+</listitem>
+<listitem>
+<para>use on the <guimenu>Open</guimenu> menu items in
+&kpackage;</para>
+</listitem>
+<listitem>
+<para>selecting an available package in the package tree</para>
+</listitem>
+</itemizedlist>
+
+<para>For a selected package, use the buttons in the right panel, the
+<guibutton>Fetch</guibutton> button will fetch the package from a remote
+source and display detailed information, the
+<guibutton>Install</guibutton> button pops up the installation
+window. </para>
+
+<para>For marked packages, use the
+<guibutton>Install Marked</guibutton> button on the left panel,
+which pops up the install
+window.</para>
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="install.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Install Dialog</phrase>
+</textobject>
+<caption>
+<para>Install Dialog</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para>The install window lists the packages to be selected to
+be installed in a panel in the top left, if Debian <acronym>APT</acronym>
+is being used the packages needed to satisfy any dependencies are
+also shown. Below this there are a set of check boxes which set options for
+the install program. For <acronym>RPM</acronym> packages the options
+are:</para>
+<itemizedlist>
+<listitem>
+<para><guilabel>Upgrade</guilabel> - Will upgrade any already
+installed package.</para>
+</listitem>
+<listitem>
+<para><guilabel>Replace Files</guilabel> - Install the packages even
+if they replace files from other, already installed, packages.</para>
+</listitem>
+<listitem>
+<para><guilabel>Check Dependencies</guilabel> - Verify dependencies.</para>
+</listitem>
+<listitem>
+<para><guilabel>Test (do not install)</guilabel></para>
+</listitem>
+</itemizedlist>
+
+<para>For Debian <acronym>APT</acronym> the options are:</para>
+<itemizedlist>
+<listitem>
+<para><guilabel>Download only</guilabel> - Fetch the packages but
+don't install them.</para>
+</listitem>
+<listitem>
+<para><guilabel>No download</guilabel> - Only use packages that
+are locally available</para>
+</listitem>
+<listitem>
+<para><guilabel>Ignore missing</guilabel> - Do the install even if
+some packages are missing</para>
+</listitem>
+<listitem>
+<para><guilabel>Ignore hold</guilabel> - Ignore holds that have been
+placed on packages</para>
+</listitem>
+<listitem>
+<para><guilabel>Allow Unauthenticated</guilabel> - Ignore any requirements that
+the packages must be signed.</para>
+</listitem>
+<listitem>
+<para><guilabel>Assume yes</guilabel> - Answer yes for any questions
+the install program would ask.</para>
+</listitem>
+<listitem>
+<para><guilabel>Test (do not install)</guilabel></para>
+</listitem>
+</itemizedlist>
+
+<para>The <guibutton>Install</guibutton> button will start the
+actual install. Normally the install window will be deleted after
+a successful install but if the
+<guibutton>Keep this window</guibutton> check box is selected the
+window will stay around.</para>
+
+<para>The panel on the right is an integrated
+terminal window in which the installation programs are run, for
+interactive installation programs the interaction is done in this
+window. </para>
+
+</sect1>
+
+<sect1 id="uninstalling-packages">
+<title>Uninstalling Packages</title>
+
+<para>A selected package can be uninstalled by using the
+<guibutton>Uninstall</guibutton> button in the right panel, the
+<guibutton>Uninstall Marked</guibutton> in the right panel
+can be used to uninstall marked packages. The buttons bring
+up the uninstall window.</para>
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="uninstall.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Uninstall Dialog</phrase>
+</textobject>
+<caption>
+<para>Uninstall Dialog</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para>The
+<guibutton>Uninstall</guibutton> button in the window causes the
+packages to be uninstalled, and the right panel provides an integrated
+terminal window for the uninstall program.</para>
+
+<para>For <acronym>RPM</acronym> packages the options
+are:</para>
+<itemizedlist>
+<listitem>
+<para><guilabel>Use scripts</guilabel> - Execute any unistall scripts</para>
+</listitem>
+<listitem>
+<para><guilabel>Check Dependencies</guilabel> - Verify dependencies.</para>
+</listitem>
+<listitem>
+<para><guilabel>Test (do not uninstall)</guilabel></para>
+</listitem>
+</itemizedlist>
+
+<para>For Debian <acronym>APT</acronym> the options are:</para>
+<itemizedlist>
+<listitem>
+<para><guilabel>Purge Config Files</guilabel> - Remove any package
+configuration files.</para>
+</listitem>
+<listitem>
+<para><guilabel>Assume yes</guilabel> - Answer yes for any questions
+the install program would ask.</para>
+</listitem>
+<listitem>
+<para><guilabel>Test (do not uninstall)</guilabel></para>
+</listitem>
+</itemizedlist>
+
+
+</sect1>
+
+<sect1 id="integrating-available-packages-in-the-tree">
+<title>Integrating available packages in the tree</title>
+
+<para>Access to available packages is setup in the menu with <menuchoice><guimenu>Settings</guimenu>
+<guimenuitem>Configure &kpackage;...</guimenuitem></menuchoice>.
+</para>
+
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="handle.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Package Handler Panel</phrase>
+</textobject>
+<caption>
+<para>Package Handler Panel </para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para>The top part of the panel has the <guilabel>Remote Host</guilabel>
+box which allows &kpackage; to operate on the packages on a remote computer,
+this functionality requires <command>ssh</command> and is only available
+when using Debian apt. The name of the remote
+computer is entered into the combobox and &kpackage; will access
+it when the <guilabel>Use remote host</guilabel> checkbox is
+selected.</para>
+
+<para>The rest of the panel allows the enabling and disabling of
+the various package types that &kpackage; can handle. If a package
+type is enabled the <guibutton>Location of Packages</guibutton> button
+will bring up a dialog for setting the location of available packages.
+If the programs required for handling a package type is not available the package
+type will be automatically disabled.
+</para>
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="rpmloc.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>RPM Location Dialog</phrase>
+</textobject>
+<caption>
+<para>RPM Location Dialog</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para>For <acronym>RPM</acronym> packages &kpackage; can read a
+folder containing packages and add these to the package tree as
+either new or updated packages. It is possible to examine or install
+these packages from the package tree. By default the information about
+the packages is extracted from the standard format of the file names and
+so it is necessary to use the <guibutton>Examine</guibutton> button to
+see the full description, it is possible though to set an option so that
+for local folders each package file is read, this is slower but
+gives a full description.</para>
+
+<para>The <acronym>RPM</acronym> locations dialog allows the specification
+of folders containing <acronym>RPM</acronym> packages, it's divided
+up into a number of tabbed panels for convenience of management. Each
+line in the panel specifies a folder, the <guilabel>Use</guilabel>
+checkbox is selected the folder is used, otherwise it's ignored.
+The text entry field can take either a folder path or an <command>ftp</command>
+URL. The <guilabel>Subfolders</guilabel> checkbox determines
+whether subfolders are searched for packages. The <guibutton>...</guibutton>
+button will pop up a folder selection dialog.</para>
+
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="debaptloc.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Debian Apt Location Dialog</phrase>
+</textobject>
+<caption>
+<para>Debian Apt Location Dialog</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para><guilabel>APT: Debian</guilabel> means that Debian packages
+are handled using the <command>deb-apt</command> command which
+can automatically fetch packages from repositories and
+resolve dependencies.</para>
+
+<para>The location of
+uninstalled package repositories can be set in the "A" panel, this is
+used to write the <filename>/etc/apt/sources.list</filename> file
+which controls where <command>deb-apt</command> searches for packages,
+each entry corresponds to a line in the file, if the
+<guilabel>Use</guilabel> checkbox is not set the line is commented
+out.</para>
+
+<para>The "D" panel allows the specification of folders containing
+Debian packages.</para>
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="debloc.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Debian DPKG Location Dialog: L and P panels</phrase>
+</textobject>
+<caption>
+<para>Debian DPKG Location Dialog: L and P panels</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+
+<para>DPKG: Debian means that packages are handled using <command>dpkg</command>
+command, there are three ways of accessing available packages, these can be
+selected in three different types of location setting panels. </para>
+
+<itemizedlist>
+<listitem>
+<para>The "I" panel specifies the location of the Debian package tree
+and selects the
+distribution and architecture. &kpackage; will look in the standard
+places for the Package files describing the available packages and these
+packages are then added to the package tree and can be examined or
+installed</para>
+</listitem>
+<listitem>
+<para>The "P" panel specifies the location of the Debian distribution along with the
+<filename>Packages</filename> files for the parts of the distribution that are of
+interest. If the <command>dselect</command> program is being
+used then the file <filename>/var/lib/dpkg/available</filename> can be
+used as a <filename>Packages</filename> file that describes the distribution that
+<command>dselect</command> uses.</para>
+</listitem>
+<listitem><para>The "D" panel specifies folders that are handled in the same way as with
+<acronym>RPM</acronym> packages.</para></listitem>
+</itemizedlist>
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="slackloc.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>Slackware Location Dialog</phrase>
+</textobject>
+<caption>
+<para>Slackware Location Dialog</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para>For Slackware packages there is very little information stored on
+installed packages, but it is possible to use a
+<filename>PACKAGE.TXT</filename> file as a source of information about
+the installed packages. The <filename>PACKAGES.TXT</filename> file is
+the equivalent of a Debian Packages file and Slackware distributions are
+structured with a folder tree containing the <literal
+role="extension">.tgz</literal> packages and a
+<filename>PACKAGES.TXT</filename> file that describes the
+packages.</para>
+
+<para>As with Debian distributions the packages in a Slackware
+distribution can be integrated into the package tree. Unfortunately the
+Slackware packages don't carry version information so it is not possible
+to tell with available packages are newer than installed ones.</para>
+
+<itemizedlist>
+<listitem><para>The "I" panel is the location of a
+<filename>PACKAGES.TXT</filename> file which is used to provided information on
+the installed packages</para></listitem>
+<listitem><para>The "P" panels can be used to specify the location of
+distributions with the folder tree containing the <literal
+role="extension">.tgz</literal> files and the location of the corresponding
+<filename>PACKAGES.TXT</filename> file</para></listitem>
+<listitem><para>The "D" panels are for folders that do
+<emphasis>not</emphasis> have a corresponding <filename>PACKAGES.TXT</filename>
+fi
+le</para></listitem>
+</itemizedlist>
+
+<screenshot>
+<screeninfo>&kpackage; Install dialog</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="bsdloc.png" format="PNG"/> </imageobject>
+<textobject>
+<phrase>BSD Location Dialog</phrase>
+</textobject>
+<caption>
+<para>BSD Location Dialog</para>
+</caption>
+</mediaobject>
+</screenshot>
+
+<para>For <acronym>BSD</acronym> packages &kpackage; will understand a
+packages distribution folder that contains an
+<filename>INDEX</filename> file (which describes all the packages) and
+also contains an <filename>All</filename> folder (with all the
+package files in it). </para>
+
+<para>The "Ports" panel gives the location of the ports tree in
+the file system </para>
+<para>The "Packages" panel allows the specifying the location of packages
+folders &ie; those containing <filename>INDEX</filename>
+files</para>
+
+<para>For remote folders and package files (&ie; those fetched via
+&FTP;) &kpackage; will do caching, the packages are by default cached in
+<filename>~/.kpackage</filename> and the folders in
+<filename>~/.kpackage/dir</filename>.</para>
+
+<note><para>For the handling of remote (&FTP;) folders to work, it
+may be necessary to not have the <guilabel>FTP Proxy</guilabel> set in the
+Browser Settings.</para></note>
+
+</sect1>
+
+<sect1 id="Searching">
+<title>Searching</title>
+<sect2>
+<title>Package Search Line</title>
+
+<screenshot>
+ <screeninfo>&kpackage; Search Line</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="searchl.png" format="PNG"/> </imageobject>
+ <textobject>
+ <phrase>Search Line</phrase>
+ </textobject>
+ <caption>
+ <para>Search Line</para>
+ </caption>
+ </mediaobject>
+</screenshot>
+
+<para>The Search line filters the package tree so that only those packages whose name or summary contains the search string are displayed.</para>
+</sect2>
+
+
+<sect2>
+ <title>Find Package</title>
+
+ <screenshot>
+ <screeninfo>&kpackage; Find Package</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="search.png" format="PNG"/> </imageobject>
+ <textobject>
+ <phrase>Find Package</phrase>
+ </textobject>
+ <caption>
+ <para>Find Package</para>
+ </caption>
+ </mediaobject>
+ </screenshot>
+
+ <para>The <guilabel>Find Package</guilabel> dialog searches the names
+ of the packages in the package tree and moves to the next matching package.
+ If <guilabel>Sub string</guilabel> is not set then it will find only exact
+ matches against packages names. If <guilabel>Wrap search</guilabel> is not
+ set the search doesn't wrap around the end of the package tree.
+ </para>
+</sect2>
+
+<sect2>
+ <title>Find File</title>
+
+ <screenshot>
+ <screeninfo>&kpackage; Find File</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="searchf.png" format="PNG"/> </imageobject>
+ <textobject>
+ <phrase>Find File</phrase>
+ </textobject>
+ <caption>
+ <para>Find File</para>
+ </caption>
+ </mediaobject>
+ </screenshot>
+
+ <para>The <guilabel>Find File</guilabel> dialog searches for files the names of
+ which contain the search string.
+ The columns in the display are:</para>
+ <itemizedlist>
+ <listitem>
+ <para><guilabel>Installed</guilabel> - Ticked if it is an installed package.</para>
+ </listitem>
+ <listitem>
+ <para><guilabel>Type</guilabel> - The type of the package.</para>
+ </listitem>
+ <listitem>
+ <para><guilabel>Package</guilabel> - The name of the package</para>
+ </listitem>
+ <listitem>
+ <para><guilabel>File Name</guilabel> - The name of the matched file</para>
+ </listitem>
+ </itemizedlist>
+ <para>Only the files in installed packages are shown unless <guilabel>Also search uninstalled packages</guilabel> is set, this will only work with Debian APT
+ packages and only if the <command>apt-file</command> command is installed.
+ The database used by the <command>apt-file</command> command is updated
+ by the <guimenuitem>Apt-File Update</guimenuitem> menu item.
+ </para>
+
+</sect2>
+
+
+</sect1>
+
+<sect1 id="Misc">
+ <title>Misc</title>
+ <sect2>
+ <title>Root Access</title>
+
+ <para>&kpackage; requires <systemitem class="username">root</systemitem>
+ access for installing/uninstalling packages, this can be can be done by
+ running &kpackage; as <systemitem class="username">root</systemitem>,
+ say by using &kdesu;.</para>
+
+ <para>Alternatively, if &kpackage; is running as a normal user it will
+ try to run the install/uninstall programs as root by logging in to a
+ pseudo terminal, it will use either <command>su</command>, <command>sudo</command> or
+ <command>ssh</command> to do this and if needed it will pop up a
+ prompt window where the <systemitem class="username">root</systemitem>
+ password or <command>ssh</command> key can be typed. For this to work the root prompt has to end in
+ <prompt># </prompt>. The <guimenuitem>Keep password</guimenuitem> option causes &kpackage; to
+ remember the password that is entered. </para>
+ <screenshot>
+ <screeninfo>&kpackage; Password prompt</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="root-prompt.png" format="PNG"/> </imageobject>
+ <textobject>
+ <phrase>Password prompt</phrase>
+ </textobject>
+ <caption>
+ <para>Password prompt</para>
+ </caption>
+ </mediaobject>
+ </screenshot>
+
+ </sect2>
+
+
+ <sect2>
+ <title>Drag and Drop</title>
+
+ <para>&kpackage; makes use of the &kde; Drag and Drop protocol. This
+ means that you can drag and drop packages onto &kpackage; to open
+ them. Dropping a file onto the <guilabel>Find File</guilabel> dialog
+ will find the package that contains the file.</para>
+
+ </sect2>
+</sect1>
+
+</chapter>
+<chapter id="menus">
+
+<title>Menus</title>
+
+<para>This describes the &kpackage; menus. </para>
+
+<sect1 id="file-menu">
+<title><guimenu>File</guimenu> menu</title>
+
+<para>The items in the <guimenu>File</guimenu> menu are:</para>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>O</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open...</guimenuitem></menuchoice></term>
+<listitem><para>Brings up file selector for local and &FTP;
+files</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>File</guimenu>
+<guisubmenu>Open Recent</guisubmenu></menuchoice></term>
+<listitem><para>A list of the most recently open package files</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>F</keycap></keycombo></shortcut>
+<guimenu>File</guimenu><guimenuitem>Find
+Package...</guimenuitem></menuchoice></term>
+<listitem><para>Search the installed package list for a package, the name
+of which contains the entered string </para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>File</guimenu>
+<guimenuitem>Find File...</guimenuitem></menuchoice></term>
+<listitem><para>Produces a list of packages that contain the entered
+file name, selecting a line will display the information on that
+package. It behaves slightly differently for <acronym>RPM</acronym>
+(where you have to enter the exact file name) and <abbrev>DEB</abbrev>
+(where you can enter a regular expression).</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycap>F5</keycap></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Reload</guimenuitem></menuchoice></term>
+<listitem><para>Reread the package data and rebuild the package
+tree</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>Q</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem></menuchoice></term>
+<listitem><para>Quit &kpackage; </para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="packages-menu">
+<title><guimenu>Packages</guimenu> menu</title>
+
+<para>The items in the <guimenu>Packages</guimenu> menu are:</para>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Alt;<keycap>Left</keycap>
+</keycombo></shortcut>
+<guimenu>Packages</guimenu>
+<guimenuitem>Back</guimenuitem></menuchoice></term>
+<listitem><para>Back button for navigation using the links in
+<guilabel>Properties</guilabel> entries in the right panel.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Alt;<keycap>Right</keycap>
+</keycombo></shortcut>
+<guimenu>Packages</guimenu>
+<guimenuitem>Forward</guimenuitem></menuchoice></term>
+<listitem><para>Forward button for navigation using the links in
+<guilabel>Properties</guilabel> entries in the right panel.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Packages</guimenu>
+<guimenuitem>Expand Tree</guimenuitem></menuchoice></term>
+<listitem><para>Fully expands the packages tree</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Packages</guimenu>
+<guimenuitem>Collapse Tree</guimenuitem> </menuchoice></term>
+<listitem><para>Collapses the package tree so that only the tree structure is
+shown</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice> <guimenu>Packages</guimenu>
+<guimenuitem>Clear Marked</guimenuitem> </menuchoice></term>
+<listitem><para>Unmarks all packages</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice> <guimenu>Packages</guimenu>
+<guimenuitem>Mark All</guimenuitem> </menuchoice></term>
+<listitem><para>Marks all packages that are members of the selected view</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Package</guimenu>
+<guimenuitem>Install</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Install the currently selected package</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Package</guimenu>
+<guimenuitem>Install Marked</guimenuitem></menuchoice></term>
+<listitem>
+<para>Install all marked packages</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Package</guimenu>
+<guimenuitem>Uninstall</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Uninstall the currently selected package</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Package</guimenu>
+<guimenuitem>Uninstall Marked</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Uninstall all marked packages</para>
+</listitem>
+</varlistentry>
+
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="cache-menu">
+<title><guimenu>Cache</guimenu> menu</title>
+
+<para>The items in the <guimenu>Cache</guimenu> menu are: </para>
+<variablelist>
+<varlistentry>
+<term><menuchoice><guimenu>Cache</guimenu> <guimenuitem>Clear
+Package Folder Cache</guimenuitem></menuchoice></term>
+<listitem><para>Delete cached copies of remote package folders and Packages
+files</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Cache</guimenu><guimenuitem>Clear Package
+Cache</guimenuitem>
+</menuchoice></term>
+<listitem><para>Delete cached copies of remote package files that have been
+fetched</para> </listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="special-menu">
+<title><guimenu>Special</guimenu> menu</title>
+
+<para>The <guimenu>Special</guimenu> contains actions
+related to specific package types:</para>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Special</guimenu><guimenuitem>
+APT: Debian</guimenuitem>
+</menuchoice></term>
+<listitem>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Update</guilabel></term>
+<listitem><para>Update <command>apt</command> indexes from package
+repositories.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Upgrade</guilabel></term>
+<listitem><para>Upgrade the Debian installation to the latest versions
+of all the packages.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Fixup</guilabel></term>
+<listitem><para><command>apt</command> is extremely strict about
+dependencies, attempt to fixup dependency problems</para></listitem>
+</varlistentry>
+
+<varlistentry>
+ <term><guilabel>Apt-File Update</guilabel></term>
+ <listitem><para>Searching for uninstall files uses the <command>apt-file</command> command, this updates the database that <command>apt-file</command> uses.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</listitem>
+
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="settings-menu">
+<title><guimenu>Settings</guimenu> menu</title>
+
+<para>The items in the <guimenu>Settings</guimenu> menu are:</para>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Show
+Toolbar</guimenuitem>
+</menuchoice></term>
+<listitem><para>Toggle displaying the toolbar</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Save
+Settings</guimenuitem></menuchoice></term>
+<listitem><para>Save options immediately</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure
+Shortcuts...</guimenuitem></menuchoice></term>
+<listitem><para>The standard &kde; dialog for setting shortcut
+keys</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure
+Toolbars...</guimenuitem></menuchoice></term>
+<listitem><para>The standard &kde; dialog for configuring tool
+bars</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu>
+<guimenuitem>Configure &kpackage;...</guimenuitem></menuchoice></term>
+<listitem>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Types</guilabel></term>
+<listitem><para>Which package types to handle, Debian using DPKG and
+Debian using APT are listed separately, it is not a good idea to
+enable both at the same time. It also sets whether to access
+a remote host for Debian apt.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Cache</guilabel></term>
+<listitem><para>Controls caching of remote (&FTP;ed) folders and Package
+files.</para>
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Cache Remote Package Folders</guilabel></term>
+<listitem><para>Whether to cache remote (&FTP;ed) folders and Package
+files.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Cache Remote Package Files</guilabel></term>
+<listitem><para>Whether to cache remote package files that have been fetched
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Cache Folder</guilabel></term>
+<listitem><para>Where to cache package files and folders
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>misc</guilabel></term>
+<listitem>
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Execute Privileged Commands Using</guilabel></term>
+<listitem><para>Use <command>su</command>, <command>sudo</command> or
+<command>ssh</command> for running privileged commands. For remote Debian APT <command>ssh</command>
+is always used.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Verify file list</guilabel></term>
+<listitem><para>If set the list of files in the package is checked to see if
+they are actually installed</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Read information from all local package files</guilabel></term>
+<listitem><para>If set all the files from a (local) package folder are read
+instead of just using the files names, this is slower but shows more
+information.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</listitem>
+</varlistentry>
+</variablelist>
+</listitem>
+</varlistentry>
+
+
+</variablelist>
+</sect1>
+
+<sect1 id="help-menu">
+<title><guimenu>Help</guimenu> menu</title>
+
+<para>The items in the <guimenu>Help</guimenu> menu are: </para>
+
+&help.menu.documentation;
+
+</sect1>
+
+<sect1 id="toolbar">
+<title>Toolbar</title>
+
+<itemizedlist>
+<listitem><para><guiicon>Open</guiicon></para></listitem>
+<listitem><para><guiicon>Back</guiicon></para></listitem>
+<listitem><para><guiicon>Forward</guiicon></para></listitem>
+<listitem><para><guiicon>Expand Tree</guiicon></para></listitem>
+<listitem><para><guiicon>Collapse Tree</guiicon></para></listitem>
+<listitem><para><guiicon>Find Package</guiicon></para></listitem>
+<listitem><para><guiicon>Find File</guiicon></para></listitem>
+<listitem><para><guiicon>Reload</guiicon></para></listitem>
+</itemizedlist>
+</sect1>
+</chapter>
+
+<chapter id="credits-and-licenses">
+<title>Credits and Licenses</title>
+
+<para>
+&kpackage;
+</para>
+
+<para>Documentation copyright 2005 Toivo Pedaste
+<email>toivo@ucs.uwa.edu.au</email></para>
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<sect1 id="how-to-obtain-kpackage">
+<title>How to obtain &kpackage;</title>
+
+&install.intro.documentation;
+
+<para>For information on how to obtain and compile it see <ulink
+url="http://www.kde.org/install-source.html">
+http://www.kde.org/install-source.html</ulink></para>
+
+<para>There is more information on compilation at <ulink
+url="http://www.kde.org/compilationfaq.html">
+http://www.kde.org/compilationfaq.html</ulink></para>
+
+<para>There is a web page at <ulink
+url="http://www.general.uwa.edu.au/u/toivo/kpackage">
+http://www.general.uwa.edu.au/u/toivo/kpackage</ulink></para>
+
+</sect1>
+
+<sect1 id="requirements">
+<title>Requirements</title>
+
+<para>For installing &kpackage; you need:</para>
+
+<itemizedlist>
+<listitem><para>&Qt; 3 and &kde; 3</para></listitem>
+</itemizedlist>
+
+<para>For listing Debian packages no other software is needed but to
+install and uninstall the packages you need:</para>
+
+<itemizedlist>
+<listitem><para>the <command>dpkg</command> package
+manager or</para></listitem>
+
+<listitem><para> <command>apt-get</command> and
+<command>apt-cache</command></para></listitem>
+</itemizedlist>
+
+<para>For <acronym>BSD</acronym> packages you need the package
+management programs: </para>
+
+<itemizedlist>
+<listitem><para><command>pkg_info</command></para></listitem>
+<listitem><para><command>pkg_add</command></para></listitem>
+<listitem><para><command>pkg_delete</command></para></listitem>
+</itemizedlist>
+
+<para>For Slackware packages you need: </para>
+
+<itemizedlist>
+<listitem><para><command>installpkg</command> </para></listitem>
+<listitem><para><command>removepkg</command></para></listitem>
+</itemizedlist>
+
+<para>For dealing with Redhat packages you need:</para>
+
+<itemizedlist>
+
+<listitem><para><command>rpm</command> </para></listitem>
+</itemizedlist>
+
+<para>For &kpackage; to work correctly with <acronym>RPM</acronym>
+packages the <acronym>RPM</acronym> database must be initialized. If
+typing <userinput><command>rpm</command>
+<option>-qa</option></userinput> gives an error about
+<computeroutput>unable to open....</computeroutput> then try
+<userinput><command>rpm</command>
+<option>--rebuilddb</option></userinput>.</para>
+
+</sect1>
+
+</appendix>
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+End:
+-->
+
diff --git a/doc/kpackage/install.png b/doc/kpackage/install.png
new file mode 100644
index 0000000..958dc44
--- /dev/null
+++ b/doc/kpackage/install.png
Binary files differ
diff --git a/doc/kpackage/left.png b/doc/kpackage/left.png
new file mode 100644
index 0000000..ad665c2
--- /dev/null
+++ b/doc/kpackage/left.png
Binary files differ
diff --git a/doc/kpackage/right-change.png b/doc/kpackage/right-change.png
new file mode 100644
index 0000000..303dd62
--- /dev/null
+++ b/doc/kpackage/right-change.png
Binary files differ
diff --git a/doc/kpackage/right-files.png b/doc/kpackage/right-files.png
new file mode 100644
index 0000000..e986caf
--- /dev/null
+++ b/doc/kpackage/right-files.png
Binary files differ
diff --git a/doc/kpackage/right-prop.png b/doc/kpackage/right-prop.png
new file mode 100644
index 0000000..94b01de
--- /dev/null
+++ b/doc/kpackage/right-prop.png
Binary files differ
diff --git a/doc/kpackage/root-prompt.png b/doc/kpackage/root-prompt.png
new file mode 100644
index 0000000..b954963
--- /dev/null
+++ b/doc/kpackage/root-prompt.png
Binary files differ
diff --git a/doc/kpackage/rpmloc.png b/doc/kpackage/rpmloc.png
new file mode 100644
index 0000000..52b03b1
--- /dev/null
+++ b/doc/kpackage/rpmloc.png
Binary files differ
diff --git a/doc/kpackage/search.png b/doc/kpackage/search.png
new file mode 100644
index 0000000..4d77cc1
--- /dev/null
+++ b/doc/kpackage/search.png
Binary files differ
diff --git a/doc/kpackage/searchf.png b/doc/kpackage/searchf.png
new file mode 100644
index 0000000..135f89b
--- /dev/null
+++ b/doc/kpackage/searchf.png
Binary files differ
diff --git a/doc/kpackage/searchl.png b/doc/kpackage/searchl.png
new file mode 100644
index 0000000..fc47d07
--- /dev/null
+++ b/doc/kpackage/searchl.png
Binary files differ
diff --git a/doc/kpackage/slackloc.png b/doc/kpackage/slackloc.png
new file mode 100644
index 0000000..210cf6b
--- /dev/null
+++ b/doc/kpackage/slackloc.png
Binary files differ
diff --git a/doc/kpackage/uninstall.png b/doc/kpackage/uninstall.png
new file mode 100644
index 0000000..b30ed5c
--- /dev/null
+++ b/doc/kpackage/uninstall.png
Binary files differ
diff --git a/doc/ksysv/Makefile.am b/doc/ksysv/Makefile.am
new file mode 100644
index 0000000..085981d
--- /dev/null
+++ b/doc/ksysv/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/ksysv/index.docbook b/doc/ksysv/index.docbook
new file mode 100644
index 0000000..9dc4f54
--- /dev/null
+++ b/doc/ksysv/index.docbook
@@ -0,0 +1,1117 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN"
+"dtd/kdex.dtd" [
+ <!ENTITY kappname "&ksysv;">
+ <!ENTITY package "kdeadmin">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+<bookinfo>
+<title>The &ksysv; Handbook</title>
+<authorgroup>
+<author>
+<firstname>Peter</firstname>
+<surname>Putzer</surname>
+<affiliation>
+<address><email>putzer@kde.org</email></address>
+</affiliation>
+</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<date>2001-03-21</date>
+<releaseinfo>1.03.06</releaseinfo>
+
+<copyright>
+<year>1998</year>
+<year>2000</year>
+<year>2001</year>
+<holder>Peter Putzer</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<abstract>
+<para>&ksysv; is a graphical editor for the SysV style init
+configuration.</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KSysV</keyword>
+<keyword>Runlevel</keyword>
+<keyword>Runlevel editor</keyword>
+<keyword>System V init</keyword>
+</keywordset>
+</bookinfo>
+
+<chapter id="Introduction">
+<title>Introduction</title>
+
+<para>
+Welcome to the &kde; System V Init Editor, commonly known (and hereafter
+referenced) as &ksysv;. This section introduces a few concepts and explains what
+you can do with &ksysv;.
+</para>
+
+</chapter>
+
+<chapter id="what-is-sysv-init">
+<title>A Brief Description of System V Init</title>
+
+<para>
+The following explanation is <quote>borrowed</quote> from
+<application>tksysv</application> (an inspiration for &ksysv;):
+</para>
+
+<para>
+System V init is fast becoming the standard in the &Linux; world to
+control the startup of software at boot time. This is because it is
+arguably easier to use and more powerful and flexible than the
+traditional <acronym>BSD</acronym> init.
+</para>
+
+<para>
+I won't go into the history here (mainly because I don't know it :-).
+</para>
+
+<para>
+The init binary is located in <filename class="directory">/sbin</filename> and
+not <filename class="directory">/etc</filename>. This is important as one might
+try and upgrade a machine to System V init without re-installing and
+reformatting. The &Linux; kernel looks in <filename
+class="directory">/etc</filename> for its init first, so you must make sure and
+delete your old init from there if any.
+</para>
+
+<para>SysV init also differs from <acronym>BSD</acronym> init in that
+the config files are in a subfolder of <filename
+class="directory">/etc</filename> instead of residing directly in
+<filename class="directory">/etc</filename>. This folder is called
+<filename class="directory">rc.d</filename>. In there you will find
+<filename>rc.sysinit</filename> and the following folders:
+</para>
+
+<itemizedlist>
+<listitem>
+<para>
+<filename class="directory">init.d/</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+<filename class="directory">rc0.d/</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+<filename class="directory">rc1.d/</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+<filename class="directory">rc2.d/</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+<filename class="directory">rc3.d/</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+<filename class="directory">rc4.d/</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+<filename class="directory">rc5.d/</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+<filename class="directory">rc6.d</filename>
+</para>
+</listitem>
+</itemizedlist>
+
+<para>
+<filename class="directory">init.d</filename> contains a bunch of
+scripts. Basically, you need one script for each service you may need to
+start at boot time or when entering another runlevel. Services include
+things like networking, <acronym>NFS</acronym>, &Sendmail;, httpd,&etc;
+Services do not include things like <command>setserial</command> that
+must only be run once and then exited. Things like that should go in
+the file <filename>rc.local</filename>.
+</para>
+
+<para>
+<filename>rc.local</filename> should be in <filename
+class="directory">/etc/rc.d</filename> if you want one. Most systems
+include one even though it doesn't do much. You can also include an
+<filename>rc.serial</filename> in <filename
+class="directory">/etc/rc.d</filename> if you need to do serial port
+specific things at boot time.
+</para>
+
+<para>The chain of events is as follows: </para>
+
+<orderedlist>
+<listitem>
+<para>
+The kernel looks in several places for init and runs the first one it
+finds.
+</para>
+</listitem>
+<listitem>
+<para>
+init runs <filename>/etc/rc.d/rc.sysinit</filename>.
+</para>
+</listitem>
+<listitem>
+<para>
+<filename>rc.sysinit</filename> does a bunch of necessary things and then runs
+<filename>rc.serial</filename> (if it exists)
+</para>
+</listitem>
+<listitem>
+<para>
+init runs <filename>rc.local</filename>
+</para>
+</listitem>
+<listitem>
+<para>
+init runs all the scripts for the default runlevel
+</para>
+</listitem>
+</orderedlist>
+
+
+<para>
+The default runlevel is decided in
+<filename>/etc/inittab</filename>. You should have a line close to the
+top like:
+</para>
+
+<screen>id:3:initdefault:</screen>
+
+<para>
+From this, you'd look in the second column and see that the default
+runlevel is 3, as should be the case for most systems. If you want to
+change it, you can edit <filename>/etc/inittab</filename> by hand and
+change the 3. Be very careful when you are messing with the inittab. If
+you do mess up, you can get in to fix it by rebooting and doing:
+</para>
+
+<screen><computeroutput>LILO boot:</computeroutput> <userinput>linux single</userinput></screen>
+
+<para>
+This <emphasis>should</emphasis> allow you to boot into single user mode
+so you can fix it. </para>
+
+<para>
+Now, how does it run all the right scripts? If you do an
+<userinput><command>ls</command> <option>-l</option></userinput> on
+<filename class="directory">rc3.d</filename>, you might see something
+like:
+</para>
+
+
+<screen>lrwxrwxrwx 1 root root 13 13:11 S10network -&gt; ../init.d/network
+lrwxrwxrwx 1 root root 16 13:11 S30syslog -&gt; ../init.d/syslog
+lrwxrwxrwx 1 root root 14 13:32 S40cron -&gt; ../init.d/cron
+lrwxrwxrwx 1 root root 14 13:11 S50inet -&gt; ../init.d/inet
+lrwxrwxrwx 1 root root 13 13:11 S60nfs -&gt; ../init.d/nfs
+lrwxrwxrwx 1 root root 15 13:11 S70nfsfs -&gt; ../init.d/nfsfs
+lrwxrwxrwx 1 root root 18 13:11 S75keytable -&gt; ../init.d/keytable
+lrwxrwxrwx 1 root root 23 13:11 S80sendmail -&gt; ../init.d/sendmail.init
+lrwxrwxrwx 1 root root 18 13:11 S90lpd -&gt; ../init.d/lpd.init
+lrwxrwxrwx 1 root root 11 13:11 S99local -&gt; ../rc.local</screen>
+
+<para>
+What you'll notice is that there are no real files in the folder.
+Everything there is a link to one of the scripts in the <filename
+class="directory">init.d</filename> folder.
+</para>
+
+<para>
+The links also have an <literal>S</literal> and a number at the
+beginning. The <literal>S</literal> means to start this particular
+script and a <literal>K</literal> would mean to stop it. The number is
+just there for ordering purposes. Init will start all the services based
+on the order they appear. You can duplicate numbers, but it will only
+confuse you somewhat. You just need to use a two digit number only,
+along with an upper case <literal>S</literal> or <literal>K</literal> to
+start or stop the services you need to.
+</para>
+
+<para>
+How does it start and stop services? Simple. Each of the scripts is
+written to accept an argument which can be <option>start</option> and
+<option>stop</option>. You can execute those scripts by hand in fact
+with a command like:
+</para>
+
+<screen><userinput><command>/etc/rc.d/init.d/httpd.init</command> <option>stop</option></userinput></screen>
+
+<para>
+To stop the httpd server. Init just reads the name and if it has a
+<literal>K</literal>, it calls the script with the <option>stop</option>
+argument. If it has an <option>S</option> it calls the script with a
+<option>start</option> argument. </para>
+
+
+<sect1 id="why-all-the-runlevels">
+<title>Why All These Runlevels ?</title>
+
+<para>
+Some people want an easy way to setup machines to be multi-purpose. I
+could have a <quote>server</quote> runlevel that just runs httpd,
+sendmail, networking, &etc; Then I could have a <quote>user</quote>
+runlevel that runs <application>kdm</application>, networking, &etc;
+</para>
+
+</sect1>
+
+</chapter>
+
+<chapter id="onscreen-fundamentals">
+<title>Onscreen Fundamentals</title>
+
+<para>
+Here you learn how to use &ksysv;, which shouldn't be hard since it was
+designed to be as user-friendly as possible.
+</para>
+
+<sect1 id="mouse">
+<title>Mouse</title>
+
+<para>
+Using &ksysv; with a mouse or other pointing device is easy: just drag
+an entry from the <guilabel> Available Services</guilabel> area onto one
+of the six runlevels to start (or resp. stop) it in that runlevel.
+</para>
+
+<para>
+You can also move scripts between runlevels, or change the position in a
+given runlevel, by dragging it around. Doing so removes the entry from
+its original runlevel (or position). This doesn't happen when you drag
+an entry from the <guilabel>Available Services</guilabel> area.
+</para>
+
+<note>
+<para>
+Entries are moved when you drag them to a new area. To copy a service to
+a different runlevel, you have to select <guimenuitem>Copy</guimenuitem>
+from the <guimenu>Edit</guimenu> or context menu and
+<guimenuitem>Paste</guimenuitem> it in the target runlevel.
+</para>
+</note>
+
+<para>
+The <quote>sorting number</quote> of an entry sometimes cannot be
+calculated. In such a case you have to edit the sorting numbers of
+surrounding entries before re-trying to insert the service.
+</para>
+
+<note>
+<para>
+Sorting numbers can range from 00 to 99, but no higher.
+</para>
+</note>
+
+<para>
+You can delete entries by dragging them onto the <guiicon>Trash
+Can</guiicon> area (symbolized by an icon depicting a garbage bin).
+</para>
+
+<warning>
+<para>
+Currently there is <emphasis>no</emphasis> way to recover items dragged
+onto the <guiicon>Trash Can</guiicon>, so be careful!
+</para>
+</warning>
+
+</sect1>
+
+<sect1 id="keyboard">
+<title>Keyboard</title>
+
+<para>
+You can use the <keycap>Tab</keycap> key to switch focus between
+different panels (<guilabel>Available Services</guilabel>,
+<guilabel>Runlevel 1 Start</guilabel>, <guilabel>Runlevel 1
+Stop</guilabel>, &etc;) and the cursor keys to move the selection up and
+down.
+</para>
+
+<para>
+To move an entry to a different runlevel, <guimenuitem>Cut</guimenuitem>
+it to the clipboard (using <keycombo action="simul">&Ctrl;
+<keycap>X</keycap></keycombo> and <guimenuitem>Paste</guimenuitem> it in
+the target runlevel (with <keycombo action="simul">&Ctrl;
+<keycap>V</keycap></keycombo>).
+</para>
+
+<para>
+To manually change an entries sorting number or name, press
+<keycap>Enter</keycap> to open the properties dialog. Use the
+<keycap>Tab</keycap> key to switch between different fields. Close the
+dialog by pressing <keycap>Enter</keycap> to accept the modifications,
+or press <keycap>Esc</keycap> to cancel any changes.
+</para>
+
+</sect1>
+
+<sect1 id="the-menu-entries">
+<title>The Menu Entries</title>
+
+<para>
+A one by one description of &ksysv;'s menu.
+</para>
+
+<sect2>
+<title>The <guimenu>File</guimenu> menu</title>
+
+<para>
+Because of the danger of data loss, all menu entries under
+<guimenu>File</guimenu> ask for confirmation before doing their work.
+</para>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Revert Configuration...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Forget any changes you have made, and revert to the last saved configuration.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Open a previously saved configuration.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>S</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Save Configuration</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Make your changes permanent.</action> Saving does not generate any
+backup files, so use with care.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Save As...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Save a copy of your new configuration.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>L</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Save Log...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Save a log</action> <!-- FIXME: find out what the log is of. Assume -->
+<!-- changes made, but best check -->
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>P</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Print Log...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Print a copy of the log.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>Q</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Quit</action> &ksysv;.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2>
+<title>The <guimenu>Edit</guimenu> menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>Z</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Undo</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Undo the last unsaved change made.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>Shift</keycap>
+<keycap>Z</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Redo</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Redo the last item undone.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>X</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Cut</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Cut the currently selected service to the clipboard.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>C</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Copy</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Copy the selected entry to the clipboard, without removing it from its
+original position.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl; <keycap>V</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Paste</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Paste the content of the clipboard at the current cursor
+position.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Properties</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Open the properties dialog for the selected item.</action>
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2>
+<title>The <guimenu>Tools</guimenu> menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Start Service...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Start the selected service</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Stop Service...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Stop the selected service</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Restart Service...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Restart the selected service.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Edit Service...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Edit the selected service</action><!-- FIXME: Add some more "meat" to
+-->
+<!-- this one! -->
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2>
+<title>The <guimenu>Settings</guimenu> menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Toolbar</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Toggle on and off display of the toolbar.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Statusbar</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Toggle on and off display of the statusbar.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Log</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Toggle on and off the display of the log window</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Save Settings</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Save your current settings.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Key bindings...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Customize the default keybindings.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Toolbars...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Customize the toolbar.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure SysV-Init Editor...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Customize the behavior</action> of &ksysv;
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+
+<sect2>
+<title>The <guimenu>Help</guimenu> menu</title>
+
+&help.menu.documentation;
+
+</sect2>
+
+</sect1>
+
+</chapter>
+
+<chapter id="Configuration">
+<title>Configuration</title>
+
+<para>
+All options are saved in
+<filename>$<envar>KDEHOME</envar>/share/config/ksysvrc</filename>. Defaults
+are taken from the global file
+(<filename>$<envar>KDEDIR</envar>/share/config/ksysvrc</filename>), if
+available, or else generated within &ksysv;. Changes to the defaults
+are stored in your local <filename>ksysvrc</filename>.
+</para>
+
+<sect1 id="recognized-sections">
+<title>Recognized Sections</title>
+
+<para>
+Recognized sections and keys plus their default values.
+</para>
+
+<sect2>
+<title>&lsqb;Path Settings&rsqb;</title>
+
+<segmentedlist>
+<segtitle>Keyword</segtitle>
+<segtitle>Default</segtitle>
+<segtitle>Description</segtitle>
+<seglistitem>
+<seg>ScriptPath</seg>
+<seg><filename class="directory">/etc/rc.d/init.d</filename></seg>
+<seg>Path to the scripts used for starting and stopping services.</seg>
+</seglistitem>
+
+<seglistitem>
+<seg>RunlevelPath</seg>
+<seg><filename class="directory">/etc/rc.d</filename></seg>
+<seg>Path to the runlevel subfolders.</seg>
+</seglistitem>
+
+</segmentedlist>
+
+</sect2>
+
+<sect2>
+<title>&lsqb;Colors&rsqb;</title>
+
+
+<segmentedlist>
+<segtitle>Keyword</segtitle>
+<segtitle>Default</segtitle>
+<segtitle>Description</segtitle>
+<seglistitem>
+<seg>Changed</seg>
+<seg>red</seg>
+<seg>Color used for changed entries</seg>
+</seglistitem>
+
+<seglistitem>
+<seg>New</seg>
+<seg>blue</seg>
+<seg>Color used for new entries</seg>
+</seglistitem>
+
+</segmentedlist>
+
+</sect2>
+
+<sect2>
+<title>&lsqb;Geometry&rsqb;</title>
+
+<segmentedlist>
+<segtitle>Keyword</segtitle>
+<segtitle>Default</segtitle>
+<segtitle>Description</segtitle>
+<seglistitem>
+<seg>Width</seg>
+<seg></seg>
+<seg>Width of &ksysv;'s window</seg>
+</seglistitem>
+
+<seglistitem>
+<seg>Height</seg>
+<seg></seg>
+<seg>Height of &ksysv;'s</seg>
+</seglistitem>
+</segmentedlist>
+
+</sect2>
+
+<sect2>
+<title>&lsqb;Other Settings&rsqb;</title>
+
+<segmentedlist>
+<segtitle>Keyword</segtitle>
+<segtitle>Default</segtitle>
+<segtitle>Description</segtitle>
+<seglistitem>
+<seg>ToolBar</seg>
+<seg>true</seg>
+<seg>If the toolbar is enabled or not</seg>
+</seglistitem>
+
+<seglistitem>
+<seg>StatusBar</seg>
+<seg>true</seg>
+<seg>If the statusbar is enabled or not</seg>
+</seglistitem>
+
+<seglistitem>
+<seg>ShowLog</seg>
+<seg>true</seg>
+<seg>If the log window is shown or not</seg>
+</seglistitem>
+
+<seglistitem>
+<seg>PanningFactor</seg>
+<seg>80</seg>
+<seg>100 - PanningFactor = percentage of window reserved for the logfile
+display</seg>
+</seglistitem>
+</segmentedlist>
+
+</sect2>
+
+</sect1>
+
+</chapter>
+
+<chapter id="questions-and-answers">
+<title>Questions and Answers</title>
+
+<qandaset>
+<qandaentry>
+<question>
+<para>
+I played around with the default runlevel, and now my machine reboots
+all the time. What can I do?
+</para>
+</question>
+<answer>
+<para>
+Enter <userinput>linux single</userinput> at the
+<acronym>LILO</acronym> prompt, and press <keycap>Enter</keycap> to
+boot into single user mode. Edit the file
+<filename>/etc/inittab</filename> and change to the default runlevel
+to something sane. <literal>3</literal> should normally be safe.
+</para>
+</answer>
+</qandaentry>
+
+<qandaentry>
+<question>
+<para>
+My Machine <quote>halts</quote> just after booting
+</para>
+</question>
+<answer>
+<para>
+See Question 1, above.
+</para>
+</answer>
+</qandaentry>
+
+<qandaentry>
+<question>
+<para>
+I scheduled some services to be run in runlevel X using &ksysv;, so why
+aren't they working?
+</para>
+</question>
+
+<answer>
+<para>
+If you're using SuSE or Delix (DLD) distributions, you also have to edit
+a distribution specific file in <filename
+class="directory">/etc</filename>. Please have a look at the manual of
+your distribution for details.
+</para>
+<para>
+<note>
+<para>
+The approach to starting services used by the above mentioned
+distributions makes configuration of services easy for the proprietary
+configuration tools these distributions provide, but it is unfortunately
+non-standard. The &ksysv; authors plan to write a generic extension for
+this approach some time in the future, but don't hold your breath.
+</para>
+</note>
+</para>
+<para>
+If you're using a different distribution, please check you have all the
+config files needed by the service, and whether they are in the correct
+locations. Some daemons for example <application>Apache</application>,
+(<acronym>aka</acronym> <command>httpd</command>) just die silently if
+their configuration files are missing or misconfigured.
+</para>
+</answer>
+</qandaentry>
+
+</qandaset>
+
+</chapter>
+
+<chapter id="standard-runlevels">
+<title>Standard semantics of Runlevels</title>
+
+<para>
+These vary by distribution, so this is an incomplete list of the most
+common &Linux; distributions. If you have additional distributions,
+please email the author and have the information added to this manual.
+</para>
+
+<variablelist>
+<varlistentry>
+<term>&RedHat;</term>
+<listitem>
+<variablelist>
+<varlistentry>
+<term>Runlevel 0:</term>
+<listitem>
+<para>
+halt (shuts down the machine)
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>Runlevel 1:</term>
+<listitem>
+<para>
+Single user mode.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>Runlevel 2:</term>
+<listitem>
+<para>
+Multi user text only, without <acronym>NFS</acronym>.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>Runlevel 3:</term>
+<listitem>
+<para>
+Multi user text-only, with full networking.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>Runlevel 4:</term>
+<listitem>
+<para>
+Not used.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>Runlevel 5:</term>
+<listitem>
+<para>
+Multi user X11 with full networking.
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>Runlevel 6:</term>
+<listitem>
+<para>
+Reboot
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</chapter>
+
+<chapter id="credits">
+<title>License and Credits</title>
+<para>&ksysv; Copyright &copy; 1997-1998 Peter Putzer</para>
+
+<itemizedlist>
+<listitem>
+<para>
+Peter Putzer, <email>putzer@kde.org</email> - Developer
+</para>
+</listitem>
+</itemizedlist>
+
+<para>
+Documentation:
+</para>
+
+<itemizedlist>
+<listitem>
+<para>Peter Putzer, <email>putzer@kde.org</email> - Original content </para>
+</listitem>
+<listitem><para>Eric Bischoff, <email>e.bischoff@noos.fr</email> - Editor
+</para>
+</listitem>
+</itemizedlist>
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+&install.intro.documentation;
+&install.compile.documentation;
+</appendix>
+
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+End:
+-->
+
diff --git a/doc/kuser/Makefile.am b/doc/kuser/Makefile.am
new file mode 100644
index 0000000..085981d
--- /dev/null
+++ b/doc/kuser/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kuser/index.docbook b/doc/kuser/index.docbook
new file mode 100644
index 0000000..9b3f006
--- /dev/null
+++ b/doc/kuser/index.docbook
@@ -0,0 +1,273 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN"
+"dtd/kdex.dtd" [
+ <!ENTITY kappname "&kuser;">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kuser; Handbook</title>
+<authorgroup>
+<author>
+<firstname>Matt</firstname>
+<surname>Johnston</surname>
+<affiliation>
+<address><email>mattj@flashmail.com</email></address>
+</affiliation>
+</author>
+
+<othercredit role="reviewer">
+<firstname>Lauri</firstname>
+<surname>Watts</surname>
+<affiliation>
+<address><email>lauri@kde.org</email></address>
+</affiliation>
+<contrib>Reviewer</contrib>
+</othercredit>
+<othercredit role="reviewer">
+<firstname>Jonathan</firstname>
+<surname>Singer</surname>
+<affiliation>
+<address><email>jsinger@leeta.net</email></address>
+</affiliation>
+<contrib>Reviewer</contrib>
+</othercredit>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>2000</year>
+<holder>Matt Johnston</holder>
+</copyright>
+<legalnotice>&FDLNotice;</legalnotice>
+
+
+<date>2002-10-08</date>
+<releaseinfo>1.0</releaseinfo>
+
+<abstract><para>This documentation describes &kuser; version 1.0. This
+program allows you to manage users and groups on your system.</para>
+</abstract>
+
+<keywordset>
+<keyword>kuser</keyword>
+<keyword>user</keyword>
+<keyword>management</keyword>
+<keyword>admin</keyword>
+<keyword>tools</keyword>
+<keyword>group</keyword>
+<keyword>password</keyword>
+</keywordset>
+</bookinfo>
+
+<chapter id="start">
+<title>Getting Started</title>
+
+<para>This is a short introduction to &kuser;. For more detailed
+information, see <link linkend="using">Usage</link>.</para>
+
+<para>Actually, you do not need to do anything to begin using &kuser;
+except <link linkend="customizing">configuration</link>.</para>
+
+<para>When you have made the changes you want, you must
+<guimenuitem>Save</guimenuitem> them for them to take effect. Either
+choose the Toolbar icon, or use the <guimenu>File</guimenu> menu.</para>
+
+</chapter>
+
+<chapter id="using">
+<title>Usage</title>
+
+<sect1 id="sec1mainwindow">
+<title>Main Window</title>
+
+<para>&kuser; is a very simple application. In the main window you can
+see two tabs: the list of users and the list of groups. To edit a user
+or a group, just double click on it. The user or group properties dialog
+will appear.</para>
+<screenshot>
+<screeninfo>&kuser; Main Window</screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="kuser.png" format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>&kuser; Main Window</phrase>
+</textobject>
+</mediaobject>
+</screenshot>
+
+</sect1>
+
+<sect1 id="user-properties">
+<title>User Properties Dialog</title>
+
+<para>The user properties dialog has various tabs.</para>
+
+<para>The number of tabs depends on the type of the user storage system
+and whether quotas are being used. Additional tabs will appear if you
+have shadow passwords, or any other similar things such as
+<filename>/etc/master.passwd</filename> in BSD flavor Unices.</para>
+
+<sect2 id="user-info">
+<title><guilabel>User Info</guilabel> Tab</title>
+
+<para>In the <guilabel>User Info</guilabel> tab you can modify:
+</para>
+
+<itemizedlist>
+<listitem><para><guilabel>User Id</guilabel></para></listitem>
+<listitem><para><guilabel>Full Name</guilabel></para></listitem>
+<listitem><para><guilabel>Login Shell</guilabel> (the list of login shells is
+taken from the <filename>/etc/shells</filename> file)</para></listitem>
+<listitem><para><guilabel>Home Folder</guilabel></para></listitem>
+<listitem><para><guilabel>Two office locations</guilabel></para></listitem>
+<listitem><para><guilabel>Address</guilabel></para></listitem>
+<listitem><para><guilabel>Password</guilabel></para></listitem>
+</itemizedlist>
+
+</sect2>
+
+<sect2 id="password-management-info">
+<title><guilabel>Password Management</guilabel> Tab</title>
+
+<para>The <guilabel>Password Management</guilabel> tab will appear if you have
+shadow passwords, or any other similar things such as
+<filename>/etc/master.passwd</filename> in <acronym>BSD</acronym> flavor
+Unices.</para>
+
+<para>In the <guilabel>Extended Info</guilabel> tab you can modify
+parameters related to extended account control: </para>
+
+<itemizedlist>
+<listitem><para>Minimum number of days between password
+changes</para></listitem>
+<listitem><para>Number of days after which a password expires if it hasn't been
+changed</para></listitem>
+<listitem><para>Number of days before expiration the user will be
+warned</para></listitem>
+<listitem><para>Whether and when an account will be disabled if the password
+expires</para></listitem>
+<listitem><para>A set date when the account expires</para></listitem>
+<listitem><para><guilabel>Class</guilabel> (on <acronym>BSD</acronym>
+systems)</para></listitem>
+</itemizedlist>
+<para>The date of the last password change is displayed near the top of the
+dialog.</para>
+
+
+</sect2>
+
+<sect2 id="quota">
+<title><guilabel>Quota</guilabel> Tab</title>
+
+<para>You will probably see the <guilabel>Quota</guilabel> tab only if you
+have at least one mounted volume with quota enabled and a quota file
+present. There you may modify all quota related parameters: </para>
+
+<itemizedlist>
+<listitem><para><guilabel>File Soft Quota</guilabel></para></listitem>
+<listitem><para><guilabel>File Hard Quota</guilabel></para></listitem>
+<listitem><para><guilabel>File Time Limit (Grace
+Period)</guilabel></para></listitem>
+<listitem><para><guilabel>iNode Soft Quota</guilabel></para></listitem>
+<listitem><para><guilabel>iNode Hard Quota</guilabel></para></listitem>
+<listitem><para><guilabel>iNode Time Limit (Grace
+Period)</guilabel></para></listitem>
+</itemizedlist>
+
+<para> All these parameters can be changed for each filesystem that has user
+quota enabled. Filesystems can be changed using the <guilabel>Quota
+Filesystem</guilabel> box.</para>
+
+</sect2>
+
+<sect2 id="group">
+<title><guilabel>Groups</guilabel> Tab</title>
+
+<para>The <guilabel>Groups</guilabel> tab contains all the information about the
+selected user's participation in groups. The primary group to which the user
+belongs
+is set in the <guilabel>Primary Group</guilabel> box. The user can be assigned
+to additional groups by checking them in the large box.</para>
+
+</sect2>
+</sect1>
+
+<sect1 id="group-properties">
+<title><guilabel>Group Properties</guilabel></title>
+
+<para>The <guilabel>Group Properties</guilabel> dialog contains a list of all
+users. Check
+the boxes for each user to be assigned to the selected group.</para>
+
+</sect1>
+
+<sect1 id="add-user">
+<title>Adding, Editing and Deleting Users or Groups</title>
+
+<para>To add a user or group to the system, either choose
+<guimenuitem>Add</guimenuitem> from the <guimenu>User</guimenu> or
+<guimenu>Group</guimenu> menu, or click the relevant <guiicon>Add</guiicon>
+button on
+the toolbar. The selected user or group can also be edited or deleted in the
+same way.</para>
+</sect1>
+</chapter>
+
+<chapter id="customizing">
+<title>Customizing &kuser;</title>
+
+<sect1 id="defaults">
+<title>Edit user creation defaults</title>
+
+<para>To edit the user creation defaults you can use the <guilabel>Edit
+defaults</guilabel> dialog, which is accessible via the menu
+<menuchoice><guimenu>Settings</guimenu>
+<guimenuitem>Configure &kuser;</guimenuitem></menuchoice>. There you may
+change the defaults that are used when creating a new user: Shell and
+Home Folder (or home folders volume). You can choose whether to
+make a home folder on <quote>create</quote> or not,and to copy a
+skeleton (standard configuration files) to the home folder or not. You can
+also enable
+<guilabel>User Private Group</guilabel> mechanism, which creates a new
+personal group with the creation of a new user, and removes the personal
+group when the user is removed.</para>
+<para>The skeleton files for new users can be specified in the <guilabel>Sources
+</guilabel> tab.</para>
+
+</sect1>
+</chapter>
+
+<chapter id="credits">
+<title>Credits and License</title>
+
+<para>&kuser;</para>
+
+<para>Program copyright 1997-2000 Denis Pershin
+<email>dyp@inetlab.com</email></para>
+
+<para>Documentation copyright 1997-2000 Denis Pershin
+<email>dyp@inetlab.com</email></para>
+<para>Documentation copyright 2000 Matt Johnston
+<email>mattj@flashmail.com</email></para>
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+&documentation.index;
+
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+End:
+-->
+
diff --git a/doc/kuser/kuser.png b/doc/kuser/kuser.png
new file mode 100644
index 0000000..e68ac2d
--- /dev/null
+++ b/doc/kuser/kuser.png
Binary files differ
diff --git a/doc/lilo-config/Makefile.am b/doc/lilo-config/Makefile.am
new file mode 100644
index 0000000..085981d
--- /dev/null
+++ b/doc/lilo-config/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/lilo-config/index.docbook b/doc/lilo-config/index.docbook
new file mode 100644
index 0000000..a0cf803
--- /dev/null
+++ b/doc/lilo-config/index.docbook
@@ -0,0 +1,177 @@
+<?xml version="1.0" ?>
+<!DOCTYPE article PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN"
+"dtd/kdex.dtd" [
+<!ENTITY package "kdebase">
+<!ENTITY liloconfig "LILO Configuration">
+<!ENTITY lilo "LILO">
+<!ENTITY % addindex "IGNORE">
+<!ENTITY % English "INCLUDE" > <!-- change language only here -->
+
+<!ENTITY Virgil.J.Nisly "<personname><firstname>Virgil</firstname><othername>J.</othername><surname>Nisly</surname></personname>">
+<!ENTITY Virgil.J.Nisly.mail "<email>virgil@vigilite.com</email>">
+]>
+
+<article lang="&language;">
+<articleinfo>
+<title>The &liloconfig; Handbook</title>
+
+<authorgroup>
+<author>&Virgil.J.Nisly; &Virgil.J.Nisly.mail;</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>2005</year>
+<holder>&Virgil.J.Nisly;</holder>
+</copyright>
+<legalnotice>&FDLNotice;&underFDL;&GPLNotice;&underGPL;</legalnotice>
+
+<date>2005-01-18</date>
+<releaseinfo>1.00.00</releaseinfo>
+<abstract><para>&liloconfig; is an application specificly designed to configure &lilo; the boot manager.</para></abstract>
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KControl</keyword>
+<keyword>lilo</keyword>
+<keyword>boot configuration</keyword>
+<keyword>booting</keyword>
+</keywordset>
+</articleinfo>
+
+<sect1 id="login-manager">
+<title>&liloconfig;</title>
+
+<para>Using this module, you can install lilo boot manager, add/remove/change boot password, change time till booting default OS, add/remove/change default OS, add/remove/change OS's, and more!</para>
+
+<para>In order to organize all of these options, this module is
+divided into three sections: <link
+linkend="lilo-general"><guilabel>General Options</guilabel></link>,
+<link linkend="lilo-OS"><guilabel>Operating Systems</guilabel></link>, and <link
+linkend="lilo-expert"><guilabel>Expert</guilabel></link></para>
+
+<para>You can switch between the sections using the tabs at the top of
+the window.</para>
+
+<note><para>If you are not currently logged in as a superuser, you
+will need to click the <guibutton>Administrator Mode</guibutton>
+Button. You will then be asked for a superuser password. Entering a
+correct password will allow you to modify the settings of this
+module.</para></note>
+</sect1>
+
+<sect1 id="lilo-general">
+<title>General Options</title>
+
+<para>From this page you can add/remove/change boot password, time till booting default OS, and more!</para>
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Install boot record to drive/partition:</guilabel></term>
+<listitem><para> Select the drive or partition where you would like to install the Lilo boot loader. Unless you intend to use other boot managers in addition to LILO, this should be the MBR (master boot record) of your boot drive. In this case, you should probably select /dev/hda if your drive is IDE, and /dev/sda if your boot drive is SCSI.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Boot the default kernel/OS after:</guilabel></term>
+<listitem><para>Lilo will wait the specified time before booting default kernel/OS.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Use linear mode</guilabel></term>
+<listitem><para>Linear mode tells the boot loader the location of the kernels in linear addressing rather than sector/head/cylinder. Linear mode is required by some SCSI drives, and shouldn't hurt unless you are planning to create a boot disk to be used with other computers. See lilo man file for more details.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Use compact mode</guilabel></term>
+<listitem><para>The compact mode trys to merge read requests for adjacent sectors in to single read request. This reduces load time and keeps boot map smaller, but will not work on all systems.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Record boot command lines for defaults</guilabel></term>
+<listitem><para>Automatic recording of boot command lines as defaults for following boots. This way, lilo "locks" on a choice until manually overridden.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Restrict parameters</guilabel></term>
+<listitem><para>A password is required only if any parameters changed (i.e. the user can boot linux, but not linux single or linux init=/bin/sh). This sets a default for all Linux kernels you want to boot. If you need a per-kernel setting, go to Operating Systems tab, and select details.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Require password:</guilabel></term>
+<listitem><para>Enter the password for bootup (if any) here. If restricted (above) is checked, the password is required for additional parameters only. <warning><para>The password is stored in clear text in /etc/lilo.conf. You'll want to make sure nobody untrusted can read this file. Also, you probably don't want to use your normal/root password here.</para></warning></para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Default graphics mode on text console:</guilabel></term>
+<listitem><para>You can select the default graphics mode here. If you intend to use a VGA graphics mode, you must compile the kernel with support for frame buffer devices. The ask setting brings up a prompt at boot time. This sets a default for all Linux kernels you want to boot. If you need a per-kernel setting, go to Operating Systems tab, and select details.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Enter LILO prompt automatically</guilabel></term>
+<listitem><para>If this box is checked, lilo goes to the lilo prompt whether or not a key is pressed. If it is turned off, lilo boots the default operating system unless shift is pushed (in that case, it goes to the lilo prompt).</para></listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+<sect1 id="lilo-OS">
+<title>Operating Systems</title>
+
+<para>Some of the things that can be done here are: settings like <guilabel>General Options</guilabel> for specific kernels/OSes, set default OS to boot, probe for available kernels, you can also edit root file system, ramdisk settings, extra parameters, etc...</para>
+
+<variablelist>
+<varlistentry>
+<term>Boot menu listbox</term>
+<listitem><para>To the far left is a list of the kernels and operating systems you can currently boot. Choose the one you would like to edit.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Kernel:</guilabel></term>
+<listitem><para>Enter the filename of the kernel you would like to boot. Pushing the <guibutton>Select...</guibutton> will bring up &kde; standard fileselector to help you find the kernel.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Label:</guilabel></term>
+<listitem><para>Enter the label (name) of the kernel you want to boot here.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Root filesystem:</guilabel></term>
+<listitem><para>Enter the root filesystem for the kernel you would like to boot. Pushing the <guibutton>Select...</guibutton> will bring up &kde; standard fileselector to help you find the root filesystem.</para>
+<note><title>Root filesystem</title><para>In this case, the root filesystem means the partition that will be mounted as / at boot time.</para></note>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Initial ramdisk:</guilabel></term>
+<listitem><para>If you want to use an initial ramdisk (initrd) for this kernel, enter its filename here. Leave this field blank if you do not intend to use an initial ramdisk for this kernel.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Extra parameters:</guilabel></term>
+<listitem><para>Enter an extra parameters you wish to pass kernel. Usually this can be left blank. This can the append option in lilo.conf.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Set Default</guibutton></term>
+<listitem><para>Boot this kernel if the user doesn't make a different choice.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Details</guibutton></term>
+<listitem><para>This brings up a dialog box with further, less commonly used, options.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Probe</guibutton></term>
+<listitem><para>Automaticly generate a (hopefully) reasonable lilo.conf for your system.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Check Configuration</guibutton></term>
+<listitem><para>Run LILO in test mode to see if the configuration is ok.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Add Kernel...</guibutton></term>
+<listitem><para>Add a new Linux kernel to the boot menu.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Add Other OS...</guibutton></term>
+<listitem><para>Add non-Linux OS to boot menu.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><guibutton>Remove Entry</guibutton></term>
+<listitem><para>Remove entry from boot menu.</para></listitem>
+</varlistentry>
+
+</variablelist>
+</sect1>
+
+<sect1 id="lilo-expert">
+<title>Expert</title>
+<para>In this page you can edit the /etc/lilo.conf file.</para>
+<warning><para>Do <emphasis>not</emphasis> edit this file so unless you know what you are doing!</para></warning>
+</sect1>
+
+</article>
diff --git a/kcron/AUTHORS b/kcron/AUTHORS
new file mode 100644
index 0000000..c182394
--- /dev/null
+++ b/kcron/AUTHORS
@@ -0,0 +1,2 @@
+Gary Meyer <gary@meyer.net>
+Robert Berry <rjmber@ntlworld.com>
diff --git a/kcron/COPYING b/kcron/COPYING
new file mode 100644
index 0000000..37ba36f
--- /dev/null
+++ b/kcron/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kcron/ChangeLog b/kcron/ChangeLog
new file mode 100644
index 0000000..b83a3eb
--- /dev/null
+++ b/kcron/ChangeLog
@@ -0,0 +1,66 @@
+gary@meyer.net September 6, 1999
+
+ Fixed bug. Program didn't exit after editing. KDE2 only.
+ Fixed bug. Variable editor didn't update icon. KDE2 only.
+ Changed default sorting. Alphabetical with System Crontab on top.
+ Removed -lkfm from Makefile.
+ Change kcron.kdelnk to kcron.desktop.
+
+gary@meyer.net September 7, 1999
+
+ cttask.h, cttash.cpp, kttask.cpp
+ Fixed bug. New syscron task didn't let user enter "run as" field.
+
+gary@meyer.net September 10, 1999
+
+ Initial implementation of cut/copy/paste.
+
+gary@meyer.net September 17, 1999
+
+ Work around for Qt 2.0 ~QListViewItem bug.
+
+gary@meyer.net November 1, 1999
+
+ Released 0.5.
+
+gary@meyer.net November 7, 1999
+
+ Added KCron handbook. Various bug fixes.
+
+gary@meyer.net November 15, 1999
+
+ Fixed bug for supporting strftime (in CTTask::describe()) on different
+ platforms.
+
+gary@meyer.net November 19, 1999
+
+ Code clean up effort.
+
+gary@meyer.net November 29, 1999
+
+ Removed dependency on langinfo.h for internationalization of days of week
+ and months. Not broadly supported across platforms/distributions.
+
+gary@meyer.net December 2, 1999
+
+ Removed CTDebug, don't really need anymore.
+ Addeed note for translators so they'll look at README.translators.
+ Cleaned up CTUnit: moved implementation to cpp file, removed macro,
+ added support for "sun, Mon" and "jan, FEB" in crontab file.
+
+code@jamesots.com January 27, 2004
+
+ * Fixed bug. If only one hour wasn't checked '*' was still being used.
+ * Fixed bug. Removed autoWrap from KTVariable, as text is wrapped
+ in the line edit box anyway. Changed to use QTextEdit instead of the
+ deprecated QMultiLineEdit.
+ * Fixed bug. Strip out newlines from variable comments, because we
+ only read one line of comment from crontab for each entry.
+ * Fixed bug. System Crontab uses correct icon.
+ * Using standard icons for everything now.
+ * Added Set/Clear All buttons.
+ * Added New, Modify and Delete buttons on toolbar. (Bug 54399 and
+ part of bug 55684. Note about 55684: Use Ctrl-X as shortcut to delete
+ item.)
+ * Enabled New action when variables and tasks are selected, instead of
+ only when the containing label is selected.
diff --git a/kcron/Makefile.am b/kcron/Makefile.am
new file mode 100644
index 0000000..1cd898d
--- /dev/null
+++ b/kcron/Makefile.am
@@ -0,0 +1,111 @@
+##########################################################################
+# Makefile.am #
+# -------------------------------------------------------------------- #
+# Makefile.am for KCron #
+# -------------------------------------------------------------------- #
+# Copyright (C) 1999, Gary Meyer <gary@meyer.net> #
+# -------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify #
+# it under 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. #
+##########################################################################
+
+bin_PROGRAMS = kcron
+
+kcron_SOURCES = \
+ cthost.cpp \
+ ctcron.cpp \
+ ctmonth.cpp \
+ ctdom.cpp \
+ ctdow.cpp \
+ cttask.cpp \
+ ctvariable.cpp \
+ kticon.cpp \
+ ktapp.cpp \
+ ktview.cpp \
+ ktlistitem.cpp \
+ ktlistcron.cpp \
+ ktlisttask.cpp \
+ ktlisttasks.cpp \
+ ktlistvar.cpp \
+ ktlistvars.cpp \
+ kttask.cpp \
+ ktvariable.cpp \
+ ktprint.cpp \
+ ktprintopt.cpp \
+ main.cpp
+
+EXTRA_DIST = \
+ ctcron.cpp \
+ ctcron.h \
+ ctdom.cpp \
+ ctdom.h \
+ ctdow.cpp \
+ ctdow.h \
+ ctexception.h \
+ cthost.cpp \
+ cthost.h \
+ cthour.h \
+ cti18n.h \
+ ctminute.h \
+ ctmonth.cpp \
+ ctmonth.h \
+ cttask.cpp \
+ cttask.h \
+ ctunit.cpp \
+ ctunit.h \
+ ctvariable.cpp \
+ ctvariable.h \
+ ktapp.h \
+ ktapp.cpp \
+ kticon.h \
+ kticon.cpp \
+ kttask.h \
+ kttask.cpp \
+ ktvariable.h \
+ ktvariable.cpp \
+ ktview.cpp \
+ ktview.h \
+ ktlistitem.h \
+ ktlistitem.cpp \
+ ktlistcron.h \
+ ktlistcron.cpp \
+ ktlisttask.h \
+ ktlisttask.cpp \
+ ktlisttasks.h \
+ ktlisttasks.cpp \
+ ktlistvar.h \
+ ktlistvar.cpp \
+ ktlistvars.h \
+ ktlistvars.cpp \
+ ktprint.h \
+ ktprint.cpp \
+ ktprintopt.h \
+ ktprintopt.cpp \
+ main.cpp \
+ README \
+ AUTHORS \
+ COPYING \
+ ChangeLog \
+ TODO \
+ kcron.desktop \
+ kcron.lsm \
+ Makefile.am
+
+INCLUDES= $(all_includes)
+
+kcron_METASOURCES = AUTO
+
+kcron_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kcron.pot
+
+kcron_LDADD = $(LIB_KFILE) -lkdeprint
+
+xdg_apps_DATA = kcron.desktop
+
+KDE_ICON = kcron
+shellrcdir = $(kde_datadir)/kcron
+shellrc_DATA = kcronui.rc
diff --git a/kcron/README b/kcron/README
new file mode 100644
index 0000000..ffcc015
--- /dev/null
+++ b/kcron/README
@@ -0,0 +1,12 @@
+KCron
+
+KDE Task Scheduler
+
+GUI crontab editor
+
+Requires:
+
+ Unix POSIX libraries for localized dates and times (glibc)
+ Cron (vixie-cron)
+ Crontab (crontabs)
+
diff --git a/kcron/README.hacking b/kcron/README.hacking
new file mode 100644
index 0000000..daa9c74
--- /dev/null
+++ b/kcron/README.hacking
@@ -0,0 +1,8 @@
+README.hacking
+
+Author: Gary Meyer <gary@meyer.net>
+Date: November 15, 1999
+
+---------------------------------------------------------------------------
+Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+I want to be able to reuse those classes with another GUI toolkit.
diff --git a/kcron/README.translators b/kcron/README.translators
new file mode 100644
index 0000000..87c4d71
--- /dev/null
+++ b/kcron/README.translators
@@ -0,0 +1,109 @@
+README.translators
+
+Author: Gary Meyer <gary@meyer.net>
+Date: November 7, 1999
+
+---------------------------------------------------------------------------
+KCron requires special care in translation. KCron does natural language
+description, such as "At 12:00am, every day." How days and times are
+described in different languages and cultures varies greatly.
+
+I have tried to accomodate this challenge through making formatting of the
+display significantly controlled by the translater.
+
+The approach I have taken makes formatting strings available to the
+translator. Where there is a string to translate that has a name
+"SUCH_AS_THIS", KCron treats "SUCH_AS_THIS" as a special token.
+
+For instance, consider "DAYS_OF_MONTH of MONTHS". The translator can
+move the ordering of the phrases around. Additionally the translator
+can translate the various words as well as separators such as the comma.
+---------------------------------------------------------------------------
+Look at CTTask::describe(). This is the most significant method used in
+creating the description string that appears in the main display.
+
+1. Change "%l:%M%P" to support time formatting for your locale.
+
+Default:
+ "%l:%M%P" -> "11:00pm"
+
+Other possibilities:
+ "%l:%M%p" -> "11:00PM"
+ "%H:%M" -> "23:00"
+
+See "man strftime" for more time formatting options available.
+
+2. Change "DAYS_OF_MONTH of MONTHS" to support how days of the month are
+combined with month names for your locale.
+
+Default:
+ "DAYS_OF_MONTH of MONTHS" -> "1st and 15th of Jan"
+
+Other possibilities:
+ "MONTHS, DAYS_OF_MONTH" -> "Jan, 1st and 15th"
+
+3. Change "every DAYS_OF_WEEK" to support how the English phrase
+"every Monday" is translated to your locale.
+
+Default:
+ "every DAYS_OF_WEEK" -> "every Mon, Wed, and Fri"
+
+Other possibilitities:
+ "DAYS_OF_WEEK" -> "Mon, Wed, and Fri"
+
+4. Change "DOM_FORMAT as well as DOW_FORMAT" to support how complex
+phrases that involve day of the month as well as day of the week are
+described in your locale.
+
+Default:
+ "DOM_FORMAT as well as DOW_FORMAT" -> "1st and 15th of every month as well
+ as every Sun"
+
+Other possibilities:
+ "DOM_FORMAT and DOW_FORMAT" -> "1st and 15th of every month and every Sun"
+
+Note how the order of the two phrases can be changed.
+
+5. Change "At TIME" to support how the English phrase "At 11:00pm" is
+translated to your locale.
+
+Default:
+ "At TIME" -> "At 11:00pm"
+
+Other possibilities:
+ "TIME" -> "11:00pm"
+
+If necessary you can put a phrase suffix after the "TIME" token.
+
+6. Change "TIME_FORMAT, DATE_FORMAT" to describe how the English phrase
+"At 11:00pm, every Sun" is best translated to your locale.
+
+Default:
+ "TIME_FORMAT, DATE_FORMAT" -> "At 11:00pm, every Sun"
+
+Other possibilities:
+ "TIME_FORMAT DATE_FORMAT" -> "At 11:00pm every Sun"
+ "DATE_FORMAT TIME_FORMAT" -> "every Sun At 11:00pm"
+
+So the following translations...
+ "%l:%M%P" -> "%H:%M"
+ "DAYS_OF_MONTH of MONTHS" -> "MONTHS DAYS_OF_MONTH"
+ "every DAYS_OF_WEEK" -> "every DAYS_OF_WEEK"
+ "DOM_FORMAT as well as DOW_FORMAT" -> "DOM_FORMAT and DOW_FORMAT"
+ "At TIME" -> "at TIME" ->
+ "TIME_FORMAT, DATE_FORMAT" -> "DATE_FORMAT TIME_FORMAT"
+
+Would produce...
+ "Jan 1st 23:00" instead of "At 11:00pm, Jan 1st"
+---------------------------------------------------------------------------
+ctunit.h and cttask.cpp also have places to describe whether or not
+your local uses:
+
+ "1, 2, and 3" or
+ "1, 2 and 3" or
+ "1, 2, 3"
+---------------------------------------------------------------------------
+Everything else should be rather clear to translate. If you can not
+support your locale through this translation, email the author at
+gary@meyer.net and I'll see if I can make changes to accomodate.
+
diff --git a/kcron/TODO b/kcron/TODO
new file mode 100644
index 0000000..6939a1c
--- /dev/null
+++ b/kcron/TODO
@@ -0,0 +1,7 @@
+Features to be added:
+
+- Import/export crontab file
+- View man page of task command
+- Edit task command if an editable script
+- New task wizard
+
diff --git a/kcron/configure.in.in b/kcron/configure.in.in
new file mode 100644
index 0000000..be677e4
--- /dev/null
+++ b/kcron/configure.in.in
@@ -0,0 +1,4 @@
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+AC_CHECK_HEADERS(sstream)
+AC_LANG_RESTORE
diff --git a/kcron/ctcron.cpp b/kcron/ctcron.cpp
new file mode 100644
index 0000000..853f6de
--- /dev/null
+++ b/kcron/ctcron.cpp
@@ -0,0 +1,333 @@
+/***************************************************************************
+ * CT Cron Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctcron.h"
+
+#include "cti18n.h"
+#include "cttask.h"
+#include "ctvariable.h"
+#include <unistd.h> // getuid(), unlink()
+#include <pwd.h> // pwd, getpwnam(), getpwuid()
+#include <stdio.h>
+#include <assert.h>
+
+#include <qfile.h>
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <ktempfile.h>
+
+#include <iostream>
+
+using namespace std;
+
+CTCron::CTCron(bool _syscron, string _login) :
+ syscron(_syscron)
+{
+ int uid(getuid());
+
+ KTempFile tmp;
+ tmp.setAutoDelete(true);
+ tmp.close();
+ tmpFileName = tmp.name();
+
+ QString readCommand;
+
+ if (uid == 0)
+ // root, so provide requested crontab
+ {
+ if (syscron)
+ {
+ readCommand = "cat /etc/crontab > " + KProcess::quote(tmpFileName);
+ writeCommand = "cat " + KProcess::quote(tmpFileName) + " > /etc/crontab";
+ login = (const char *)i18n("(System Crontab)").local8Bit();
+ name = "";
+ }
+ else
+ {
+ readCommand = QString("crontab -u ") + _login.c_str() + " -l > " + KProcess::quote(tmpFileName);
+ writeCommand = QString("crontab -u ") + _login.c_str() + " " + KProcess::quote(tmpFileName);
+ if (!initFromPasswd(getpwnam(_login.c_str())))
+ {
+ error = i18n("No password entry found for user '%1'").arg(_login.c_str());
+ }
+ }
+ }
+ else
+ // regular user, so provide user's own crontab
+ {
+ readCommand = "crontab -l > " + KProcess::quote(tmpFileName);
+ writeCommand = "crontab " + KProcess::quote(tmpFileName);
+ if (!initFromPasswd(getpwuid(uid)))
+ {
+ error = i18n("No password entry found for uid '%1'").arg(uid);
+ }
+ }
+
+ if (name.empty())
+ name = login;
+
+ initialTaskCount = 0;
+ initialVariableCount = 0;
+
+ if (isError())
+ return;
+
+ // Don't set error if it can't be read, it means the user
+ // doesn't have a crontab.
+ if (system(QFile::encodeName(readCommand)) == 0)
+ {
+ ifstream cronfile(QFile::encodeName(tmpFileName));
+ cronfile >> *this;
+ }
+
+ initialTaskCount = task.size();
+ initialVariableCount = variable.size();
+}
+
+CTCron::CTCron(const struct passwd *pwd) :
+ syscron(false)
+{
+ Q_ASSERT(pwd != 0L);
+
+ KTempFile tmp;
+ tmp.setAutoDelete(true);
+ tmp.close();
+ tmpFileName = tmp.name();
+
+ QString readCommand = QString("crontab -u ") + QString(pwd->pw_name) + " -l > " + KProcess::quote(tmpFileName);
+ writeCommand = QString("crontab -u ") + QString(pwd->pw_name) + " " + KProcess::quote(tmpFileName);
+
+ initFromPasswd(pwd);
+
+ initialTaskCount = 0;
+ initialVariableCount = 0;
+
+ if (isError())
+ return;
+
+ // Don't set error if it can't be read, it means the user
+ // doesn't have a crontab.
+ if (system(QFile::encodeName(readCommand)) == 0)
+ {
+ ifstream cronfile(QFile::encodeName(tmpFileName));
+ cronfile >> *this;
+ }
+
+ initialTaskCount = task.size();
+ initialVariableCount = variable.size();
+}
+
+bool CTCron::initFromPasswd(const struct passwd *pwd)
+{
+ if (pwd == 0)
+ {
+ return false;
+ }
+ else
+ {
+ login = pwd->pw_name;
+ name = pwd->pw_gecos;
+ return true;
+ }
+}
+
+void CTCron::operator = (const CTCron& source)
+{
+ assert(!source.syscron);
+
+ for (CTVariableIterator i = const_cast<CTCron&>(source).variable.begin();
+ i != source.variable.end(); ++i)
+ {
+ CTVariable* tmp = new CTVariable(**i);
+ variable.push_back(tmp);
+ }
+
+ for (CTTaskIterator i = const_cast<CTCron&>(source).task.begin();
+ i != source.task.end(); ++i)
+ {
+ CTTask* tmp = new CTTask(**i);
+ task.push_back(tmp);
+ }
+}
+
+istream& operator >> (istream& inputStream, CTCron& cron)
+{
+ const int MAX = 1024;
+ char buffer[MAX];
+ string line("");
+ string comment("");
+
+ while (inputStream)
+ {
+ inputStream.getline(buffer, MAX);
+ line = buffer;
+
+ // search for comments "#" but not disabled tasks "#\"
+ if ((line.find("#") == 0) && (line.find("\\") != 1))
+ {
+ // If the first 10 characters don't contain a character, it's probably a disabled entry.
+ int first_text = line.find_first_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ if (first_text < 0)
+ continue;
+
+ if (first_text < 10)
+ {
+ // remove leading pound sign
+ line = line.substr(1,line.length()-1);
+ // remove leading whitespace
+ while (line.find_first_of(" \t") == 0)
+ line = line.substr(1,line.length()-1);
+ comment = line;
+ continue;
+ }
+ }
+
+ // else
+ {
+ // either a task or a variable
+ int firstWhiteSpace(line.find_first_of(" \t"));
+ int firstEquals(line.find("="));
+
+ // if there is an equals sign and either there is no
+ // whitespace or the first whitespace is after the equals
+ // sign, it must be a variable
+ if ((firstEquals > 0) && ((firstWhiteSpace == -1) ||
+ firstWhiteSpace > firstEquals))
+ {
+ // create variable
+ CTVariable *tmp = new CTVariable(line, comment);
+ cron.variable.push_back(tmp);
+ comment = "";
+ }
+ else
+ // must be a task, either enabled or disabled
+ {
+ if (firstWhiteSpace > 0)
+ {
+ CTTask *tmp = new CTTask(line, comment, cron.syscron);
+ cron.task.push_back(tmp);
+ comment = "";
+ }
+ }
+ }
+ }
+ return inputStream;
+}
+
+ostream& operator << (ostream& outputStream, const CTCron& cron)
+{
+ int itemCount(0);
+
+ for (CTVariableIterator i = const_cast<CTCron&>(cron).variable.begin();
+ i != cron.variable.end(); ++i)
+ {
+ outputStream << **i;
+ itemCount++;
+ }
+
+ for (CTTaskIterator i = const_cast<CTCron&>(cron).task.begin();
+ i != cron.task.end(); ++i)
+ {
+ outputStream << **i;
+ itemCount++;
+ }
+
+ if (itemCount > 0)
+ {
+ outputStream << "# This file was written by KCron. Copyright (c) 1999, Gary Meyer\n";
+ outputStream << "# Although KCron supports most crontab formats, use care when editing.\n";
+ outputStream << "# Note: Lines beginning with \"#\\\" indicates a disabled task.\n";
+ }
+
+ return outputStream;
+}
+
+CTCron::~CTCron()
+{
+ for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
+ delete *i;
+ for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
+ delete *i;
+}
+
+void CTCron::apply()
+{
+ // write to temp file
+ ofstream cronfile(QFile::encodeName(tmpFileName));
+ cronfile << *this << flush;
+
+ // install temp file into crontab
+ if (system(QFile::encodeName(writeCommand)) != 0)
+ {
+ error = i18n("An error occurred while updating crontab.");
+ }
+
+ // remove the temp file
+ (void) unlink(QFile::encodeName(tmpFileName));
+
+ if (isError())
+ return;
+
+ // mark as applied
+ for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
+ (*i)->apply();
+
+ for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
+ (*i)->apply();
+
+ initialTaskCount = task.size();
+ initialVariableCount = variable.size();
+}
+
+void CTCron::cancel()
+{
+ for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
+ (*i)->cancel();
+
+ for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
+ (*i)->cancel();
+}
+
+bool CTCron::dirty()
+{
+ bool isDirty(false);
+
+ if (initialTaskCount != task.size()) isDirty = true;
+
+ if (initialVariableCount != variable.size()) isDirty = true;
+
+ for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
+ if ((*i)->dirty()) isDirty = true;
+
+ for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
+ if ((*i)->dirty()) isDirty = true;
+
+ return isDirty;
+}
+
+string CTCron::path() const
+{
+ string path;
+
+ for (CTVariableIterator var = const_cast<CTCron*>(this)->variable.begin();
+ var != variable.end(); var++)
+ {
+ if ((*var)->variable == "PATH")
+ {
+ path = (*var)->value;
+ }
+ }
+ return path;
+}
diff --git a/kcron/ctcron.h b/kcron/ctcron.h
new file mode 100644
index 0000000..b8d03fe
--- /dev/null
+++ b/kcron/ctcron.h
@@ -0,0 +1,154 @@
+/***************************************************************************
+ * CT Cron Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTCRON_H
+#define CTCRON_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include <vector>
+#include <string>
+#include <iostream>
+
+#include <qstring.h> // Anarchy! -WABA
+
+class CTException;
+class CTTask;
+class CTVariable;
+
+struct passwd;
+
+/**
+ * A user (encapsulation of a single crontab file). Encapsulates
+ * file i/o, parsing, tokenization, and natural language description.
+ */
+class CTCron
+{
+public:
+
+/**
+ * Constructs the scheduled tasks, environment variables from crontab
+ * files and obtains some information about the user from the system.
+ *
+ * Default is to construct from the user's crontab. Can also be called,
+ * passing TRUE, to construct from the system crontab. Throws an
+ * exception if the crontab file can not be found, read, or parsed.
+ */
+ CTCron(bool _syscron = false, std::string _login = "");
+/**
+ * If you already have a struct passwd, use it instead. This
+ * is never used for the system crontab.
+ */
+ CTCron(const struct passwd * _login = 0L);
+
+/**
+ * Copy one user's tasks and environement variables to another user.
+ */
+ void operator = (const CTCron& source);
+
+/**
+ * Parses crontab file format.
+ */
+ friend std::istream& operator >> (std::istream& inputStream, CTCron& cron);
+
+/**
+ * Tokenizes to crontab file format.
+ */
+ friend std::ostream& operator << (std::ostream& outputStream, const CTCron& cron);
+
+/**
+ * Apply changes.
+ */
+ void apply();
+
+/**
+ * Cancel changes.
+ */
+ void cancel();
+
+/**
+ * Indicates whether or not dirty.
+ */
+ bool dirty();
+
+/**
+ * Returns the PATH environment variable value. A short cut to iterating
+ * the tasks vector.
+ */
+ std::string path() const;
+
+ /**
+ * Returns whether an error has occured
+ */
+ bool isError() { return !error.isEmpty(); }
+
+ /**
+ * Return error description
+ */
+ QString errorMessage() { QString r = error; error = QString::null; return r; }
+
+
+/**
+ * Indicates whether or not the crontab belongs to the system.
+ */
+ const bool syscron;
+
+/**
+ * User login.
+ */
+ std::string login;
+
+/**
+ * User real name.
+ */
+ std::string name;
+
+/**
+ * User's scheduled tasks.
+ */
+ std::vector<CTTask *> task;
+
+/**
+ * User's environment variables. Note: These are only environment variables
+ * found in the user's crontab file and does not include any set in a
+ * login or shell script such as ".bash_profile".
+ */
+ std::vector<CTVariable *> variable;
+
+/**
+ * Destructor.
+ */
+ ~CTCron();
+
+private:
+
+/**
+ * Can't copy a user!
+ */
+ CTCron(const CTCron& source);
+
+ unsigned int initialTaskCount;
+ unsigned int initialVariableCount;
+ QString writeCommand;
+ QString tmpFileName;
+
+ QString error;
+
+protected:
+ // Initialize member variables from the struct passwd.
+ bool initFromPasswd(const struct passwd *);
+};
+
+typedef std::vector<CTTask*>::iterator CTTaskIterator;
+typedef std::vector<CTVariable*>::iterator CTVariableIterator;
+
+#endif // CTCRON_H
diff --git a/kcron/ctdom.cpp b/kcron/ctdom.cpp
new file mode 100644
index 0000000..b1d7f5e
--- /dev/null
+++ b/kcron/ctdom.cpp
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * CT Day of Month Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctdom.h"
+#include "cti18n.h"
+
+string CTDayOfMonth::shortName[32] =
+{
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
+};
+
+CTDayOfMonth::CTDayOfMonth(const string& tokStr) :
+ CTUnit<1,31>(tokStr)
+{
+}
+
+string CTDayOfMonth::describe() const
+{
+ initializeNames();
+ return (count() == 31) ?
+ (const char*)i18n("every day ").local8Bit() :
+ CTUnit<1,31>::describe(shortName);
+}
+
+string CTDayOfMonth::getName(const int ndx)
+{
+ initializeNames();
+ return shortName[ndx];
+}
+
+void CTDayOfMonth::initializeNames()
+{
+ if (shortName[1].empty())
+ {
+ const string shortDOMName[32] =
+ {
+ "",
+ (const char*)i18n("1st").local8Bit(), (const char*)i18n("2nd").local8Bit(),
+ (const char*)i18n("3rd").local8Bit(), (const char*)i18n("4th").local8Bit(),
+ (const char*)i18n("5th").local8Bit(), (const char*)i18n("6th").local8Bit(),
+ (const char*)i18n("7th").local8Bit(), (const char*)i18n("8th").local8Bit(),
+ (const char*)i18n("9th").local8Bit(), (const char*)i18n("10th").local8Bit(),
+ (const char*)i18n("11th").local8Bit(), (const char*)i18n("12th").local8Bit(),
+ (const char*)i18n("13th").local8Bit(), (const char*)i18n("14th").local8Bit(),
+ (const char*)i18n("15th").local8Bit(), (const char*)i18n("16th").local8Bit(),
+ (const char*)i18n("17th").local8Bit(), (const char*)i18n("18th").local8Bit(),
+ (const char*)i18n("19th").local8Bit(), (const char*)i18n("20th").local8Bit(),
+ (const char*)i18n("21st").local8Bit(), (const char*)i18n("22nd").local8Bit(),
+ (const char*)i18n("23rd").local8Bit(), (const char*)i18n("24th").local8Bit(),
+ (const char*)i18n("25th").local8Bit(), (const char*)i18n("26th").local8Bit(),
+ (const char*)i18n("27th").local8Bit(), (const char*)i18n("28th").local8Bit(),
+ (const char*)i18n("29th").local8Bit(), (const char*)i18n("30th").local8Bit(),
+ (const char*)i18n("31st").local8Bit()
+ };
+
+ for (int i = 1; i <= 31; i++)
+ {
+ shortName[i] = shortDOMName[i];
+ }
+ }
+}
diff --git a/kcron/ctdom.h b/kcron/ctdom.h
new file mode 100644
index 0000000..4e66747
--- /dev/null
+++ b/kcron/ctdom.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * CT Day of Month Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTDOM_H
+#define CTDOM_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctunit.h"
+#include <string>
+
+/**
+ * Scheduled task days of month.
+ */
+class CTDayOfMonth : public CTUnit<1,31>
+{
+public:
+/**
+ * Constructs from a tokenized string.
+ */
+ CTDayOfMonth(const string& tokStr = "");
+
+/**
+ * Default copy constructor.
+ */
+ // CTDayOfMonth(const CTDayOfMonth& source);
+
+/**
+ * Default assignment operator
+ */
+ // void operator = (const CTDayOfMonth& source);
+
+/**
+ * Default destructor.
+ */
+ // ~CTDayOfMonth();
+
+/**
+ * Get natural language description.
+ */
+ virtual string describe() const;
+
+/**
+ * Get day of month name.
+ */
+ static string getName(const int ndx);
+
+private:
+ static void initializeNames();
+ static string shortName[32];
+};
+
+#endif // CTDOM_H
diff --git a/kcron/ctdow.cpp b/kcron/ctdow.cpp
new file mode 100644
index 0000000..fe93c86
--- /dev/null
+++ b/kcron/ctdow.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * CT Day Of Week Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctdow.h"
+#include "cti18n.h"
+
+string CTDayOfWeek::shortName[8] =
+{
+ "", "", "", "", "", "", "", ""
+};
+
+string CTDayOfWeek::longName[8] =
+{
+ "", "", "", "", "", "", "", ""
+};
+
+CTDayOfWeek::CTDayOfWeek(const string& tokStr) :
+ CTUnit<1,7>(tokStr)
+{
+ // Compensate for cron supporting Sunday as both 0 and 7.
+
+ if (get(0))
+ {
+ set(0,false);
+ set(7,true);
+ }
+}
+
+void CTDayOfWeek::initialize(const string &tokStr)
+{
+ CTUnit<1,7>::initialize(tokStr);
+
+ // Compensate for cron supporting Sunday as both 0 and 7.
+
+ if (get(0))
+ {
+ set(0,false);
+ set(7,true);
+ apply();
+ }
+}
+
+string CTDayOfWeek::describe() const
+{
+ initializeNames();
+ if (count() == 7)
+ return (const char*)i18n("every day ").local8Bit();
+ else if (get(1) && get(2) && get(3) && get(4) && get(5))
+ return (const char*)i18n("weekday ").local8Bit();
+ else
+ return CTUnit<1,7>::describe(shortName);
+}
+
+string CTDayOfWeek::getName(const int ndx, const bool format)
+{
+ initializeNames();
+ return (format == shortFormat) ? shortName[ndx] : longName[ndx];
+}
+
+void CTDayOfWeek::initializeNames()
+{
+ if (shortName[1].empty())
+ {
+ const string shortDOWName[8] =
+ {
+ "",
+ (const char*)i18n("Mon").local8Bit(), (const char*)i18n("Tue").local8Bit(),
+ (const char*)i18n("Wed").local8Bit(), (const char*)i18n("Thu").local8Bit(),
+ (const char*)i18n("Fri").local8Bit(), (const char*)i18n("Sat").local8Bit(),
+ (const char*)i18n("Sun").local8Bit()
+ };
+
+ const string longDOWName[8] =
+ {
+ "",
+ (const char*)i18n("Monday").local8Bit(), (const char*)i18n("Tuesday").local8Bit(),
+ (const char*)i18n("Wednesday").local8Bit(), (const char*)i18n("Thursday").local8Bit(),
+ (const char*)i18n("Friday").local8Bit(), (const char*)i18n("Saturday").local8Bit(),
+ (const char*)i18n("Sunday").local8Bit()
+ };
+
+ for (int i = 1; i <= 7; i++)
+ {
+ shortName[i] = shortDOWName[i];
+ longName[i] = longDOWName[i];
+ }
+ }
+}
diff --git a/kcron/ctdow.h b/kcron/ctdow.h
new file mode 100644
index 0000000..05b6357
--- /dev/null
+++ b/kcron/ctdow.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * CT Day of Week Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTDOW_H
+#define CTDOW_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctunit.h"
+#include <string>
+
+/**
+ * Scheduled task days of week.
+ */
+class CTDayOfWeek : public CTUnit<1,7>
+{
+public:
+/**
+ * Constructs from a tokenized string.
+ */
+ CTDayOfWeek(const string& tokStr = "");
+
+/**
+ * Default copy constructor.
+ */
+ // CTDayOfWeek(const CTDayOfWeek& source);
+
+/**
+ * Default assignment operator
+ */
+ // void operator = (const CTDayOfWeek& source);
+
+/**
+ * Default destructor.
+ */
+ // ~CTDayOfWeek();
+
+/**
+ * Override initialize to support crontab using both 0 and 7 for
+ * Sunday.
+ */
+ void initialize(const string &tokStr = "");
+
+/**
+ * Get natural language description.
+ */
+ virtual string describe() const;
+
+/**
+ * Get day of week name.
+ */
+ static string getName(const int ndx,
+ const bool format = CTDayOfWeek::longFormat);
+
+private:
+ static void initializeNames();
+ static string shortName[8];
+ static string longName[8];
+};
+
+#endif // CTDOW_H
diff --git a/kcron/cthost.cpp b/kcron/cthost.cpp
new file mode 100644
index 0000000..356047d
--- /dev/null
+++ b/kcron/cthost.cpp
@@ -0,0 +1,117 @@
+/***************************************************************************
+ * -------------------------------------------------------------------- *
+ * CT Host Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "cthost.h"
+
+#include "ctcron.h"
+
+#include <unistd.h> // getuid()
+
+#include <sys/types.h>
+#include <pwd.h>
+
+
+using namespace std;
+
+CTHost::CTHost()
+{
+ struct passwd *pwd = 0L;
+
+ // If it is the root user
+ if (getuid() == 0)
+ {
+ // Create the system cron table.
+ createCTCron(true);
+
+ // Read /etc/passwd
+ setpwent(); // restart
+ while((pwd=getpwent()))
+ {
+ createCTCron(pwd);
+ }
+ setpwent(); // restart again for others
+ }
+ else
+ // Non-root user, so just create user's cron table.
+ {
+ createCTCron();
+ }
+}
+
+CTHost::~CTHost()
+{
+ for (CTCronIterator i = cron.begin(); i != cron.end(); ++i)
+ delete *i;
+}
+
+void CTHost::apply()
+{
+ for (CTCronIterator i = cron.begin(); i != cron.end(); ++i)
+ {
+ (*i)->apply();
+ if ((*i)->isError())
+ {
+ error = (*i)->errorMessage();
+ return;
+ }
+ }
+}
+
+void CTHost::cancel()
+{
+ for (CTCronIterator i = cron.begin(); i != cron.end(); ++i)
+ (*i)->cancel();
+}
+
+bool CTHost::dirty()
+{
+ bool isDirty(false);
+
+ for (CTCronIterator i = cron.begin(); i != cron.end(); ++i)
+ if ((*i)->dirty()) isDirty = true;
+
+ return isDirty;
+}
+
+CTCron* CTHost::createCTCron(bool _syscron, string _login)
+{
+ CTCron *p = new CTCron(_syscron, _login);
+ if (p->isError())
+ {
+ error = p->errorMessage();
+ delete p;
+ return 0;
+ }
+ cron.push_back(p);
+ return p;
+}
+
+CTCron* CTHost::createCTCron(const struct passwd *pwd)
+{
+ CTCron *p = new CTCron(pwd);
+ if (p->isError())
+ {
+ error = p->errorMessage();
+ delete p;
+ return 0;
+ }
+ cron.push_back(p);
+ return p;
+}
+
+bool CTHost::root() const
+{
+ return (!getuid());
+}
diff --git a/kcron/cthost.h b/kcron/cthost.h
new file mode 100644
index 0000000..6d601c3
--- /dev/null
+++ b/kcron/cthost.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * CT Host Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTHOST_H
+#define CTHOST_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include <vector>
+#include <string>
+
+#include <qstring.h> // Whatever
+
+class CTCron;
+struct passwd;
+
+/**
+ * The host machine, or computer (encapsulation of crontab files on the
+ * host).
+ *
+ * If the user is the root user, the cron vector will have a member for
+ * each user of the host plus one for the system crontab.
+ *
+ * If the user is a non-root user, there will be only one member in the
+ * cron vector.
+ */
+class CTHost
+{
+public:
+
+/**
+ * Constructs the user(s), scheduled tasks, and environment variables
+ * from crontab files.
+ */
+ CTHost();
+
+/**
+ * Destroys the user(s), scheduled tasks, and environment variable
+ * objects. Does not make any changes to the crontab files. Any unapplied
+ * changes are consequently "cancelled."
+ */
+ ~CTHost();
+
+/**
+ * Apply changes.
+ */
+ void apply();
+
+/**
+ * Cancel changes.
+ */
+ void cancel();
+
+/**
+ * Indicates whether or not dirty.
+ */
+ bool dirty();
+
+/**
+ * Indicates whether or not the user is the root user.
+ */
+ bool root() const;
+
+/**
+ * Indicates an error has occured.
+ */
+ bool isError() { return !error.isEmpty(); }
+
+/**
+ * Error message
+ */
+ QString errorMessage() { QString r = error; error = QString::null; return r; }
+
+
+/**
+ * User(s).
+ *
+ * If the user is the root user, the cron vector will have a member for
+ * each user of the host plus one for the system crontab.
+ *
+ * If the user is a non-root user, there will be only one member in the
+ * cron vector.
+ */
+ std::vector<CTCron*> cron;
+
+private:
+
+/**
+ * Copy construction not allowed.
+ */
+ CTHost(const CTHost& source);
+
+/**
+ * Assignment not allowed
+ */
+ void operator = (const CTHost& source);
+
+/**
+ * Factory create a cron table. Appends to the end of cron.
+ */
+ CTCron* createCTCron(bool _syscron = false, std::string _login = "");
+ CTCron* createCTCron(const struct passwd *);
+
+ QString error;
+};
+
+typedef std::vector<CTCron*>::iterator CTCronIterator;
+
+#endif // CTHOST_H
diff --git a/kcron/cthour.h b/kcron/cthour.h
new file mode 100644
index 0000000..702c410
--- /dev/null
+++ b/kcron/cthour.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * CT Hour Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTHOUR_H
+#define CTHOUR_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctunit.h"
+#include <string>
+
+/**
+ * Scheduled task hours.
+ */
+class CTHour : public CTUnit<0,23>
+{
+public:
+
+/**
+ * Constructs from a tokenized string.
+ */
+ CTHour(const string &tokStr = "") : CTUnit<0,23>(tokStr) { };
+
+/**
+ * Default copy constructor.
+ */
+ // CTHour(const CTHour& source);
+
+/**
+ * Default assignment operator
+ */
+ // void operator = (const CTHour& source);
+
+/**
+ * Default destructor.
+ */
+ // ~CTHour();
+
+};
+
+#endif // CTHOUR_H
diff --git a/kcron/cti18n.h b/kcron/cti18n.h
new file mode 100644
index 0000000..e3a1757
--- /dev/null
+++ b/kcron/cti18n.h
@@ -0,0 +1,27 @@
+/***************************************************************************
+ * CT Internationalization Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTI18N_H
+#define CTI18N_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+//
+// Note: I do make an exception to the above rule for this file, as it is
+// necessary to support internationalization.
+//
+// Regardless, please don't introduce any other Qt or KDE dependencies here.
+// -GM 11/99
+
+#include <klocale.h>
+#include <kapplication.h>
+
+#endif // CTI18N_H
diff --git a/kcron/ctminute.h b/kcron/ctminute.h
new file mode 100644
index 0000000..6d93e08
--- /dev/null
+++ b/kcron/ctminute.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * CT Minute Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTMINUTE_H
+#define CTMINUTE_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctunit.h"
+#include <string>
+
+/**
+ * Scheduled task minutes.
+ */
+class CTMinute : public CTUnit<0,59>
+{
+public:
+
+/**
+ * Constructs from a tokenized string.
+ */
+ CTMinute(const string &tokStr = "") : CTUnit<0,59>(tokStr) { };
+
+/**
+ * Default copy constructor.
+ */
+ // CTMinute(const CTMinute& source);
+
+/**
+ * Default assignment operator
+ */
+ // void operator = (const CTMinute& source);
+
+/**
+ * Default destructor.
+ */
+ // ~CTMinute();
+
+};
+
+#endif // CTMINUTE_H
diff --git a/kcron/ctmonth.cpp b/kcron/ctmonth.cpp
new file mode 100644
index 0000000..b66cd39
--- /dev/null
+++ b/kcron/ctmonth.cpp
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * CT Month Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctmonth.h"
+#include "cti18n.h"
+
+string CTMonth::shortName[13] =
+{
+ "", "", "", "", "", "", "", "", "", "", "", "", "",
+};
+
+CTMonth::CTMonth(const string& tokStr) :
+ CTUnit<1,12>(tokStr)
+{
+}
+
+string CTMonth::describe () const
+{
+ initializeNames();
+ return (count() == 12) ?
+ (const char*)i18n("every month ").local8Bit() :
+ CTUnit<1,12>::describe(shortName);
+}
+
+string CTMonth::getName(const int ndx)
+{
+ initializeNames();
+ return shortName[ndx];
+}
+
+void CTMonth::initializeNames()
+{
+ if (shortName[1].empty())
+ {
+ const string shortMonthName[13] =
+ {
+ "",
+ (const char*)i18n("January").local8Bit(), (const char*)i18n("February").local8Bit(),
+ (const char*)i18n("March").local8Bit(), (const char*)i18n("April").local8Bit(),
+ (const char*)i18n("May long","May").local8Bit(), (const char*)i18n("June").local8Bit(),
+ (const char*)i18n("July").local8Bit(), (const char*)i18n("August").local8Bit(),
+ (const char*)i18n("September").local8Bit(), (const char*)i18n("October").local8Bit(),
+ (const char*)i18n("November").local8Bit(), (const char*)i18n("December").local8Bit()
+ };
+
+ for (int i = 1; i <= 12; i++)
+ {
+ shortName[i] = shortMonthName[i];
+ }
+ }
+}
diff --git a/kcron/ctmonth.h b/kcron/ctmonth.h
new file mode 100644
index 0000000..f7aa8af
--- /dev/null
+++ b/kcron/ctmonth.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * CT Month Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTMONTH_H
+#define CTMONTH_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctunit.h"
+#include <string>
+
+/**
+ * Scheduled task months.
+ */
+class CTMonth : public CTUnit<1,12>
+{
+public:
+
+/**
+ * Constructs from a tokenized string.
+ */
+ CTMonth(const string& tokStr = "");
+
+/**
+ * Default copy constructor.
+ */
+ // CTMonth(const CTMonth& source);
+
+/**
+ * Default assignment operator
+ */
+ // void operator = (const CTMonth& source);
+
+/**
+ * Default destructor.
+ */
+ // ~CTMonth();
+
+/**
+ * Get natural language description.
+ */
+ virtual string describe() const;
+
+/**
+ * Get month name.
+ */
+ static string getName(const int ndx);
+
+private:
+ static void initializeNames();
+ static string shortName[13];
+};
+
+#endif // CTMONTH_H
diff --git a/kcron/cttask.cpp b/kcron/cttask.cpp
new file mode 100644
index 0000000..1b7b299
--- /dev/null
+++ b/kcron/cttask.cpp
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * CT Task Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "cttask.h"
+
+#include "cti18n.h"
+#include <time.h> // tm, strftime()
+
+CTTask::CTTask(string tokStr, string _comment, bool _syscron) :
+ syscron(_syscron)
+{
+ if (tokStr.substr(0,2) == "#\\")
+ {
+ tokStr = tokStr.substr(2,tokStr.length() - 2);
+ enabled = false;
+ }
+ else if (tokStr.substr(0,1) == "#")
+ {
+ tokStr = tokStr.substr(1,tokStr.length() - 1);
+ enabled = false;
+ }
+ else
+ enabled = true;
+
+ if (tokStr.substr(0,1) == "-")
+ {
+ tokStr = tokStr.substr(1,tokStr.length() - 1);
+ silent = true;
+ }
+ else
+ {
+ silent = false;
+ }
+
+ if (tokStr.substr(0,1) == "@")
+ {
+ if (tokStr.substr(1,6) == "reboot")
+ {
+ // Dunno what to do with this...
+ tokStr = "0 0 1 1 *"+tokStr.substr(7,tokStr.length()-1);
+ }
+ else if (tokStr.substr(1,6) == "yearly")
+ {
+ tokStr = "0 0 1 1 *"+tokStr.substr(7,tokStr.length()-1);
+ }
+ else if (tokStr.substr(1,8) == "annually")
+ {
+ tokStr = "0 0 1 1 *"+tokStr.substr(9,tokStr.length()-1);
+ }
+ else if (tokStr.substr(1,7) == "monthly")
+ {
+ tokStr = "0 0 1 * *"+tokStr.substr(8,tokStr.length()-1);
+ }
+ else if (tokStr.substr(1,6) == "weekly")
+ {
+ tokStr = "0 0 * * 0"+tokStr.substr(7,tokStr.length()-1);
+ }
+ else if (tokStr.substr(1,5) == "daily")
+ {
+ tokStr = "0 0 * * *"+tokStr.substr(6,tokStr.length()-1);
+ }
+ else if (tokStr.substr(1,6) == "hourly")
+ {
+ tokStr = "0 * * * *"+tokStr.substr(7,tokStr.length()-1);
+ }
+ }
+
+ int spacepos(tokStr.find_first_of(" \t"));
+ minute.initialize(tokStr.substr(0,spacepos));
+
+ while(isspace(tokStr[spacepos+1])) spacepos++;
+ tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
+ spacepos = tokStr.find_first_of(" \t");
+ hour.initialize(tokStr.substr(0,spacepos));
+
+ while(isspace(tokStr[spacepos+1])) spacepos++;
+ tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
+ spacepos = tokStr.find_first_of(" \t");
+ dayOfMonth.initialize(tokStr.substr(0,spacepos));
+
+ while(isspace(tokStr[spacepos+1])) spacepos++;
+ tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
+ spacepos = tokStr.find_first_of(" \t");
+ month.initialize(tokStr.substr(0,spacepos));
+
+ while(isspace(tokStr[spacepos+1])) spacepos++;
+ tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
+ spacepos = tokStr.find_first_of(" \t");
+ dayOfWeek.initialize(tokStr.substr(0,spacepos));
+
+ if (syscron)
+ {
+ while(isspace(tokStr[spacepos+1])) spacepos++;
+ tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
+ spacepos = tokStr.find_first_of(" \t");
+ user = tokStr.substr(0,spacepos);
+ }
+ else
+ user = string("");
+
+ command = tokStr.substr(spacepos+1,tokStr.length()-1);
+ // remove leading whitespace
+ while (command.find_first_of(" \t") == 0)
+ command = command.substr(1,command.length()-1);
+ comment = _comment;
+
+ initialUser = user;
+ initialCommand = command;
+ initialComment = comment;
+ initialEnabled = enabled;
+ initialSilent = silent;
+}
+
+CTTask::CTTask(const CTTask &source) :
+ month(source.month),
+ dayOfMonth(source.dayOfMonth),
+ dayOfWeek(source.dayOfWeek),
+ hour(source.hour),
+ minute(source.minute),
+ user(source.user),
+ command(source.command),
+ comment(source.comment),
+ enabled(source.enabled),
+ silent(source.silent),
+ initialUser(""),
+ initialCommand(""),
+ initialComment(""),
+ initialEnabled(true),
+ initialSilent(false)
+{
+}
+
+void CTTask::operator = (const CTTask& source)
+{
+ month = source.month;
+ dayOfMonth = source.dayOfMonth;
+ dayOfWeek = source.dayOfWeek;
+ hour = source.hour;
+ minute = source.minute;
+ user = source.user;
+ command = source.command;
+ comment = source.comment;
+ enabled = source.enabled;
+ silent = source.silent;
+ initialUser = "";
+ initialCommand = "";
+ initialComment = "";
+ initialEnabled = true;
+ initialSilent = false;
+ return;
+}
+
+ostream& operator << (ostream& outputStream, const CTTask& task)
+{
+// if (task.comment != string(""))
+ outputStream << "# " << task.comment << "\n";
+
+ if (!task.enabled)
+ outputStream << "#\\";
+
+ if (task.silent)
+ outputStream << "-";
+
+ outputStream << task.minute << " ";
+ outputStream << task.hour << " ";
+ outputStream << task.dayOfMonth << " ";
+ outputStream << task.month << " ";
+ outputStream << task.dayOfWeek << "\t";
+
+ if (task.user != string(""))
+ outputStream << task.user << "\t";
+
+ outputStream << task.command << "\n";
+
+ return outputStream;
+}
+
+void CTTask::apply()
+{
+ month.apply();
+ dayOfMonth.apply();
+ dayOfWeek.apply();
+ hour.apply();
+ minute.apply();
+ initialUser = user;
+ initialCommand = command;
+ initialComment = comment;
+ initialEnabled = enabled;
+ initialSilent = silent;
+}
+
+void CTTask::cancel()
+{
+ month.cancel();
+ dayOfMonth.cancel();
+ dayOfWeek.cancel();
+ hour.cancel();
+ minute.cancel();
+ user = initialUser;
+ command = initialCommand;
+ comment = initialComment;
+ enabled = initialEnabled;
+ silent = initialSilent;
+}
+
+bool CTTask::dirty() const
+{
+ return (month.dirty() || dayOfMonth.dirty() || dayOfWeek.dirty() ||
+ hour.dirty() || minute.dirty() || (user != initialUser) ||
+ (command != initialCommand) || (comment != initialComment) ||
+ (enabled != initialEnabled) || (silent != initialSilent));
+}
+
+string CTTask::describe() const
+{
+
+ // Of the whole program, this method is probably the trickiest.
+ //
+ // This method creates the natural language description, such as
+ // "At 1:00am, every Sun".
+ //
+ // First, I declare some strings for holding what can be internationalized.
+ // Note the tokens such as "MONTHS". Translators should reuse these
+ // tokens in their translations. See README.translators for more
+ // information.
+ //
+ // Second, I get the descriptions from the component parts such as
+ // days of the month.
+ //
+ // Third, I get hour/minute time combinations. Although a little bit
+ // awkward, I use the tm struct and strftime from <time.h>. This
+ // way this code is portable across all Unixes.
+ //
+ // Fourth, I know that "every day of the week" and "every day of the
+ // month" simply makes "every day".
+ //
+ // Fifth and finally I do tag substitution to create the natural language
+ // description.
+
+ string tmFormat((const char *)i18n("%H:%M").local8Bit());
+ string DOMFormat((const char *)i18n("Please translator, read the README.translators file in kcron's source code","DAYS_OF_MONTH of MONTHS").local8Bit());
+ string DOWFormat((const char *)i18n("Really, read that file","every DAYS_OF_WEEK").local8Bit());
+ string dateFormat((const char *)i18n("DOM_FORMAT as well as DOW_FORMAT").local8Bit());
+ string timeFormat((const char *)i18n("At TIME").local8Bit());
+ string format((const char *)i18n("TIME_FORMAT, DATE_FORMAT").local8Bit());
+
+ // Get natural language description of day of month,
+ // month name, and day of week.
+
+ string DOMDesc(dayOfMonth.describe());
+ string monthDesc(month.describe());
+ string DOWDesc(dayOfWeek.describe());
+
+ // Create time description.
+
+ int total(minute.count()*hour.count());
+
+ string timeDesc("");
+ int count(0);
+
+ for (int h = 0; h <= 23; h++)
+ if (hour.get(h))
+ for (int m = 0; m <= 59; m++)
+ if (minute.get(m))
+ {
+ tm time;
+ time.tm_sec = 0;
+ time.tm_min = m;
+ time.tm_hour = h;
+ time.tm_mday = 0;
+ time.tm_mon = 0;
+ time.tm_year = 0;
+ time.tm_wday = 0;
+ time.tm_yday = 0;
+ time.tm_isdst= 0;
+
+ char tmp[12];
+ strftime(tmp, 12, tmFormat.c_str(), &time);
+ string tmpStr = tmp;
+
+ // remove leading space
+ if (tmpStr.substr(0,1) == " ")
+ tmpStr = tmpStr.substr(1,tmpStr.length()-1);
+
+ timeDesc += tmpStr;
+ count++;
+ switch (total - count)
+ {
+ case 0: break;
+ case 1: if (total > 2)
+ timeDesc += (const char *)i18n(", and ").local8Bit();
+ else
+ timeDesc += (const char *)i18n(" and ").local8Bit();
+ break;
+ default: timeDesc += (const char*)i18n(", ").local8Bit();
+ }
+ }
+
+ // "* * *" means truly every day.
+ // Note: Languages may use different phrases to indicate
+ // every day of month versus every day of week.
+
+ if ((dayOfMonth.count() == 31) &&
+ (dayOfWeek.count() == 7))
+ dateFormat = (const char *)i18n("every day ").local8Bit();
+ else
+ {
+ // Day of month not specified, so use day of week.
+ if (dayOfMonth.count() == 31)
+ dateFormat = "DOW_FORMAT";
+ // Day of week not specified, so use day of month.
+ if (dayOfWeek.count() == 7)
+ dateFormat = "DOM_FORMAT";
+ }
+
+ // Replace tags to build natural language description.
+
+ int pos(0);
+
+ if ((pos = DOMFormat.find("DAYS_OF_MONTH")) > -1)
+ DOMFormat.replace(pos,13,DOMDesc);
+
+ if ((pos = DOMFormat.find("MONTHS")) > -1)
+ DOMFormat.replace(pos,6,monthDesc);
+
+ if ((pos = DOWFormat.find("DAYS_OF_WEEK")) > -1)
+ DOWFormat.replace(pos,12,DOWDesc);
+
+ if ((pos = dateFormat.find("DOM_FORMAT")) > -1)
+ dateFormat.replace(pos,10,DOMFormat);
+
+ if ((pos = dateFormat.find("DOW_FORMAT")) > -1)
+ dateFormat.replace(pos,10,DOWFormat);
+
+ if ((pos = timeFormat.find("TIME")) > -1)
+ timeFormat.replace(pos,4,timeDesc);
+
+ if ((pos = format.find("DATE_FORMAT")) > -1)
+ format.replace(pos,11,dateFormat);
+
+ if ((pos = format.find("TIME_FORMAT")) > -1)
+ format.replace(pos,11,timeFormat);
+
+ return format;
+}
+
+bool CTTask::system() const
+{
+ return syscron;
+}
diff --git a/kcron/cttask.h b/kcron/cttask.h
new file mode 100644
index 0000000..3665c61
--- /dev/null
+++ b/kcron/cttask.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+ * CT Task Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTTASK_H
+#define CTTASK_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include <string>
+
+#include "ctmonth.h"
+#include "ctdom.h"
+#include "ctdow.h"
+#include "cthour.h"
+#include "ctminute.h"
+
+/**
+ * A scheduled task (encapsulation of crontab entry). Encapsulates
+ * parsing, tokenization, and natural language description.
+ */
+class CTTask
+{
+public:
+
+/**
+ * Constructs scheduled task from crontab format string.
+ */
+ CTTask(string tokStr = "", string _comment = "", bool syscron = false);
+
+/**
+ * Copy constructor.
+ */
+ CTTask(const CTTask& source);
+
+/**
+ * Assignment operator.
+ */
+ void operator = (const CTTask& source);
+
+/**
+ * Default constructor.
+ */
+ // ~CTTask();
+
+/**
+ * Tokenizes scheduled task to crontab format.
+ */
+ friend ostream& operator << (ostream& outputStream, const CTTask& task);
+
+/**
+ * Mark changes as applied.
+ */
+ void apply();
+
+/**
+ * Cancel changes.
+ */
+ void cancel();
+
+/**
+ * Indicates whether or not the task has been modified.
+ */
+ bool dirty() const;
+
+/**
+ * Returns natural language description of the task's schedule.
+ */
+ string describe() const;
+
+/**
+ * Indicates whether or not the task belongs to the system crontab.
+ */
+ bool system() const;
+
+ CTMonth month;
+ CTDayOfMonth dayOfMonth;
+ CTDayOfWeek dayOfWeek;
+ CTHour hour;
+ CTMinute minute;
+ string user;
+ string command;
+ string comment;
+ bool enabled;
+ bool silent;
+
+private:
+ bool syscron;
+ string initialUser;
+ string initialCommand;
+ string initialComment;
+ bool initialEnabled;
+ bool initialSilent;
+};
+
+#endif // CTTASK_H
diff --git a/kcron/ctunit.cpp b/kcron/ctunit.cpp
new file mode 100644
index 0000000..0532131
--- /dev/null
+++ b/kcron/ctunit.cpp
@@ -0,0 +1,319 @@
+/***************************************************************************
+ * CT Unit of Time Interval Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "cti18n.h"
+#include <vector>
+#include <string>
+#include <stdio.h> // sprintf
+#include <ctype.h> // tolower
+#include <stdlib.h>
+
+using namespace std;
+
+template<int min, int max>
+CTUnit<min, max>::CTUnit(const string &tokStr)
+{
+ initialize(tokStr);
+}
+
+template<int min, int max>
+CTUnit<min, max>::CTUnit(const CTUnit& source)
+{
+ for (int i = 0; i <= max; i++)
+ {
+ initialEnabled[i] = 0;
+ enabled[i] = source.enabled[i];
+ }
+ initialTokStr = "";
+ isDirty = true;
+}
+
+template<int min, int max>
+CTUnit<min, max>::~CTUnit()
+{
+}
+
+template<int min, int max>
+void CTUnit<min, max>::operator = (const CTUnit<min,max>& unit)
+{
+ for (int i = 0; i <= max; i++)
+ enabled[i] = unit.enabled[i];
+ isDirty = true;
+ return;
+}
+
+template<int min, int max>
+void CTUnit<min, max>::initialize(const string &tokStr)
+{
+ for (int i = 0; i <= max; i++)
+ enabled[i] = 0;
+
+ parse(tokStr);
+
+ for (int i = min; i <= max; i++)
+ initialEnabled[i] = enabled[i];
+
+ initialTokStr = tokStr;
+ isDirty = false;
+
+ return;
+}
+
+template<int min, int max>
+void CTUnit<min, max>::parse(string tokStr)
+{
+ // subelement is that which is between commas
+ string subelement;
+ int commapos, slashpos, dashpos;
+ int beginat, endat, step;
+
+ // loop through each subelement
+ tokStr += ",";
+ while ((commapos = tokStr.find(",")) > 0)
+ {
+ subelement = tokStr.substr(0,commapos);
+
+ // find "/" to determine step
+ slashpos = subelement.find("/");
+ if (slashpos == -1)
+ {
+ step = 1;
+ slashpos = subelement.length();
+ }
+ else
+ {
+ step = fieldToValue(subelement.substr(slashpos+1,
+ subelement.length()-slashpos-1));
+ if (step < 1)
+ step = 1;
+ }
+
+ // find "=" to determine range
+ dashpos = subelement.find("-");
+ if (dashpos == -1)
+ {
+ // deal with "*"
+ if (subelement.substr(0,slashpos) == "*")
+ {
+ beginat = min;
+ endat = max;
+ }
+ else
+ {
+ beginat = fieldToValue(subelement.substr(0,slashpos));
+ endat = beginat;
+ }
+ }
+ else
+ {
+ beginat = fieldToValue(subelement.substr(0,dashpos));
+ endat = fieldToValue(subelement.substr(dashpos+1,slashpos-dashpos-1));
+ }
+
+ // ignore out of range
+ if (beginat < 0)
+ beginat = 0;
+ if (endat > max)
+ endat = max;
+
+ // setup enabled
+ for (int i = beginat; i <= endat; i+=step)
+ enabled[i] = 1;
+
+ tokStr = tokStr.substr(commapos+1, tokStr.length()-commapos-1);
+ }
+ return;
+}
+
+template<int min, int max>
+string CTUnit<min, max>::tokenize() const
+{
+ if (!isDirty)
+ {
+ return initialTokStr;
+ }
+ else
+ {
+ int total(count());
+ int count(0);
+ int num(min);
+ string tmpStr;
+
+ while (num <= max)
+ {
+ if (enabled[num])
+ {
+ char cnum[3];
+ sprintf(cnum, "%u", num);
+ tmpStr += cnum;
+ if (++count < total)
+ tmpStr += ",";
+ }
+ num++;
+ }
+ if (count == (max - min + 1))
+ tmpStr = "*";
+ return tmpStr;
+ }
+}
+
+template<int min, int max>
+string CTUnit<min, max>::describe(const string *label) const
+{
+ int total(count());
+ int count(0);
+ string tmpStr;
+ for (int i = min; i <= max; i++)
+ {
+ if (enabled[i])
+ {
+ tmpStr += label[i];
+ count++;
+ switch (total - count)
+ {
+ case 0: break;
+ case 1: if (total > 2) tmpStr += (const char *)i18n(",").local8Bit();
+ tmpStr += (const char *)i18n(" and ").local8Bit();
+ break;
+ default: tmpStr += (const char *)i18n(", ").local8Bit();
+ break;
+ }
+ }
+ }
+ return tmpStr;
+}
+
+template<int min, int max>
+int CTUnit<min, max>::begin()
+{
+ return min;
+}
+
+template<int min, int max>
+int CTUnit<min, max>::end()
+{
+ return max;
+}
+
+template<int min, int max>
+bool CTUnit<min, max>::get(int pos) const
+{
+ return enabled[pos];
+}
+
+template<int min, int max>
+void CTUnit<min, max>::set(int pos, bool value)
+{
+ enabled[pos] = value;
+ isDirty = true;
+ return;
+}
+
+template<int min, int max>
+void CTUnit<min, max>::enable(int pos)
+{
+ enabled[pos] = true;
+ isDirty = true;
+ return;
+}
+
+template<int min, int max>
+void CTUnit<min, max>::disable(int pos)
+{
+ enabled[pos] = false;
+ isDirty = true;
+ return;
+}
+
+template<int min, int max>
+bool CTUnit<min, max>::dirty() const
+{
+ return isDirty;
+}
+
+template<int min, int max>
+int CTUnit<min, max>::count() const
+{
+ int total(0);
+ for (int i = min; i <= max; i++)
+ total += (enabled[i] == true);
+ return total;
+}
+
+template<int min, int max>
+void CTUnit<min, max>::apply()
+{
+ initialTokStr = tokenize();
+ for (int i = min; i <= max; i++)
+ initialEnabled[i] = enabled[i];
+ isDirty = false;
+ return;
+}
+
+template<int min, int max>
+void CTUnit<min, max>::cancel()
+{
+ for (int i = min; i <= max; i++)
+ enabled[i] = initialEnabled[i];
+ isDirty = false;
+ return;
+}
+
+template<int min, int max>
+int CTUnit<min, max>::fieldToValue(string entry) const
+{
+ // GNU C++ STL has no String::toLower() so we have to lower
+ // by hand.
+
+ string lower("");
+ int length = entry.length();
+ for (int i = 0; i < length; i++)
+ lower += tolower(*(entry.substr(i, 1).c_str()));
+
+ // check for days
+ string days[7] =
+ {
+ "sun", "mon", "tue", "wed", "thu", "fri", "sat"
+ };
+
+ for (int day = 0; day < 7; day++)
+ {
+ if (lower == days[day])
+ {
+ char cnum[3];
+ sprintf(cnum, "%u", day);
+ entry = cnum;
+ }
+ }
+
+ // check for months
+ string months[13] =
+ {
+ "",
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec"
+ };
+
+ for (int month = 1; month < 13; month++)
+ {
+ if (lower == months[month])
+ {
+ char cnum[3];
+ sprintf(cnum, "%u", month);
+ entry = cnum;
+ }
+ }
+
+ return atoi(entry.c_str());
+}
diff --git a/kcron/ctunit.h b/kcron/ctunit.h
new file mode 100644
index 0000000..871a274
--- /dev/null
+++ b/kcron/ctunit.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+ * CT Unit of Time Interval Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTUNIT_H
+#define CTUNIT_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include <string>
+#include <iostream>
+
+/**
+ * A cron table unit parser and tokenizer.
+ * Parses/tokenizes unit such as "0-3,5,6,10-30/5"
+ * Also provides default natural language description.
+ */
+template<int min, int max> class CTUnit
+{
+public:
+
+/**
+ * Constant indicating short format.
+ */
+ static const bool shortFormat = 0;
+
+/**
+ * Constant indicating long format.
+ */
+ static const bool longFormat = 1;
+
+/**
+ * Initialize including parsing and saving initial image.
+ */
+ CTUnit(const std::string &tokStr = "");
+
+/**
+ * Base initial image as empty and copy enabled intervals.
+ */
+ CTUnit(const CTUnit& source);
+
+/**
+ * Destructor.
+ */
+ virtual ~CTUnit();
+
+/**
+ * Copy enabled intervals.
+ */
+ void operator = (const CTUnit<min,max>& unit);
+
+/**
+ * Returns tokenization to output stream.
+ */
+ friend std::ostream& operator << (std::ostream& outStr, const CTUnit<min,max>& unit)
+ {
+ if (unit.count() == (max - min + 1))
+ outStr << "*";
+ else
+ outStr << ((const CTUnit<min, max>) unit).tokenize();
+ return outStr;
+ };
+
+/**
+ * Parses unit such as "0-3,5,6,10-30/5".
+ * And initialize array of enabled intervals.
+ */
+ void initialize(const std::string &tokStr = "");
+
+/**
+ * Parses unit such as "0-3,5,6,10-30/5".
+ * Does not initialize array of enabled intervals.
+ */
+ void parse(std::string tokStr = "");
+
+/**
+ * Tokenizes unit into string such as
+ * "0,1,2,3,5,6,10,15,20,25,30".
+ */
+ std::string tokenize() const;
+
+/**
+ * Get default natural language description.
+ */
+ virtual std::string describe(const std::string *label) const;
+
+/**
+ * Lower bound.
+ */
+ int begin();
+
+/**
+ * Upper bound.
+ */
+ int end();
+
+/**
+ * Accessor.
+ */
+ bool get(int pos) const;
+
+/**
+ * Mutator.
+ */
+ void set(int pos, bool value);
+
+/**
+ * Enable.
+ */
+ void enable(int pos);
+
+/**
+ * Disable.
+ */
+ void disable(int pos);
+
+/**
+ * Indicates whether enabled intervals have been modified.
+ */
+ bool dirty() const;
+
+/**
+ * Total count of enabled intervals.
+ */
+ int count() const;
+
+/**
+ * Mark changes as applied.
+ */
+ void apply();
+
+/**
+ * Mark cancel changes and revert to initial or last applied
+ * image.
+ */
+ void cancel();
+
+private:
+
+ int fieldToValue(std::string entry) const;
+ bool isDirty;
+ bool enabled[max+1];
+ bool initialEnabled[max+1];
+ std::string initialTokStr;
+
+};
+
+#include "ctunit.cpp"
+
+#endif // CTUNIT_H
diff --git a/kcron/ctvariable.cpp b/kcron/ctvariable.cpp
new file mode 100644
index 0000000..f736c76
--- /dev/null
+++ b/kcron/ctvariable.cpp
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * CT Environment Variable Implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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. *
+ ***************************************************************************/
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include "ctvariable.h"
+
+using namespace std;
+
+CTVariable::CTVariable(string tokStr, string _comment)
+{
+ if (tokStr.substr(0,2) == "#\\")
+ {
+ tokStr = tokStr.substr(2,tokStr.length() - 2);
+ enabled = false;
+ }
+ else
+ enabled = true;
+
+ int spacepos(0);
+
+ spacepos = tokStr.find_first_of(" =");
+ variable = tokStr.substr(0,spacepos);
+
+ value = tokStr.substr(spacepos+1,tokStr.length()-spacepos-1);
+ comment = _comment;
+
+ initialVariable = variable;
+ initialValue = value;
+ initialComment = comment;
+ initialEnabled = enabled;
+}
+
+CTVariable::CTVariable(const CTVariable &source) :
+ variable(source.variable),
+ value(source.value),
+ comment(source.comment),
+ enabled(source.enabled),
+ initialVariable(""),
+ initialValue(""),
+ initialComment(""),
+ initialEnabled(true)
+{
+}
+
+void CTVariable::operator = (const CTVariable& source)
+{
+ variable = source.variable;
+ value = source.value;
+ comment = source.comment;
+ enabled = source.enabled;
+ initialVariable = "";
+ initialValue = "";
+ initialComment = "";
+ initialEnabled = true;
+ return;
+}
+
+ostream& operator << (ostream& outputStream, const CTVariable& source)
+{
+ if (source.comment != string(""))
+ outputStream << "# " << source.comment << "\n";
+
+ if (!source.enabled)
+ outputStream << "#\\";
+
+ outputStream << source.variable << "=" << source.value << "\n";
+
+ return outputStream;
+}
+
+void CTVariable::apply()
+{
+ initialVariable = variable;
+ initialValue = value;
+ initialComment = comment;
+ initialEnabled = enabled;
+}
+
+void CTVariable::cancel()
+{
+ variable = initialVariable;
+ value = initialValue;
+ comment = initialComment;
+ enabled = initialEnabled;
+}
+
+bool CTVariable::dirty() const
+{
+ return ((variable != initialVariable) || (value != initialValue) ||
+ (comment != initialComment) || (enabled != initialEnabled));
+}
diff --git a/kcron/ctvariable.h b/kcron/ctvariable.h
new file mode 100644
index 0000000..3f20600
--- /dev/null
+++ b/kcron/ctvariable.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * CT Environment Variable Header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 CTVARIABLE_H
+#define CTVARIABLE_H
+
+// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
+// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
+
+#include <string>
+#include <fstream>
+
+/**
+ * An environment variable (encapsulation of crontab environment variable
+ * entry). Encapsulates parsing and tokenization.
+ */
+class CTVariable
+{
+public:
+
+/**
+ * Constructs environment variable from crontab format string.
+ */
+ CTVariable(std::string tokStr = "", std::string _comment = "");
+
+/**
+ * Copy constructor.
+ */
+ CTVariable(const CTVariable& source);
+
+/**
+ * Assignment operator.
+ */
+ void operator = (const CTVariable& source);
+
+/**
+ * Default destructor.
+ */
+ // ~CTVariable();
+
+/**
+ * Tokenizes environment variable to crontab format.
+ */
+ friend std::ostream& operator << (std::ostream& outputStream, const CTVariable& task);
+
+/**
+ * Mark changes as applied.
+ */
+ void apply();
+
+/**
+ * Cancel changes.
+ */
+ void cancel();
+
+/**
+ * Indicates whether or not the environment variable has been modified.
+ */
+ bool dirty() const;
+
+ std::string variable;
+ std::string value;
+ std::string comment;
+ bool enabled;
+
+private:
+ std::string initialVariable;
+ std::string initialValue;
+ std::string initialComment;
+ bool initialEnabled;
+
+};
+
+#endif // CTVARIABLE_H
diff --git a/kcron/hi16-app-kcron.png b/kcron/hi16-app-kcron.png
new file mode 100644
index 0000000..d7c1b21
--- /dev/null
+++ b/kcron/hi16-app-kcron.png
Binary files differ
diff --git a/kcron/hi22-app-kcron.png b/kcron/hi22-app-kcron.png
new file mode 100644
index 0000000..f97e3bc
--- /dev/null
+++ b/kcron/hi22-app-kcron.png
Binary files differ
diff --git a/kcron/hi32-app-kcron.png b/kcron/hi32-app-kcron.png
new file mode 100644
index 0000000..1cfe6b7
--- /dev/null
+++ b/kcron/hi32-app-kcron.png
Binary files differ
diff --git a/kcron/kcron.desktop b/kcron/kcron.desktop
new file mode 100644
index 0000000..af1e675
--- /dev/null
+++ b/kcron/kcron.desktop
@@ -0,0 +1,94 @@
+[Desktop Entry]
+Type=Application
+Exec=kcron %i %m -caption "%c"
+Icon=kcron
+DocPath=kcron/index.html
+Name=KCron
+Name[af]= kcron
+Name[ar]=برنامج KCron
+Name[bn]=কে-ক্রন
+Name[eo]=Taskoplanilo
+Name[hi]=के-क्रॉन
+Name[mn]=КДЕ Крон
+Name[ne]=केडीई क्रोन
+Name[sv]=Kcron
+Name[ta]=கேக்ரொன்
+Name[tg]=Kрон
+Name[th]=ตารางงาน - K
+GenericName=Task Scheduler
+GenericName[af]=Opdrag Skeduleerder
+GenericName[ar]=مجدول المهام
+GenericName[az]=Vəzifə Zamanlayıcısı
+GenericName[bg]=Диспечер на задачи
+GenericName[bn]=কর্ম সূচী নির্ধারনকারী
+GenericName[br]=Steuñvaer dleadoù
+GenericName[bs]=Zakazivanje zadataka
+GenericName[ca]=Planificador de tasques
+GenericName[cs]=Plánovač úloh
+GenericName[cy]=Trefnlennydd Tasgau
+GenericName[da]=Opgaveskemalægger
+GenericName[de]=Aufgabenplaner
+GenericName[el]=Προγραμματισμός εργασιών
+GenericName[eo]=Planas taskojn por lanĉo je certaj tempoj
+GenericName[es]=Planificador de tareas
+GenericName[et]=Crontabi haldamine
+GenericName[eu]=Lan kudeatzailea
+GenericName[fa]=زمان‌بند تکلیف
+GenericName[fi]=Tehtävien ajastus
+GenericName[fo]=Uppgávuplanleggjari
+GenericName[fr]=Planificateur de tâches
+GenericName[ga]=Sceidealóir na dTascanna
+GenericName[gl]=Programador de Tarefas
+GenericName[he]=מתזמן משימות
+GenericName[hi]=टास्क शेड्यूलर
+GenericName[hr]=Planer zadataka
+GenericName[hu]=Feladatütemező
+GenericName[is]=Verkefnastjóri
+GenericName[it]=Pianificatore di operazioni
+GenericName[ja]=タスクスケジューラ
+GenericName[ka]=ამოცანათა დამგეგმავი
+GenericName[kk]=Тапсырма жоспарлағыш
+GenericName[km]=កម្មវិធី​កំណត់​ពេល​ភារកិច្ច
+GenericName[ko]=작업 스케줄러
+GenericName[lt]=Užduočių planuotojas
+GenericName[lv]=Uzdevumu Plānotājs
+GenericName[mk]=Распоредувач на задачи
+GenericName[mn]=Ажлын Төлөвлөгч
+GenericName[ms]=Penjadual Tugas
+GenericName[mt]=Skeda ta' Xogħol
+GenericName[nb]=Oppgavebehandler
+GenericName[nds]=Opgavenpleger
+GenericName[ne]=कार्य अनुसूचक
+GenericName[nl]=Takenplanner
+GenericName[nn]=Oppgåveplanleggjar
+GenericName[pa]=ਕੰਮ ਨਿਯਮਕਾਰ
+GenericName[pl]=Harmonogram zadań
+GenericName[pt]=Escalonador de Tarefas
+GenericName[pt_BR]=Agendador de Tarefas
+GenericName[ro]=Planificator de procese
+GenericName[ru]=Планировщик задач
+GenericName[se]=Bargoplánejeaddji
+GenericName[sk]=Plánovač úloh
+GenericName[sl]=Razporejevalnik opravil
+GenericName[sr]=Организатор задатака
+GenericName[sr@Latn]=Organizator zadataka
+GenericName[sv]=Jobbschemaläggare
+GenericName[ta]=பணி அமைப்பான்
+GenericName[tg]=Нақшаи Масъала
+GenericName[th]=ตารางงาน
+GenericName[tr]=Görev Zamanlayıcı
+GenericName[uk]=Планувальник задач
+GenericName[uz]=Vazifani jadval boʻyicha bajargich
+GenericName[uz@cyrillic]=Вазифани жадвал бўйича бажаргич
+GenericName[ven]=Muvhekanyi wa Mushumo
+GenericName[vi]=Bộ lập lịch công việc
+GenericName[wa]=Tiestires C
+GenericName[xh]=Umcwangcisi Womsebenzi
+GenericName[zh_CN]=任务调度程序
+GenericName[zh_HK]=工作排程器
+GenericName[zh_TW]=工作排程器
+GenericName[zu]=Umgcini sikhathi Somsebenzi
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;System;
diff --git a/kcron/kcron.lsm b/kcron/kcron.lsm
new file mode 100644
index 0000000..87f9688
--- /dev/null
+++ b/kcron/kcron.lsm
@@ -0,0 +1,14 @@
+Begin3
+Title: KCron
+Version: 1.0
+Entered-date: 1 September 1999
+Description: KDE Task Scheduler
+Keywords: KDE, X11, Qt
+Author: Gary Meyer <gary@meyer.net> Robert Berry <rjmber@ntlworld.com>
+Maintained-by: Gary Meyer <gary@meyer.net>
+Primary-site:
+Home-page: http://gary.meyer.net/
+Original-site:
+Platform: Linux and other Unices, needs Qt, KDE, and cron
+Copying-policy: GNU Public License
+End
diff --git a/kcron/kcronui.rc b/kcron/kcronui.rc
new file mode 100644
index 0000000..aab97db
--- /dev/null
+++ b/kcron/kcronui.rc
@@ -0,0 +1,54 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kcron" version="1">
+<MenuBar>
+ <Menu name="edit">
+ <Separator/>
+ <Action name="edit_new"/>
+ <Action name="edit_modify"/>
+ <Action name="edit_delete"/>
+ <Separator/>
+ <Action name="edit_enable"/>
+ <Separator/>
+ <Action name="edit_run"/>
+ </Menu>
+ <Menu name="settings">
+ <Action name="show_toolbar"/>
+ <Action name="show_statusbar"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="mainToolBar">
+ <Action name="edit_new"/>
+ <Action name="edit_modify"/>
+ <Action name="edit_delete"/>
+</ToolBar>
+
+<ActionProperties>
+ <Action name="edit_new" icon="filenew"/>
+ <Action name="edit_modify" icon="edit"/>
+ <Action name="edit_delete" icon="editdelete"/>
+ <Action name="edit_run" icon="run"/>
+</ActionProperties>
+
+<State name="no_task_selected">
+ <Disable>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_modify"/>
+ <Action name="edit_delete"/>
+ </Disable>
+</State>
+
+<State name="paste_disabled">
+ <Disable>
+ <Action name="edit_paste"/>
+ </Disable>
+</State>
+
+<State name="runnow_enabled">
+ <Enable>
+ <Action name="edit_run"/>
+ </Enable>
+</State>
+
+</kpartgui>
diff --git a/kcron/ktapp.cpp b/kcron/ktapp.cpp
new file mode 100644
index 0000000..76f0e08
--- /dev/null
+++ b/kcron/ktapp.cpp
@@ -0,0 +1,463 @@
+/***************************************************************************
+ * KT application implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktapp.h"
+#include <kmenubar.h>
+#include <kstdaccel.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <klocale.h> // i18n()
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+#include <kstatusbar.h>
+
+#include "cthost.h"
+#include "ctcron.h"
+#include "cttask.h"
+
+#include "kticon.h"
+#include "ktview.h"
+
+
+const int KTApp::statusMessage (1001);
+
+
+KTApp::KTApp() : KMainWindow(0)
+{
+ config=kapp->config();
+
+ setIcon(KTIcon::application(true));
+
+ setCaption(i18n("Task Scheduler"));
+
+
+ // Initialize document.
+ cthost = new CTHost();
+
+ // Initialize view.
+ view = new KTView(this);
+ setCentralWidget(view);
+
+ // Call inits to invoke all other construction parts.
+ setupActions();
+ initStatusBar();
+ createGUI();
+ view->disableIcons();
+
+ //Connections
+ KPopupMenu *editMenu = static_cast<KPopupMenu*>(guiFactory()->container("edit", this));
+ KPopupMenu *settingsMenu = static_cast<KPopupMenu*>(guiFactory()->container("settings", this));
+
+ connect(editMenu,SIGNAL(highlighted(int)),this,SLOT(statusEditCallback(int)));
+ connect(settingsMenu,SIGNAL(highlighted(int)),this,SLOT(statusSettingsCallback(int)));
+ // Read options.
+ readOptions();
+}
+
+bool KTApp::init()
+{
+ if (cthost->isError())
+ {
+ KMessageBox::error(this, i18n("The following error occurred while initializing KCron:"
+ "\n\n%1\n\nKCron will now exit.\n").arg(cthost->errorMessage()));
+ return false;
+ }
+
+ // Display greeting screen.
+ // if there currently are no scheduled tasks...
+ if (!cthost->root())
+ {
+ int taskCount(0);
+
+ for (CTCronIterator i = (CTCronIterator)cthost->cron.begin();
+ i != cthost->cron.end(); i++)
+ {
+ for (CTTaskIterator j = (CTTaskIterator)(*i)->task.begin();
+ j != (*i)->task.end(); j++)
+ {
+ taskCount++;
+ }
+ }
+
+ if (taskCount == 0)
+ {
+ show();
+ KMessageBox::information(this, i18n("You can use this application to schedule programs to run in the background.\nTo schedule a new task now, click on the Tasks folder and select Edit/New from the menu."), i18n("Welcome to the Task Scheduler"), "welcome");
+ }
+ }
+ return true;
+}
+
+KTApp::~KTApp()
+{
+ delete view;
+ delete cthost;
+}
+
+const CTHost& KTApp::getCTHost() const
+{
+ return *cthost;
+}
+
+
+QString KTApp::caption()
+{
+ QString cap(kapp->caption());
+ return cap;
+}
+
+void KTApp::setupActions()
+{
+ //File Menu
+ KStdAction::save(this, SLOT(slotFileSave()), actionCollection());
+ KStdAction::print(this, SLOT(slotFilePrint()), actionCollection());
+ KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection());
+
+ //Edit menu
+ KStdAction::cut(this, SLOT(slotEditCut()), actionCollection());
+ KStdAction::copy(this, SLOT(slotEditCopy()), actionCollection());
+ KStdAction::paste(this, SLOT(slotEditPaste()), actionCollection());
+ (void)new KAction(i18n("&New..."), KStdAccel::openNew(), this,SLOT(slotEditNew()),actionCollection(),"edit_new");
+ //I don't like this KStdAccel::open() for modifying, but I'm just porting this to xmlui
+ (void)new KAction(i18n("M&odify..."), KStdAccel::open(), this,SLOT(slotEditModify()),actionCollection(),"edit_modify");
+ (void)new KAction(i18n("&Delete"), 0, this,SLOT(slotEditDelete()),actionCollection(),"edit_delete");
+ (void)new KAction(i18n("&Enabled"), 0, this,SLOT(slotEditEnable()),actionCollection(),"edit_enable");
+ (void)new KAction(i18n("&Run Now"), 0, this,SLOT(slotEditRunNow()),actionCollection(),"edit_run");
+
+ //Settings menu
+ (void)new KAction(i18n("Show &Toolbar"), 0, this,SLOT(slotViewToolBar()),actionCollection(),"show_toolbar");
+ (void)new KAction(i18n("Show &Statusbar"), 0, this,SLOT(slotViewStatusBar()),actionCollection(),"show_statusbar");
+
+}
+
+void KTApp::initStatusBar()
+{
+ statusBar()->insertItem(i18n("Ready."), statusMessage, 1);
+ statusBar()->setItemAlignment(statusMessage, Qt::AlignLeft | Qt::AlignVCenter);
+}
+
+void KTApp::saveOptions()
+{
+ config->setGroup(QString("General Options"));
+ config->writeEntry(QString("Geometry"), size());
+ config->writeEntry(QString("Show Toolbar"), toolBar()->isVisible());
+ config->writeEntry(QString("Show Statusbar"), statusBar()->isVisible());
+ config->writeEntry(QString("ToolBarPos"), (int)toolBar()->barPos());
+}
+
+
+void KTApp::readOptions()
+{
+ config->setGroup(QString("General Options"));
+ KPopupMenu *settingsMenu = static_cast<KPopupMenu*>(guiFactory()->container("settings", this));
+
+ // bar status settings
+ bool bViewToolbar = config->readBoolEntry(QString("Show Toolbar"), true);
+ settingsMenu->setItemChecked(settingsMenu->idAt(0),bViewToolbar);
+ if (!bViewToolbar)
+ toolBar()->hide();
+
+ bool bViewStatusbar = config->readBoolEntry(QString("Show Statusbar"), true);
+ settingsMenu->setItemChecked(settingsMenu->idAt(1),bViewStatusbar);
+ if (!bViewStatusbar)
+ statusBar()->hide();
+
+ // bar position settings
+ KToolBar::BarPosition tool_bar_pos;
+ tool_bar_pos=(KToolBar::BarPosition)
+ config->readNumEntry(QString("ToolBarPos"),
+ KToolBar::Top);
+
+ toolBar()->setBarPos(tool_bar_pos);
+
+ QSize size=config->readSizeEntry(QString("Geometry"));
+
+ // Minimum size is 350 by 250
+
+ if (size.isEmpty())
+ {
+ size.setWidth(350);
+ size.setHeight(250);
+ }
+
+ if (size.width() < 350)
+ {
+ size.setWidth(350);
+ }
+ if (size.height() < 250)
+ {
+ size.setHeight(250);
+ }
+
+ resize(size);
+
+}
+
+bool KTApp::queryClose()
+{
+ if(cthost->dirty())
+ {
+ KTApp* win = (KTApp*)parent();
+
+ int retVal = KMessageBox::warningYesNoCancel(win,
+ i18n("Scheduled tasks have been modified.\nDo you want to save changes?"),
+ QString::null,
+ KStdGuiItem::save(), KStdGuiItem::discard()
+ );
+
+ switch (retVal)
+ {
+ case KMessageBox::Yes:
+ cthost->apply();
+ if (cthost->isError())
+ {
+ KMessageBox::error(win, cthost->errorMessage());
+ return false;
+ }
+ return true;
+ break;
+ case KMessageBox::No:
+ return true;
+ break;
+ case KMessageBox::Cancel:
+ return false;
+ break;
+ default:
+ return false;
+ break;
+ }
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool KTApp::queryExit()
+{
+ saveOptions();
+ return true;
+}
+
+void KTApp::slotFileSave()
+{
+ slotStatusMsg(i18n("Saving..."));
+ cthost->apply();
+ slotStatusMsg(i18n("Ready."));
+ if (cthost->isError())
+ {
+ KMessageBox::error(this, cthost->errorMessage());
+ }
+}
+
+void KTApp::slotFilePrint()
+{
+ slotStatusMsg(i18n("Printing..."));
+ view->print();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotFileQuit()
+{
+ saveOptions();
+ close();
+}
+
+void KTApp::slotEdit(const QPoint& qp)
+{
+ KPopupMenu *editMenu = static_cast<KPopupMenu*>(guiFactory()->container("edit", this));
+ editMenu->exec(qp, 0);
+}
+
+void KTApp::slotEditCut()
+{
+ slotStatusMsg(i18n("Cutting to clipboard..."));
+ view->copy();
+ view->remove();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotEditCopy()
+{
+ slotStatusMsg(i18n("Copying to clipboard..."));
+ view->copy();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotEditPaste()
+{
+ slotStatusMsg(i18n("Pasting from clipboard..."));
+ view->paste();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotEditNew()
+{
+ slotStatusMsg(i18n("Adding new entry..."));
+ view->create();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotEditModify()
+{
+ slotStatusMsg(i18n("Modifying entry..."));
+ view->edit();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotEditDelete()
+{
+ slotStatusMsg(i18n("Deleting entry..."));
+ view->remove();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotEditEnable()
+{
+ KPopupMenu *editMenu = static_cast<KPopupMenu*>(guiFactory()->container("edit", this));
+ if (editMenu->isItemChecked(editMenu->idAt(8)))
+ {
+ slotStatusMsg(i18n("Disabling entry..."));
+ view->enable(false);
+ editMenu->setItemChecked(editMenu->idAt(8), false);
+ }
+ else
+ {
+ slotStatusMsg(i18n("Enabling entry..."));
+ view->enable(true);
+ editMenu->setItemChecked(editMenu->idAt(8), true);
+ }
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotEditRunNow()
+{
+ slotStatusMsg(i18n("Running command..."));
+ view->run();
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotViewToolBar()
+{
+ if(toolBar()->isVisible())
+ toolBar()->hide();
+ else
+ toolBar()->show();
+
+ KPopupMenu *settingsMenu = static_cast<KPopupMenu*>(guiFactory()->container("settings", this));
+ settingsMenu->setItemChecked(settingsMenu->idAt(0),toolBar()->isVisible());
+
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotViewStatusBar()
+{
+ if (statusBar()->isVisible())
+ statusBar()->hide();
+ else
+ statusBar()->show();
+
+ KPopupMenu *settingsMenu = static_cast<KPopupMenu*>(guiFactory()->container("settings", this));
+ settingsMenu->setItemChecked(settingsMenu->idAt(1),statusBar()->isVisible());
+
+ slotStatusMsg(i18n("Ready."));
+}
+
+void KTApp::slotStatusMsg(const QString & text)
+{
+ statusBar()->clear();
+ statusBar()->changeItem(text, statusMessage);
+ setCaption(i18n("Task Scheduler"), cthost->dirty());
+}
+
+void KTApp::slotStatusHelpMsg(const QString & text)
+{
+ statusBar()->message(text, 2000);
+}
+
+void KTApp::statusEditCallback(int id_)
+{
+ KPopupMenu *editMenu = static_cast<KPopupMenu*>(guiFactory()->container("edit", this));
+ int index = editMenu->indexOf(id_);
+ switch (index) {
+ case menuEditNew:
+ slotStatusHelpMsg(i18n("Create a new task or variable."));
+ break;
+ case menuEditModify:
+ slotStatusHelpMsg(i18n("Edit the selected task or variable."));
+ break;
+ case menuEditDelete:
+ slotStatusHelpMsg(i18n("Delete the selected task or variable."));
+ break;
+ case menuEditEnabled:
+ slotStatusHelpMsg(i18n("Enable/disable the selected task or variable."));
+ break;
+ case menuEditRunNow:
+ slotStatusHelpMsg(i18n("Run the selected task now."));
+ break;
+
+ default:
+ break;
+ }
+}
+
+void KTApp::statusSettingsCallback(int id_)
+{
+ KPopupMenu *settingsMenu = static_cast<KPopupMenu*>(guiFactory()->container("settings", this));
+ int index = settingsMenu->indexOf(id_);
+ switch (index) {
+ case menuSettingsShowToolBar:
+ slotStatusHelpMsg(i18n("Enable/disable the tool bar."));
+ break;
+ case menuSettingsShowStatusBar:
+ slotStatusHelpMsg(i18n("Enable/disable the status bar."));
+ break;
+
+ default:
+ break;
+ }
+}
+
+void KTApp::slotEnableModificationButtons(bool state)
+{
+ if (state)
+ stateChanged("no_task_selected", StateReverse);
+ else
+ stateChanged("no_task_selected");
+
+}
+
+void KTApp::slotEnablePaste(bool state)
+{
+ if (state)
+ stateChanged("paste_disabled", StateReverse);
+ else
+ stateChanged("paste_disabled");
+}
+
+void KTApp::slotEnableRunNow(bool state)
+{
+ if (state)
+ stateChanged("runnow_enabled");
+ else
+ stateChanged("runnow_enabled", StateReverse);
+}
+
+void KTApp::slotEnableEnabled(bool state)
+{
+ KPopupMenu *editMenu = static_cast<KPopupMenu*>(guiFactory()->container("edit", this));
+ editMenu->setItemChecked(editMenu->idAt(8),state);
+}
+
+#include "ktapp.moc"
diff --git a/kcron/ktapp.h b/kcron/ktapp.h
new file mode 100644
index 0000000..c42ad06
--- /dev/null
+++ b/kcron/ktapp.h
@@ -0,0 +1,267 @@
+/***************************************************************************
+ * KT application header. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTAPP_H
+#define KTAPP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kmainwindow.h>
+
+class KAction;
+class QString;
+class KTView;
+class CTHost;
+
+/**
+ * Application that sets up the main window, reads the config file,
+ * sets up the menu bar, toolbar, and status bar. Obtains the document
+ * (here the crontab entries) and give it to the view for display.
+ *
+ * Provides main window handling, session management and keyboard
+ * acceleration.
+ */
+class KTApp : public KMainWindow
+{
+ Q_OBJECT
+
+ friend class KTView;
+
+public:
+
+ // Menu constants
+ enum editEntries
+ {
+ menuEditNew=4,
+ menuEditModify,
+ menuEditDelete,
+ menuEditEnabled=8,
+ menuEditRunNow=10
+ };
+
+ enum settingsEntries
+ {
+ menuSettingsShowToolBar,
+ menuSettingsShowStatusBar
+ };
+
+ static const int statusMessage;
+
+/**
+ * Initialize the application.
+ */
+ KTApp();
+
+/**
+ * Quit the application..
+ */
+ ~KTApp();
+
+/**
+ * Additional init
+ */
+ bool init();
+
+/**
+ * Returns a reference to the document.
+ */
+ const CTHost& getCTHost() const;
+
+protected:
+
+/** Called on window close event. Asks the document if it is dirty
+ * and if so, prompts the user for saving before exiting..
+ */
+ virtual bool queryClose();
+
+/** Called when the last window of the application is going to be
+ * closed. Saves options.
+ */
+ virtual bool queryExit();
+
+public slots:
+
+/**
+ * Switch argument for status ar help entries on slot selection. Add your
+ * ID's help here for toolbars and menubar entries. This
+ * function is only for the edit menu
+ */
+ void statusEditCallback(int id_);
+
+/**
+ * Switch argument for status ar help entries on slot selection. Add your
+ * ID's help here for toolbars and menubar entries. This
+ * function is only for the settings menu
+ */
+ void statusSettingsCallback(int id_);
+
+/**
+ * Save document.
+ */
+ void slotFileSave();
+
+/**
+ * Print document.
+ */
+ void slotFilePrint();
+
+/**
+ * Close all open windows then quits the application. If queryClose()
+ * returns false because the user canceled the saveModified() dialog, the
+ * closing breaks.
+ */
+ void slotFileQuit();
+
+/**
+ * Pop up an edit menu.
+ */
+ void slotEdit(const QPoint& qp);
+
+/**
+ * Put the marked objects on the clipboard and remove it from the
+ * document.
+ */
+ void slotEditCut();
+
+/**
+ * Put the marked objects on the clipboard.
+ */
+ void slotEditCopy();
+
+/**
+ * Paste the object on clipboard into the document
+ */
+ void slotEditPaste();
+
+/**
+ * New.
+ */
+ void slotEditNew();
+
+/**
+ * Modify.
+ */
+ void slotEditModify();
+
+/**
+ * Delete.
+ */
+ void slotEditDelete();
+
+/**
+ * Toggle enabled.
+ */
+ void slotEditEnable();
+
+/**
+ * Run program now.
+ */
+ void slotEditRunNow();
+
+/**
+ * Toggle the toolbar being visible.
+ */
+ void slotViewToolBar();
+
+/**
+ * Toggles the status bar being visible.
+ */
+ void slotViewStatusBar();
+
+/**
+ * Changes the status bar contents for the standard label permanently;
+ * used to indicate current actions.
+ */
+ void slotStatusMsg(const QString & text);
+
+/**
+ * Changes the status message of the whole status bar for two seconds,
+ * then restores the last status. This is used to display status bar
+ * messages that give information about actions for toolbar icons and
+ * menu entries.
+ */
+ void slotStatusHelpMsg(const QString & text);
+
+/** Enables/disables modification buttons
+ */
+ void slotEnableModificationButtons(bool);
+
+/** Enables/disables paste button
+ */
+ void slotEnablePaste(bool);
+
+/** Enables/disables "Run now"
+ */
+ void slotEnableRunNow(bool);
+
+/** Enables/disables "Activated"
+ */
+ void slotEnableEnabled(bool);
+
+private:
+
+/**
+ * Disabled copy constructor.
+ */
+ KTApp(const KTApp& source);
+
+/**
+ * Disabled assignment operator.
+ */
+ void operator = (const KTApp& source);
+
+/**
+ * Get application caption.
+ */
+ QString caption();
+
+/**
+ * Initialize actions.
+ */
+ void setupActions();
+
+/**
+ * Initialize status bar.
+ */
+ void initStatusBar();
+
+/**
+ * Read general options again and initialize all variables like the
+ * geometry.
+ */
+ void readOptions();
+
+/**
+ * Save general options like all bar positions and status as well as the
+ * geometry to the configuration file.
+ */
+ void saveOptions();
+
+/**
+ * Configuration object of the application.
+ */
+ KConfig* config;
+
+/**
+ * Main GUI view/working area.
+ */
+ KTView* view;
+
+/**
+ * Document object, here crotab enries.
+ */
+ CTHost* cthost;
+
+};
+
+#endif // KTAPP_H
diff --git a/kcron/kticon.cpp b/kcron/kticon.cpp
new file mode 100644
index 0000000..eff9f3e
--- /dev/null
+++ b/kcron/kticon.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * KT icons implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "kticon.h"
+
+#include <qimage.h>
+
+#include <kglobal.h>
+#include <kiconloader.h>
+
+QPixmap KTIcon::getMiniIcon(const QString& name)
+{
+ return SmallIcon(name);
+}
+
+QPixmap KTIcon::getIcon(const QString& name)
+{
+ return BarIcon(name);
+}
+
+QPixmap KTIcon::application(bool mini)
+{
+ if (mini)
+ return getMiniIcon("kcron");
+ else
+ return getIcon("kcron");
+}
+
+QPixmap KTIcon::system(bool mini)
+{
+ if (mini)
+ return getMiniIcon("openterm");
+ else
+ return getIcon("openterm");
+}
+
+QPixmap KTIcon::user(bool mini)
+{
+ if (mini)
+ return getMiniIcon("kuser");
+ else
+ return getIcon("kuser");
+}
+
+QPixmap KTIcon::variables(bool mini)
+{
+ if (mini)
+ return getMiniIcon("folder");
+ else
+ return getIcon("folder");
+}
+
+QPixmap KTIcon::variable(bool mini)
+{
+ if (mini)
+ return getMiniIcon("mime_empty");
+ else
+ return getIcon("mime_empty");
+}
+
+QPixmap KTIcon::mail(bool mini)
+{
+ if (mini)
+ return getMiniIcon("mail_generic");
+ else
+ return getIcon("mail_generic");
+}
+
+QPixmap KTIcon::shell(bool mini)
+{
+ if (mini)
+ return getMiniIcon("openterm");
+ else
+ return getIcon("openterm");
+}
+
+QPixmap KTIcon::home(bool mini)
+{
+ if (mini)
+ return getMiniIcon("gohome");
+ else
+ return getIcon("gohome");
+}
+
+QPixmap KTIcon::path(bool mini)
+{
+ if (mini)
+ return getMiniIcon("folder");
+ else
+ return getIcon("folder");
+}
+
+QPixmap KTIcon::tasks(bool mini)
+{
+ if (mini)
+ return getMiniIcon("folder");
+ else
+ return getIcon("folder");
+}
+
+QPixmap KTIcon::task(bool mini)
+{
+ if (mini)
+ return getMiniIcon("gear");
+ else
+ return getIcon("gear");
+}
diff --git a/kcron/kticon.h b/kcron/kticon.h
new file mode 100644
index 0000000..013f726
--- /dev/null
+++ b/kcron/kticon.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * KT icons. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTICON_H
+#define KTICON_H
+
+#include <qpixmap.h>
+#include <qstring.h>
+
+/**
+ * Wraps all icons used by the application.
+ */
+
+class KTIcon
+{
+
+public:
+
+ static QPixmap getMiniIcon(const QString& name);
+ static QPixmap getIcon(const QString& name);
+ static QPixmap application(bool mini);
+ static QPixmap system(bool mini);
+ static QPixmap user(bool mini);
+ static QPixmap variables(bool mini);
+ static QPixmap variable(bool mini);
+ static QPixmap mail(bool mini);
+ static QPixmap shell(bool mini);
+ static QPixmap home(bool mini);
+ static QPixmap path(bool mini);
+ static QPixmap tasks(bool mini);
+ static QPixmap task(bool mini);
+
+};
+
+#endif // KTICON_H
diff --git a/kcron/ktlistcron.cpp b/kcron/ktlistcron.cpp
new file mode 100644
index 0000000..e2535bb
--- /dev/null
+++ b/kcron/ktlistcron.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * KT list view item cron implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktlistcron.h"
+
+#include <qstring.h>
+#include <klocale.h>
+
+#include "ctcron.h"
+
+#include "kticon.h"
+#include "ktprint.h"
+
+KTListCron::KTListCron(KTListItem* parent, const char* name,
+ CTCron* _ctcron) :
+ KTListItem(parent, name, _ctcron)
+{
+ refresh();
+}
+
+KTListCron::KTListCron(QListView* parent, const char* name,
+ CTCron* _ctcron) :
+ KTListItem(parent, name, _ctcron)
+{
+ refresh();
+}
+
+KTListCron::KTListCron(QListView* parent, CTCron* _ctcron) :
+ KTListItem(parent, (const char*)0, _ctcron)
+{
+ refresh();
+}
+
+void KTListCron::refresh()
+{
+ setPixmap(0, getCTCron()->login.c_str() == (i18n("(System Crontab)")) ?
+ KTIcon::system(true) : KTIcon::user(true));
+
+ QString userName = QString::fromLocal8Bit(getCTCron()->login.c_str());
+
+ if (getCTCron()->login != getCTCron()->name)
+ {
+ userName += QString(" (");
+ userName += QString::fromLocal8Bit(getCTCron()->name.c_str());
+ userName += QString(")");
+ }
+ setText(0, userName);
+}
+
+void KTListCron::print (KTPrint& printer) const
+{
+ QString userInfo;
+ userInfo = QString::fromLocal8Bit(getCTCron()->name.c_str());
+
+ KTListItem* ktli = (KTListItem*)this->firstChild();
+ Q_CHECK_PTR(ktli);
+ while (ktli) {
+ ktli->print(printer);
+ ktli = (KTListItem*)ktli->nextSibling();
+ }
+}
diff --git a/kcron/ktlistcron.h b/kcron/ktlistcron.h
new file mode 100644
index 0000000..9fe5fe2
--- /dev/null
+++ b/kcron/ktlistcron.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * KT list view item cron header. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTLISTCRON_H
+#define KTLISTCRON_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ktlistitem.h"
+
+/**
+ * QListViewItem view of a CTCron.
+ */
+class KTListCron : public KTListItem
+{
+public:
+
+/**
+ * Construct tasks or variables folder from branch.
+ */
+ KTListCron(KTListItem* parent, const char* name, CTCron* _ctcron);
+
+/**
+ * Construct tasks or variables folder from root.
+ */
+ KTListCron(QListView* parent, const char* name, CTCron* _ctcron);
+
+/**
+ * Construct user folder from root.
+ */
+ KTListCron(QListView* parent, CTCron* _ctcron);
+
+/**
+ * Refresh.
+ */
+ virtual void refresh();
+
+/**
+ *Print user's crontab
+ */
+ virtual void print(KTPrint &printer) const;
+
+};
+
+#endif // KTLISTCRON_H
diff --git a/kcron/ktlistitem.cpp b/kcron/ktlistitem.cpp
new file mode 100644
index 0000000..02cd163
--- /dev/null
+++ b/kcron/ktlistitem.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * KT list view item abstract base class implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktlistitem.h"
+#include "ktprint.h"
+
+#include "ctcron.h"
+
+KTListItem::KTListItem(KTListItem* parent, const char* name, CTCron* _ctcron) :
+ QListViewItem(parent, name),
+ ctcron(_ctcron)
+{
+}
+
+KTListItem::KTListItem(QListView* parent, const char* name, CTCron* _ctcron) :
+ QListViewItem(parent, name),
+ ctcron(_ctcron)
+{
+}
+
+KTListItem::~KTListItem()
+{
+}
+
+void KTListItem::create()
+{
+ return;
+}
+
+void KTListItem::edit()
+{
+ return;
+}
+
+CTCron* KTListItem::getCTCron() const
+{
+ return ctcron;
+}
diff --git a/kcron/ktlistitem.h b/kcron/ktlistitem.h
new file mode 100644
index 0000000..6d10974
--- /dev/null
+++ b/kcron/ktlistitem.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * KT list view item abstract base class. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTLISTITEM_H
+#define KTLISTITEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qlistview.h>
+
+class KTPrint;
+class CTCron;
+
+/**
+ * An enhanced QListViewItem that ensures all list view items have the
+ * same interface.
+ */
+class KTListItem : public QListViewItem
+{
+public:
+
+/**
+ * Construct a root list view item from a CTCron.
+ */
+ KTListItem(KTListItem* parent, const char* name, CTCron* _ctcron);
+
+/**
+ * Construct a non-root list view item from a CTCron.
+ */
+ KTListItem(QListView* parent, const char* name, CTCron* _ctcron);
+
+/**
+ * Destructor.
+ */
+ virtual ~KTListItem();
+
+/**
+ * Create.
+ */
+ virtual void create();
+
+/**
+ * Edit.
+ */
+ virtual void edit();
+
+/**
+ * Refresh.
+ */
+ virtual void refresh() = 0;
+
+/**
+ * Print.
+ */
+ virtual void print(KTPrint &printer) const =0;
+
+/**
+ * Get the user's crontab.
+ */
+ CTCron* getCTCron() const;
+
+private:
+
+/**
+ * User's crontab.
+ */
+ CTCron* ctcron;
+
+};
+
+#endif // KTLISTITEM_H
diff --git a/kcron/ktlisttask.cpp b/kcron/ktlisttask.cpp
new file mode 100644
index 0000000..b496b77
--- /dev/null
+++ b/kcron/ktlisttask.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * KT list view item task implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 <klocale.h> // i18n()
+
+#include "cttask.h"
+
+#include "ktlisttask.h"
+#include "kticon.h"
+#include "kttask.h"
+#include "ktprint.h"
+
+KTListTask::KTListTask(KTListItem* parent,
+ CTCron* _ctcron, CTTask* _cttask) :
+ KTListItem(parent, 0, _ctcron),
+ cttask(_cttask)
+
+{
+ refresh();
+ parent->setOpen(true);
+}
+
+void KTListTask::refresh()
+{
+ setText(0, QString::fromLocal8Bit(cttask->comment.c_str()));
+
+ if (cttask->enabled)
+ {
+ setText(1, QString::fromLocal8Bit(cttask->command.c_str()));
+ setText(2, QString::fromLocal8Bit(cttask->describe().c_str()));
+ }
+ else
+ {
+ setText(1, "");
+ setText(2, i18n("Disabled"));
+ }
+
+ setPixmap(0, KTIcon::task(true));
+}
+
+void KTListTask::print (KTPrint &printer) const
+{
+ printer.print(QString::fromLocal8Bit(cttask->comment.c_str()), 1, KTPrint::alignTextLeft);
+ if (cttask->enabled) {
+ printer.print(QString::fromLocal8Bit(cttask->command.c_str()),2, KTPrint::alignTextCenter);
+ printer.print(QString::fromLocal8Bit(cttask->describe().c_str()),3, KTPrint::alignTextRight);
+ }
+ else
+ printer.print(i18n("Disabled."), 3, KTPrint::alignTextRight);
+}
+
+void KTListTask::edit()
+{
+ KTTask(cttask,i18n("Modify Task")).exec();
+ refresh();
+ parent()->sortChildItems(1, true);
+}
+
+CTTask* KTListTask::getCTTask() const
+{
+ return cttask;
+}
diff --git a/kcron/ktlisttask.h b/kcron/ktlisttask.h
new file mode 100644
index 0000000..bd8054e
--- /dev/null
+++ b/kcron/ktlisttask.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * KT list view item task header. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTLISTTASK_H
+#define KTLISTTASK_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ktlistitem.h"
+
+class CTTask;
+
+/**
+ * QListViewItem with a CTTask.
+ */
+class KTListTask : public KTListItem
+{
+public:
+
+/**
+ * Initialize the list view item and task.
+ */
+ KTListTask(KTListItem* parent, CTCron* _ctcron, CTTask* _cttask);
+
+/**
+ * Refresh from underlying task.
+ */
+ virtual void refresh();
+
+/**
+ * Print task.
+ */
+ virtual void print(KTPrint &printer) const;
+
+/**
+ * Edit task.
+ */
+ virtual void edit();
+
+/**
+ * Get the task.
+ */
+ CTTask* getCTTask() const;
+
+private:
+
+/**
+ * Task.
+ */
+ CTTask* cttask;
+};
+
+#endif // KTLISTTASK_H
diff --git a/kcron/ktlisttasks.cpp b/kcron/ktlisttasks.cpp
new file mode 100644
index 0000000..e1fc19b
--- /dev/null
+++ b/kcron/ktlisttasks.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * KT list view item tasks implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktlisttasks.h"
+
+#include <qstring.h>
+
+#include <klocale.h> // i18n()
+#include <kglobalsettings.h>
+
+#include "ctcron.h"
+#include "cttask.h"
+
+#include "kticon.h"
+#include "ktlisttask.h"
+#include "kttask.h"
+#include "ktprint.h"
+
+KTListTasks::KTListTasks(KTListItem* parent, CTCron* _ctcron) :
+ KTListItem(parent, 0, _ctcron)
+{
+ refresh();
+}
+
+KTListTasks::KTListTasks(QListView* parent, CTCron* _ctcron) :
+ KTListItem(parent, 0, _ctcron)
+{
+ refresh();
+}
+
+QString KTListTasks::getDescription()
+{
+ return i18n("Tasks");
+}
+
+void KTListTasks::create()
+{
+ CTTask* temptask = new CTTask ("", "", getCTCron()->syscron);
+ KTTask* kttask = new KTTask(temptask,i18n("Edit Task"));
+ kttask->exec();
+ delete kttask;
+ if (temptask->dirty())
+ {
+ getCTCron()->task.push_back(temptask);
+ new KTListTask(this, getCTCron(), temptask); // Qt will clean up
+ }
+ else
+ {
+ delete temptask;
+ }
+}
+
+void KTListTasks::refresh()
+{
+ setText(0, getDescription());
+ setPixmap(0, KTIcon::tasks(true));
+}
+
+void KTListTasks::print (KTPrint& printer) const
+{
+ QFont stnd;
+
+ stnd = printer.getFont();
+
+ printer.setFont(QFont( KGlobalSettings::generalFont().family(), 10, QFont::Bold ));
+ printer.print (i18n("Task name:"), 1, KTPrint::alignTextLeft);
+ printer.print (i18n("Program:"), 2, KTPrint::alignTextCenter);
+ printer.print (i18n("Description:"),3,KTPrint::alignTextRight);
+
+ printer.setFont(stnd);
+
+ //firstChild() does not return null if there are no children, therefore
+ //we need to check the validation of the pointer without terminating
+ //the application. This maybe a bug in QT 1.44
+
+ if (this->childCount() ==0) {
+ printer.print(i18n("No tasks..."),1,KTPrint::alignTextLeft, false);
+ printer.levelColumns(20);
+ return;
+ }
+
+ KTListItem* ktli = (KTListItem*)this->firstChild();
+ Q_CHECK_PTR(ktli);
+
+ while (ktli) {
+ ktli->print(printer);
+ ktli = (KTListItem*)ktli->nextSibling();
+ printer.levelColumns();
+ }
+ printer.levelColumns(20);
+}
diff --git a/kcron/ktlisttasks.h b/kcron/ktlisttasks.h
new file mode 100644
index 0000000..075edde
--- /dev/null
+++ b/kcron/ktlisttasks.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * KT list view item cron tasks folder. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTLISTTASKS_H
+#define KTLISTTASKS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ktlistitem.h"
+
+class QString;
+
+/**
+ * QListViewItem of a "tasks" folder.
+ */
+class KTListTasks : public KTListItem
+{
+public:
+
+/**
+ * Construct tasks folder from branch.
+ */
+ KTListTasks(KTListItem* parent, CTCron* _ctcron);
+
+/**
+ * Construct tasks folder from root.
+ */
+ KTListTasks(QListView* parent, CTCron* _ctcron);
+
+ /**
+ * Internationalized description.
+ */
+ static QString getDescription();
+
+/**
+ * Create.
+ */
+ virtual void create();
+
+/**
+ * Refresh.
+ */
+ virtual void refresh();
+
+/**
+ * Print all tasks.
+ */
+ virtual void print(KTPrint &printer)const;
+
+};
+
+#endif // KTLISTTASKS_H
diff --git a/kcron/ktlistvar.cpp b/kcron/ktlistvar.cpp
new file mode 100644
index 0000000..1157683
--- /dev/null
+++ b/kcron/ktlistvar.cpp
@@ -0,0 +1,80 @@
+/***************************************************************************
+ * KT list view item variable implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktlistvar.h"
+#include "ktprint.h"
+
+#include <klocale.h> // i18n()
+
+#include "ctvariable.h"
+
+#include "kticon.h"
+#include "ktvariable.h"
+
+KTListVar::KTListVar(KTListItem* parent, CTCron* _ctcron,
+ CTVariable* _ctvariable) :
+ KTListItem(parent, 0, _ctcron),
+ ctvar(_ctvariable)
+{
+ refresh();
+ parent->setOpen(true);
+}
+
+void KTListVar::refresh()
+{
+ setText (0,QString::fromLocal8Bit(ctvar->variable.c_str()));
+
+ if (ctvar->enabled)
+ {
+ setText (1,QString::fromLocal8Bit(ctvar->value.c_str()));
+ setText (2,QString::fromLocal8Bit(ctvar->comment.c_str()));
+ }
+ else
+ {
+ setText(1, "");
+ setText(2, i18n("Disabled"));
+ }
+
+ if (ctvar->variable == "MAILTO")
+ setPixmap(0, KTIcon::mail(true));
+ else if (ctvar->variable == "SHELL")
+ setPixmap(0, KTIcon::shell(true));
+ else if (ctvar->variable == "HOME")
+ setPixmap(0, KTIcon::home(true));
+ else if (ctvar->variable == "PATH")
+ setPixmap(0, KTIcon::path(true));
+ else
+ setPixmap(0, KTIcon::variable(true));
+}
+
+void KTListVar::print(KTPrint& printer) const
+{
+ printer.print(QString::fromLocal8Bit(ctvar->variable.c_str()), 1, KTPrint::alignTextLeft);
+ if (ctvar->enabled) {
+ printer.print(QString::fromLocal8Bit(ctvar->value.c_str()),2, KTPrint::alignTextCenter);
+ printer.print(QString::fromLocal8Bit(ctvar->comment.c_str()),3,KTPrint::alignTextRight);
+ }
+ else
+ printer.print(i18n("Disabled."),3, KTPrint::alignTextRight);
+
+}
+
+void KTListVar::edit()
+{
+ KTVariable(ctvar,i18n("Modify Variable")).exec();
+ refresh();
+ parent()->sortChildItems(1, true);
+}
+
+CTVariable* KTListVar::getCTVariable() const
+{
+ return ctvar;
+}
diff --git a/kcron/ktlistvar.h b/kcron/ktlistvar.h
new file mode 100644
index 0000000..c5880a4
--- /dev/null
+++ b/kcron/ktlistvar.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * KT list view item variable header. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTLISTVAR_H
+#define KTLISTVAR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ktlistitem.h"
+
+class CTVariable;
+
+/**
+ * QListViewItem with a CTVariable.
+ */
+class KTListVar : public KTListItem
+{
+public:
+
+/**
+ * Initialize the list view item and environment variable.
+ */
+ KTListVar(KTListItem* parent, CTCron* _ctcron, CTVariable* _ctvariable);
+
+/**
+ * Refresh from underlying variable.
+ */
+ void refresh();
+
+/**
+ * Print variable.
+ */
+ void print(KTPrint &printer) const;
+
+/**
+ * Edit variable.
+ */
+ virtual void edit();
+
+/**
+ * Get the environment variable.
+ */
+ CTVariable* getCTVariable() const;
+
+private:
+
+/**
+ * Environment variable.
+ */
+ CTVariable* ctvar;
+};
+
+#endif // KTLISTVAR_H
diff --git a/kcron/ktlistvars.cpp b/kcron/ktlistvars.cpp
new file mode 100644
index 0000000..6bdde2d
--- /dev/null
+++ b/kcron/ktlistvars.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * -------------------------------------------------------------------- *
+ * KT list view item cron variables folder implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktlistvars.h"
+
+#include <qstring.h>
+
+#include <klocale.h> // i18n()
+#include <kglobalsettings.h>
+
+#include "ctcron.h"
+#include "ctvariable.h"
+
+#include "kticon.h"
+#include "ktlistvar.h"
+#include "ktvariable.h"
+#include "ktprint.h"
+
+KTListVars::KTListVars(KTListItem* parent, CTCron* _ctcron) :
+ KTListItem(parent, 0, _ctcron)
+{
+ refresh();
+}
+
+KTListVars::KTListVars(QListView* parent, CTCron* _ctcron) :
+ KTListItem(parent, 0, _ctcron)
+{
+ refresh();
+}
+
+void KTListVars::create()
+{
+ CTVariable* tempvar = new CTVariable();
+ KTVariable* ktvar = new KTVariable(tempvar,i18n("Edit Variable"));
+ ktvar->exec();
+ delete ktvar;
+ if (tempvar->dirty())
+ {
+ getCTCron()->variable.push_back(tempvar);
+ new KTListVar(this, getCTCron(), tempvar); // Qt will clean up
+ }
+ else
+ {
+ delete tempvar;
+ }
+}
+
+void KTListVars::refresh()
+{
+ setText(0, getDescription());
+ setPixmap(0, KTIcon::variables(true));
+}
+
+void KTListVars::print(KTPrint& printer) const
+{
+ QFont stnd;
+
+ stnd = printer.getFont() ;
+ printer.setFont(QFont( KGlobalSettings::generalFont().family(), 10, QFont::Bold ));
+
+ printer.print(i18n("Variable:"), 1, KTPrint::alignTextLeft);
+ printer.print(i18n("Value:"), 2, KTPrint::alignTextCenter);
+ printer.print(i18n("Description:"), 3, KTPrint::alignTextRight);
+
+ printer.setFont(stnd);
+
+ //firstChild() does not return null if there are no children, therefore
+ //we need to check the validation of the pointer without terminating
+ //the application. This maybe a bug in QT 1.44
+
+ if (this->childCount() ==0) {
+ printer.print(i18n("No variables..."),1,KTPrint::alignTextLeft, false);
+ printer.levelColumns(20);
+ return;
+ }
+
+ KTListItem* ktli = (KTListItem*)this->firstChild();
+ Q_CHECK_PTR(ktli);
+ while (ktli) {
+ ktli->print(printer);
+ ktli = (KTListItem*)ktli->nextSibling();
+ printer.levelColumns();
+ }
+ printer.levelColumns(20);
+}
+
+QString KTListVars::getDescription()
+{
+ return i18n("Variables");
+}
diff --git a/kcron/ktlistvars.h b/kcron/ktlistvars.h
new file mode 100644
index 0000000..b338082
--- /dev/null
+++ b/kcron/ktlistvars.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * -------------------------------------------------------------------- *
+ * KT list view item cron variables folder. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTLISTVARS_H
+#define KTLISTVARS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ktlistitem.h"
+
+class QString;
+
+/**
+ * QListViewItem of a "variables" folder.
+ */
+class KTListVars : public KTListItem
+{
+public:
+
+/**
+ * Construct variables folder from branch.
+ */
+ KTListVars(KTListItem* parent, CTCron* _ctcron);
+
+/**
+ * Construct variables folder from root.
+ */
+ KTListVars(QListView* parent, CTCron* _ctcron);
+
+/**
+ * Internationalized description.
+ */
+ static QString getDescription();
+
+/**
+ * Refresh.
+ */
+ void refresh();
+
+/**
+ * print all variables.
+ */
+ void print(KTPrint &printer) const;
+
+/**
+ * Edit.
+ */
+ void create();
+
+};
+
+#endif // KTLISTVARS_H
diff --git a/kcron/ktprint.cpp b/kcron/ktprint.cpp
new file mode 100644
index 0000000..423b6a1
--- /dev/null
+++ b/kcron/ktprint.cpp
@@ -0,0 +1,188 @@
+
+/***************************************************************************
+ * -------------------------------------------------------------------- *
+ * KDE\QT printing implementation. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Robert Berry <rjmber@ntlworld.com> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 <qpainter.h>
+#include <qstring.h>
+#include <qpaintdevicemetrics.h>
+
+#include <ktprintopt.h>
+#include <klocale.h>
+#include "ktprint.h"
+
+const int KTPrint::alignTextLeft (1000);
+const int KTPrint::alignTextRight (2000);
+const int KTPrint::alignTextCenter (3000);
+
+const int KTPrint::defaultLeftMargin (20);
+const int KTPrint::defaultRightMargin (20);
+const int KTPrint::defaultTopMargin (30);
+const int KTPrint::defaultBottomMargin (30);
+
+/*
+ I had to add this enum to get the file to compile. Since I ported
+ this class to QT2.1.1 the compiler throws errors about these flags.
+ When I figure why I will fix this ugly solution.
+*/
+
+enum AlignmentFlags { AlignLeft = 0x0001, AlignRight = 0x0002,
+ AlignHCenter = 0x0004, AlignTop = 0x0008,
+ AlignBottom = 0x0010, AlignVCenter = 0x0020,
+ AlignCenter = AlignVCenter | AlignHCenter,
+ SingleLine = 0x0040, DontClip = 0x0080,
+ ExpandTabs = 0x0100, ShowPrefix = 0x0200,
+ WordBreak = 0x0400, DontPrint = 0x1000 };
+
+KTPrint::~KTPrint()
+{
+ delete prnt;
+ if (columns.size()>0)
+ columns.erase(columns.begin(), columns.end());
+
+}
+
+void KTPrint :: createColumns (unsigned num_columns)
+{
+//Construct all of the columns to be equal in size
+//I am going to add a function which works on percentages
+
+ int start;
+ Column *col;
+ int col_width(width / num_columns);
+
+ if (columns.size()>0)
+ columns.erase(columns.begin(), columns.end());
+
+ for (unsigned i = 0, start = leftMargin; i < num_columns; i++) {
+ col = new Column;
+ col->start = start;
+ col->finish = start + (col_width - 5);
+ col->height = topMargin;
+ columns.push_back(col);
+ start+=col_width;
+ }
+
+}
+
+bool KTPrint:: start ()
+{
+ prnt->setDocName("Cron Tab");
+ prnt->addDialogPage(new KTPrintOpt(root));
+
+ if (prnt->setup(0L, i18n("Print Cron Tab"))) { //Setup a printer
+ if (paint!=NULL) delete paint;
+ paint = new QPainter ();
+ paint->begin(prnt);
+ paint->setTabStops(20); // Setup a defualt tab stop size
+
+ //Get the information about the page size
+ QPaintDeviceMetrics metrics (prnt);
+ width = metrics.width () - (leftMargin + rightMargin);
+ height = metrics.height () - (topMargin + bottomMargin);
+ return true;
+ }
+ else
+ return false;
+}
+
+void KTPrint :: setFont (const QFont &font)
+{
+ paint->setFont(font);
+}
+
+QFont KTPrint :: getFont () const
+{
+ return paint->font();
+}
+
+void KTPrint :: print (const QString &str, int col, int alignment, bool wordWrap)
+{
+//Prints the string str into the column col using
+//the remaining arguments as format flags
+
+ int format;
+
+ if (paint==NULL)
+ return;
+
+
+ //Setup the alignment
+ switch (alignment) {
+ case alignTextLeft : format = AlignLeft | AlignTop | DontClip | ExpandTabs; break;
+ case alignTextCenter : format = AlignHCenter | AlignTop | DontClip | ExpandTabs; break;
+ case alignTextRight : format = AlignRight | AlignTop | DontClip | ExpandTabs; break;
+ default :
+ //add error trap
+ break;
+
+ }
+
+ //Check if we are wrapping words
+ if (wordWrap)
+ format = format | WordBreak;
+
+ //Whats left of the page
+ int remainder (height - columns[col-1]->height);
+ QRect rect=paint->boundingRect(columns[col-1]->start,columns[col-1]->height, columns[col-1]->width(), remainder,format, str);
+
+ if (rect.height() <= remainder)
+ {
+ //Draw the text
+ paint->drawText(columns[col-1]->start,columns[col-1]->height, columns[col-1]->width(), remainder, format, str);
+ //Reset the columns height
+ columns[col-1]->height += rect.height();
+ }
+ else
+ {
+ newPage();
+ remainder = height - columns[col-1]->height;
+ rect=paint->boundingRect(columns[col-1]->start,columns[col-1]->height, columns[col-1]->width(), remainder,format, str);
+ paint->drawText(columns[col-1]->start,columns[col-1]->height, columns[col-1]->width(), remainder, format, str);
+ columns[col-1]->height += rect.height();
+ }
+}
+
+void KTPrint :: levelColumns(int space)
+{
+ int ht(0);
+
+ //Find the heighest height
+ for (unsigned i(0); i < columns.size(); i++) {
+ if (ht < columns[i]->height)
+ ht = columns[i]->height;
+ }
+
+ //Set all the columns to that height and then add the space argument
+ for (unsigned i(0); i < columns.size(); i++)
+ columns[i]->height = ht+space;
+}
+
+void KTPrint :: finished ()
+{
+ if (paint!=NULL) {
+ paint->end(); //Send to printer or file
+ delete paint;
+ }
+}
+
+void KTPrint :: newPage ()
+{
+ prnt->newPage();
+ for (unsigned i(0); i < columns.size(); i++)
+ columns[i]->height = topMargin;
+}
+
+int KTPrint :: numCopies () const
+{
+ return prnt->numCopies();
+}
+
diff --git a/kcron/ktprint.h b/kcron/ktprint.h
new file mode 100644
index 0000000..da22ff3
--- /dev/null
+++ b/kcron/ktprint.h
@@ -0,0 +1,216 @@
+
+/***************************************************************************
+ * -------------------------------------------------------------------- *
+ * KDE\QT Printing class *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Robert Berry <rjmber@ntlworld.com> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTPRINT_H
+#define KTPRINT_H
+
+#include <vector>
+#include <kprinter.h>
+
+class QPainter;
+class KPrinter;
+class QString;
+class QFont;
+
+/**
+ *Provides a wrapper for simple printing of text.
+ */
+class KTPrint{
+public:
+
+/**
+ *Static formatting constants
+ */
+ static const int alignTextLeft;
+ static const int alignTextRight;
+ static const int alignTextCenter;
+
+/**
+ *Static Default Margin Constants
+ */
+ static const int defaultLeftMargin;
+ static const int defaultRightMargin;
+ static const int defaultTopMargin;
+ static const int defaultBottomMargin;
+
+/**
+ * Contructor
+ */
+ KTPrint(bool _root) :
+ leftMargin(defaultLeftMargin),
+ rightMargin (defaultRightMargin),
+ topMargin(defaultTopMargin),
+ bottomMargin(defaultBottomMargin),
+ paint(0),
+ root(_root)
+ {
+ prnt = new KPrinter;
+ prnt->setOption("crontab","true");
+ createColumns(1);
+ }
+
+/**
+ * Destructor
+ */
+ ~KTPrint();
+
+/**
+ * Start the printing process, gain page info
+ */
+ bool start ();
+
+/**
+ * Send the information to the printer
+ */
+ void finished ();
+
+/**
+ * Set the font to be used
+ */
+ void setFont (const QFont &font);
+
+/**
+ * Get the current font
+ */
+ QFont getFont ()const;
+
+/**
+ * Print text
+ */
+ void print (const QString &str, int col =1, int alignment=KTPrint::defaultLeftMargin, bool wordWrap = true);
+
+/**
+ * Constructs the columns
+ */
+ void createColumns(unsigned num_columns =1);
+
+/**
+ * Make sure that all columns start printing on the same line
+ */
+ void levelColumns(int space = 5);
+
+/**
+ * Insert a new page
+ */
+ void newPage();
+
+/**
+ *
+ */
+ int numCopies () const;
+
+/**
+ * Whether crontab should be printed
+ */
+ bool crontab() const
+ {
+ return (prnt->option("crontab") == "true");
+ }
+
+/**
+ * Whether all users should be printed (root only)
+ */
+ bool allUsers() const
+ {
+ return (prnt->option("allusers") == "true");
+ }
+private:
+
+ /**
+ *Disable the copy constructor and the assignment operator
+ */
+ KTPrint (const KTPrint&) {}
+ KTPrint& operator=(const KTPrint&) {return *this;}
+
+/**
+ * Left boundary
+ */
+ int leftMargin;
+
+/**
+ * Right boundary
+ */
+ int rightMargin;
+
+/**
+ * Top boundary
+ */
+ int topMargin;
+
+/**
+ * Bottom boundary
+ */
+ int bottomMargin;
+
+/**
+ * Width of the page
+ */
+ int width;
+
+/**
+ * Height of the page
+ */
+ int height;
+
+/**
+ * Pointer to a painter object
+ */
+ QPainter *paint;
+
+/**
+ * Whether we are root or not
+ */
+ bool root;
+
+/**
+ * Pointer a printer object
+ */
+ KPrinter *prnt;
+
+/**
+ *Nest a column class to make text layout nicer
+ */
+
+ class Column {
+ public:
+
+ /**
+ *Starting X co-ord
+ */
+ int start;
+
+ /**
+ *Finishing X co-ord
+ */
+ int finish;
+
+ /**
+ *Current Y co-ord
+ */
+ int height;
+
+
+ /**
+ *Return the width of the column
+ */
+ int width () const {return finish-start;}
+ };
+
+/**
+ * Keep a vector of the columns
+ */
+ std::vector <Column*> columns;
+
+};
+
+#endif
diff --git a/kcron/ktprintopt.cpp b/kcron/ktprintopt.cpp
new file mode 100644
index 0000000..68315c5
--- /dev/null
+++ b/kcron/ktprintopt.cpp
@@ -0,0 +1,68 @@
+
+/***************************************************************************
+ * -------------------------------------------------------------------- *
+ * Print Options Dialog *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Robert Berry <rjmber@ntlwolrd.com> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 <qlayout.h>
+
+#include <kdialog.h>
+#include <kaccel.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include "ktprintopt.h"
+
+KTPrintOpt::KTPrintOpt(bool root) :
+ KPrintDialogPage(0, "ktprintopt")
+{
+ m_title = i18n("Cron Options");
+
+ QVBoxLayout *main_ = new QVBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint());
+
+ chkPrintCrontab = new QCheckBox(i18n("Print cron&tab"), this, "chkPrintCrontab");
+ main_->addWidget(chkPrintCrontab);
+
+ chkPrintAllUsers = new QCheckBox(i18n("Print &all users"), this, "chkPrintAllUsers");
+ main_->addWidget(chkPrintAllUsers);
+
+ if (!root) {
+ chkPrintAllUsers->setChecked(false);
+ chkPrintAllUsers->setEnabled(false);
+ }
+}
+
+KTPrintOpt::~KTPrintOpt()
+{
+}
+
+void
+KTPrintOpt::setOptions(const QMap<QString,QString>& opts)
+{
+ QString value;
+
+ value = opts["crontab"];
+ chkPrintCrontab->setChecked(value == "true");
+
+ if (chkPrintAllUsers->isEnabled())
+ {
+ value = opts["allusers"];
+ chkPrintAllUsers->setChecked(value == "true");
+ }
+}
+
+void KTPrintOpt::getOptions(QMap<QString,QString>& opts, bool)
+{
+ opts["crontab"] = chkPrintCrontab->isChecked() ? "true" : "false";
+ opts["allusers"] = chkPrintAllUsers->isChecked() ? "true" : "false";
+}
+
+
+#include "ktprintopt.moc"
diff --git a/kcron/ktprintopt.h b/kcron/ktprintopt.h
new file mode 100644
index 0000000..0ab1810
--- /dev/null
+++ b/kcron/ktprintopt.h
@@ -0,0 +1,52 @@
+
+/***************************************************************************
+ * -------------------------------------------------------------------- *
+ * Print Options Dialog *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Robert Berry <rjmber@ntlwolrd.com> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTPRINTOPT_H
+#define KTPRINTOPT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdeprint/kprintdialogpage.h>
+
+class QCheckBox;
+class KAccel;
+
+/**
+ *Give the user the option to print the crontab file.
+ *If the user is root ask if they want to print all the users
+ */
+
+class KTPrintOpt : public KPrintDialogPage
+{
+ Q_OBJECT
+public:
+
+/**
+ * Constructs the dialog, if root is true the print all users is not disabled
+ */
+ KTPrintOpt(bool root = false);
+
+ ~KTPrintOpt();
+
+ void setOptions(const QMap<QString,QString>& options);
+ void getOptions(QMap<QString,QString>& options, bool incldef = false);
+
+
+private:
+ QCheckBox* chkPrintCrontab;
+ QCheckBox* chkPrintAllUsers;
+};
+
+#endif
diff --git a/kcron/kttask.cpp b/kcron/kttask.cpp
new file mode 100644
index 0000000..8b78b49
--- /dev/null
+++ b/kcron/kttask.cpp
@@ -0,0 +1,900 @@
+/***************************************************************************
+ * KT task editor window implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "kttask.h"
+
+#include <qlabel.h>
+#include <qstring.h>
+#include <qfileinfo.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qbuttongroup.h>
+#include <qpainter.h>
+#include <qpalette.h>
+
+#include <kapplication.h>
+#include <kaccel.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "cttask.h"
+
+#include "kticon.h"
+
+class KTPushButton : public QPushButton
+{
+public:
+ KTPushButton(QWidget * parent, const char * name = 0 )
+ : QPushButton(parent, name), isSelected(false), isDirty(false)
+ {
+ updatePalette();
+ }
+
+ void updatePalette()
+ {
+ palNormal = ((QWidget *)parent())->palette();
+ palSelected = palNormal;
+ for(int cg = (int) QPalette::Disabled; cg < (int) QPalette::NColorGroups; cg++)
+ {
+ palSelected.setColor((QPalette::ColorGroup)cg, QColorGroup::Button,
+ palSelected.color((QPalette::ColorGroup)cg, QColorGroup::Highlight));
+ palSelected.setColor((QPalette::ColorGroup)cg, QColorGroup::ButtonText,
+ palSelected.color((QPalette::ColorGroup)cg, QColorGroup::HighlightedText));
+ }
+ isDirty = true;
+ }
+
+ bool event( QEvent *e)
+ {
+ if (e->type() == QEvent::ParentPaletteChange)
+ {
+ updatePalette();
+ update();
+ }
+ return QPushButton::event(e);
+ }
+
+ void drawButton ( QPainter *p )
+ {
+ if (isDirty || (isOn() != isSelected)) // Prevent infinite recursion
+ {
+ isDirty = false;
+ isSelected = isOn();
+ if (isSelected)
+ setPalette(palSelected);
+ else
+ setPalette(palNormal);
+ }
+ QPushButton::drawButton(p);
+ }
+ void drawButtonLabel ( QPainter *p )
+ {
+ p->save();
+ if (isOn())
+ {
+ QFont f = p->font();
+ f.setUnderline(true);
+ p->setFont(f);
+ }
+ QPushButton::drawButtonLabel(p);
+ p->restore();
+ }
+ bool isSelected;
+ bool isDirty;
+ QPalette palSelected;
+ QPalette palNormal;
+};
+
+KTTask::KTTask(CTTask* _cttask, const QString & _caption)
+ :KDialog( 0, "kttask", true, WStyle_DialogBorder )
+{
+ cttask = _cttask;
+
+ bool everyDay(true);
+
+ QVBoxLayout *ml = new QVBoxLayout( this, KDialogBase::spacingHint() );
+
+ QHBoxLayout *h1 = new QHBoxLayout( ml, KDialogBase::spacingHint() );
+
+ // user
+ labUser = new QLabel( i18n("&Run as:"), this, "labUser" );
+ h1->addWidget( labUser );
+
+ leUser = new QLineEdit( this, "leUser");
+ labUser->setBuddy(leUser);
+ h1->addWidget( leUser );
+
+ if (cttask->system())
+ {
+ leUser->setText(QString::fromLocal8Bit(cttask->user.c_str()));
+ }
+ else
+ {
+ labUser->hide();
+ leUser->hide();
+ }
+
+ // icon
+ labIcon = new QLabel(this, "labIcon");
+ labIcon->setFixedSize(32, 32);
+ h1->addStretch( 1 );
+ h1->addWidget( labIcon );
+
+ // comment
+ QHBoxLayout *h2 = new QHBoxLayout( ml, KDialogBase::spacingHint() );
+
+ labComment = new QLabel( i18n("&Comment:"), this, "labComment" );
+ h2->addWidget( labComment );
+
+ leComment = new QLineEdit(this, "leComment");
+ labComment->setBuddy(leComment);
+ h2->addWidget( leComment );
+
+ leComment->setText(QString::fromLocal8Bit(cttask->comment.c_str()));
+
+ // command
+ QHBoxLayout *h3 = new QHBoxLayout( ml, KDialogBase::spacingHint() );
+
+ labCommand = new QLabel( i18n("&Program:"), this, "labCommand" );
+ h3->addWidget( labCommand );
+
+ leCommand = new QLineEdit(this, "leCommand");
+ labCommand->setBuddy(leCommand);
+ h3->addWidget( leCommand );
+
+ leCommand->setText(QString::fromLocal8Bit(cttask->command.c_str()));
+
+ labComment->setFixedWidth( QMAX( labComment->width(), labCommand->width()) );
+ labCommand->setFixedWidth( QMAX( labComment->width(), labCommand->width()) );
+
+ slotCommandChanged();
+
+ pbBrowse = new QPushButton(this, "pbBrowse");
+ pbBrowse->setText(i18n("&Browse..."));
+ h3->addWidget( pbBrowse );
+
+ QHBoxLayout *h3a = new QHBoxLayout( ml, KDialogBase::spacingHint() );
+
+ // enabled
+ chkEnabled = new QCheckBox(i18n("&Enabled"), this, "chkEnabled");
+ chkEnabled->setChecked(cttask->enabled);
+ h3a->addWidget( chkEnabled );
+
+ // enabled
+ chkSilent = new QCheckBox(i18n("&Silent"), this, "chkSilent");
+ chkSilent->setChecked(cttask->silent);
+ h3a->addWidget( chkSilent );
+
+ QHBoxLayout *h4 = new QHBoxLayout( ml, KDialogBase::spacingHint() );
+
+ ml->addSpacing( 2 * KDialogBase::spacingHint() );
+
+ // months
+ bgMonth = new QButtonGroup( i18n("Months"), this, "bgMonth");
+ h4->addWidget( bgMonth );
+
+ QVBoxLayout *vmonths = new QVBoxLayout( bgMonth, KDialogBase::spacingHint() );
+ vmonths->addSpacing( 2 * KDialogBase::spacingHint() );
+
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ cbMonth[mo] = new QCheckBox(bgMonth, "cbMonth");
+ cbMonth[mo]->setText(QString::fromLocal8Bit(cttask->month.getName(mo).c_str()));
+ cbMonth[mo]->setChecked(cttask->month.get(mo));
+ vmonths->addWidget( cbMonth[mo], AlignLeft );
+
+ if (!cttask->month.get(mo)) everyDay = false;
+ }
+ pbAllMonths = new QPushButton(bgMonth, "pbAllMonths");
+ pbAllMonths->setText( i18n("Set All") );
+ vmonths->addWidget( pbAllMonths, AlignLeft );
+
+ QVBoxLayout *v1 = new QVBoxLayout( h4, KDialogBase::spacingHint() );
+
+ // days of the month
+ bgDayOfMonth = new QButtonGroup( i18n("Days of Month"), this, "bgDayOfMonth");
+ v1->addWidget( bgDayOfMonth );
+
+ QPushButton* day;
+ QString tmp;
+
+ QVBoxLayout *vdays = new QVBoxLayout( bgDayOfMonth, KDialogBase::spacingHint() );
+ vdays->addSpacing( 2 * KDialogBase::spacingHint() );
+ QHBoxLayout *hdays = 0;
+
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ if( (dm % 7) == 1 )
+ hdays = new QHBoxLayout( vdays, KDialogBase::spacingHint() );
+
+ day = new KTPushButton(bgDayOfMonth);
+ day->setFixedSize(25, 25);
+ day->setText(tmp.setNum(dm));
+ day->setToggleButton(true);
+ day->setOn(cttask->dayOfMonth.get(dm));
+ pbDayOfMonth[dm] = day;
+ if (!cttask->dayOfMonth.get(dm)) everyDay = false;
+
+ hdays->addWidget( day, AlignLeft );
+ }
+ hdays->addStretch( 1 );
+ pbAllDaysOfMonth = new QPushButton(bgDayOfMonth, "pbAllDaysOfMonth");
+ pbAllDaysOfMonth->setText( i18n("Set All") );
+ hdays->addWidget( pbAllDaysOfMonth, AlignLeft );
+
+ // days of the week
+ bgDayOfWeek = new QButtonGroup( i18n("Days of Week"), this, "bgDayOfWeek");
+ v1->addWidget( bgDayOfWeek );
+
+ QVBoxLayout *v3 = new QVBoxLayout( bgDayOfWeek, KDialogBase::spacingHint() );
+ v3->addSpacing( 2 * KDialogBase::spacingHint() );
+
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ cbDayOfWeek[dw] = new QCheckBox(bgDayOfWeek);
+ cbDayOfWeek[dw]->setText(QString::fromLocal8Bit(cttask->dayOfWeek.getName(dw).c_str()));
+ cbDayOfWeek[dw]->setChecked(cttask->dayOfWeek.get(dw));
+ v3->addWidget( cbDayOfWeek[dw] );
+
+ if (!cttask->dayOfWeek.get(dw)) everyDay = false;
+ }
+ pbAllDaysOfWeek = new QPushButton(bgDayOfWeek, "pbAllDaysOfWeek");
+ pbAllDaysOfWeek->setText( i18n("Set All") );
+ v3->addWidget( pbAllDaysOfWeek, AlignLeft );
+
+ QVBoxLayout *v2 = new QVBoxLayout( h4, KDialogBase::spacingHint() );
+
+ // daily
+ bgEveryDay = new QButtonGroup( i18n("Daily"), this, "bgEveryDay");
+ v2->addWidget( bgEveryDay );
+
+ QVBoxLayout *v9 = new QVBoxLayout( bgEveryDay, KDialogBase::spacingHint() );
+ v9->addSpacing( 2 * KDialogBase::spacingHint() );
+
+ cbEveryDay = new QCheckBox( i18n("Run every day"), bgEveryDay, "cbEveryDay");
+ cbEveryDay->setChecked(everyDay);
+ v9->addWidget( cbEveryDay );
+
+ // hours
+ bgHour = new QButtonGroup( i18n("Hours"), this, "bgHour");
+ v2->addWidget( bgHour );
+ QVBoxLayout *v4 = new QVBoxLayout( bgHour, KDialogBase::spacingHint() );
+ v4->addSpacing( 2 * KDialogBase::spacingHint() );
+
+ labAM = new QLabel( i18n("AM"), bgHour, "labAM");
+ labAM->setAlignment(AlignRight | AlignVCenter);
+ v4->addWidget( labAM );
+
+
+ for (int ho = 0; ho <= 23; ho++)
+ {
+ pbHour[ho] = new KTPushButton(bgHour);
+ pbHour[ho]->setText(tmp.setNum(ho));
+ pbHour[ho]->setToggleButton(true);
+ pbHour[ho]->setOn(cttask->hour.get(ho));
+ pbHour[ho]->setFixedSize(25, 25);
+ }
+
+ QHBoxLayout *hhours = new QHBoxLayout( v4, KDialogBase::spacingHint() );
+ for (int ho1 = 0; ho1 <= 11; ho1++)
+ {
+ if( ho1 == 6 )
+ hhours = new QHBoxLayout( v4, KDialogBase::spacingHint() );
+
+ hhours->addWidget( pbHour[ho1] );
+ }
+
+ labPM = new QLabel( i18n("PM"), bgHour, "labPM");
+ labPM->setAlignment(AlignRight | AlignVCenter);
+ v4->addWidget( labPM );
+
+ hhours = new QHBoxLayout( v4, KDialogBase::spacingHint() );
+ for (int ho1 = 12; ho1 <= 23; ho1++)
+ {
+ if( ho1 == 18 )
+ hhours = new QHBoxLayout( v4, KDialogBase::spacingHint() );
+
+ hhours->addWidget( pbHour[ho1] );
+ }
+
+ hhours = new QHBoxLayout( v4, KDialogBase::spacingHint() );
+ pbAllHours = new QPushButton(bgHour, "pbAllHours");
+ pbAllHours->setText( i18n("Set All") );
+ hhours->addWidget( pbAllHours, AlignLeft );
+
+ // minutes
+ bgMinute = new QButtonGroup( i18n("Minutes"), this, "bgMinute");
+ v2->addWidget( bgMinute );
+ QVBoxLayout *vmin = new QVBoxLayout( bgMinute, KDialogBase::spacingHint() );
+ vmin->addSpacing( 2 * KDialogBase::spacingHint() );
+
+ for (int mi = 0; mi <= 55; mi+=5)
+ {
+ pbMinute[mi] = new KTPushButton(bgMinute);
+ pbMinute[mi]->setText(tmp.setNum(mi));
+ pbMinute[mi]->setToggleButton(true);
+ pbMinute[mi]->setOn(cttask->minute.get(mi));
+ pbMinute[mi]->setFixedSize(25, 25);
+ }
+
+ QHBoxLayout *hmin = new QHBoxLayout( vmin, KDialogBase::spacingHint() );
+ for (int mi1 = 0; mi1 <= 55; mi1+=5)
+ {
+ if( mi1 == 30 )
+ hmin = new QHBoxLayout( vmin, KDialogBase::spacingHint() );
+
+ hmin->addWidget( pbMinute[mi1] );
+ }
+
+ hmin = new QHBoxLayout( vmin, KDialogBase::spacingHint() );
+ pbAllMinutes = new QPushButton(bgMinute, "pbAllMinutes");
+ pbAllMinutes->setText( i18n("Set All") );
+ hmin->addWidget( pbAllMinutes, AlignLeft );
+
+ QHBoxLayout *h5 = new QHBoxLayout( ml, KDialogBase::spacingHint() );
+ h5->addStretch( 1 );
+
+ // OK
+ pbOk = new KPushButton(KStdGuiItem::ok(), this, "pbOk");
+ pbOk->setDefault(true);
+ h5->addWidget( pbOk );
+
+ // Cancel
+ pbCancel = new KPushButton(KStdGuiItem::cancel(), this, "pbCancel");
+ h5->addWidget( pbCancel );
+
+ // window
+ setIcon(KTIcon::application(true));
+ setCaption(_caption/*i18n("Edit Task")*/);
+
+ // set focus to first widget
+ if (cttask->system())
+ {
+ leUser->setFocus();
+ }
+ else
+ {
+ leComment->setFocus();
+ }
+
+ // connect them up
+ connect(pbBrowse, SIGNAL(clicked()), SLOT(slotBrowse()));
+ connect(leCommand, SIGNAL(textChanged(const QString&)),
+ SLOT(slotCommandChanged()));
+ connect(cbEveryDay, SIGNAL(clicked()), SLOT(slotDailyChanged()));
+ connect(pbOk, SIGNAL(clicked()), SLOT(slotOK()));
+ connect(pbCancel, SIGNAL(clicked()), SLOT(slotCancel()));
+ connect(pbAllMonths, SIGNAL(clicked()), SLOT(slotAllMonths()));
+ for (int mo = 1; mo <= 12; mo++) {
+ connect(cbMonth[mo], SIGNAL(clicked()), SLOT(slotMonthChanged()));
+ }
+ connect(pbAllDaysOfMonth, SIGNAL(clicked()), SLOT(slotAllDaysOfMonth()));
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ connect(pbDayOfMonth[dm], SIGNAL(clicked()), SLOT(slotDayOfMonthChanged()));
+ }
+ connect(pbAllDaysOfWeek, SIGNAL(clicked()), SLOT(slotAllDaysOfWeek()));
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ connect(cbDayOfWeek[dw], SIGNAL(clicked()), SLOT(slotDayOfWeekChanged()));
+ }
+ connect(pbAllHours, SIGNAL(clicked()), SLOT(slotAllHours()));
+ for (int ho = 0; ho <= 23; ho++)
+ {
+ connect(pbHour[ho], SIGNAL(clicked()), SLOT(slotHourChanged()));
+ }
+ connect(pbAllMinutes, SIGNAL(clicked()), SLOT(slotAllMinutes()));
+ for (int mi = 0; mi <= 55; mi+=5)
+ {
+ connect(pbMinute[mi], SIGNAL(clicked()), SLOT(slotMinuteChanged()));
+ }
+
+ // key acceleration
+ key_accel = new KAccel(this);
+ key_accel->insert(KStdAccel::Open, this, SLOT(slotOK()));
+ key_accel->insert(KStdAccel::Close, this, SLOT(slotCancel()));
+ key_accel->insert(KStdAccel::Quit, this, SLOT(slotCancel()));
+ key_accel->readSettings();
+
+ setFixedSize( minimumSize() );
+ slotDailyChanged();
+ slotMonthChanged();
+ slotDayOfMonthChanged();
+ slotDayOfWeekChanged();
+ slotHourChanged();
+ slotMinuteChanged();
+}
+
+KTTask::~KTTask()
+{
+}
+
+void KTTask::slotCommandChanged()
+{
+ /*
+ QString qs(leCommand->text());
+
+ int beginPos(qs.findRev("/", qs.length()) + 1);
+ if (beginPos < 0) beginPos = 0;
+
+ int endPos(qs.findRev(" ", qs.length()));
+ if (endPos < 0) endPos = qs.length();
+
+ QString iconName(qs.mid(beginPos, endPos-beginPos) + ".xpm");
+
+ QPixmap qp(KTIcon::getIcon(iconName));
+ if (qp.isNull())
+ labIcon->setPixmap(KTIcon::task(false));
+ else
+ labIcon->setPixmap(qp);
+ */
+
+ labIcon->setPixmap(KTIcon::task(false));
+ return;
+}
+
+void KTTask::slotDailyChanged()
+{
+ if (cbEveryDay->isChecked())
+ {
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ cbMonth[mo]->setChecked(true);
+ cbMonth[mo]->setEnabled(false);
+ }
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ pbDayOfMonth[dm]->setOn(true);
+ pbDayOfMonth[dm]->setEnabled(false);
+ }
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ cbDayOfWeek[dw]->setChecked(true);
+ cbDayOfWeek[dw]->setEnabled(false);
+ }
+ pbAllMonths->setEnabled(false);
+ pbAllDaysOfMonth->setEnabled(false);
+ pbAllDaysOfWeek->setEnabled(false);
+ }
+ else
+ {
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ cbMonth[mo]->setEnabled(true);
+ }
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ pbDayOfMonth[dm]->setEnabled(true);
+ }
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ cbDayOfWeek[dw]->setEnabled(true);
+ }
+ pbAllMonths->setEnabled(true);
+ pbAllDaysOfMonth->setEnabled(true);
+ pbAllDaysOfWeek->setEnabled(true);
+ }
+ slotMonthChanged();
+ slotDayOfMonthChanged();
+ slotDayOfWeekChanged();
+}
+
+void KTTask::slotOK()
+{
+ // Make it friendly for just selecting days of the month or
+ // days of the week.
+
+ int monthDaysSelected(0);
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ if (pbDayOfMonth[dm]->isOn()) monthDaysSelected++;
+ }
+
+ int weekDaysSelected(0);
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ if (cbDayOfWeek[dw]->isChecked()) weekDaysSelected++;
+ }
+
+ if ((monthDaysSelected == 0) && (weekDaysSelected > 0))
+ {
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ pbDayOfMonth[dm]->setOn(1);
+ }
+ }
+
+ if ((weekDaysSelected == 0) && (monthDaysSelected > 0))
+ {
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ cbDayOfWeek[dw]->setChecked(1);
+ }
+ }
+
+ // Now validate
+ QString message(i18n("Please enter the following to schedule the task:\n"));
+ QString sep("\n- ");
+ bool showMessage(false);
+
+ if (leCommand->text().isEmpty())
+ {
+ message += sep + i18n("the program to run");
+ leCommand->setFocus();
+ showMessage = true;
+ }
+
+ bool valid(false);
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ if (cbMonth[mo]->isChecked()) valid = true;
+ }
+ if (!valid)
+ {
+ message += sep + i18n("the months");
+ if (!showMessage)
+ {
+ cbMonth[1]->setFocus();
+ }
+ showMessage = true;
+ }
+
+ valid = false;
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ if (pbDayOfMonth[dm]->isOn()) valid = true;
+ }
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ if (cbDayOfWeek[dw]->isChecked()) valid = true;
+ }
+
+ if (!valid)
+ {
+ message += sep +
+ i18n("either the days of the month or the days of the week");
+ if (!showMessage)
+ {
+ pbDayOfMonth[1]->setFocus();
+ }
+ showMessage = true;
+ }
+
+ valid = false;
+ for (int ho = 0; ho <= 23; ho++)
+ {
+ if (pbHour[ho]->isOn()) valid = true;
+ }
+
+ if (!valid)
+ {
+ message += sep + i18n("the hours");
+ if (!showMessage)
+ {
+ pbHour[0]->setFocus();
+ }
+ showMessage = true;
+ }
+
+ valid = false;
+ for (int mi1 = 0; mi1 <= 55; mi1+=5)
+ {
+ if (pbMinute[mi1]->isOn()) valid = true;
+ }
+
+ if (!valid)
+ {
+ message += sep + i18n("the minutes");
+ if (!showMessage)
+ {
+ pbMinute[0]->setFocus();
+ }
+ showMessage = true;
+ }
+
+ if (showMessage)
+ {
+ KMessageBox::information(this, message);
+ return;
+ }
+
+ // make sure the file name is a good one if we have an
+ // absolute path
+
+ QString qs(leCommand->text());
+ if (qs.find("/") == 0)
+ {
+ int spacePos(qs.find(" "));
+ if (spacePos < 0) spacePos = qs.length();
+ QString programName(qs.left(spacePos));
+ QFileInfo file(programName);
+
+ if (!file.isReadable())
+ {
+ KMessageBox::information(this,
+ i18n("Cannot locate program. Please re-enter."));
+ leCommand->setFocus();
+ return;
+ }
+
+ if (!file.isExecutable())
+ {
+ KMessageBox::information(this,
+ i18n("Program is not an executable file. Please re-enter."));
+ leCommand->setFocus();
+ return;
+ }
+ }
+
+ // save work in process
+ if (!cttask->user.empty())
+ {
+ cttask->user = QFile::encodeName(leUser->text());
+ }
+ else
+ {
+ cttask->user = "";
+ }
+
+ cttask->comment = (const char *)leComment->text().local8Bit();
+ cttask->command = (const char *)leCommand->text().local8Bit();
+ cttask->enabled = chkEnabled->isChecked();
+ cttask->silent = chkSilent->isChecked();
+
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ cttask->month.set(mo, cbMonth[mo]->isChecked());
+ }
+
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ cttask->dayOfMonth.set(dm, pbDayOfMonth[dm]->isOn());
+ }
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ cttask->dayOfWeek.set(dw, cbDayOfWeek[dw]->isChecked());
+ }
+ for (int ho = 0; ho <= 23; ho++)
+ {
+ cttask->hour.set(ho, pbHour[ho]->isOn());
+ }
+ for (int mi = 0; mi <= 59; mi++)
+ {
+ cttask->minute.set(mi, false);
+ }
+ for (int mi1 = 0; mi1 <= 55; mi1+=5)
+ {
+ cttask->minute.set(mi1, pbMinute[mi1]->isOn());
+ }
+
+ close();
+}
+
+void KTTask::slotCancel()
+{
+ close();
+}
+
+void KTTask::slotBrowse()
+{
+ KURL url = KFileDialog::getOpenURL();
+
+ if(!url.isEmpty())
+ {
+ if(url.isLocalFile())
+ {
+ leCommand->setText(url.path());
+ }
+ else
+ {
+ KMessageBox::sorry(this,
+ i18n("Only local or mounted files can be executed by crontab."));
+ }
+ }
+
+ leCommand->setFocus();
+}
+
+void KTTask::slotAllMonths()
+{
+ if (pbAllMonths->text() == i18n("Set All")) {
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ cbMonth[mo]->setChecked(true);
+ }
+ }
+ else {
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ cbMonth[mo]->setChecked(false);
+ }
+ }
+ slotMonthChanged();
+}
+
+void KTTask::slotMonthChanged()
+{
+ bool allChecked = true;
+ bool allCleared = true;
+ for (int mo = 1; mo <= 12; mo++)
+ {
+ if (cbMonth[mo]->isChecked()) {
+ allCleared = false;
+ }
+ else {
+ allChecked = false;
+ }
+ }
+ if (allCleared) {
+ pbAllMonths->setText( i18n("Set All") );
+ }
+ else {
+ pbAllMonths->setText( i18n("Clear All") );
+ }
+}
+
+void KTTask::slotAllDaysOfMonth()
+{
+ if (pbAllDaysOfMonth->text() == i18n("Set All")) {
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ pbDayOfMonth[dm]->setOn(true);
+ }
+ }
+ else {
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ pbDayOfMonth[dm]->setOn(false);
+ }
+ }
+ slotDayOfMonthChanged();
+}
+
+void KTTask::slotDayOfMonthChanged()
+{
+ bool allChecked = true;
+ bool allCleared = true;
+ for (int dm = 1; dm <= 31; dm++)
+ {
+ if (pbDayOfMonth[dm]->isOn()) {
+ allCleared = false;
+ }
+ else {
+ allChecked = false;
+ }
+ }
+ if (allCleared) {
+ pbAllDaysOfMonth->setText( i18n("Set All") );
+ }
+ else {
+ pbAllDaysOfMonth->setText( i18n("Clear All") );
+ }
+ }
+
+void KTTask::slotAllDaysOfWeek()
+{
+ if (pbAllDaysOfWeek->text() == i18n("Set All")) {
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ cbDayOfWeek[dw]->setChecked(true);
+ }
+ }
+ else {
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ cbDayOfWeek[dw]->setChecked(false);
+ }
+ }
+ slotDayOfWeekChanged();
+}
+
+void KTTask::slotDayOfWeekChanged()
+{
+ bool allChecked = true;
+ bool allCleared = true;
+ for (int dw = 1; dw <= 7; dw++)
+ {
+ if (cbDayOfWeek[dw]->isChecked()) {
+ allCleared = false;
+ }
+ else {
+ allChecked = false;
+ }
+ }
+ if (allCleared) {
+ pbAllDaysOfWeek->setText( i18n("Set All") );
+ }
+ else {
+ pbAllDaysOfWeek->setText( i18n("Clear All") );
+ }
+ }
+
+void KTTask::slotAllHours()
+{
+ if (pbAllHours->text() == i18n("Set All")) {
+ for (int ho = 0; ho <= 23; ho++)
+ {
+ pbHour[ho]->setOn(true);
+ }
+ }
+ else {
+ for (int ho = 0; ho <= 23; ho++)
+ {
+ pbHour[ho]->setOn(false);
+ }
+ }
+ slotHourChanged();
+}
+
+void KTTask::slotHourChanged()
+{
+ bool allChecked = true;
+ bool allCleared = true;
+ for (int ho = 0; ho <= 23; ho++)
+ {
+ if (pbHour[ho]->isOn()) {
+ allCleared = false;
+ }
+ else {
+ allChecked = false;
+ }
+ }
+ if (allCleared) {
+ pbAllHours->setText( i18n("Set All") );
+ }
+ else {
+ pbAllHours->setText( i18n("Clear All") );
+ }
+ }
+
+void KTTask::slotAllMinutes()
+{
+ if (pbAllMinutes->text() == i18n("Set All")) {
+ for (int mi = 0; mi <= 55; mi+=5)
+ {
+ pbMinute[mi]->setOn(true);
+ }
+ }
+ else {
+ for (int mi = 0; mi <= 55; mi+=5)
+ {
+ pbMinute[mi]->setOn(false);
+ }
+ }
+ slotMinuteChanged();
+}
+
+void KTTask::slotMinuteChanged()
+{
+ bool allChecked = true;
+ bool allCleared = true;
+ for (int mi = 0; mi <= 55; mi+=5)
+ {
+ if (pbMinute[mi]->isOn()) {
+ allCleared = false;
+ }
+ else {
+ allChecked = false;
+ }
+ }
+ if (allCleared) {
+ pbAllMinutes->setText( i18n("Set All") );
+ }
+ else {
+ pbAllMinutes->setText( i18n("Clear All") );
+ }
+ }
+
+#include "kttask.moc"
diff --git a/kcron/kttask.h b/kcron/kttask.h
new file mode 100644
index 0000000..7920593
--- /dev/null
+++ b/kcron/kttask.h
@@ -0,0 +1,184 @@
+/***************************************************************************
+ * KT task editor window header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTTASK_H
+#define KTTASK_H
+
+#include <config.h>
+
+#include <kdialog.h>
+
+class QLabel;
+class QLineEdit;
+class QCheckBox;
+class QButtonGroup;
+class QPushButton;
+class KAccel;
+
+class CTTask;
+
+/**
+ * Task editor window.
+ */
+class KTTask : public KDialog
+{
+ Q_OBJECT
+
+public:
+
+/**
+ * Initialize from CTTask.
+ */
+ KTTask(CTTask* _cttask = 0, const QString &_caption="");
+
+/**
+ * Destroy.
+ */
+ ~KTTask();
+
+private slots:
+
+/**
+ * Browse for command file.
+ */
+ void slotBrowse();
+
+/**
+ * Command has been changed. Refresh icon.
+ */
+ void slotCommandChanged();
+
+/**
+ * Daily checkbox has been changed.
+ */
+ void slotDailyChanged();
+
+/**
+ * Apply changes and close.
+ */
+ void slotOK();
+
+/**
+ * Cancel and close.
+ */
+ void slotCancel();
+
+/**
+ * Set or clear all month checkboxes
+ */
+ void slotAllMonths();
+
+/**
+ * A month checkbox has changed
+ */
+ void slotMonthChanged();
+
+/**
+ * Set or clear all day of month checkboxes
+ */
+ void slotAllDaysOfMonth();
+
+/**
+ * A day of month checkbox has changed
+ */
+ void slotDayOfMonthChanged();
+
+/**
+ * Set or clear all day of week checkboxes
+ */
+ void slotAllDaysOfWeek();
+
+/**
+ * A day of week checkbox has changed
+ */
+ void slotDayOfWeekChanged();
+
+/**
+ * Set or clear all hour checkboxes
+ */
+ void slotAllHours();
+
+/**
+ * An hour checkbox has changed
+ */
+ void slotHourChanged();
+
+/**
+ * Set or clear all minute checkboxes
+ */
+ void slotAllMinutes();
+
+/**
+ * A minute checkbox has changed
+ */
+ void slotMinuteChanged();
+
+private:
+
+/**
+ * Task.
+ */
+ CTTask* cttask;
+
+/**
+ * Key accelerator.
+ */
+
+ KAccel* key_accel;
+
+ // Widgets.
+
+ QLabel* labUser;
+ QLineEdit* leUser;
+
+ QLabel* labIcon;
+
+ QLabel* labComment;
+ QLineEdit* leComment;
+
+ QLabel* labCommand;
+ QLineEdit* leCommand;
+ QPushButton* pbBrowse;
+
+ QCheckBox* chkEnabled;
+ QCheckBox* chkSilent;
+
+ QButtonGroup* bgMonth;
+ QCheckBox* cbMonth[13];
+ QPushButton* pbAllMonths;
+
+ QButtonGroup* bgDayOfMonth;
+ QPushButton* pbDayOfMonth[32];
+ QPushButton* pbAllDaysOfMonth;
+
+ QButtonGroup* bgDayOfWeek;
+ QCheckBox* cbDayOfWeek[8];
+ QPushButton* pbAllDaysOfWeek;
+
+ QButtonGroup* bgEveryDay;
+ QCheckBox* cbEveryDay;
+
+ QButtonGroup* bgHour;
+ QLabel* labAM;
+ QLabel* labPM;
+ QPushButton* pbHour[25];
+ QPushButton* pbAllHours;
+
+ QButtonGroup* bgMinute;
+ QPushButton* pbMinute[61];
+ QPushButton* pbAllMinutes;
+
+ QPushButton* pbOk;
+ QPushButton* pbCancel;
+
+};
+
+#endif // KTTASK_H
diff --git a/kcron/ktvariable.cpp b/kcron/ktvariable.cpp
new file mode 100644
index 0000000..014bdf6
--- /dev/null
+++ b/kcron/ktvariable.cpp
@@ -0,0 +1,152 @@
+/***************************************************************************
+ * KT environment variable editor window implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktvariable.h"
+
+#include <qlayout.h>
+
+#include <kapplication.h> // kapp
+#include <klocale.h> // i18n()
+#include <kmessagebox.h>
+#include <ktextedit.h>
+
+#include "ctvariable.h"
+
+#include "kticon.h"
+
+KTVariable::KTVariable(CTVariable* _ctvar,const QString &_caption) :
+ KDialogBase(0, "ktvariable", true, _caption, Ok|Cancel, Ok, true),
+ ctvar( _ctvar)
+{
+ QFrame *page = makeMainWidget();
+ QGridLayout *layout = new QGridLayout( page, 5, 3, 0, spacingHint() );
+ layout->setRowStretch(3, 1);
+ layout->setColStretch(1, 1);
+
+ setIcon(KTIcon::application(true));
+
+ // variable
+ labVariable = new QLabel(i18n("&Variable:"), page, "labVariable");
+ layout->addWidget(labVariable, 1, 0, Qt::AlignLeft | Qt::AlignTop);
+
+ cmbVariable = new QComboBox(true, page, "cmbVariable");
+ layout->addWidget(cmbVariable, 1, 1);
+
+ cmbVariable->insertItem("HOME");
+ cmbVariable->insertItem("MAILTO");
+ cmbVariable->insertItem("PATH");
+ cmbVariable->insertItem("SHELL");
+
+ labVariable->setBuddy(cmbVariable);
+
+ // icon
+ labIcon = new QLabel(page, "labIcon");
+ layout->addMultiCellWidget(labIcon, 0, 1, 2, 2);
+
+ // value
+ labValue = new QLabel(i18n("Va&lue:"), page, "labValue");
+ layout->addWidget(labValue, 2, 0, Qt::AlignLeft | Qt::AlignTop);
+
+ leValue = new QLineEdit(page, "leValue");
+ layout->addMultiCellWidget(leValue, 2, 2, 1, 2);
+ leValue->setMaxLength(255);
+ labValue->setBuddy(leValue);
+
+ // comment
+ labComment = new QLabel(i18n("Co&mment:"), page, "labComment");
+ layout->addWidget(labComment, 3, 0, Qt::AlignLeft | Qt::AlignTop);
+
+ teComment = new KTextEdit(page, "teComment");
+ teComment->setTextFormat(Qt::PlainText);
+ layout->addMultiCellWidget(teComment, 3, 3, 1, 2);
+
+ labComment->setBuddy(teComment);
+
+ // enabled
+ chkEnabled = new QCheckBox(i18n("&Enabled"), page, "chkEnabled");
+ layout->addWidget(chkEnabled, 4, 0);
+
+ // set starting field values
+ cmbVariable->setEditText(QString::fromLocal8Bit(ctvar->variable.c_str()));
+ slotVariableChanged();
+
+ leValue->setText(QString::fromLocal8Bit(ctvar->value.c_str()));
+
+ teComment->setText(QString::fromLocal8Bit(ctvar->comment.c_str()));
+
+ chkEnabled->setChecked(ctvar->enabled);
+
+ cmbVariable->setFocus();
+
+ // connect them up
+ connect(cmbVariable,SIGNAL(highlighted(const QString&)),
+ SLOT(slotVariableChanged()));
+ connect(cmbVariable,SIGNAL(activated(const QString&)),
+ SLOT(slotVariableChanged()));
+}
+
+KTVariable::~KTVariable()
+{
+}
+
+void KTVariable::slotVariableChanged()
+{
+ QString variable = cmbVariable->currentText();
+ if (variable == "HOME")
+ {
+ labIcon->setPixmap(KTIcon::home(false));
+ teComment->setText(i18n("Override default home folder."));
+ }
+ else if (variable == "MAILTO")
+ {
+ labIcon->setPixmap(KTIcon::mail(false));
+ teComment->setText(i18n("Email output to specified account."));
+ }
+ else if (variable == "SHELL")
+ {
+ labIcon->setPixmap(KTIcon::shell(false));
+ teComment->setText(i18n("Override default shell."));
+ }
+ else if (variable == "PATH")
+ {
+ labIcon->setPixmap(KTIcon::path(false));
+ teComment->setText(i18n("Folders to search for program files."));
+ }
+ else
+ {
+ labIcon->setPixmap(KTIcon::variable(false));
+ }
+}
+
+void KTVariable::slotOk()
+{
+ if (cmbVariable->currentText().isEmpty())
+ {
+ KMessageBox::information(this, i18n("Please enter the variable name."));
+ cmbVariable->setFocus();
+ return;
+ }
+
+ if (leValue->text().isEmpty())
+ {
+ KMessageBox::information(this, i18n("Please enter the variable value."));
+ cmbVariable->setFocus();
+ return;
+ }
+
+ ctvar->variable = cmbVariable->currentText().local8Bit();
+ ctvar->value = leValue->text().local8Bit();
+ ctvar->comment = teComment->text().replace('\n',' ').replace('\r',' ').local8Bit();
+ ctvar->enabled = chkEnabled->isChecked();
+ close();
+}
+
+#include "ktvariable.moc"
diff --git a/kcron/ktvariable.h b/kcron/ktvariable.h
new file mode 100644
index 0000000..eb5eb57
--- /dev/null
+++ b/kcron/ktvariable.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * KT environment variable editor window header *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTVARIABLE_H
+#define KTVARIABLE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+
+#include <kdialogbase.h>
+
+class KTextEdit;
+
+class CTVariable;
+
+/**
+ * Environment variable editor window.
+ */
+class KTVariable : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+/**
+ * Initialize from CTVariable.
+ */
+ KTVariable(CTVariable* _ctvar = 0, const QString &_caption="");
+
+/**
+ * Destroy.
+ */
+ ~KTVariable();
+
+private slots:
+
+/**
+ * Variable name has been changed. Refresh icon.
+ */
+ void slotVariableChanged();
+
+ /**
+ * Apply changes and close.
+ */
+ void slotOk();
+
+private:
+
+/**
+ * Environment variable.
+ */
+ CTVariable* ctvar;
+
+ // Widgets.
+
+ QLabel* labIcon;
+
+ QLabel* labVariable;
+ QComboBox* cmbVariable;
+
+ QLabel* labValue;
+ QLineEdit* leValue;
+
+ QLabel* labComment;
+ KTextEdit* teComment;
+
+ QCheckBox* chkEnabled;
+};
+
+#endif // KTVARIABLE_H
diff --git a/kcron/ktview.cpp b/kcron/ktview.cpp
new file mode 100644
index 0000000..87c90c0
--- /dev/null
+++ b/kcron/ktview.cpp
@@ -0,0 +1,576 @@
+/**************************************************************************
+ * KT main GUI view implementation *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "ktview.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <config.h>
+
+#ifdef HAVE_SSTREAM
+#include <sstream>
+#else
+#include <strstream.h>
+#endif
+
+#include <string>
+
+#include <qstring.h>
+#include <qheader.h>
+#include <qpopupmenu.h>
+#include <qfileinfo.h>
+#include <qfile.h>
+#include <qdatetime.h>
+
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+
+#include "cthost.h"
+#include "ctcron.h"
+#include "ctvariable.h"
+#include "cttask.h"
+
+#include "kticon.h"
+#include "ktlistcron.h"
+#include "ktlistvars.h"
+#include "ktlistvar.h"
+#include "ktlisttasks.h"
+#include "ktlisttask.h"
+#include "ktapp.h"
+#include "ktvariable.h"
+#include "kttask.h"
+#include "ktprint.h"
+
+KTView::KTView(QWidget *parent, const char* name) :
+ QWidget(parent, name),
+ listView(0),
+ currentCTCron(0),
+ currentIsTask(true),
+ currentCTTask(0),
+ currentCTVariable(0),
+ clipboardIsTask(true),
+ clipboardCTTask(0),
+ clipboardCTVariable(0)
+{
+ ktapp = (KTApp*)parentWidget();
+ setBackgroundMode(PaletteBase);
+ refresh();
+ listView->setSelected(listView->firstChild(), true);
+
+ connect(this, SIGNAL(enableModificationButtons(bool)), parent,
+ SLOT(slotEnableModificationButtons(bool)));
+
+ connect(this, SIGNAL(enablePaste(bool)), parent,
+ SLOT(slotEnablePaste(bool)));
+
+ connect(this, SIGNAL(enableRunNow(bool)), parent,
+ SLOT(slotEnableRunNow(bool)));
+
+ connect(this, SIGNAL(enableEnabled(bool)), parent,
+ SLOT(slotEnableEnabled(bool)));
+}
+
+void KTView::disableIcons()
+{
+ emit(enableModificationButtons(false));
+ emit(enablePaste(clipboardCTVariable));
+ emit(enableRunNow(false));
+}
+
+void KTView::refresh()
+{
+ QListView* tmpListView(listView);
+
+ listView = new QListView(this);
+
+ listView->setFrameStyle(QListView::Panel | QListView::Sunken);
+ listView->setRootIsDecorated(true);
+ listView->setAllColumnsShowFocus(true);
+ listView->setShowSortIndicator(true);
+
+ const CTHost& cth(ktapp->getCTHost());
+
+ if (cth.root())
+ listView->addColumn(i18n("Users/Tasks/Variables"));
+ else
+ listView->addColumn(i18n("Tasks/Variables"));
+
+ listView->addColumn(i18n("Value"));
+ listView->addColumn(i18n("Description"));
+
+ for (int item = 0; item <=2; item++)
+ listView->setColumnWidthMode(item, QListView::Maximum);
+
+ // for each user
+ for (CTCronIterator i = const_cast<CTHost&>(cth).cron.begin();
+ i != cth.cron.end(); i++)
+ {
+ CTCron* ctcron((CTCron*)*i);
+
+ KTListVars* variables(0);
+ KTListTasks* tasks(0);
+
+ if (cth.root())
+ {
+ KTListCron* user = new KTListCron(listView, ctcron);
+ if (currentCTCron == ctcron)
+ {
+ listView->setSelected(user, true);
+ }
+
+ variables = new KTListVars(user, ctcron);
+ tasks = new KTListTasks(user, ctcron);
+ }
+ else
+ {
+ variables = new KTListVars(listView, ctcron);
+ tasks = new KTListTasks(listView, ctcron);
+ }
+
+ if (currentIsTask)
+ {
+ listView->setSelected(tasks, true);
+ slotSetCurrent(tasks);
+ }
+ else
+ {
+ listView->setSelected(variables, true);
+ slotSetCurrent(variables);
+ }
+
+ for (CTVariableIterator j = (CTVariableIterator)ctcron->variable.begin();
+ j != ctcron->variable.end(); j++)
+ {
+ new KTListVar(variables, ctcron, (CTVariable*)*j);
+ }
+
+ for (CTTaskIterator k = (CTTaskIterator)ctcron->task.begin();
+ k != ctcron->task.end(); k++)
+ {
+ new KTListTask(tasks, ctcron, (CTTask*)*k);
+ }
+ }
+
+ resizeEvent();
+
+ connect(listView, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
+ SLOT(slotMenu(QListViewItem*, const QPoint&, int)));
+
+ connect(listView, SIGNAL(selectionChanged(QListViewItem*)),
+ SLOT(slotSetCurrent(QListViewItem*)));
+
+ connect(listView, SIGNAL(doubleClicked(QListViewItem*)),
+ SLOT(slotEdit(QListViewItem*)));
+
+ connect(listView, SIGNAL(returnPressed(QListViewItem*)),
+ SLOT(slotEdit(QListViewItem*)));
+
+ // switch to the new view
+ if (tmpListView)
+ {
+ tmpListView->hide();
+ listView->show();
+ listView->setFocus();
+ delete tmpListView;
+ }
+}
+
+void KTView::print () const
+{
+ bool crontab, allUsers;
+ KTListItem *ktli, *user;
+
+ const CTHost& cth(ktapp->getCTHost());
+
+ KTPrint printer(cth.root());
+
+ if (printer.start())
+ {
+ crontab = printer.crontab();
+ allUsers = printer.allUsers();
+
+ printer.createColumns(3);
+
+ int copies = printer.numCopies();
+ while (copies != 0)
+ {
+ if (allUsers || !cth.root())
+ {
+ ktli = (KTListItem*)listView->firstChild();
+ }
+ else
+ {
+ ktli = (KTListItem*)listView->currentItem();
+ }
+
+ //Check that the correct item is selected, they must
+ //select the top level entry for all items to print
+ while (ktli->depth() != 0)
+ ktli = (KTListItem*)ktli->parent();
+
+ user = ktli; //Used to store user's name
+
+ if (allUsers)
+ {
+ while (ktli)
+ {
+ pageHeading(ktli, printer);
+ ktli->print(printer);
+ if (crontab)
+ pageFooter(ktli, printer);
+ ktli = (KTListItem*)ktli->nextSibling();
+ if (ktli)
+ printer.newPage();
+ }
+ }
+ else
+ {
+ //ktli goes out of range here hence the need for user
+ pageHeading(user, printer);
+ if (!cth.root())
+ {
+ while (ktli)
+ {
+ ktli->print(printer);
+ ktli = (KTListItem*)ktli->nextSibling();
+ }
+ }
+ else
+ ktli->print(printer);
+
+ if (crontab)
+ pageFooter(user, printer);
+
+ }
+
+ copies--; //Keep a track of how many copies we have printed
+ if (copies != 0) printer.newPage();
+ }//End printing loop (for more than one copy)
+
+ printer.finished(); //End the print
+
+ }//End Printing if
+}
+
+void KTView :: pageHeading (KTListItem* user, KTPrint &printer) const
+{
+ QFont stnd;
+ QString logonInfo;
+ QDateTime now (QDateTime::currentDateTime());
+ char hostName[20];
+
+ gethostname(hostName, 20);
+ // SSA : Fix Me user name, logon name and host name musst be
+ // SSA : not only in us-ascii ??
+ logonInfo = i18n("user on host", "%1 <%2> on %3")
+ .arg(QString::fromLocal8Bit(user->getCTCron()->name.c_str()))
+ .arg(QString::fromLocal8Bit(user->getCTCron()->login.c_str()))
+ .arg(QString::fromLocal8Bit(hostName));
+
+ stnd = printer.getFont();
+ printer.setFont(QFont( KGlobalSettings::generalFont().family(), 14, QFont::Bold ));
+
+ printer.print (i18n("Scheduled Tasks"), 2, KTPrint::alignTextCenter, false);
+ printer.print (logonInfo, 2, KTPrint::alignTextCenter, false);
+ printer.print (KGlobal::locale()->formatDateTime(now), 2, KTPrint::alignTextCenter, false);
+ printer.setFont(stnd);
+
+ printer.levelColumns(20);
+
+}
+
+void KTView :: pageFooter (KTListItem* user, KTPrint &printer) const
+{
+#ifdef HAVE_SSTREAM
+ ostringstream oss;
+#else
+ char buffer[4096];
+ ostrstream oss(buffer, sizeof(buffer));
+#endif
+
+ oss<<*(user->getCTCron())<<ends;
+
+ if (oss) {
+ string crontab(oss.str());
+ printer.print(crontab.c_str(), 1, KTPrint::alignTextLeft, false);
+ }
+}
+
+KTView::~KTView()
+{
+ delete listView;
+}
+
+void KTView::resizeEvent (QResizeEvent*)
+{
+ listView->setFixedWidth(width());
+ listView->setFixedHeight(height());
+ repaint();
+}
+
+void KTView::copy()
+{
+ if (clipboardCTTask)
+ {
+ delete clipboardCTTask;
+ clipboardCTTask = 0;
+ }
+
+ if (clipboardCTVariable)
+ {
+ delete clipboardCTVariable;
+ clipboardCTVariable = 0;
+ }
+
+ if (currentIsTask)
+ {
+ clipboardCTTask = new CTTask(*currentCTTask);
+ }
+ else
+ {
+ clipboardCTVariable = new CTVariable(*currentCTVariable);
+ }
+ clipboardIsTask = currentIsTask;
+}
+
+void KTView::paste()
+{
+ KTListItem* qlvi = (KTListItem*)listView->currentItem();
+
+ if (currentIsTask)
+ {
+ CTTask* temptask = new CTTask(*clipboardCTTask);
+ currentCTCron->task.push_back(temptask);
+ KTListTask* ktlt = new KTListTask(qlvi, currentCTCron, temptask);
+ listView->setSelected(ktlt, true);
+ }
+ else
+ {
+ CTVariable* tempvar = new CTVariable(*clipboardCTVariable);
+ currentCTCron->variable.push_back(tempvar);
+ KTListVar* ktlv = new KTListVar(qlvi, currentCTCron, tempvar);
+ listView->setSelected(ktlv, true);
+ }
+}
+
+void KTView::create()
+{
+ KTListItem* ktli = (KTListItem*)listView->currentItem();
+ if ((ktli->text(0) != KTListTasks::getDescription()) && (ktli->text(0) != KTListVars::getDescription())) {
+ ktli = (KTListItem*)ktli->parent();
+ }
+ Q_CHECK_PTR(ktli);
+ ktli->create();
+ listView->triggerUpdate();
+}
+
+void KTView::edit()
+{
+ KTListItem* ktli = (KTListItem*)listView->currentItem();
+ Q_CHECK_PTR(ktli);
+ ktli->edit();
+ listView->triggerUpdate();
+}
+
+void KTView::remove()
+{
+ if (currentIsTask)
+ {
+ if (currentCTTask)
+ {
+ for (CTTaskIterator i = (CTTaskIterator)
+ (currentCTCron->task.begin());
+ i != currentCTCron->task.end(); i++)
+ {
+ if (*i == currentCTTask)
+ {
+ currentCTCron->task.erase(i);
+ delete currentCTTask;
+ currentCTTask = 0;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (currentCTVariable)
+ {
+ for (CTVariableIterator j = (CTVariableIterator)
+ (currentCTCron->variable.begin());
+ j != currentCTCron->variable.end(); j++)
+ {
+ if (*j == currentCTVariable)
+ {
+ currentCTCron->variable.erase(j);
+ delete currentCTVariable;
+ currentCTVariable = 0;
+ break;
+ }
+ }
+ }
+ }
+ refresh();
+}
+
+QString KTView::absolute() const
+{
+ QString fullCommand = QString::fromLocal8Bit(currentCTTask->command.c_str());
+ QString command(fullCommand);
+ int pos(command.find(" "));
+ if (pos > 0) command = command.left(pos);
+
+ if (command.find("/") == 0)
+ return fullCommand;
+
+ QString path = QString::fromLocal8Bit(currentCTCron->path().c_str());
+ int begin(0);
+ int end(0);
+ QString prefix;
+ QString full;
+
+ while ((end = path.find(":", begin)) > 0)
+ {
+ prefix = path.mid(begin, begin + end) + "/";
+ full = prefix + command;
+ if (QFileInfo(full).isExecutable())
+ return QString(prefix + fullCommand);
+ begin = end + 1;
+ }
+ prefix = path.mid(begin, begin + end) + "/";
+ full = prefix + command;
+ if (QFileInfo(full).isExecutable())
+ return QString(prefix + fullCommand);
+ return QString("");
+}
+
+void KTView::run() const
+{
+ QString command(absolute() + " &");
+ system(QFile::encodeName(command));
+}
+
+void KTView::enable(bool enable)
+{
+ QListViewItem* qlvi = listView->currentItem();
+
+ if (currentIsTask)
+ {
+ if (currentCTTask)
+ {
+ currentCTTask->enabled = enable;
+ ((KTListTask*)(qlvi))->refresh();
+ }
+ }
+ else
+ {
+ if (currentCTVariable)
+ {
+ currentCTVariable->enabled = enable;
+ ((KTListVar*)(qlvi))->refresh();
+ }
+ }
+}
+
+void KTView::slotMenu(QListViewItem* qlvi, const QPoint& qp, int /*i*/)
+{
+ if (qlvi !=0 ) {
+ listView->setSelected(qlvi, true);
+ slotSetCurrent(qlvi);
+ ktapp->slotEdit(qp);
+ }
+}
+
+void KTView::slotEdit(QListViewItem* /*qlvi*/)
+{
+ edit();
+}
+
+void KTView::slotSetCurrent (QListViewItem* qlvi)
+{
+ QListViewItem* parent = qlvi->parent();
+
+ if (qlvi->text(0) == KTListVars::getDescription())
+ {
+ // variable label
+ currentCTCron = ((KTListCron*)qlvi)->getCTCron();
+ currentCTVariable = 0;
+ currentCTTask = 0;
+ currentIsTask = false;
+ emit(enableModificationButtons(false));
+ emit(enablePaste(clipboardCTVariable));
+ emit(enableRunNow(false));
+ emit(enableEnabled(false));
+
+ }
+ else if (qlvi->text(0) == KTListTasks::getDescription())
+ {
+ // task label
+ currentCTCron = ((KTListCron*)qlvi)->getCTCron();
+ currentCTVariable = 0;
+ currentCTTask = 0;
+ currentIsTask = true;
+
+ emit(enableModificationButtons(false));
+ emit(enablePaste(clipboardCTTask));
+ emit(enableRunNow(false));
+ emit(enableEnabled(false));
+
+ }
+ else if (parent)
+ {
+ if (parent->text(0) == KTListVars::getDescription())
+ {
+ // variable
+ currentCTCron = ((KTListVar*)qlvi)->getCTCron();
+ currentCTVariable = ((KTListVar*)qlvi)->getCTVariable();
+ currentCTTask = 0;
+ currentIsTask = false;
+
+ emit(enableModificationButtons(true));
+ emit(enableRunNow(false));
+ emit(enableEnabled(currentCTVariable->enabled));
+
+ }
+ else if (parent->text(0) == KTListTasks::getDescription())
+ {
+ // task
+ currentCTCron = ((KTListTask*)qlvi)->getCTCron();
+ currentCTVariable = 0;
+ currentCTTask = ((KTListTask*)qlvi)->getCTTask();
+ currentIsTask = true;
+
+ emit(enableModificationButtons(true));
+ emit(enableRunNow((currentCTTask->enabled) &&
+ (!absolute().isEmpty())));
+ emit(enableEnabled(currentCTTask->enabled));
+
+ }
+ }
+ else
+ {
+ // user
+ currentCTCron = ((KTListCron*)qlvi)->getCTCron();
+ currentCTVariable = 0;
+ currentCTTask = 0;
+ currentIsTask = true;
+
+ emit(enableModificationButtons(true));
+ emit(enablePaste(false));
+ emit(enableRunNow(false));
+ emit(enableEnabled(false));
+
+ }
+}
+
+#include "ktview.moc"
diff --git a/kcron/ktview.h b/kcron/ktview.h
new file mode 100644
index 0000000..e25129a
--- /dev/null
+++ b/kcron/ktview.h
@@ -0,0 +1,215 @@
+/***************************************************************************
+ * KT main view header. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KTVIEW_H
+#define KTVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+
+class QString;
+class QListView;
+class QListViewItem;
+class KTApp;
+class KTPrint;
+class KTListItem;
+class CTCron;
+class CTVariable;
+class CTTask;
+
+/**
+ * Main GUI view of the crontab entries.
+ */
+class KTView : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+/**
+ * Initializes view.
+ */
+ KTView (QWidget* parent = 0, const char* name=0);
+
+/**
+ * Destructor.
+ */
+ ~KTView();
+
+/**
+ * Print crontab.
+ */
+ void print() const;
+
+/**
+ * Print page heading.
+ */
+ void pageHeading (KTListItem *user, KTPrint &printer) const;
+
+/**
+ * Print page footer.
+ */
+ void pageFooter (KTListItem *user, KTPrint &printer) const;
+
+/**
+ * Copies variables and/or tasks.
+ */
+ void copy();
+
+/**
+ * Pastes variables and/or tasks from the clipboard.
+ */
+ void paste();
+
+/**
+ * Create a new variable or task. Default is which type is most recently
+ * selected.
+ */
+ void create();
+
+/**
+ * Edit variable or task. Default is most recently selected.
+ */
+ void edit();
+
+/**
+ * Delete variables and/or tasks.
+ */
+ void remove();
+
+/**
+ * Enables/disables variables and/or tasks.
+ */
+ void enable(bool enable = true);
+
+/**
+ * Run task now.
+ */
+ void run() const;
+
+/**
+ * Disable selected icons
+ */
+ void disableIcons();
+
+signals:
+
+/** Enables/disables modification
+ * buttons depending
+ * on if a task is selected
+ */
+ void enableModificationButtons(bool);
+
+/** Enables/disables paste button depending
+ * on clipboard contents
+ */
+ void enablePaste(bool);
+
+/** Enables/disables "Run now" depending
+ * on the task settings
+ */
+ void enableRunNow(bool);
+
+/** Enables/disables "Activated" setting
+ * on the menu depending on the task
+ * configuration
+ */
+ void enableEnabled(bool);
+
+public slots:
+
+/**
+ * Pop up context sensitive menu.
+ */
+ void slotMenu(QListViewItem* qlvi, const QPoint& qp, int i);
+
+/**
+ * Default action, edit.
+ */
+ void slotEdit(QListViewItem* qlvi = 0);
+
+protected slots:
+
+/**
+ * Set current and update menu
+ */
+ void slotSetCurrent (QListViewItem* qlvi);
+
+protected:
+
+/**
+ * Resize view contents.
+ */
+ virtual void resizeEvent (QResizeEvent* = 0);
+
+private:
+
+/**
+ * Get absolute path of command.
+ */
+ QString absolute() const;
+
+/**
+ * Refresh view from underlying objects.
+ */
+ void refresh();
+
+/**
+ * The application.
+ */
+ KTApp* ktapp;
+
+/**
+ * Tree view of the crontab entries.
+ */
+ QListView* listView;
+
+/**
+ * Current user's crontab.
+ */
+ CTCron* currentCTCron;
+
+/**
+ * Indicates whether or not currently selected item is a task.
+ */
+ bool currentIsTask;
+
+/**
+ * Current task.
+ */
+ CTTask* currentCTTask;
+
+/**
+ * Current variable.
+ */
+ CTVariable* currentCTVariable;
+
+/**
+ * Indicates whether or not the item on the clipboard is a task.
+ */
+ bool clipboardIsTask;
+
+/**
+ * Clipboard task.
+ */
+ CTTask* clipboardCTTask;
+
+/**
+ * Clipboard variable.
+ */
+ CTVariable* clipboardCTVariable;
+
+};
+
+#endif // KTVIEW_H
diff --git a/kcron/main.cpp b/kcron/main.cpp
new file mode 100644
index 0000000..b77ec27
--- /dev/null
+++ b/kcron/main.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Main. *
+ * -------------------------------------------------------------------- *
+ * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
+ * -------------------------------------------------------------------- *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 <kapplication.h>
+#include <klocale.h>
+#include "ktapp.h"
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+
+int main(int argc, char* argv[])
+{
+ static const char description[] = I18N_NOOP("KDE Task Scheduler");
+
+ KAboutData aboutData("kcron", I18N_NOOP("KCron"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 1999-2000, Gary Meyer");
+
+ aboutData.addAuthor("Gary Meyer", 0, "gary@meyer.net");
+ aboutData.addAuthor("Robert Berry", 0, "rjmber@ntlworld.com");
+ aboutData.addAuthor("James Ots", 0, "code@jamesots.com");
+ aboutData.addAuthor("Alberto G. Hierro", 0, "alberto.hierro@kdemail.net");
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+
+ KApplication app;
+
+ if (app.isRestored())
+ {
+ RESTORE(KTApp);
+ }
+ else
+ {
+ KTApp* kcron = new KTApp;
+ if (!kcron->init())
+ return 1;
+ kcron->show();
+ }
+ return app.exec();
+}
diff --git a/kdat/Archive.cpp b/kdat/Archive.cpp
new file mode 100644
index 0000000..0933265
--- /dev/null
+++ b/kdat/Archive.cpp
@@ -0,0 +1,389 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <assert.h>
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+
+#include "Archive.h"
+#include "Options.h"
+#include "TapeManager.h"
+
+Archive::Archive( Tape* tape, int ctime, const QString & name )
+ : _stubbed( FALSE ),
+ _fptr( 0 ),
+ _offset( 0 ),
+ _name( name ),
+ _tape( tape )
+{
+ assert( _tape );
+
+ _ctime = ctime;
+}
+
+Archive::Archive( Tape* tape, FILE* fptr, int offset )
+ : _stubbed( TRUE ),
+ _tape( tape )
+{
+ assert( _tape );
+
+ _fptr = fptr;
+ _offset = offset;
+}
+
+Archive::~Archive()
+{
+}
+
+void Archive::read( int version )
+{
+ if ( !_stubbed ) {
+ return;
+ }
+
+ _stubbed = FALSE;
+
+ fseek( _fptr, _offset, SEEK_SET );
+
+ // Archive name (4 bytes + n chars).
+ int ival;
+ fread( &ival, sizeof( ival ), 1, _fptr );
+
+ char *buf = new char[ival + 1];
+ buf[ival] = '\0';
+ fread( buf, sizeof( char ), ival, _fptr );
+ _name = buf;
+ delete [] buf;
+
+ // Archive creation time (4 bytes).
+ fread( &ival, sizeof( ival ), 1, _fptr );
+ _ctime = ival;
+
+ // Archive ending block (4 bytes).
+ fread( &ival, sizeof( ival ), 1, _fptr );
+ _endBlock = ival;
+
+ if ( version > 3 ) {
+ fread( &ival, sizeof( ival ), 1, _fptr );
+ int rc = ival;
+ int start = 0;
+ int end = 0;
+ for ( int ii = 0; ii < rc; ii++ ) {
+ fread( &ival, sizeof( ival ), 1, _fptr );
+ start = ival;
+ fread( &ival, sizeof( ival ), 1, _fptr );
+ end = ival;
+ _ranges.addRange( start, end );
+ }
+ }
+
+ // Number of immediate children (4 bytes).
+ fread( &ival, sizeof( ival ), 1, _fptr );
+
+ //===== Read files =====
+ for ( int count = ival; count > 0; count-- ) {
+ fread( &ival, sizeof( ival ), 1, _fptr );
+ addChild( new File( 0, _fptr, ival ) );
+ }
+}
+
+void Archive::readAll( int version )
+{
+ read( version );
+
+ QPtrListIterator<File> i( getChildren() );
+ for ( ; i.current(); ++i ) {
+ i.current()->readAll( version );
+ }
+}
+
+void Archive::write( FILE* fptr )
+{
+ _fptr = fptr;
+ _offset = ftell( _fptr );
+
+ int zero = 0;
+
+ // Archive name (4 bytes + n chars).
+ int ival = 4096;
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+ char buf[4096];
+ memset( buf, 0, 4096 );
+ memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
+ fwrite( buf, sizeof( char ), 4096, _fptr );
+
+ // Archive creation time (4 bytes).
+ ival = getCTime();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+
+ // Archive ending block (4 bytes).
+ ival = getEndBlock();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+
+ // Child range list.
+ ival = _ranges.getRanges().count();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+ QPtrListIterator<Range> it( _ranges.getRanges() );
+ for ( ; it.current(); ++it ) {
+ ival = it.current()->getStart();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+ ival = it.current()->getEnd();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+ }
+
+ // Number of immediate children (4 bytes).
+ ival = getChildren().count();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+
+ // Fill in file offsets later...
+ int fileTable = ftell( _fptr );
+ for ( ; ival > 0; ival-- ) {
+ fwrite( &zero, sizeof( zero ), 1, _fptr );
+ }
+
+ //===== Write files =====
+ QPtrListIterator<File> i( getChildren() );
+ int count = 0;
+ for ( ; i.current(); ++i, count++ ) {
+ // Fill in the file offset.
+ int here = ftell( _fptr );
+ fseek( _fptr, fileTable + 4*count, SEEK_SET );
+ fwrite( &here, sizeof( here ), 1, _fptr );
+ fseek( _fptr, here, SEEK_SET );
+
+ i.current()->write( _fptr );
+ }
+}
+
+int Archive::getCTime()
+{
+ read();
+
+ return _ctime;
+}
+
+int Archive::getEndBlock()
+{
+ read();
+
+ return _endBlock;
+}
+
+QString Archive::getName()
+{
+ read();
+
+ return _name;
+}
+
+Tape* Archive::getTape()
+{
+ return _tape;
+}
+
+const QPtrList<File>& Archive::getChildren()
+{
+ read();
+
+ return _children;
+}
+
+const QPtrList<Range>& Archive::getRanges()
+{
+ read();
+
+ return _ranges.getRanges();
+}
+
+void Archive::setEndBlock( int endBlock )
+{
+ read();
+
+ _endBlock = endBlock;
+
+ if ( _fptr ) {
+ fseek( _fptr, _offset + 4 + 4096 + 4, SEEK_SET );
+ fwrite( &_endBlock, sizeof( _endBlock ), 1, _fptr );
+ }
+
+ TapeManager::instance()->tapeModified( _tape );
+}
+
+void Archive::setName( const QString & name )
+{
+ read();
+
+ _name = name;
+
+ if ( _fptr ) {
+ char buf[4096];
+ fseek( _fptr, _offset + 4, SEEK_SET );
+ memset( buf, 0, 4096 );
+ memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
+ fwrite( buf, sizeof( char ), 4096, _fptr );
+ fflush( _fptr );
+ }
+ /* 2002-01-31 LEW */
+#ifdef DEBUG
+ else {
+ printf("Archive::setName::_fptr is NULL. %s %d\n", __FILE__, __LINE__);
+ }
+#endif /* DEBUG */
+ /* 2002-01-31 LEW */
+
+ TapeManager::instance()->tapeModified( _tape );
+}
+
+void Archive::addChild( File* file )
+{
+ read();
+
+ _children.append( file );
+}
+
+File* Archive::addFile( int size, int mtime, int startRecord, int endRecord, const QString & filename )
+{
+ read();
+
+ QStringList path;
+
+ QString fn( filename );
+ int idx = 0;
+ while ( ( idx = fn.find( '/' ) ) > -1 ) {
+ path.append( fn.left( idx + 1 ) );
+ fn.remove( 0, idx + 1 );
+ }
+
+ if ( fn.length() == 0 ) {
+ fn = path.last();
+ path.remove(path.last());
+ }
+
+ File* file = 0;
+ if ( path.count() == 0 ) {
+ // Top level file/directory.
+ file = new File( 0, size, mtime, startRecord, endRecord, fn );
+
+ addChild( file );
+ return file;
+ }
+
+ QString dir = path.first();
+ //path.remove(path.first());
+ path.remove(path.begin());
+ QPtrListIterator<File> i( getChildren() );
+ File* parent = 0;
+ for ( ; i.current() ; ++i ) {
+ if ( i.current()->getName() == dir ) {
+ parent = i.current();
+ break;
+ }
+ }
+
+ if ( parent == 0 ) {
+ parent = new File( 0, 0, 0, startRecord, endRecord, dir );
+ addChild( parent );
+ }
+
+ for ( QStringList::Iterator j = path.begin();
+ j != path.end();
+ ++j ) {
+ QString dir = *j;
+ File* pparent = parent;
+ QPtrListIterator<File> i( pparent->getChildren() );
+ for ( parent = 0; i.current() ; ++i ) {
+ if ( i.current()->getName() == dir ) {
+ parent = i.current();
+ break;
+ }
+ }
+
+ if ( parent == 0 ) {
+ parent = new File( pparent, 0, 0, 0, 0, dir );
+ pparent->addChild( parent );
+ }
+ }
+
+ file = new File( parent, size, mtime, startRecord, endRecord, fn );
+ parent->addChild( file );
+
+ return file;
+}
+
+void Archive::calcRanges()
+{
+ assert( !_stubbed );
+
+ _ranges.clear();
+
+ QPtrListIterator<File> it( getChildren() );
+ for ( ; it.current(); ++it ) {
+ it.current()->calcRanges();
+ QPtrListIterator<Range> it2( it.current()->getRanges() );
+ for ( ; it2.current(); ++it2 ) {
+ _ranges.addRange( it2.current()->getStart(), it2.current()->getEnd() );
+ }
+ }
+
+ //%%% This is a kludge to cope with a bug that I haven't found yet.
+ //%%% If there is more than one range, then all of the ranges are merged
+ //%%% into one big contiguous range.
+ if ( _ranges.getRanges().count() > 1 ) {
+ kdDebug() << "Archive::calcRanges() -- extra ranges detected, fixing..." << endl;
+ QPtrListIterator<Range> iter( _ranges.getRanges() );
+ for ( ; iter.current(); ++iter ) {
+ kdDebug() << "Archive::calcRanges() -- range = " << iter.current() << " to " << iter.current()->getEnd() << endl;
+ }
+ int start = _ranges.getRanges().getFirst()->getStart();
+ int end = _ranges.getRanges().getLast()->getEnd();
+ _ranges.clear();
+ _ranges.addRange( start, end );
+ }
+
+ /* 2002-01-26 LEW */
+ // printf("Ranges of tar files on tape (1):\n");
+ /* 2002-01-26 LEW */
+ assert( _ranges.getRanges().count() <= 1 );
+
+ /* 2002-01-26 LEW */
+ {
+#ifdef DEBUG
+#if 0 /* commented out because of compile warnings. Fix 'em if this is needed. */
+ Range *ptr;
+ // printf("Ranges of tar files on tape (2):\n");
+ for ( ptr = _ranges.getRanges().first();
+ ptr;
+ ptr = _ranges.getRanges().next() ){
+ // printf("Range: start %d, end %d\n", ptr->getStart(), ptr->getEnd());
+ }
+#endif
+#endif /* DEBUG */
+ if( _ranges.getRanges().getFirst() == NULL ){
+ printf("There aren't any tar files on this tape as far as kdat can tell!\n");
+ _endBlock = 0;
+ return;
+ }
+ /* 2002-01-26 LEW */
+
+ _endBlock = _ranges.getRanges().getFirst()->getEnd()
+ / ( Options::instance()->getTapeBlockSize() / 512 );
+ }
+}
+
diff --git a/kdat/Archive.h b/kdat/Archive.h
new file mode 100644
index 0000000..b64ae36
--- /dev/null
+++ b/kdat/Archive.h
@@ -0,0 +1,184 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _Archive_h_
+#define _Archive_h_
+
+#include <stdio.h>
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+#include "File.h"
+
+class Tape;
+
+/**
+ * @short This class represents a single tar archive.
+ */
+class Archive {
+ bool _stubbed;
+
+ int _endBlock;
+ int _ctime;
+ FILE* _fptr;
+ int _offset;
+ QString _name;
+ QPtrList<File> _children;
+ RangeList _ranges;
+ Tape* _tape;
+public:
+ /**
+ * Create a new archive.
+ *
+ * @param tape The tape containing this archive.
+ * @param ctime The create time of the archive.
+ * @param name The name given to this archive by the user.
+ */
+ Archive( Tape* tape, int ctime, const QString & name );
+
+ /**
+ * Create a new stubbed instance of an archive. The file pointer and
+ * offset specify where the actual instance data can be found. The real
+ * data is read on demand when one of the accessor functions is called.
+ *
+ * @param tape The tape containing this archive.
+ * @param fptr The open index file containing this archive entry. The file
+ * must be left open so that the archive entry information can
+ * be read at a later time.
+ * @param offset The offset that will be seeked to when reading the archive
+ * entry information.
+ */
+ Archive( Tape* tape, FILE* fptr, int offset );
+
+ /**
+ * Destroy the archive entry and all of its children.
+ */
+ ~Archive();
+
+ /**
+ * Insure that all of the data fields for this archive entry have been read
+ * in. If the archive entry is a stub then the actual data is read from the
+ * index file. If the archive entry is not a stub then no action is taken.
+ *
+ * @param version The version of the old tape index.
+ */
+ void read( int version = KDAT_INDEX_FILE_VERSION );
+
+ /**
+ * Recursively read the instance data for this archive entry and all of its
+ * children. This method is used when converting from an older index format.
+ *
+ * @param version The version of the old tape index.
+ */
+ void readAll( int version );
+
+ /**
+ * Write out the archive entry to the open file. Entries for each of its
+ * children will also be written.
+ */
+ void write( FILE* fptr );
+
+ /**
+ * Get the creation time for this archive.
+ *
+ * @return The creation time in seconds since the Epoch.
+ */
+ int getCTime();
+
+ /**
+ * Get the last tape block of this archive.
+ *
+ * @return The last tape block used by this archive.
+ */
+ int getEndBlock();
+
+ /**
+ * Get the name of this archive.
+ *
+ * @return The name of this archive.
+ */
+ QString getName();
+
+ /**
+ * Get the tape that contains this archive.
+ *
+ * @return A pointer to the tape containing this archive.
+ */
+ Tape* getTape();
+
+ /**
+ * Get the list of top-level files in this archive.
+ *
+ * @return A list of the immediate children of this archive.
+ */
+ const QPtrList<File>& getChildren();
+
+ /**
+ * Get the list of ranges of this file and all of its children.
+ *
+ * @return A list of ranges.
+ */
+ const QPtrList<Range>& getRanges();
+
+ /**
+ * Set the ending tape block for this archive.
+ *
+ * @param endBlock The last tape block used by this archive.
+ */
+ void setEndBlock( int endBlock );
+
+ /**
+ * Set the name of this archive.
+ *
+ * @param name The new archive name.
+ */
+ void setName( const QString & name );
+
+ /**
+ * Add a new top level file as a child of this archive.
+ *
+ * @param file The file to add.
+ */
+ void addChild( File* file );
+
+ /**
+ * Create a new file entry, and add it to the archive. Based on the
+ * full path name of the file, an appropriate parent is found. The parent
+ * may be this archive or another file entry. File entries will be created
+ * on demand if some or all of the file's path does not yet exist in this
+ * archive.
+ *
+ * @param size The size, in bytes, of the file.
+ * @param mtime The last modification time for the file, in seconds since
+ * the Epoch.
+ * @param startRecord The first tar record number of this file.
+ * @param endRecord The last tar record number of this file.
+ * @param name The full path name for the file.
+ *
+ * @return A pointer to the newly created file entry.
+ */
+ File* addFile( int size, int mtime, int startRecord, int endRecord, const QString & filename );
+
+ /**
+ * Recursively calculate the list of ranges for all of the archive's children.
+ */
+ void calcRanges();
+};
+
+#endif
diff --git a/kdat/ArchiveInfoWidget.cpp b/kdat/ArchiveInfoWidget.cpp
new file mode 100644
index 0000000..225d229
--- /dev/null
+++ b/kdat/ArchiveInfoWidget.cpp
@@ -0,0 +1,145 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <time.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+
+#include <kapplication.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "Archive.h"
+#include "ArchiveInfoWidget.h"
+#include "Options.h"
+#include "Tape.h"
+#include "Util.h"
+#include <klocale.h>
+
+#include "ArchiveInfoWidget.moc"
+
+ArchiveInfoWidget::ArchiveInfoWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name ),
+ _archive( 0 )
+{
+ QLabel* lbl1 = new QLabel( i18n( "Archive name:" ), this );
+ QLabel* lbl2 = new QLabel( i18n( "Created on:" ), this );
+ QLabel* lbl3 = new QLabel( i18n( "Size:" ), this );
+
+ int max = lbl1->sizeHint().width();
+ if ( lbl2->sizeHint().width() > max ) max = lbl2->sizeHint().width();
+ if ( lbl3->sizeHint().width() > max ) max = lbl3->sizeHint().width();
+
+ lbl1->setFixedSize( max, lbl1->sizeHint().height() );
+ lbl2->setFixedSize( max, lbl2->sizeHint().height() );
+ lbl3->setFixedSize( max, lbl3->sizeHint().height() );
+
+ _archiveName = new QLineEdit( this );
+ _archiveName->setFixedHeight( _archiveName->sizeHint().height() );
+
+ _ctime = new QLabel( "???", this );
+ _ctime->setFixedHeight( _ctime->sizeHint().height() );
+
+ _size = new QLabel( "???", this );
+ _size->setFixedHeight( _size->sizeHint().height() );
+
+ _apply = new KPushButton( KStdGuiItem::apply(), this );
+ _apply->setFixedSize( 80, _apply->sizeHint().height() );
+ _apply->setEnabled( FALSE );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 4, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addWidget( lbl1 );
+ l1_1->addWidget( _archiveName, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addWidget( lbl2 );
+ l1_2->addWidget( _ctime );
+
+ QHBoxLayout* l1_3 = new QHBoxLayout();
+ l1->addLayout( l1_3 );
+ l1_3->addWidget( lbl3 );
+ l1_3->addWidget( _size );
+
+ l1->addStretch( 1 );
+
+ QHBoxLayout* l1_4 = new QHBoxLayout();
+ l1->addLayout( l1_4 );
+ l1_4->addStretch( 1 );
+ l1_4->addWidget( _apply );
+
+ connect( _archiveName, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotTextChanged( const QString& ) ) );
+ connect( _apply , SIGNAL( clicked() ) , this, SLOT( slotApply() ) );
+}
+
+ArchiveInfoWidget::~ArchiveInfoWidget()
+{
+}
+
+void ArchiveInfoWidget::setArchive( Archive* archive )
+{
+ _archive = archive;
+
+ if ( !_archive ) {
+ return;
+ }
+
+ _archiveName->setText( _archive->getName() );
+
+ QString tmp;
+ time_t tm = _archive->getCTime();
+ tmp = ctime( &tm );
+ tmp = tmp.stripWhiteSpace();
+ _ctime->setText( tmp );
+
+ int used = _archive->getEndBlock();
+ int blockSize = Options::instance()->getTapeBlockSize();
+ if ( blockSize < 1024 ) {
+ used /= 1024 / blockSize;
+ } else if ( blockSize > 1024 ) {
+ used *= blockSize / 1024;
+ }
+ _size->setText( Util::kbytesToString( used ) );
+}
+
+void ArchiveInfoWidget::slotTextChanged( const QString& text )
+{
+ if ( !_archive ) {
+ return;
+ }
+
+ _apply->setEnabled( _archive->getName() != text );
+}
+
+void ArchiveInfoWidget::slotApply()
+{
+ if ( !_archive ) {
+ return;
+ }
+
+ if ( _archive->getName() != _archiveName->text() ) {
+ _archive->setName( _archiveName->text() );
+ }
+
+ _apply->setEnabled( FALSE );
+}
diff --git a/kdat/ArchiveInfoWidget.h b/kdat/ArchiveInfoWidget.h
new file mode 100644
index 0000000..83d7bab
--- /dev/null
+++ b/kdat/ArchiveInfoWidget.h
@@ -0,0 +1,62 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _ArchiveInfoWidget_h_
+#define _ArchiveInfoWidget_h_
+
+#include <qwidget.h>
+
+class QLabel;
+class QLineEdit;
+class QPushButton;
+
+class Archive;
+
+/**
+ * @short Display/edit information about an archive index.
+ */
+class ArchiveInfoWidget : public QWidget {
+ Q_OBJECT
+ Archive* _archive;
+ QLineEdit* _archiveName;
+ QLabel* _ctime;
+ QLabel* _size;
+ QPushButton* _apply;
+private slots:
+ void slotTextChanged( const QString& text );
+ void slotApply();
+public:
+ /**
+ * Create a new archive info widget.
+ */
+ ArchiveInfoWidget( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the archive info widget.
+ */
+ ~ArchiveInfoWidget();
+
+ /**
+ * Change the archive index that the widget displays/edits.
+ *
+ * @param archive The new archive index to display/edit.
+ */
+ void setArchive( Archive* archive );
+};
+
+#endif
diff --git a/kdat/BackupDlg.cpp b/kdat/BackupDlg.cpp
new file mode 100644
index 0000000..1f237ab
--- /dev/null
+++ b/kdat/BackupDlg.cpp
@@ -0,0 +1,432 @@
+// $Id$
+//
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <assert.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+
+#include <qdir.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include <kapplication.h>
+#include <kprocess.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "Archive.h"
+#include "BackupDlg.h"
+#include "LoggerWidget.h"
+#include "Options.h"
+#include "Tape.h"
+#include "TapeDrive.h"
+#include "TarParser.h"
+#include "Util.h"
+#include <klocale.h>
+
+#include "BackupDlg.moc"
+
+BackupDlg::BackupDlg( const QString & archiveName, const QString & workingDir, const QStringList& files, bool oneFilesystem, bool incremental,
+ const QString & snapshot, bool removeSnapshot, int archiveSize, Tape* tape,
+ QWidget* parent, const char* name )
+ : QDialog( parent, name, TRUE ),
+ _proc( NULL ),
+ _tarParser( NULL ),
+ _archiveName( archiveName ),
+ _workingDir( workingDir ),
+ _files(files),
+ _oneFilesystem( oneFilesystem ),
+ _incremental( incremental ),
+ _snapshot( snapshot ),
+ _removeSnapshot( removeSnapshot ),
+ _archiveSize( archiveSize ),
+ _tape( tape ),
+ _totalKBytes( 0.0 ),
+ _totalRecords( 0 ),
+ _startTime( 0 ),
+ _archive( NULL ),
+ _aborted( FALSE ),
+ _numFiles( 0 ),
+ _fileSize( -1 ),
+ _fileMTime( -1 ),
+ _fileStartRecord( -1 )
+{
+ // Copy the list of files to archive.
+
+ setCaption( i18n( "KDat: Backup" ) );
+ setIconText( i18n( "KDat: Backup" ) );
+
+ resize( 515, 300 );
+
+ /* 2002-01-26 LEW: "Time remaining" was cut off in mid-"g"
+ so we'll provide that plus some space beyond it. */
+ // const int labelWidth = 96;
+ const int labelWidth = 110;
+
+ QFrame* f1 = new QFrame( this );
+ f1->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ QFrame* f2 = new QFrame( this );
+ f2->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ QLabel* lbl1 = new QLabel( i18n( "Elapsed time:" ), f1 );
+ lbl1->setFixedSize( labelWidth, lbl1->sizeHint().height() );
+
+ _elapsedTime = new QLabel( i18n( "00:00:00" ), f1 );
+ _elapsedTime->setFixedHeight( _elapsedTime->sizeHint().height() );
+
+ QLabel* lbl2 = new QLabel( i18n( "Time remaining:" ), f2 );
+ lbl2->setFixedSize( labelWidth, lbl2->sizeHint().height() );
+
+ _timeRemaining = new QLabel( i18n( "00:00:00" ), f2 );
+ _timeRemaining->setFixedHeight( _timeRemaining->sizeHint().height() );
+
+ QLabel* lbl3 = new QLabel( i18n( "Total KB:" ), f1 );
+ lbl3->setFixedSize( labelWidth, lbl3->sizeHint().height() );
+
+ QLabel* totalKbytes = new QLabel( Util::kbytesToString( archiveSize ), f1 );
+ totalKbytes->setFixedHeight( totalKbytes->sizeHint().height() );
+
+ QLabel* lbl4 = new QLabel( i18n( "KB written:" ), f2 );
+ lbl4->setFixedSize( labelWidth, lbl4->sizeHint().height() );
+
+ _kbytesWritten = new QLabel( i18n( "0KB" ), f2 );
+ _kbytesWritten->setFixedHeight( _kbytesWritten->sizeHint().height() );
+
+ QLabel* lbl5 = new QLabel( i18n( "Transfer rate:" ), f1 );
+ lbl5->setFixedSize( labelWidth, lbl5->sizeHint().height() );
+
+ _transferRate = new QLabel( i18n( "0KB/min" ), f1 );
+ _transferRate->setFixedHeight( _transferRate->sizeHint().height() );
+
+ QLabel* lbl6 = new QLabel( i18n( "Files:" ), f2 );
+ lbl6->setFixedSize( labelWidth, lbl6->sizeHint().height() );
+
+ _fileCount = new QLabel( i18n( "0" ), f2 );
+ _fileCount->setFixedHeight( _fileCount->sizeHint().height() );
+
+ _log = new LoggerWidget( i18n( "Backup log:" ), this );
+
+ _ok = new KPushButton( KStdGuiItem::ok(), this );
+ _ok->setFixedSize( 80, _ok->sizeHint().height() );
+ connect( _ok, SIGNAL( clicked() ), this, SLOT( slotOK() ) );
+ _ok->setEnabled( FALSE );
+
+ _save = new QPushButton( i18n( "Save Log..." ), this );
+ _save->setFixedSize( 80, _save->sizeHint().height() );
+ connect( _save, SIGNAL( clicked() ), _log, SLOT( save() ) );
+ _save->setEnabled( FALSE );
+
+ _abort = new KPushButton( KStdGuiItem::cancel(), this );
+ _abort->setFixedSize( 80, _abort->sizeHint().height() );
+ connect( _abort, SIGNAL( clicked() ), this, SLOT( slotAbort() ) );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 8, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addStrut( 3 * lbl1->height() + 16 );
+ l1_1->addWidget( f1 );
+ l1_1->addWidget( f2 );
+
+ QVBoxLayout* l1_1_1 = new QVBoxLayout( f1, 4, 4 );
+
+ QHBoxLayout* l1_1_1_1 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_1 );
+ l1_1_1_1->addWidget( lbl1 );
+ l1_1_1_1->addWidget( _elapsedTime, 1 );
+
+ QHBoxLayout* l1_1_1_2 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_2 );
+ l1_1_1_2->addWidget( lbl3 );
+ l1_1_1_2->addWidget( totalKbytes, 1 );
+
+ QHBoxLayout* l1_1_1_3 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_3 );
+ l1_1_1_3->addWidget( lbl5 );
+ l1_1_1_3->addWidget( _transferRate, 1 );
+
+ QVBoxLayout* l1_1_2 = new QVBoxLayout( f2, 4, 4 );
+
+ QHBoxLayout* l1_1_2_1 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_1 );
+ l1_1_2_1->addWidget( lbl2 );
+ l1_1_2_1->addWidget( _timeRemaining, 1 );
+
+ QHBoxLayout* l1_1_2_2 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_2 );
+ l1_1_2_2->addWidget( lbl4 );
+ l1_1_2_2->addWidget( _kbytesWritten, 1 );
+
+ QHBoxLayout* l1_1_2_3 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_3 );
+ l1_1_2_3->addWidget( lbl6 );
+ l1_1_2_3->addWidget( _fileCount, 1 );
+
+ l1->addWidget( _log, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addStretch( 1 );
+ l1_2->addWidget( _ok );
+ l1_2->addWidget( _save );
+ l1_2->addWidget( _abort );
+}
+
+BackupDlg::~BackupDlg()
+{
+ delete _tarParser;
+}
+
+void BackupDlg::show()
+{
+ bool bGoOn = false;
+
+ _archive = new Archive( _tape, time( NULL ), _archiveName.utf8() );
+
+ chdir( QFile::encodeName(_workingDir) );
+
+ if ( _removeSnapshot ) {
+ unlink( QFile::encodeName(_snapshot) );
+ }
+
+ _tarParser = new TarParser();
+ connect( _tarParser, SIGNAL( sigEntry( const QString &, int, int, int ) ), this, SLOT( slotEntry( const QString &, int, int, int ) ) );
+
+ _proc = new KProcess();
+ *_proc << Options::instance()->getTarCommand();
+ if ( _oneFilesystem ) {
+ *_proc << "-l";
+ }
+ if ( _incremental ) {
+ *_proc << "-g" << _snapshot;
+ }
+ *_proc << "-Spcf" << "-";
+
+ // Append the list of files to archive.
+ if ( _files.count() == 1 && _files.first() == "." ) {
+ dev_t device = 0;
+ struct stat info;
+ if ( _oneFilesystem ) {
+ if ( lstat( ".", &info ) == 0 ) {
+ device = info.st_dev;
+ }
+ }
+
+ // Backup all files in current working directory.
+ QDir dir;
+ //roland
+ //QStringList::Iterator i = dir.entryList( QDir::All, QDir::Name | QDir::DirsFirst ).begin();
+ QStringList FilesList = dir.entryList( QDir::All, QDir::Name | QDir::DirsFirst );
+ QStringList::Iterator i = FilesList.begin();
+ //roland
+ for ( ; !(*i).isNull() ; ++i ) {
+ if ( *i != "." && *i != ".." ) {
+ if ( _oneFilesystem ) {
+ if ( lstat( QFile::encodeName(*i), &info ) == 0 )
+ {
+ if ( info.st_dev == device ) {
+ *_proc << *i;
+ bGoOn = true;
+ }
+ }
+ } else {
+ *_proc << *i;
+ bGoOn = true;
+ }
+ }
+ }
+ } else {
+ // Backup listed files only.
+ /* 2002-01-28 LEW */
+ // printf("Fixing to list the files/dirs to be dumped:\n");
+ /* 2002-01-28 LEW */
+ for ( QStringList::Iterator it = _files.begin();
+ it != _files.end();
+ ++it ) {
+ /* 2002-01-28 LEW */
+ // printf("tar argument: \"%s\"\n", (*it).latin1());
+ /* 2002-01-28 LEW */
+ *_proc << *it;
+ bGoOn = true;
+ }
+ }
+
+ if (bGoOn == false) {
+ KMessageBox::information(this, i18n("No files to back up. Aborting."));
+ slotAbort();
+ return;
+ }
+
+ connect( _proc, SIGNAL( processExited( KProcess* ) ), this, SLOT( slotProcessExited( KProcess* ) ) );
+ connect( _proc, SIGNAL( receivedStdout( KProcess*, char*, int ) ), this, SLOT( slotStdout( KProcess*, char*, int ) ) );
+
+ startTimer( 1000 );
+
+ _proc->start( KProcess::NotifyOnExit, KProcess::Stdout );
+
+ QDialog::show();
+}
+
+void BackupDlg::slotProcessExited( KProcess* )
+{
+ updateStats();
+
+ _archive->setEndBlock( _totalRecords / ( Options::instance()->getTapeBlockSize() / 512 ) );
+
+ if ( _fileName.length() > 0 ) {
+ _archive->addFile( _fileSize, _fileMTime, _fileStartRecord, _totalRecords, _fileName );
+ _fileName = QString::null;
+ }
+
+ TapeDrive::instance()->close();
+ TapeDrive::instance()->open();
+
+ killTimers();
+ delete _proc;
+
+ _tape->addChild( _archive );
+
+ _ok->setEnabled( TRUE );
+ _ok->setDefault( TRUE );
+ _save->setEnabled( TRUE );
+ _abort->setEnabled( FALSE );
+}
+
+// the KProcess passes the arguments to tar, and tar's output is piped here.
+// The output is shown to _tarParser->slotData(), which figures out which files
+// are going to tape and their file parameters, and saves these data into
+// kdat's archive. The raw data are then written to tape with write().
+// 2002-01-27 LEW
+void BackupDlg::slotStdout( KProcess*, char* buf, int len )
+{
+ // Don't start throughput timer until the first block of data is written.
+ if ( _startTime == 0 ) {
+ _startTime = time( NULL );
+ }
+
+ /* 2002-01-26 LEW */
+ // printf("got a line from tar, length %d bytes...\n", len);
+ /* 2002-01-26 LEW */
+
+ // Pass the data through the tar parser to extract the file info.
+ _tarParser->slotData( buf, len );
+
+ _totalKBytes += (float)len / 1024.0;
+ assert( len % 512 == 0 );
+ _totalRecords += len / 512;
+ if ( TapeDrive::instance()->write( buf, len ) < len ) {
+ _log->append( i18n( "*** Write failed, giving up." ) );
+
+ if ( _proc ) {
+ _proc->kill();
+ }
+
+ slotProcessExited( 0 );
+ }
+}
+
+void BackupDlg::slotEntry( const QString& name, int size, int mtime, int record )
+{
+ if ( _fileName.length() > 0 ) {
+ _archive->addFile( _fileSize, _fileMTime, _fileStartRecord, record, _fileName );
+ }
+
+ /* 2002-01-28 LEW */
+ // printf("BackupDlg::slotEntry called with \"%s\", %d bytes\n", name.latin1(), size);
+ /* 2002-01-28 LEW */
+
+ _fileName = name;
+ _fileSize = size;
+ _fileMTime = mtime;
+ _fileStartRecord = record;
+
+ QString tmp;
+ tmp.setNum( ++_numFiles );
+ _fileCount->setText( tmp );
+ _log->append( name );
+}
+
+void BackupDlg::slotOK()
+{
+ if ( _aborted ) {
+ reject();
+ } else {
+ accept();
+ }
+}
+
+void BackupDlg::slotAbort()
+{
+ killTimers();
+ if ( _proc ) {
+ _proc->kill();
+ delete _proc;
+ }
+ delete _archive;
+ _aborted = TRUE;
+
+ _ok->setEnabled( TRUE );
+ _ok->setDefault( TRUE );
+ _save->setEnabled( TRUE );
+ _abort->setEnabled( FALSE );
+}
+
+void BackupDlg::timerEvent( QTimerEvent* )
+{
+ updateStats();
+}
+
+void BackupDlg::updateStats()
+{
+ if ( _startTime == 0 ) {
+ return;
+ }
+
+ QString str;
+
+ int elapsed = time( NULL ) - _startTime;
+ str = QString::fromUtf8( QCString().sprintf( i18n( "%02d:%02d:%02d" ).utf8().data(), elapsed / 3600, elapsed / 60 % 60, elapsed % 60 ) );
+ _elapsedTime->setText( str );
+
+ int remain = 0;
+ if ( (int)_totalKBytes > 0 ) {
+ remain = (int)(( (float)_archiveSize - _totalKBytes ) * (float)elapsed / _totalKBytes);
+ }
+ if ( remain < 0 ) {
+ remain = 0;
+ }
+ str = QString::fromUtf8( QCString().sprintf( i18n( "%02d:%02d:%02d" ).utf8().data(), remain / 3600, remain / 60 % 60, remain % 60 ) );
+ _timeRemaining->setText( str );
+
+ str = Util::kbytesToString( (int)_totalKBytes );
+ _kbytesWritten->setText( str );
+
+ if ( elapsed > 0 ) {
+ str = i18n( "%1/min" ).arg(Util::kbytesToString( (int)_totalKBytes *60 / elapsed ) );
+ _transferRate->setText( str );
+ }
+}
diff --git a/kdat/BackupDlg.h b/kdat/BackupDlg.h
new file mode 100644
index 0000000..d15f5c4
--- /dev/null
+++ b/kdat/BackupDlg.h
@@ -0,0 +1,108 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _BackupDlg_h_
+#define _BackupDlg_h_
+
+#include <qdialog.h>
+
+class QLabel;
+class QPushButton;
+
+class KProcess;
+
+class Archive;
+class File;
+class LoggerWidget;
+class Tape;
+class TarParser;
+
+/**
+ * @short Status dialog for backing up files.
+ */
+class BackupDlg : public QDialog {
+ Q_OBJECT
+ KProcess* _proc;
+ TarParser* _tarParser;
+ QString _archiveName;
+ QString _workingDir;
+ QStringList _files;
+ bool _oneFilesystem;
+ bool _incremental;
+ QString _snapshot;
+ bool _removeSnapshot;
+ int _archiveSize;
+ Tape* _tape;
+ float _totalKBytes;
+ uint _totalRecords;
+ QLabel* _elapsedTime;
+ QLabel* _timeRemaining;
+ QLabel* _kbytesWritten;
+ QLabel* _transferRate;
+ QLabel* _fileCount;
+ LoggerWidget* _log;
+ QPushButton* _ok;
+ QPushButton* _save;
+ QPushButton* _abort;
+ int _startTime;
+ Archive* _archive;
+ bool _aborted;
+ int _numFiles;
+
+ int _fileSize;
+ int _fileMTime;
+ int _fileStartRecord;
+ QString _fileName;
+
+ void updateStats();
+private slots:
+ void slotProcessExited( KProcess* proc );
+ void slotStdout( KProcess* proc, char* buf, int len );
+ void slotOK();
+ void slotAbort();
+ void slotEntry( const QString& name, int size, int mtime, int record );
+protected:
+ void show();
+ void timerEvent( QTimerEvent* e );
+public:
+ /**
+ * Create a backup dialog.
+ *
+ * @param archiveName The name for the new archive.
+ * @param workingDir The directory to backup from.
+ * @param files The list of files to backup.
+ * @param oneFilesystem TRUE means do not follow symbolic links across filesystems.
+ * @param incremental TRUE mean do a GNU listed incremental backup.
+ * @param snapshot The name of the snapshot file for an incremental backup.
+ * @param removeSnapshot Remove the snapshot before backing up.
+ * @param archiveSize The estimate size of the archive in kilobytes.
+ * @param tape The tape index to add the archive to.
+ * @param parent The parent widget for this dialog.
+ * @param name The name of this widget.
+ */
+ BackupDlg( const QString & archiveName, const QString & workingDir, const QStringList& files, bool oneFilesystem, bool incremental,
+ const QString & snapshot, bool removeSnapshot, int archiveSize, Tape* tape,
+ QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the backup dialog.
+ */
+ ~BackupDlg();
+};
+
+#endif
diff --git a/kdat/BackupOptDlg.cpp b/kdat/BackupOptDlg.cpp
new file mode 100644
index 0000000..de4622a
--- /dev/null
+++ b/kdat/BackupOptDlg.cpp
@@ -0,0 +1,100 @@
+// $Id$
+//
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <qlayout.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include <kapplication.h>
+
+#include "BackupOptDlg.h"
+#include "BackupProfileWidget.h"
+#include <klocale.h>
+
+#include "BackupOptDlg.moc"
+
+BackupOptDlg::BackupOptDlg( BackupProfile* backupProfile, QWidget* parent, const char* name )
+ : QDialog( parent, name, TRUE )
+{
+ setIconText( i18n( "KDat: Backup Options" ) );
+ setCaption( i18n( "KDat: Backup Options" ) );
+
+ resize( 400, 300 );
+
+ _profile = new BackupProfileWidget( this );
+ _profile->setBackupProfile( backupProfile );
+
+ KPushButton* ok = new KPushButton( KStdGuiItem::ok(), this );
+ ok->setFixedSize( 80, ok->sizeHint().height() );
+ connect( ok, SIGNAL( clicked() ), this, SLOT( accept() ) );
+ KPushButton* cancel = new KPushButton( KStdGuiItem::cancel(), this );
+ cancel->setFixedSize( 80, ok->sizeHint().height() );
+ connect( cancel, SIGNAL( clicked() ), this, SLOT( reject() ) );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 8, 4 );
+ l1->addWidget( _profile, 1 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addStretch( 1 );
+ l1_1->addWidget( ok );
+ l1_1->addWidget( cancel );
+
+ ok->setDefault( TRUE );
+}
+
+BackupOptDlg::~BackupOptDlg()
+{
+}
+
+QString BackupOptDlg::getArchiveName()
+{
+ return _profile->getArchiveName();
+}
+
+QString BackupOptDlg::getWorkingDirectory()
+{
+ return _profile->getWorkingDirectory();
+}
+
+const QStringList& BackupOptDlg::getRelativeFiles()
+{
+ return _profile->getRelativeFiles();
+}
+
+bool BackupOptDlg::isOneFilesystem()
+{
+ return _profile->isOneFilesystem();
+}
+
+bool BackupOptDlg::isIncremental()
+{
+ return _profile->isIncremental();
+}
+
+QString BackupOptDlg::getSnapshotFile()
+{
+ return _profile->getSnapshotFile();
+}
+
+bool BackupOptDlg::getRemoveSnapshot()
+{
+ return _profile->getRemoveSnapshot();
+}
diff --git a/kdat/BackupOptDlg.h b/kdat/BackupOptDlg.h
new file mode 100644
index 0000000..f76a7da
--- /dev/null
+++ b/kdat/BackupOptDlg.h
@@ -0,0 +1,99 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _BackupOptDlg_h_
+#define _BackupOptDlg_h_
+
+#include <qdialog.h>
+
+class BackupProfile;
+class BackupProfileWidget;
+
+/**
+ * @short Display/edit the parameters for a backup operation.
+ */
+class BackupOptDlg : public QDialog {
+ Q_OBJECT
+ BackupProfileWidget* _profile;
+public:
+ /**
+ * Create a backup options dialog.
+ *
+ * @param backupProfile The backup profile.
+ */
+ BackupOptDlg( BackupProfile* backupProfile, QWidget* parent=0, const char* name=0 );
+
+ /**
+ * Destroy the backup options dialog.
+ */
+ ~BackupOptDlg();
+
+ /**
+ * Query the name of the archive.
+ *
+ * @return The name of the new archive.
+ */
+ QString getArchiveName();
+
+ /**
+ * Query the working directory for the tar command.
+ *
+ * @return The working directory.
+ */
+ QString getWorkingDirectory();
+
+ /**
+ * Query the list of files to backup, relative to the working directory.
+ *
+ * @return The file list.
+ */
+ const QStringList& getRelativeFiles();
+
+ /**
+ * Query whether or not to cross filesystem boundaries when performing the
+ * backup.
+ *
+ * @return TRUE if the backup is restricted to a single filesystem, FALSE
+ * if the backup can cross filesystem boundaries.
+ */
+ bool isOneFilesystem();
+
+ /**
+ * Query whether this is to be a GNU incremental backup.
+ *
+ * @return TRUE if incremental, otherwise FALSE.
+ */
+ bool isIncremental();
+
+ /**
+ * Query the name of the snapshot file to use for an incremental backup.
+ *
+ * @return The name of the snapshot file.
+ */
+ QString getSnapshotFile();
+
+ /**
+ * Query whether to remove the snapshot file before beginning an
+ * incremental backup. This has the effect of performing a full backup.
+ *
+ * @return TRUE if the snapshot file should be removed, otherwise FALSE.
+ */
+ bool getRemoveSnapshot();
+};
+
+#endif
diff --git a/kdat/BackupProfile.cpp b/kdat/BackupProfile.cpp
new file mode 100644
index 0000000..2116005
--- /dev/null
+++ b/kdat/BackupProfile.cpp
@@ -0,0 +1,293 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qfile.h>
+
+#include <kstandarddirs.h>
+
+#include "BackupProfile.h"
+#include "BackupProfileManager.h"
+#include "Util.h"
+
+BackupProfile::BackupProfile()
+{
+}
+
+BackupProfile::BackupProfile( const QString & name )
+ : _name( name ),
+ _lastSavedName( name )
+{
+ load();
+}
+
+BackupProfile::~BackupProfile()
+{
+}
+
+void BackupProfile::load()
+{
+ QString filename = locateLocal( "appdata", _lastSavedName + ".bp");
+
+ FILE* fptr = fopen( QFile::encodeName(filename), "r" );
+ if ( !fptr ) {
+ return;
+ }
+
+ char buf[4096];
+
+ fgets( buf, 4096, fptr );
+ int version = 0;
+ sscanf( buf, "%d", &version );
+
+ fgets( buf, 4096, fptr );
+ _name = buf;
+ _name.truncate( _name.length() - 1 );
+
+ fgets( buf, 4096, fptr );
+ _archiveName = buf;
+ _archiveName.truncate( _archiveName.length() - 1 );
+
+ fgets( buf, 4096, fptr );
+ _workingDirectory = buf;
+ _workingDirectory.truncate( _workingDirectory.length() - 1 );
+
+ _absoluteFiles.clear();
+ fgets( buf, 4096, fptr );
+ int filecount = 0;
+ sscanf( buf, "%d", &filecount );
+ for ( int i = 0; i < filecount; i++ ) {
+ fgets( buf, 4096, fptr );
+ QString filename = buf;
+ filename.truncate( filename.length() - 1 );
+ _absoluteFiles.append( filename );
+ }
+
+ calcRelativeFiles();
+
+ fgets( buf, 4096, fptr );
+ int tmpBool = 0;
+ sscanf( buf, "%d", &tmpBool );
+ _oneFilesystem = tmpBool;
+
+ fgets( buf, 4096, fptr );
+ sscanf( buf, "%d", &tmpBool );
+ _incremental = tmpBool;
+
+ fgets( buf, 4096, fptr );
+ _snapshotFile = buf;
+ _snapshotFile.truncate( _snapshotFile.length() - 1 );
+
+ fgets( buf, 4096, fptr );
+ sscanf( buf, "%d", &tmpBool );
+ _removeSnapshot = tmpBool;
+
+ fclose( fptr );
+}
+
+void BackupProfile::save()
+{
+ QString filename = locateLocal( "appdata", _lastSavedName + ".bp");
+ bool null_name_p = _lastSavedName.isEmpty();
+
+ _lastSavedName = _name.copy();
+
+ if( TRUE == null_name_p ){
+ return;
+ }
+
+ unlink( QFile::encodeName(filename) );
+
+ FILE* fptr = fopen( QFile::encodeName(filename), "w" );
+ if ( !fptr ) {
+ return;
+ }
+
+ fprintf( fptr, "%d\n", 1 ); // Version
+ fprintf( fptr, "%s\n", _name.utf8().data() );
+ fprintf( fptr, "%s\n", _archiveName.utf8().data() );
+ fprintf( fptr, "%s\n", _workingDirectory.utf8().data() );
+ fprintf( fptr, "%d\n", _absoluteFiles.count() );
+ for ( QStringList::Iterator it = _absoluteFiles.begin();
+ it != _absoluteFiles.end();
+ ++it )
+ fprintf( fptr, "%s\n", (*it).utf8().data() );
+ fprintf( fptr, "%d\n", _oneFilesystem );
+ fprintf( fptr, "%d\n", _incremental );
+ fprintf( fptr, "%s\n", _snapshotFile.utf8().data() );
+ fprintf( fptr, "%d\n", _removeSnapshot );
+
+ fclose( fptr );
+}
+
+QString BackupProfile::getName()
+{
+ return _name;
+}
+
+QString BackupProfile::getArchiveName()
+{
+ return _archiveName;
+}
+
+QString BackupProfile::getWorkingDirectory()
+{
+ return _workingDirectory;
+
+ // LEW: is this fix necessary?
+#ifdef LEW
+ if ( FALSE == _workingDirectory.isEmpty() ) {
+ return _workingDirectory;
+ } else {
+ return 0;
+ }
+#endif
+}
+
+const QStringList& BackupProfile::getRelativeFiles()
+{
+ return _relativeFiles;
+}
+
+const QStringList& BackupProfile::getAbsoluteFiles()
+{
+ return _absoluteFiles;
+}
+
+bool BackupProfile::isOneFilesystem()
+{
+ return _oneFilesystem;
+}
+
+bool BackupProfile::isIncremental()
+{
+ return _incremental;
+}
+
+QString BackupProfile::getSnapshotFile()
+{
+ return _snapshotFile;
+}
+
+bool BackupProfile::getRemoveSnapshot()
+{
+ return _removeSnapshot;
+}
+
+void BackupProfile::setName( const QString & name )
+{
+ _name = name;
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::setArchiveName( const QString & archiveName )
+{
+ _archiveName = archiveName;
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::setWorkingDirectory( const QString & workingDirectory )
+{
+ _workingDirectory = workingDirectory;
+
+ // Regenerate the list of relative files.
+ calcRelativeFiles();
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::setAbsoluteFiles( const QStringList& files )
+{
+ _absoluteFiles = files;
+
+ // Make sure working directory is still valid.
+ QStringList::Iterator it = _absoluteFiles.begin();
+ for ( ;
+ it != _absoluteFiles.end();
+ ++it )
+ {
+ if ( *it != _workingDirectory ) {
+ // Working directory is not a prefix for this file.
+ break;
+ }
+ }
+
+ if ( it != _absoluteFiles.end() ) {
+ // Pick another working directory.
+ _workingDirectory = Util::longestCommonPath( _absoluteFiles );
+ }
+
+ // Regenerate the list of relative files.
+ calcRelativeFiles();
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::setOneFilesystem( bool oneFilesystem )
+{
+ _oneFilesystem = oneFilesystem;
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::setIncremental( bool incremental )
+{
+ _incremental = incremental;
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::setSnapshotFile( const QString & snapshotFile )
+{
+ _snapshotFile = snapshotFile;
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::setRemoveSnapshot( bool removeSnapshot )
+{
+ _removeSnapshot = removeSnapshot;
+
+ BackupProfileManager::instance()->backupProfileModified( this );
+}
+
+void BackupProfile::calcRelativeFiles()
+{
+ _relativeFiles.clear();
+ int remove = _workingDirectory.length();
+ if ( remove > 1 ) {
+ remove++;
+ }
+
+ for ( QStringList::Iterator it = _absoluteFiles.begin();
+ it != _absoluteFiles.end();
+ ++it )
+ {
+ QString fn = *it;
+ fn.remove( 0, remove );
+ if ( fn.isEmpty() ) {
+ fn = ".";
+ }
+ _relativeFiles.append( fn );
+ }
+}
diff --git a/kdat/BackupProfile.h b/kdat/BackupProfile.h
new file mode 100644
index 0000000..2438fc5
--- /dev/null
+++ b/kdat/BackupProfile.h
@@ -0,0 +1,198 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _BackupProfile_h_
+#define _BackupProfile_h_
+
+#include <qstring.h>
+#include <qstrlist.h>
+
+/**
+ * @short This class stores all the information necessary to perform a backup.
+ */
+class BackupProfile {
+ QString _name;
+ QString _lastSavedName;
+ QString _archiveName;
+ QString _workingDirectory;
+ QStringList _relativeFiles;
+ QStringList _absoluteFiles;
+ bool _oneFilesystem;
+ bool _incremental;
+ QString _snapshotFile;
+ bool _removeSnapshot;
+
+ void calcRelativeFiles();
+public:
+ /**
+ * Create a new backup profile.
+ */
+ BackupProfile();
+
+ /**
+ * Load the named backup profile from disk.
+ *
+ * @param name The name of the backup profile.
+ */
+ BackupProfile( const QString & name );
+
+ /**
+ * Destroy the backup profile.
+ */
+ ~BackupProfile();
+
+ /**
+ * Load the backup profile from disk.
+ */
+ void load();
+
+ /**
+ * Save the backup profile to disk. If the backup profile was renamed,
+ * the old backup profile will be removed.
+ */
+ void save();
+
+ /**
+ * Query the name of this backup profile.
+ *
+ * @return The name of this profile.
+ */
+ QString getName();
+
+ /**
+ * Query the name of the archive.
+ *
+ * @return The name of the new archive.
+ */
+ QString getArchiveName();
+
+ /**
+ * Query the working directory for the tar command.
+ *
+ * @return The working directory.
+ */
+ QString getWorkingDirectory();
+
+ /**
+ * Query the list of files to backup, relative to the working directory.
+ *
+ * @return The file list.
+ */
+ const QStringList& getRelativeFiles();
+
+ /**
+ * Query the list of files to backup, with their full paths.
+ *
+ * @return The file list.
+ */
+ const QStringList& getAbsoluteFiles();
+
+ /**
+ * Query whether or not to cross filesystem boundaries when performing the
+ * backup.
+ *
+ * @return TRUE if the backup is restricted to a single filesystem, FALSE
+ * if the backup can cross filesystem boundaries.
+ */
+ bool isOneFilesystem();
+
+ /**
+ * Query whether this is to be a GNU incremental backup.
+ *
+ * @return TRUE if incremental, otherwise FALSE.
+ */
+ bool isIncremental();
+
+ /**
+ * Query the name of the snapshot file to use for an incremental backup.
+ *
+ * @return The name of the snapshot file.
+ */
+ QString getSnapshotFile();
+
+ /**
+ * Query whether to remove the snapshot file before beginning an
+ * incremental backup. This has the effect of performing a full backup.
+ *
+ * @return TRUE if the snapshot file should be removed, otherwise FALSE.
+ */
+ bool getRemoveSnapshot();
+
+ /**
+ * Set the name of this backup profile.
+ *
+ * @param name The name of this profile.
+ */
+ void setName( const QString & name );
+
+ /**
+ * Set the name of the archive.
+ *
+ * @param archiveName The name of the new archive.
+ */
+ void setArchiveName( const QString & archiveName );
+
+ /**
+ * Set the working directory for the tar command.
+ *
+ * @param workingDirectory The working directory.
+ */
+ void setWorkingDirectory( const QString & workingDirectory );
+
+ /**
+ * Set the list of files to backup, with their full paths.
+ *
+ * @param files The file list.
+ */
+ void setAbsoluteFiles( const QStringList& files );
+
+ /**
+ * Set whether or not to cross filesystem boundaries when performing the
+ * backup.
+ *
+ * @param oneFilesystem TRUE if the backup is restricted to a single
+ * filesystem, FALSE if the backup can cross
+ * filesystem boundaries.
+ */
+ void setOneFilesystem( bool oneFilesystem );
+
+ /**
+ * Set whether this is to be a GNU incremental backup.
+ *
+ * @param incremental TRUE if incremental, otherwise FALSE.
+ */
+ void setIncremental( bool incremental );
+
+ /**
+ * Set the name of the snapshot file to use for an incremental backup.
+ *
+ * @param snapshotFile The name of the snapshot file.
+ */
+ void setSnapshotFile( const QString & snapshotFile );
+
+ /**
+ * Set whether to remove the snapshot file before beginning an
+ * incremental backup. This has the effect of performing a full backup.
+ *
+ * @param removeSnapshot TRUE if the snapshot file should be removed,
+ * otherwise FALSE.
+ */
+ void setRemoveSnapshot( bool removeSnapshot );
+};
+
+#endif
diff --git a/kdat/BackupProfileInfoWidget.cpp b/kdat/BackupProfileInfoWidget.cpp
new file mode 100644
index 0000000..e294c04
--- /dev/null
+++ b/kdat/BackupProfileInfoWidget.cpp
@@ -0,0 +1,209 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+
+#include <kapplication.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "BackupProfile.h"
+#include "BackupProfileInfoWidget.h"
+#include "BackupProfileWidget.h"
+#include "KDatMainWindow.h"
+#include "Options.h"
+#include <klocale.h>
+
+#include "BackupProfileInfoWidget.moc"
+
+BackupProfileInfoWidget::BackupProfileInfoWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name ),
+ _backupProfile( 0 )
+{
+ QLabel* lbl1 = new QLabel( i18n( "Backup profile name:" ), this );
+
+ int max = lbl1->sizeHint().width();
+
+ lbl1->setFixedSize( max, lbl1->sizeHint().height() );
+
+ _name = new QLineEdit( this );
+ _name->setFixedHeight( _name->sizeHint().height() );
+
+ _profile = new BackupProfileWidget( this );
+
+ QPushButton* getSelection = new QPushButton( i18n( "Files >>" ), this );
+ getSelection->setFixedSize( 80, getSelection->sizeHint().height() );
+
+ QPushButton* setSelection = new QPushButton( i18n( "<< Files" ), this );
+ setSelection->setFixedSize( 80, setSelection->sizeHint().height() );
+
+ _apply = new KPushButton( KStdGuiItem::apply(), this );
+ _apply->setFixedSize( 80, _apply->sizeHint().height() );
+ _apply->setEnabled( FALSE );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 4, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addWidget( lbl1 );
+ l1_1->addWidget( _name, 1 );
+
+ l1->addWidget( _profile, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addWidget( setSelection );
+ l1_2->addWidget( getSelection );
+ l1_2->addStretch( 1 );
+ l1_2->addWidget( _apply );
+
+ connect( setSelection, SIGNAL( clicked() ) , this, SLOT( slotSetSelection() ) );
+ connect( getSelection, SIGNAL( clicked() ) , this, SLOT( slotGetSelection() ) );
+ connect( _name , SIGNAL( textChanged( const QString & ) ), this, SLOT( slotTextChanged( const QString & ) ) );
+ connect( _profile , SIGNAL( sigSomethingChanged() ) , this, SLOT( slotSomethingChanged() ) );
+ connect( _apply , SIGNAL( clicked() ) , this, SLOT( slotApply() ) );
+}
+
+BackupProfileInfoWidget::~BackupProfileInfoWidget()
+{
+}
+
+void BackupProfileInfoWidget::setBackupProfile( BackupProfile* backupProfile )
+{
+ _backupProfile = backupProfile;
+
+ if ( !_backupProfile ) {
+ return;
+ }
+
+ _name->setText( _backupProfile->getName() );
+
+ _profile->setBackupProfile( _backupProfile );
+}
+
+bool BackupProfileInfoWidget::isModified()
+{
+ if ( _backupProfile->getName() != _name->text() ) {
+ return TRUE;
+ }
+
+ if ( _profile->getArchiveName() != _backupProfile->getArchiveName() ) {
+ return TRUE;
+ }
+
+ QString one = _backupProfile->getWorkingDirectory();
+ QString two = _profile->getWorkingDirectory();
+ // 7/31/01: this breaks
+ // if ( _profile->getWorkingDirectory() != _backupProfile->getWorkingDirectory() ) {
+ if( one != two ){
+ return TRUE;
+ }
+
+ if ( _profile->getAbsoluteFiles().count() != _backupProfile->getAbsoluteFiles().count() ) {
+ return TRUE;
+ }
+
+ QStringList list1 = _profile->getAbsoluteFiles();
+ QStringList list2 = _backupProfile->getAbsoluteFiles();
+ QStringList::Iterator i = list1.begin();
+ QStringList::Iterator j = list2.begin();
+ for ( ; i != list1.end(); ++i ) {
+ for ( ; j != list2.end(); ++j ) {
+ if ( *i == *j ) {
+ break;
+ }
+ }
+ if ( j == list2.end() ) {
+ // Could not find i.current() in j => lists are not equal.
+ return TRUE;
+ }
+ }
+
+ if ( _profile->isOneFilesystem() != _backupProfile->isOneFilesystem() ) {
+ return TRUE;
+ }
+
+ if ( _profile->isIncremental() != _backupProfile->isIncremental() ) {
+ return TRUE;
+ }
+
+ if ( _profile->getSnapshotFile() != _backupProfile->getSnapshotFile() ) {
+ return TRUE;
+ }
+
+ if ( _profile->getRemoveSnapshot() != _backupProfile->getRemoveSnapshot() ) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void BackupProfileInfoWidget::slotTextChanged( const QString & )
+{
+ if ( !_backupProfile ) {
+ return;
+ }
+
+ _apply->setEnabled( isModified() );
+}
+
+void BackupProfileInfoWidget::slotSomethingChanged()
+{
+ if ( !_backupProfile ) {
+ return;
+ }
+
+ _apply->setEnabled( isModified() );
+}
+
+void BackupProfileInfoWidget::slotApply()
+{
+ if ( !_backupProfile ) {
+ return;
+ }
+
+ _backupProfile->setName( _name->text() );
+ _backupProfile->setArchiveName( _profile->getArchiveName() );
+ _backupProfile->setWorkingDirectory( _profile->getWorkingDirectory() );
+ _backupProfile->setAbsoluteFiles( _profile->getAbsoluteFiles() );
+ _backupProfile->setOneFilesystem( _profile->isOneFilesystem() );
+ _backupProfile->setIncremental( _profile->isIncremental() );
+ _backupProfile->setSnapshotFile( _profile->getSnapshotFile() );
+ _backupProfile->setRemoveSnapshot( _profile->getRemoveSnapshot() );
+
+ _backupProfile->save();
+
+ _apply->setEnabled( FALSE );
+}
+
+void BackupProfileInfoWidget::slotSetSelection()
+{
+ KDatMainWindow::getInstance()->setBackupFiles( _profile->getAbsoluteFiles() );
+}
+
+void BackupProfileInfoWidget::slotGetSelection()
+{
+ QStringList files;
+ KDatMainWindow::getInstance()->getBackupFiles( files );
+ _profile->setAbsoluteFiles( files );
+}
diff --git a/kdat/BackupProfileInfoWidget.h b/kdat/BackupProfileInfoWidget.h
new file mode 100644
index 0000000..413cf63
--- /dev/null
+++ b/kdat/BackupProfileInfoWidget.h
@@ -0,0 +1,62 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _BackupProfileInfoWidget_h_
+#define _BackupProfileInfoWidget_h_
+
+#include <qwidget.h>
+
+class BackupProfileWidget;
+
+/**
+ * @short Display/edit information about a backup profile.
+ */
+class BackupProfileInfoWidget : public QWidget {
+ Q_OBJECT
+ BackupProfile* _backupProfile;
+ QLineEdit* _name;
+ BackupProfileWidget* _profile;
+ QPushButton* _apply;
+
+ bool isModified();
+private slots:
+ void slotTextChanged( const QString & text );
+ void slotSomethingChanged();
+ void slotApply();
+ void slotSetSelection();
+ void slotGetSelection();
+public:
+ /**
+ * Create a new backup profile info widget.
+ */
+ BackupProfileInfoWidget( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the backup profile widget.
+ */
+ ~BackupProfileInfoWidget();
+
+ /**
+ * Change the backup profile that the widget displays/edits.
+ *
+ * @param backupProfile The new backup profile to display/edit.
+ */
+ void setBackupProfile( BackupProfile* backupProfile );
+};
+
+#endif
diff --git a/kdat/BackupProfileManager.cpp b/kdat/BackupProfileManager.cpp
new file mode 100644
index 0000000..7fc2411
--- /dev/null
+++ b/kdat/BackupProfileManager.cpp
@@ -0,0 +1,112 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qdir.h>
+#include <qregexp.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#include "BackupProfileManager.h"
+
+#include "BackupProfileManager.moc"
+
+BackupProfileManager::BackupProfileManager()
+{
+ _backupProfiles.setAutoDelete( TRUE );
+
+ // Get a list of all available backup profiles.
+ QStringList relList;
+ (void) KGlobal::dirs()->findAllResources( "appdata", "*.bp", false, true, relList);
+
+ for(QStringList::Iterator it = relList.begin();
+ it != relList.end();
+ it++)
+ {
+ QString fn = *it;
+ // Strip extension
+ _backupProfileNames.append( fn.left( fn.length() - 3 ) );
+ }
+}
+
+BackupProfileManager::~BackupProfileManager()
+{
+}
+
+BackupProfileManager* BackupProfileManager::_instance = 0;
+
+BackupProfileManager* BackupProfileManager::instance()
+{
+ if ( _instance == 0 ) {
+ _instance = new BackupProfileManager();
+ }
+
+ return _instance;
+}
+
+const QStringList& BackupProfileManager::getBackupProfileNames()
+{
+ return _backupProfileNames;
+}
+
+BackupProfile* BackupProfileManager::findBackupProfile( const QString & name )
+{
+ BackupProfile* backupProfile = _backupProfiles[ name ];
+
+ if ( !backupProfile ) {
+ backupProfile = new BackupProfile( name );
+ _backupProfiles.insert( backupProfile->getName(), backupProfile );
+ }
+
+ return backupProfile;
+}
+
+void BackupProfileManager::addBackupProfile( BackupProfile* backupProfile )
+{
+ BackupProfile* old = _backupProfiles[ backupProfile->getName() ];
+ if ( old ) {
+ removeBackupProfile( old );
+ }
+
+ _backupProfileNames.append( backupProfile->getName() );
+ _backupProfiles.insert( backupProfile->getName(), backupProfile );
+
+ emit sigBackupProfileAdded( backupProfile );
+}
+
+void BackupProfileManager::removeBackupProfile( BackupProfile* backupProfile )
+{
+ emit sigBackupProfileRemoved( backupProfile );
+
+ // Remove the index file.
+ QString filename = locateLocal( "appdata",
+ QString(backupProfile->getName()) + ".bp");
+
+ unlink( QFile::encodeName(filename) );
+
+ _backupProfileNames.remove( backupProfile->getName() );
+ _backupProfiles.remove( backupProfile->getName() );
+}
+
+void BackupProfileManager::backupProfileModified( BackupProfile* backupProfile )
+{
+ emit sigBackupProfileModified( backupProfile );
+}
diff --git a/kdat/BackupProfileManager.h b/kdat/BackupProfileManager.h
new file mode 100644
index 0000000..fa6939e
--- /dev/null
+++ b/kdat/BackupProfileManager.h
@@ -0,0 +1,120 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _BackupProfileManager_h_
+#define _BackupProfileManager_h_
+
+#include <qdict.h>
+#include <qobject.h>
+
+#include "BackupProfile.h"
+
+/**
+ * @short Control access to the set of backup profiles.
+ *
+ * Each user has a set of backup profiles that are stored under
+ * <TT>$HOME/.kde/share/apps/kdat/</TT>. (Changed from $HOME/.kdat in KDE1.)
+ * This class provides a single point of access for reading and writing
+ * these backup profiles.
+ *
+ * Other objects can register to be notified when a backup profile is added or
+ * removed, and when a backup profile is modified.
+ *
+ * The BackupProfileManager follows the Singleton pattern.
+ */
+class BackupProfileManager : public QObject {
+ Q_OBJECT
+
+ static BackupProfileManager* _instance;
+
+ QDict<BackupProfile> _backupProfiles;
+ QStringList _backupProfileNames;
+
+ BackupProfileManager();
+public:
+ ~BackupProfileManager();
+
+ /**
+ * All access to the BackupProfileManager goes through this method.
+ *
+ * @return a pointer to the single instance of the BackupProfileManager.
+ */
+ static BackupProfileManager* instance();
+
+ /**
+ * Get the list of all known backup profiles.
+ *
+ * @return a QStringList containing the backup profile names.
+ */
+ const QStringList& getBackupProfileNames();
+
+ /**
+ * Retrieve the named backup profile.
+ *
+ * @param name The name of the backup profile.
+ * @return A pointer to the backup profile.
+ */
+ BackupProfile* findBackupProfile( const QString & name );
+
+ /**
+ * Add a new backup profile.
+ *
+ * @param backupProfile A pointer to the new backup profile.
+ */
+ void addBackupProfile( BackupProfile* backupProfile );
+
+ /**
+ * Remove a backup profile. The backup profile is removed from memory and
+ * from disk. A signal is emitted before the profile is actually removed.
+ *
+ * @param backupProfile A pointer to the backup profile to remove.
+ */
+ void removeBackupProfile( BackupProfile* backupProfile );
+
+ /**
+ * Notify anyone who cares that the backup profile has been modified.
+ *
+ * @param backupProfile A pointer to the backup profile that was modified.
+ */
+ void backupProfileModified( BackupProfile* backupProfile );
+signals:
+ /**
+ * Emitted after a new backup profile is created.
+ *
+ * @param backupProfile A pointer to the new backup profile.
+ */
+ void sigBackupProfileAdded( BackupProfile* backupProfile );
+
+ /**
+ * Emitted before a backup profile is destroyed. This signal is emitted
+ * immediately before the backup profile is deleted.
+ *
+ * @param backupProfile A pointer to the backup profile that is about to
+ * be destroyed.
+ */
+ void sigBackupProfileRemoved( BackupProfile* backupProfile );
+
+ /**
+ * Emitted after a backup profile has been changed in some way.
+ *
+ * @param backupProfile A pointer to the backup profile that has been modified.
+ */
+ void sigBackupProfileModified( BackupProfile* backupProfile );
+};
+
+#endif
diff --git a/kdat/BackupProfileWidget.cpp b/kdat/BackupProfileWidget.cpp
new file mode 100644
index 0000000..0b4dfa0
--- /dev/null
+++ b/kdat/BackupProfileWidget.cpp
@@ -0,0 +1,259 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+
+#include <kapplication.h>
+
+#include "BackupProfile.h"
+#include "BackupProfileWidget.h"
+#include "Util.h"
+#include <klocale.h>
+
+#include "BackupProfileWidget.moc"
+
+BackupProfileWidget::BackupProfileWidget( QWidget* parent, const char* name )
+ : KTabCtl( parent, name )
+{
+ QWidget* one = new QWidget( this );
+ addTab( one, i18n( "Backup" ) );
+
+ QLabel* lbl1 = new QLabel( i18n( "Archive name:" ), one );
+ lbl1->setFixedSize( lbl1->sizeHint() );
+
+ _archiveName = new QLineEdit( one );
+ _archiveName->setFixedHeight( _archiveName->sizeHint().height() );
+
+ QLabel* lbl2 = new QLabel( i18n( "Working folder:" ), one );
+ lbl2->setFixedSize( lbl2->sizeHint() );
+
+ _workingDir = new QComboBox( FALSE, one );
+ _workingDir->setFixedHeight( _workingDir->sizeHint().height() );
+
+ QLabel* lbl3 = new QLabel( i18n( "Backup files:" ), one );
+ lbl3->setFixedHeight( lbl3->sizeHint().height() );
+
+ _files = new QListBox( one );
+
+ QWidget* two = new QWidget( this );
+ addTab( two, i18n( "Tar Options" ) );
+
+ _oneFilesystem = new QCheckBox( i18n( "Stay on one filesystem" ), two );
+ _oneFilesystem->setFixedHeight( _oneFilesystem->sizeHint().height() );
+
+ _incremental = new QCheckBox( i18n( "GNU listed incremental" ), two );
+ _incremental->setFixedHeight( _incremental->sizeHint().height() );
+ connect( _incremental, SIGNAL( toggled( bool ) ), this, SLOT( slotIncrementalToggled( bool ) ) );
+
+ _snapshotLabel = new QLabel( i18n( "Snapshot file:" ), two );
+ _snapshotLabel->setFixedSize( _snapshotLabel->sizeHint() );
+
+ _snapshotFile = new QLineEdit( two );
+ _snapshotFile->setFixedHeight( _snapshotFile->sizeHint().height() );
+
+ _removeSnapshot = new QCheckBox( i18n( "Remove snapshot file before backup" ), two );
+ _removeSnapshot->setFixedHeight( _removeSnapshot->sizeHint().height() );
+
+ slotIncrementalToggled( FALSE );
+
+ QVBoxLayout* l1 = new QVBoxLayout( one, 8, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addWidget( lbl1 );
+ l1_1->addWidget( _archiveName, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addWidget( lbl2 );
+ l1_2->addWidget( _workingDir, 1 );
+
+ l1->addWidget( lbl3 );
+ l1->addWidget( _files, 1 );
+
+ QVBoxLayout* l2 = new QVBoxLayout( two, 8, 4 );
+ l2->addWidget( _oneFilesystem );
+ l2->addWidget( _incremental );
+
+ QHBoxLayout* l2_1 = new QHBoxLayout();
+ l2->addLayout( l2_1 );
+ l2_1->addSpacing( 20 );
+ l2_1->addWidget( _snapshotLabel );
+ l2_1->addWidget( _snapshotFile, 1 );
+
+ QHBoxLayout* l2_2 = new QHBoxLayout();
+ l2->addLayout( l2_2 );
+ l2_2->addSpacing( 20 );
+ l2_2->addWidget( _removeSnapshot );
+
+ l2->addStretch( 1 );
+
+ connect( _archiveName , SIGNAL( textChanged( const QString & ) ), this, SLOT( slotTextChanged( const QString & ) ) );
+ connect( _workingDir , SIGNAL( activated( const QString & ) ) , this, SLOT( slotWorkingDirActivated( const QString & ) ) );
+ connect( _oneFilesystem , SIGNAL( toggled( bool ) ) , this, SLOT( slotToggled( bool ) ) );
+ connect( _incremental , SIGNAL( toggled( bool ) ) , this, SLOT( slotIncrementalToggled( bool ) ) );
+ connect( _snapshotFile , SIGNAL( textChanged( const QString & ) ), this, SLOT( slotTextChanged( const QString & ) ) );
+ connect( _removeSnapshot, SIGNAL( toggled( bool ) ) , this, SLOT( slotToggled( bool ) ) );
+}
+
+BackupProfileWidget::~BackupProfileWidget()
+{
+}
+
+void BackupProfileWidget::slotTextChanged( const QString & )
+{
+ emit sigSomethingChanged();
+}
+
+void BackupProfileWidget::slotToggled( bool )
+{
+ emit sigSomethingChanged();
+}
+
+void BackupProfileWidget::slotIncrementalToggled( bool set )
+{
+ _snapshotLabel->setEnabled( set );
+ _snapshotFile->setEnabled( set );
+ _removeSnapshot->setEnabled( set );
+
+ emit sigSomethingChanged();
+}
+
+void BackupProfileWidget::slotWorkingDirActivated( const QString & text )
+{
+ while ( FALSE == _relativeFiles.isEmpty() ) {
+ QString my_first = _relativeFiles.first();
+ _relativeFiles.remove( my_first );
+ }
+ _files->clear();
+
+ QStringList::Iterator i = _absoluteFiles.begin();
+ int remove = text.length();
+ if ( remove > 1 ) {
+ remove++;
+ }
+ for ( ; i != _absoluteFiles.end(); ++i ) {
+ QString fn = *i;
+ fn.remove( 0, remove );
+ if ( fn.isEmpty() ) {
+ fn = ".";
+ }
+ _files->insertItem( fn );
+ _relativeFiles.append( fn );
+ }
+
+ emit sigSomethingChanged();
+}
+
+void BackupProfileWidget::setBackupProfile( BackupProfile* backupProfile )
+{
+ // Set the archive name.
+ _archiveName->setText( backupProfile->getArchiveName() );
+
+ setAbsoluteFiles( backupProfile->getAbsoluteFiles() );
+
+ if ( !backupProfile->getWorkingDirectory().isNull() ) {
+ for ( int ii = 0; ii < _workingDir->count(); ii++ ) {
+ QString one = _workingDir->text( ii );
+ QString two = backupProfile->getWorkingDirectory();
+ // if ( _workingDir->text( ii ) == backupProfile->getWorkingDirectory() ) {
+ if( one == two ){
+ _workingDir->setCurrentItem( ii );
+ break;
+ }
+ }
+ }
+
+ // slotWorkingDirActivated( _workingDir->currentText() );
+ QString one = _workingDir->currentText();
+ slotWorkingDirActivated( one );
+
+ _oneFilesystem->setChecked( backupProfile->isOneFilesystem() );
+ _incremental->setChecked( backupProfile->isIncremental() );
+ _snapshotFile->setText( backupProfile->getSnapshotFile() );
+ _removeSnapshot->setChecked( backupProfile->getRemoveSnapshot() );
+
+ slotIncrementalToggled( backupProfile->isIncremental() );
+}
+
+void BackupProfileWidget::setAbsoluteFiles( const QStringList& files )
+{
+ // Copy the string list.
+ _absoluteFiles = files;
+
+ QString prefix = Util::longestCommonPath( files );
+
+ _workingDir->clear();
+ for ( int pos = prefix.length(); pos > 0; pos = prefix.findRev( '/', pos - 1 ) ) {
+ _workingDir->insertItem( prefix.left( pos ) );
+ }
+ _workingDir->insertItem( "/" );
+ _workingDir->setCurrentItem( 0 );
+
+ slotWorkingDirActivated( _workingDir->currentText() );
+}
+
+QString BackupProfileWidget::getArchiveName()
+{
+ return _archiveName->text();
+}
+
+QString BackupProfileWidget::getWorkingDirectory()
+{
+ if ( _workingDir->count() > 0 ) {
+ return _workingDir->currentText();
+ } else {
+ return 0;
+ }
+}
+
+const QStringList& BackupProfileWidget::getRelativeFiles()
+{
+ return _relativeFiles;
+}
+
+const QStringList& BackupProfileWidget::getAbsoluteFiles()
+{
+ return _absoluteFiles;
+}
+
+bool BackupProfileWidget::isOneFilesystem()
+{
+ return _oneFilesystem->isChecked();
+}
+
+bool BackupProfileWidget::isIncremental()
+{
+ return _incremental->isChecked();
+}
+
+QString BackupProfileWidget::getSnapshotFile()
+{
+ return _snapshotFile->text();
+}
+
+bool BackupProfileWidget::getRemoveSnapshot()
+{
+ return _removeSnapshot->isChecked();
+}
diff --git a/kdat/BackupProfileWidget.h b/kdat/BackupProfileWidget.h
new file mode 100644
index 0000000..08826b9
--- /dev/null
+++ b/kdat/BackupProfileWidget.h
@@ -0,0 +1,148 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _BackupProfileWidget_h_
+#define _BackupProfileWidget_h_
+
+#include <ktabctl.h>
+#include <qstrlist.h>
+
+class QCheckBox;
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QListBox;
+
+class BackupProfile;
+
+/**
+ * @short Display/edit the parameters for a backup operation.
+ */
+class BackupProfileWidget : public KTabCtl {
+ Q_OBJECT
+ QLineEdit* _archiveName;
+ QComboBox* _workingDir;
+ QListBox* _files;
+ QCheckBox* _oneFilesystem;
+ QCheckBox* _incremental;
+ QLabel* _snapshotLabel;
+ QLineEdit* _snapshotFile;
+ QCheckBox* _removeSnapshot;
+ QStringList _absoluteFiles;
+ QStringList _relativeFiles;
+private slots:
+ void slotTextChanged( const QString & text );
+ void slotIncrementalToggled( bool set );
+ void slotToggled( bool set );
+ void slotWorkingDirActivated( const QString & text );
+public:
+ /**
+ * Create a backup profile widget.
+ *
+ * @param archiveName The default name for the new archive.
+ * @param files The list of files to be archived.
+ * @param parent The parent widget of this dialog.
+ * @param name The widget name of this dialog.
+ */
+ BackupProfileWidget( QWidget* parent=0, const char* name=0 );
+
+ /**
+ * Destroy the backup profile widget.
+ */
+ ~BackupProfileWidget();
+
+ /**
+ * Set the parameters for the backup profile.
+ *
+ * @param backupProfile The backup profile to display/edit.
+ */
+ void setBackupProfile( BackupProfile* backupProfile );
+
+ /**
+ * Set the list of files for the backup profile, with full paths.
+ *
+ * @param files The list.
+ */
+ void setAbsoluteFiles( const QStringList& files );
+
+ /**
+ * Query the name of the archive.
+ *
+ * @return The name of the new archive.
+ */
+ QString getArchiveName();
+
+ /**
+ * Query the working directory for the tar command.
+ *
+ * @return The working directory.
+ */
+ QString getWorkingDirectory();
+
+ /**
+ * Query the list of files to backup, relative to the working directory.
+ *
+ * @return The file list.
+ */
+ const QStringList& getRelativeFiles();
+
+ /**
+ * Query the list of files to backup, with full paths.
+ *
+ * @return The file list.
+ */
+ const QStringList& getAbsoluteFiles();
+
+ /**
+ * Query whether or not to cross filesystem boundaries when performing the
+ * backup.
+ *
+ * @return TRUE if the backup is restricted to a single filesystem, FALSE
+ * if the backup can cross filesystem boundaries.
+ */
+ bool isOneFilesystem();
+
+ /**
+ * Query whether this is to be a GNU incremental backup.
+ *
+ * @return TRUE if incremental, otherwise FALSE.
+ */
+ bool isIncremental();
+
+ /**
+ * Query the name of the snapshot file to use for an incremental backup.
+ *
+ * @return The name of the snapshot file.
+ */
+ QString getSnapshotFile();
+
+ /**
+ * Query whether to remove the snapshot file before beginning an
+ * incremental backup. This has the effect of performing a full backup.
+ *
+ * @return TRUE if the snapshot file should be removed, otherwise FALSE.
+ */
+ bool getRemoveSnapshot();
+signals:
+ /**
+ * Emitted whenever the user changes anything.
+ */
+ void sigSomethingChanged();
+};
+
+#endif
diff --git a/kdat/CREDITS b/kdat/CREDITS
new file mode 100644
index 0000000..21089f7
--- /dev/null
+++ b/kdat/CREDITS
@@ -0,0 +1,45 @@
+CREDITS
+
+2002-04-23
+
+Bas Blender <cybersurfer at euronet.nl> offered to make a splash screen.
+
+2002-01-24
+
+Frank Pieczynski <pieczy at knuut.de> provided improved blue icons.
+
+2002-01-23
+
+Roland Gigler <rolandg at onlinehome.de> provided a fix for the
+filename corruption on the screen display when a tape is restored.
+
+2002-01-20
+
+Frank Pieczynski <pieczy at knuut.de> provided a workaround for
+loading icons in high-color themes when repeated questions to
+kde-devel yielded no useful advice.
+
+2001-11-25
+
+All versions of kdat prior to KDE-2.x were developed and/or
+supported by Sean Vyain (svyain@mail.tds.net). Starting with
+KDE-2.x, Larry Widman (kdat@cardiothink.com) volunteered
+to serve as maintainer because the package was about to be
+dropped for lack of a maintainer.
+
+It is unclear what happened to Sean. One email correspondent
+reported that he had been killed in a car crash. The KDE
+coordinator said that multiple attempts to contact him by email
+had been unsuccessful.
+
+Anyone who has information about Sean Vyain, who has made many
+contributions to the Open Source movement, would be appreciated
+and may be directed to Larry Widman (email address above).
+
+Re legal stuff. The copyright to the kdat source code up to
+when maintainership changed is owned by Sean Vyain. If he is
+in fact deceased, the copyright ownership presumably passes to
+his estate. Any representative of that estate should feel free
+to contact the current kdat maintainer in case licensing issues
+should arise in the future.
+
diff --git a/kdat/ErrorHandler.cpp b/kdat/ErrorHandler.cpp
new file mode 100644
index 0000000..7a60295
--- /dev/null
+++ b/kdat/ErrorHandler.cpp
@@ -0,0 +1,114 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <kglobal.h>
+#include <qmessagebox.h>
+#include <klocale.h>
+//#include <kstandarddirs.h>
+//#include <kapplication.h>
+
+void error_handler(int err_sig);
+
+/* include the following in main():
+ signal(SIGHUP, error_handler);
+ signal(SIGINT, error_handler);
+ signal(SIGFPE, error_handler);
+ signal(SIGSEGV, error_handler);
+ signal(SIGTERM, error_handler);
+
+ printf("Error_handler installed\n");
+*/
+
+// from /usr/include/bits/signum.h:
+// #define SIGHUP 1 /* Hangup (POSIX). */
+// #define SIGINT 2 /* Interrupt (ANSI). */
+// #define SIGFPE 8 /* Floating-point exception (ANSI). */
+// #define SIGSEGV 11 /* Segmentation violation (ANSI). */
+// #define SIGTERM 15 /* Termination (ANSI). */
+
+void error_handler(int err_sig)
+{
+ QString base1a, base1b, base2a, base2b, msg1, msg2, msg3;
+ int i;
+
+ base1a = i18n( " caught.\nExit the program from File->Quit or do "
+ "\"kill -9 <pid>\" if you like.\n" );
+ base1b = base1a; // deep copy
+
+ base2a = i18n( "You can dump core by selecting the \"Abort\" button.\n"
+ "Please notify the maintainer (see Help->About KDat)." );
+ base2b = base2a; // deep copy
+
+ msg1 = base1a.append(base2a);
+ msg2 = base1b.append("It is strongly recommended to do this!\n");
+ msg2 = msg2.append(base2b);
+ msg3 = i18n( "An Error Signal was Received" );
+
+ switch (err_sig) {
+ case SIGHUP:
+ fprintf(stderr, "kdat: SIGHUP signal (\"Hangup (POSIX)\") caught\n");
+ i = QMessageBox::critical( (QWidget *)NULL,
+ msg3,
+ i18n( "SIGHUP signal (\"Hangup (POSIX)\")" ).append( msg1 ),
+ QMessageBox::Ignore, QMessageBox::Abort, QMessageBox::NoButton);
+ if( i == QMessageBox::Abort ){ abort(); }
+ break;
+ case SIGINT:
+ fprintf(stderr, "kdat: SIGINT signal (\"Interrupt (ANSI)\") caught\n");
+ i = QMessageBox::critical( (QWidget *)NULL,
+ msg3,
+ i18n( "SIGINT signal (\"Interrupt (ANSI)\")" ).append( msg1 ),
+ QMessageBox::Ignore, QMessageBox::Abort, QMessageBox::NoButton);
+ if( i == QMessageBox::Abort ){ abort(); }
+ break;
+ case SIGFPE:
+ fprintf(stderr, "kdat: SIGFPE signal (\"Floating-point exception (ANSI)\") caught\n");
+ i = QMessageBox::critical( (QWidget *)NULL,
+ msg3,
+ i18n("SIGFPE signal (\"Floating-point exception (ANSI)\")").append (msg2),
+ QMessageBox::Ignore, QMessageBox::Abort, QMessageBox::NoButton);
+ if( i == QMessageBox::Abort ){ abort(); }
+ break;
+ case SIGSEGV:
+ fprintf(stderr, "kdat: SIGSEGV signal (\"Segmentation violation (ANSI)\") caught\n");
+ i = QMessageBox::critical( (QWidget *)NULL,
+ msg3,
+ i18n( "SIGSEGV signal (\"Segmentation violation (ANSI)\")").append(msg2),
+ /* button1, button2 */
+ QMessageBox::Ignore, QMessageBox::Abort, QMessageBox::NoButton);
+ if( i == QMessageBox::Abort ){ abort(); }
+ break;
+ case SIGTERM:
+ fprintf(stderr, "kdat: SIGTERM signal (\"Termination (ANSI)\") caught\n");
+ i = QMessageBox::critical( (QWidget *)NULL,
+ msg3,
+ i18n( "SIGTERM signal (\"Termination (ANSI)\")").append(msg1),
+ QMessageBox::Ignore, QMessageBox::Abort, QMessageBox::NoButton);
+ if( i == QMessageBox::Abort ){ abort(); }
+ break;
+ }
+
+ // Deinstall the signal handlers
+ // signal(SIGHUP, SIG_DFL);
+ // signal(SIGINT, SIG_DFL);
+ // signal(SIGFPE, SIG_DFL);
+ // signal(SIGSEGV, SIG_DFL);
+ // signal(SIGTERM, SIG_DFL);
+}
diff --git a/kdat/File.cpp b/kdat/File.cpp
new file mode 100644
index 0000000..7fc8f97
--- /dev/null
+++ b/kdat/File.cpp
@@ -0,0 +1,287 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <assert.h>
+#include <values.h>
+
+#include "File.h"
+
+File::File( File* parent, int size, int mtime, int startRecord, int endRecord, const QString & name )
+ : _stubbed( FALSE ),
+ _name( name ),
+ _parent( parent )
+{
+ assert( endRecord >= startRecord );
+
+ _union._data._size = size;
+ _union._data._mtime = mtime;
+ _union._data._startRecord = startRecord;
+ _union._data._endRecord = endRecord;
+}
+
+File::File( File* parent, FILE* fptr, int offset )
+ : _stubbed( TRUE ),
+ _parent( parent )
+{
+ _union._stub._fptr = fptr;
+ _union._stub._offset = offset;
+}
+
+File::~File()
+{
+ while ( _children.first() ) {
+ delete _children.first();
+ _children.removeFirst();
+ }
+}
+
+void File::read( int version )
+{
+ if ( !_stubbed ) {
+ return;
+ }
+
+ _stubbed = FALSE;
+
+ FILE* fptr = _union._stub._fptr;
+
+ fseek( fptr, _union._stub._offset, SEEK_SET );
+
+ // File name (4 bytes + n chars).
+ int ival;
+ fread( &ival, sizeof( ival ), 1, fptr );
+
+ char * buf = new char[ival+1];
+ buf[ival] = '\0';
+ fread( buf, sizeof( char ), ival, fptr );
+ _name = buf;
+
+ delete [] buf;
+
+ // File size (4 bytes).
+ fread( &ival, sizeof( ival ), 1, fptr );
+ _union._data._size = ival;
+
+ // File modification time (4 bytes).
+ fread( &ival, sizeof( ival ), 1, fptr );
+ _union._data._mtime = ival;
+
+ // Start record number.
+ fread( &ival, sizeof( ival ), 1, fptr );
+ _union._data._startRecord = ival;
+
+ // End record number.
+ fread( &ival, sizeof( ival ), 1, fptr );
+ _union._data._endRecord = ival;
+
+ //%%% This is a kludge to cope with some screwed up tape indexes.
+ //%%% Hopefully the file with the zero end record is *always* at
+ //%%% the end of the archive.
+ if ( ( _union._data._endRecord <= 0 ) && ( _union._data._startRecord != _union._data._endRecord ) ) {
+ _union._data._endRecord = MAXINT;
+ }
+
+ if ( version > 3 ) {
+ fread( &ival, sizeof( ival ), 1, fptr );
+ int rc = ival;
+ int start = 0;
+ int end = 0;
+ for ( int ii = 0; ii < rc; ii++ ) {
+ fread( &ival, sizeof( ival ), 1, fptr );
+ start = ival;
+ fread( &ival, sizeof( ival ), 1, fptr );
+ end = ival;
+ _ranges.addRange( start, end );
+ }
+ }
+
+ //===== Read files =====
+ fread( &ival, sizeof( ival ), 1, fptr );
+ for ( int count = ival; count > 0; count-- ) {
+ fread( &ival, sizeof( ival ), 1, fptr );
+ addChild( new File( this, fptr, ival ) );
+ }
+}
+
+void File::readAll( int version )
+{
+ read( version );
+
+ QPtrListIterator<File> i( getChildren() );
+ for ( ; i.current(); ++i ) {
+ i.current()->readAll( version );
+ }
+}
+
+void File::write( FILE* fptr )
+{
+ int zero = 0;
+
+ // File name (4 bytes + n chars).
+ int ival = getName().length();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+ fwrite( getName().ascii(), sizeof( char ), ival, fptr );
+
+ // File size (4 bytes).
+ ival = getSize();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+
+ // File modification time (4 bytes).
+ ival = getMTime();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+
+ // Start record number.
+ ival = getStartRecord();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+
+ // End record number.
+ ival = getEndRecord();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+
+ // Child range list.
+ ival = _ranges.getRanges().count();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+ QPtrListIterator<Range> it( _ranges.getRanges() );
+ for ( ; it.current(); ++it ) {
+ ival = it.current()->getStart();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+ ival = it.current()->getEnd();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+ }
+
+ // Number of immediate children (4 bytes).
+ ival = getChildren().count();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+
+ // Fill in file offsets later...
+ int fileTable = ftell( fptr );
+ for ( ; ival > 0; ival-- ) {
+ fwrite( &zero, sizeof( zero ), 1, fptr );
+ }
+
+ //===== Write files =====
+ ival = _children.count();
+ fwrite( &ival, sizeof( ival ), 1, fptr );
+
+ QPtrListIterator<File> i( _children );
+ int count = 0;
+ for ( ; i.current(); ++i, count++ ) {
+ // Fill in the file offset.
+ int here = ftell( fptr );
+ fseek( fptr, fileTable + 4*count, SEEK_SET );
+ fwrite( &here, sizeof( here ), 1, fptr );
+ fseek( fptr, here, SEEK_SET );
+
+ i.current()->write( fptr );
+ }
+}
+
+bool File::isDirectory()
+{
+ read();
+
+ return _name[ _name.length() - 1 ] == '/';
+}
+
+int File::getSize()
+{
+ read();
+
+ return _union._data._size;
+}
+
+int File::getMTime()
+{
+ read();
+
+ return _union._data._mtime;
+}
+
+int File::getStartRecord()
+{
+ read();
+
+ return _union._data._startRecord;
+}
+
+int File::getEndRecord()
+{
+ read();
+
+ return _union._data._endRecord;
+}
+
+QString File::getName()
+{
+ read();
+
+ return _name;
+}
+
+QString File::getFullPathName()
+{
+ QString tmp = _name.copy();
+ for ( File* parent = getParent(); parent; parent = parent->getParent() ) {
+ tmp.prepend( parent->getName() );
+ }
+
+ return tmp;
+}
+
+File* File::getParent()
+{
+ return _parent;
+}
+
+const QPtrList<File>& File::getChildren()
+{
+ read();
+
+ return _children;
+}
+
+const QPtrList<Range>& File::getRanges()
+{
+ read();
+
+ return _ranges.getRanges();
+}
+
+void File::addChild( File* file )
+{
+ read();
+
+ _children.append( file );
+}
+
+void File::calcRanges()
+{
+ assert( !_stubbed );
+
+ _ranges.clear();
+ _ranges.addRange( getStartRecord(), getEndRecord() );
+
+ QPtrListIterator<File> it( getChildren() );
+ for ( ; it.current(); ++it ) {
+ it.current()->calcRanges();
+ QPtrListIterator<Range> it2( it.current()->getRanges() );
+ for ( ; it2.current(); ++it2 ) {
+ _ranges.addRange( it2.current()->getStart(), it2.current()->getEnd() );
+ }
+ }
+}
diff --git a/kdat/File.h b/kdat/File.h
new file mode 100644
index 0000000..0dda512
--- /dev/null
+++ b/kdat/File.h
@@ -0,0 +1,201 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef File_H
+#define File_H
+
+#include <stdio.h>
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+#include "Range.h"
+#include "kdat.h"
+
+/**
+ * @short This class represents a single file or directory in a tar file.
+ */
+class File {
+ bool _stubbed;
+ union {
+ struct {
+ int _size;
+ int _mtime;
+ int _startRecord;
+ int _endRecord;
+ } _data;
+ struct {
+ FILE* _fptr;
+ int _offset;
+ } _stub;
+ } _union;
+ QString _name;
+ File* _parent;
+ QPtrList<File> _children;
+ RangeList _ranges;
+public:
+ /**
+ * Create a new file entry.
+ *
+ * @param parent The directory file entry that contains this file.
+ * @param size The size of the file in bytes.
+ * @param mtime The last modification time of the file in seconds since
+ * the Epoch.
+ * @param startRecord The first tar record number in the file.
+ * @param endRecord The last tar record number in the file.
+ * @param name The file name. If the file name ends with a '/' then it
+ * is assumed to be a directory name. Only the last part of
+ * the file's path name should be passed in. The rest of the
+ * path is determined by this file entry's ancestors.
+ */
+ File( File* parent, int size, int mtime, int startRecord, int endRecord, const QString & name );
+
+ /**
+ * Create a new stubbed instance of a file entry. The file pointer and
+ * offset specify where the actual instance data can be found. The real
+ * data is read on demand when one of the accessor functions is called.
+ *
+ * @param parent The directory file entry that contains this file.
+ * @param fptr The open index file containing this file entry. The file
+ * must be left open so that the file entry information can
+ * be read at a later time.
+ * @param offset The offset that will be seeked to when reading the file
+ * entry information.
+ */
+ File( File* parent, FILE* fptr, int offset );
+
+ /**
+ * Destroy the file entry and all of its children.
+ */
+ ~File();
+
+ /**
+ * Insure that all of the data fields for this file entry have been read
+ * in. If the file entry is a stub then the actual data is read from the
+ * index file. If the file entry is not a stub then no action is taken.
+ *
+ * @param version The version of the old tape index.
+ */
+ void read( int version = KDAT_INDEX_FILE_VERSION );
+
+ /**
+ * Recursively read the instance for this file entry and all of it's
+ * children. This method is used when converting from an older index format.
+ *
+ * @param version The version of the old tape index.
+ */
+ void readAll( int version );
+
+ /**
+ * Write out the file entry to the open file. Entries for each of its
+ * children will also be written.
+ */
+ void write( FILE* fptr );
+
+ /**
+ * Determine whether this file entry represents a directory. If the file
+ * name ends in a '/' then it is assumed that it is a directory.
+ *
+ * @return TRUE if the file represents a directory, or FALSE if it is an
+ * ordinary file.
+ */
+ bool isDirectory();
+
+ /**
+ * Get the size of the file.
+ *
+ * @return The size, in bytes, of the file.
+ */
+ int getSize();
+
+ /**
+ * Get the last modification time for the file.
+ *
+ * @ return The last time the file was modified, in seconds since the Epoch.
+ */
+ int getMTime();
+
+ /**
+ * Get the tar record number for the file. This is the number of 512-byte
+ * tar blocks that must be read before getting to this file.
+ *
+ * @return The tar record number for the file.
+ */
+ int getStartRecord();
+
+ /**
+ * Get the tar record number that is just past the end of the file. This
+ * number minus the start record gives the number of 512-byte tar blocks
+ * that this file occupies in the archive.
+ *
+ * @return The last tar record number for the file.
+ */
+ int getEndRecord();
+
+ /**
+ * Get the name of this file. Only the last component of the full path
+ * name is returned.
+ *
+ * @return The file's name.
+ */
+ QString getName();
+
+ /**
+ * Get the full path name of the file.
+ *
+ * @return The full path to the file.
+ */
+ QString getFullPathName();
+
+ /**
+ * Get the file entry's parent. A NULL parent indicates that this is one
+ * of (possibly) many top level directories within the tar archive.
+ *
+ * @return A pointer to the file entry that contains this file entry.
+ */
+ File* getParent();
+
+ /**
+ * Get the children of this file entry. A normal file will never have any
+ * children. A directory may or may not have children.
+ *
+ * @return A list of the immediate children of this file entry.
+ */
+ const QPtrList<File>& getChildren();
+
+ /**
+ * Get the list of ranges of this file and all of its children.
+ *
+ * @return A list of ranges.
+ */
+ const QPtrList<Range>& getRanges();
+
+ /**
+ * Add a new file entry as a child of this file entry.
+ *
+ * @param file The file to add.
+ */
+ void addChild( File* file );
+
+ /**
+ * Recursively calculate the list of ranges for all of the file's children.
+ */
+ void calcRanges();
+};
+
+#endif
diff --git a/kdat/FileInfoWidget.cpp b/kdat/FileInfoWidget.cpp
new file mode 100644
index 0000000..4a2a986
--- /dev/null
+++ b/kdat/FileInfoWidget.cpp
@@ -0,0 +1,173 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <grp.h>
+#include <time.h>
+
+#include <qdatetime.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qfile.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "FileInfoWidget.h"
+#include "Util.h"
+
+#include "FileInfoWidget.moc"
+
+FileInfoWidget::FileInfoWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ QLabel* lbl1 = new QLabel( i18n( "File name:" ), this );
+ QLabel* lbl2 = new QLabel( i18n( "Created on:" ), this );
+ QLabel* lbl3 = new QLabel( i18n( "Last modified:" ), this );
+ QLabel* lbl4 = new QLabel( i18n( "Last accessed:" ), this );
+ QLabel* lbl5 = new QLabel( i18n( "Size:" ), this );
+ QLabel* lbl6 = new QLabel( i18n( "Owner:" ), this );
+ QLabel* lbl7 = new QLabel( i18n( "Group:" ), this );
+
+ int max = lbl1->sizeHint().width();
+ if ( lbl2->sizeHint().width() > max ) max = lbl2->sizeHint().width();
+ if ( lbl3->sizeHint().width() > max ) max = lbl3->sizeHint().width();
+ if ( lbl4->sizeHint().width() > max ) max = lbl4->sizeHint().width();
+ if ( lbl5->sizeHint().width() > max ) max = lbl5->sizeHint().width();
+ if ( lbl6->sizeHint().width() > max ) max = lbl6->sizeHint().width();
+ if ( lbl7->sizeHint().width() > max ) max = lbl7->sizeHint().width();
+
+ lbl1->setFixedSize( max, lbl1->sizeHint().height() );
+ lbl2->setFixedSize( max, lbl2->sizeHint().height() );
+ lbl3->setFixedSize( max, lbl3->sizeHint().height() );
+ lbl4->setFixedSize( max, lbl4->sizeHint().height() );
+ lbl5->setFixedSize( max, lbl5->sizeHint().height() );
+ lbl6->setFixedSize( max, lbl6->sizeHint().height() );
+ lbl7->setFixedSize( max, lbl7->sizeHint().height() );
+
+ _fileName = new QLabel( "???", this );
+ _fileName->setFixedHeight( _fileName->sizeHint().height() );
+
+ _ctime = new QLabel( "???", this );
+ _ctime->setFixedHeight( _ctime->sizeHint().height() );
+
+ _mtime = new QLabel( "???", this );
+ _mtime->setFixedHeight( _mtime->sizeHint().height() );
+
+ _atime = new QLabel( "???", this );
+ _atime->setFixedHeight( _atime->sizeHint().height() );
+
+ _size = new QLabel( "???", this );
+ _size->setFixedHeight( _size->sizeHint().height() );
+
+ _owner = new QLabel( "???", this );
+ _owner->setFixedHeight( _owner->sizeHint().height() );
+
+ _group = new QLabel( "???", this );
+ _group->setFixedHeight( _group->sizeHint().height() );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 4, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addWidget( lbl1 );
+ l1_1->addWidget( _fileName, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addWidget( lbl2 );
+ l1_2->addWidget( _ctime, 1 );
+
+ QHBoxLayout* l1_3 = new QHBoxLayout();
+ l1->addLayout( l1_3 );
+ l1_3->addWidget( lbl3 );
+ l1_3->addWidget( _mtime, 1 );
+
+ QHBoxLayout* l1_4 = new QHBoxLayout();
+ l1->addLayout( l1_4 );
+ l1_4->addWidget( lbl4 );
+ l1_4->addWidget( _atime, 1 );
+
+ QHBoxLayout* l1_5 = new QHBoxLayout();
+ l1->addLayout( l1_5 );
+ l1_5->addWidget( lbl5 );
+ l1_5->addWidget( _size, 1 );
+
+ QHBoxLayout* l1_6 = new QHBoxLayout();
+ l1->addLayout( l1_6 );
+ l1_6->addWidget( lbl6 );
+ l1_6->addWidget( _owner, 1 );
+
+ QHBoxLayout* l1_7 = new QHBoxLayout();
+ l1->addLayout( l1_7 );
+ l1_7->addWidget( lbl7 );
+ l1_7->addWidget( _group, 1 );
+
+ l1->addStretch( 1 );
+}
+
+FileInfoWidget::~FileInfoWidget()
+{
+}
+
+void FileInfoWidget::setFile( const QString & name )
+{
+ if ( name.isNull() ) {
+ return;
+ }
+
+ _fileName->setText( name );
+
+ struct stat info;
+ lstat( QFile::encodeName(name), &info );
+
+ QString tmp;
+ QDateTime datetime;
+
+ datetime.setTime_t(info.st_ctime);
+ _ctime->setText( KGlobal::locale()->formatDateTime(datetime, false) );
+
+ datetime.setTime_t(info.st_mtime);
+ _mtime->setText( KGlobal::locale()->formatDateTime(datetime, false) );
+
+ datetime.setTime_t(info.st_atime);
+ _atime->setText( KGlobal::locale()->formatDateTime(datetime, false) );
+
+ _size->setText( Util::bytesToString( info.st_size ) );
+
+ struct passwd* p;
+ p = getpwuid( info.st_uid );
+ if ( p ) {
+ tmp = p->pw_name;
+ } else {
+ tmp.setNum( info.st_uid );
+ }
+ _owner->setText( tmp );
+
+ struct group* g;
+ g = getgrgid( info.st_gid );
+ if ( g ) {
+ tmp = g->gr_name;
+ } else {
+ tmp.setNum( info.st_gid );
+ }
+ _group->setText( tmp );
+}
diff --git a/kdat/FileInfoWidget.h b/kdat/FileInfoWidget.h
new file mode 100644
index 0000000..c763886
--- /dev/null
+++ b/kdat/FileInfoWidget.h
@@ -0,0 +1,58 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _FileInfoWidget_h_
+#define _FileInfoWidget_h_
+
+#include <qwidget.h>
+
+class QLabel;
+
+/**
+ * @short Display information about a local file.
+ */
+class FileInfoWidget : public QWidget {
+ Q_OBJECT
+ QLabel* _fileName;
+ QLabel* _ctime;
+ QLabel* _mtime;
+ QLabel* _atime;
+ QLabel* _size;
+ QLabel* _owner;
+ QLabel* _group;
+public:
+ /**
+ * Create a new file info widget.
+ *
+ * @param parent The parent widget.
+ * @param name The name of this widget.
+ */
+ FileInfoWidget( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the file info widget.
+ */
+ ~FileInfoWidget();
+
+ /**
+ * Display the information for the given file.
+ */
+ void setFile( const QString & name );
+};
+
+#endif
diff --git a/kdat/FormatOptDlg.cpp b/kdat/FormatOptDlg.cpp
new file mode 100644
index 0000000..8ed79f9
--- /dev/null
+++ b/kdat/FormatOptDlg.cpp
@@ -0,0 +1,142 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdlib.h>
+
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "Options.h"
+#include "FormatOptDlg.h"
+
+#include "FormatOptDlg.moc"
+
+FormatOptDlg::FormatOptDlg( const QString & def, QWidget* parent, const char* name )
+ : QDialog( parent, name, TRUE )
+{
+ setIconText( i18n( "KDat: Format Options" ) );
+ setCaption( i18n( "KDat: Format Options" ) );
+
+ QLabel* lbl1 = new QLabel( i18n( "Tape name:" ), this );
+ QLabel* lbl2 = new QLabel( i18n( "Tape size:" ), this );
+
+ int max = lbl1->sizeHint().width();
+ if ( lbl2->sizeHint().width() > max ) max = lbl2->sizeHint().width();
+
+ lbl1->setFixedSize( max, lbl1->sizeHint().height() );
+ lbl2->setFixedSize( max, lbl2->sizeHint().height() );
+
+ _entry = new QLineEdit( this );
+ _entry->setText( def );
+ _entry->setFixedHeight( _entry->sizeHint().height() );
+
+ _tapeSize = new QLineEdit( this );
+ _tapeSize->setFixedSize( 48, _tapeSize->sizeHint().height() );
+
+ _tapeSizeUnits = new QComboBox( this );
+ _tapeSizeUnits->setFixedSize( 48, _tapeSizeUnits->sizeHint().height() );
+ _tapeSizeUnits->insertItem( "MB" );
+ _tapeSizeUnits->insertItem( "GB" );
+
+ KPushButton* ok = new KPushButton( KStdGuiItem::ok(), this );
+ ok->setFixedSize( 80, ok->sizeHint().height() );
+ KPushButton* cancel = new KPushButton( KStdGuiItem::cancel(), this );
+ cancel->setFixedSize( 80, cancel->sizeHint().height() );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 8, 4 );
+ QHBoxLayout* l2 = new QHBoxLayout();
+ QHBoxLayout* l3 = new QHBoxLayout();
+ QHBoxLayout* l4 = new QHBoxLayout();
+
+ l1->addLayout( l2, 0 );
+ l1->addLayout( l3, 0 );
+ l1->addStretch( 1 );
+
+ l1->addLayout( l4, 0 );
+
+ l2->addWidget( lbl1, 0 );
+ l2->addWidget( _entry, 1 );
+
+ l3->addWidget( lbl2 );
+ l3->addWidget( _tapeSize );
+ l3->addWidget( _tapeSizeUnits );
+ l3->addStretch( 1 );
+
+ l4->addStretch( 1 );
+ l4->addWidget( ok, 0 );
+ l4->addWidget( cancel, 0 );
+
+ resize( 400, 120 );
+
+ _entry->setFocus();
+ _entry->selectAll();
+
+ connect( _entry, SIGNAL( returnPressed() ), this, SLOT( okClicked() ) );
+ connect( ok , SIGNAL( clicked() ) , this, SLOT( okClicked() ) );
+ connect( cancel, SIGNAL( clicked() ) , this, SLOT( reject() ) );
+
+ int size = Options::instance()->getDefaultTapeSize();
+ if ( ( size >= 1024*1024 ) && ( size % ( 1024*1024 ) == 0 ) ) {
+ // GB
+ size /= 1024*1024;
+ _tapeSizeUnits->setCurrentItem( 1 );
+ } else {
+ // MB
+ size /= 1024;
+ _tapeSizeUnits->setCurrentItem( 0 );
+ }
+ _tapeSize->setText( KGlobal::locale()->formatNumber(size, 0) );
+}
+
+FormatOptDlg::~FormatOptDlg()
+{
+}
+
+void FormatOptDlg::okClicked()
+{
+ _name = _entry->text();
+
+ _size = (int)KGlobal::locale()->readNumber( _tapeSize->text() );
+ if ( _tapeSizeUnits->currentItem() == 0 ) {
+ // MB
+ _size *= 1024;
+ } else {
+ // GB
+ _size *= 1024*1024;
+ }
+
+ accept();
+}
+
+QString FormatOptDlg::getName()
+{
+ return _name;
+}
+
+int FormatOptDlg::getSize()
+{
+ return _size;
+}
diff --git a/kdat/FormatOptDlg.h b/kdat/FormatOptDlg.h
new file mode 100644
index 0000000..b4c5540
--- /dev/null
+++ b/kdat/FormatOptDlg.h
@@ -0,0 +1,70 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _FormatOptDlg_h_
+#define _FormatOptDlg_h_
+
+#include <qdialog.h>
+#include <qstring.h>
+
+class QComboBox;
+class QLineEdit;
+
+/**
+ * @short Display/edit options for formatting a tape.
+ */
+class FormatOptDlg : public QDialog {
+ Q_OBJECT
+ QString _name;
+ int _size;
+ QLineEdit* _entry;
+ QLineEdit* _tapeSize;
+ QComboBox* _tapeSizeUnits;
+private slots:
+ void okClicked();
+public:
+ /**
+ * Create a new format options dialog.
+ *
+ * @param def The default value for the tape name.
+ * @param parent The parent widget for the dialog.
+ * @param name The name for the dialog.
+ */
+ FormatOptDlg( const QString & def, QWidget* parent=0, const char* name=0 );
+
+ /**
+ * Destroy the format options dialog.
+ */
+ ~FormatOptDlg();
+
+ /**
+ * Get the name for the new tape.
+ *
+ * @return The name for the tape being formatted.
+ */
+ QString getName();
+
+ /**
+ * Get the capacity of the new tape.
+ *
+ * @return The size of the tape.
+ */
+ int getSize();
+};
+
+#endif
diff --git a/kdat/ImageCache.cpp b/kdat/ImageCache.cpp
new file mode 100644
index 0000000..016fc61
--- /dev/null
+++ b/kdat/ImageCache.cpp
@@ -0,0 +1,137 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <qpixmap.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+
+#include "ImageCache.h"
+
+ImageCache::ImageCache()
+{
+ KIconLoader *l = KGlobal::iconLoader();
+ /* 2002-01-24 FP */
+ // _archive = new QPixmap(l->iconPath("package", KIcon::Toolbar));
+ _archive = new QPixmap(l->iconPath("tar", KIcon::Small));
+ /* 2002-01-24 FP */
+ _backup = new QPixmap(l->iconPath("kdat_backup", KIcon::Toolbar));
+ _file = new QPixmap(l->iconPath("mime_empty", KIcon::Small));
+ _folderClosed = new QPixmap(l->iconPath("folder_blue", KIcon::Small));
+ _folderOpen = new QPixmap(l->iconPath("folder_blue_open", KIcon::Small));
+ _restore = new QPixmap(l->iconPath("kdat_restore", KIcon::Toolbar));
+ _selectAll = new QPixmap(l->iconPath("kdat_select_all", KIcon::Toolbar));
+ _selectNone = new QPixmap(l->iconPath("kdat_select_none", KIcon::Toolbar));
+ _selectSome = new QPixmap(l->iconPath("kdat_select_some", KIcon::Toolbar));
+ // 2002-01-28 FP
+ // _tape = new QPixmap(l->iconPath("kdat_archive", KIcon::Toolbar));
+ _tape = new QPixmap(l->iconPath("kdat", KIcon::Small));
+ // 2002-01-28 FP
+ _tapeMounted = new QPixmap(l->iconPath("kdat_mounted", KIcon::Toolbar));
+ _tapeUnmounted = new QPixmap(l->iconPath("kdat_unmounted", KIcon::Toolbar));
+ _verify = new QPixmap(l->iconPath("kdat_verify", KIcon::Toolbar));
+}
+
+ImageCache::~ImageCache()
+{
+ delete _archive;
+ delete _backup;
+ delete _file;
+ delete _folderClosed;
+ delete _folderOpen;
+ delete _restore;
+ delete _tape;
+ delete _tapeMounted;
+ delete _tapeUnmounted;
+ delete _verify;
+}
+
+ImageCache* ImageCache::_instance = 0;
+
+ImageCache* ImageCache::instance()
+{
+ if ( _instance == 0 ) {
+ _instance = new ImageCache();
+ }
+
+ return _instance;
+}
+
+const QPixmap* ImageCache::getArchive()
+{
+ return _archive;
+}
+
+const QPixmap* ImageCache::getBackup()
+{
+ return _backup;
+}
+
+const QPixmap* ImageCache::getFile()
+{
+ return _file;
+}
+
+const QPixmap* ImageCache::getFolderClosed()
+{
+ return _folderClosed;
+}
+
+const QPixmap* ImageCache::getFolderOpen()
+{
+ return _folderOpen;
+}
+
+const QPixmap* ImageCache::getRestore()
+{
+ return _restore;
+}
+
+const QPixmap* ImageCache::getSelectAll()
+{
+ return _selectAll;
+}
+
+const QPixmap* ImageCache::getSelectNone()
+{
+ return _selectNone;
+}
+
+const QPixmap* ImageCache::getSelectSome()
+{
+ return _selectSome;
+}
+
+const QPixmap* ImageCache::getTape()
+{
+ return _tape;
+}
+
+const QPixmap* ImageCache::getTapeMounted()
+{
+ return _tapeMounted;
+}
+
+const QPixmap* ImageCache::getTapeUnmounted()
+{
+ return _tapeUnmounted;
+}
+
+const QPixmap* ImageCache::getVerify()
+{
+ return _verify;
+}
diff --git a/kdat/ImageCache.h b/kdat/ImageCache.h
new file mode 100644
index 0000000..b9bf59b
--- /dev/null
+++ b/kdat/ImageCache.h
@@ -0,0 +1,150 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _ImageCache_h_
+#define _ImageCache_h_
+
+class QPixmap;
+
+/**
+ * @short A container for commonly used icons.
+ */
+class ImageCache {
+ static ImageCache* _instance;
+
+ QPixmap* _archive;
+ QPixmap* _backup;
+ QPixmap* _file;
+ QPixmap* _folderClosed;
+ QPixmap* _folderOpen;
+ QPixmap* _restore;
+ QPixmap* _selectAll;
+ QPixmap* _selectNone;
+ QPixmap* _selectSome;
+ QPixmap* _tape;
+ QPixmap* _tapeMounted;
+ QPixmap* _tapeUnmounted;
+ QPixmap* _verify;
+
+ ImageCache();
+public:
+ /**
+ * Destroy the image cache and free the icons.
+ */
+ ~ImageCache();
+
+ /**
+ * This method is an accessor for the single instance of the image cache.
+ *
+ * @return A pointer to the single instance of the image cache.
+ */
+ static ImageCache* instance();
+
+ /**
+ * Get the tree-node icon used for archives.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getArchive();
+
+ /**
+ * Get the toolbar icon used for the backup action.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getBackup();
+
+ /**
+ * Get the tree-node icon used for files.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getFile();
+
+ /**
+ * Get the tree-node icon used for a closed folder.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getFolderClosed();
+
+ /**
+ * Get the tree-node icon used for an open folder.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getFolderOpen();
+
+ /**
+ * Get the toolbar icon used for the restore action.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getRestore();
+
+ /**
+ * Get the tree-node icon used when all subnodes are selected.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getSelectAll();
+
+ /**
+ * Get the tree-node icon used when no subnodes are selected.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getSelectNone();
+
+ /**
+ * Get the tree-node icon used when some subnodes are selected.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getSelectSome();
+
+ /**
+ * Get the tree-node icon used for tape indexes.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getTape();
+
+ /**
+ * Get the tree-node/toolbar icon used for a mounted tape drive.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getTapeMounted();
+
+ /**
+ * Get the tree-node/toolbar icon used for an unmounted tape drive.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getTapeUnmounted();
+
+ /**
+ * Get the toolbar icon used for the verify action.
+ *
+ * @return A pointer to the icon.
+ */
+ const QPixmap* getVerify();
+};
+
+#endif
diff --git a/kdat/IndexDlg.cpp b/kdat/IndexDlg.cpp
new file mode 100644
index 0000000..decea36
--- /dev/null
+++ b/kdat/IndexDlg.cpp
@@ -0,0 +1,355 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "LoggerWidget.h"
+#include "Options.h"
+#include "IndexDlg.h"
+#include "Tape.h"
+#include "TapeDrive.h"
+#include "TapeManager.h"
+#include "TarParser.h"
+#include "Util.h"
+
+#include "IndexDlg.moc"
+
+IndexDlg::IndexDlg( Tape* tape, QWidget* parent, const char* name )
+ : QDialog( parent, name, TRUE ),
+ _tarParser( NULL ),
+ _tape( tape ),
+ _archive( NULL ),
+ _totalKBytes( 0.0 ),
+ _archiveCount( 0 ),
+ _fileCount( 0 ),
+ _totalFileCount( 0 ),
+ _aborted( FALSE ),
+ _numFiles( 0 ),
+ _fileSize( -1 ),
+ _fileMTime( -1 ),
+ _fileStartRecord( -1 )
+{
+ setCaption( i18n( "KDat: Index" ) );
+ setIconText( i18n( "KDat: Index" ) );
+
+ resize( 500, 300 );
+
+ const int labelWidth = 96;
+
+ QFrame* f1 = new QFrame( this );
+ f1->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ QFrame* f2 = new QFrame( this );
+ f2->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ QLabel* lbl1 = new QLabel( i18n( "Elapsed time:" ), f1 );
+ lbl1->setFixedSize( labelWidth, lbl1->sizeHint().height() );
+
+ _elapsedTime = new QLabel( i18n( "00:00:00" ), f1 );
+ _elapsedTime->setFixedHeight( _elapsedTime->sizeHint().height() );
+
+ QLabel* lbl2 = new QLabel( i18n( "Archives:" ), f2 );
+ lbl2->setFixedSize( labelWidth, lbl2->sizeHint().height() );
+
+ _archives = new QLabel( i18n( "0" ), f2 );
+ _archives->setFixedHeight( _archives->sizeHint().height() );
+
+ QLabel* lbl3 = new QLabel( i18n( "KB read:" ), f1 );
+ lbl3->setFixedSize( labelWidth, lbl3->sizeHint().height() );
+
+ _kbytesRead = new QLabel( i18n( "0KB" ), f1 );
+ _kbytesRead->setFixedHeight( _kbytesRead->sizeHint().height() );
+
+ QLabel* lbl4 = new QLabel( i18n( "Files:" ), f2 );
+ lbl4->setFixedSize( labelWidth, lbl4->sizeHint().height() );
+
+ _files = new QLabel( i18n( "0" ), f2 );
+ _files->setFixedHeight( _kbytesRead->sizeHint().height() );
+
+ QLabel* lbl5 = new QLabel( i18n( "Transfer rate:" ), f1 );
+ lbl5->setFixedSize( labelWidth, lbl5->sizeHint().height() );
+
+ _transferRate = new QLabel( i18n( "0KB/min" ), f1 );
+ _transferRate->setFixedHeight( _transferRate->sizeHint().height() );
+
+ QLabel* lbl6 = new QLabel( i18n( "Total files:" ), f2 );
+ lbl6->setFixedSize( labelWidth, lbl6->sizeHint().height() );
+
+ _totalFiles = new QLabel( i18n( "0" ), f2 );
+ _totalFiles->setFixedHeight( _totalFiles->sizeHint().height() );
+
+ _log = new LoggerWidget( i18n( "Index log:" ), this );
+
+ _ok = new KPushButton( KStdGuiItem::ok(), this );
+ _ok->setFixedSize( 80, _ok->sizeHint().height() );
+ connect( _ok, SIGNAL( clicked() ), this, SLOT( slotOK() ) );
+ _ok->setEnabled( FALSE );
+
+ _save = new QPushButton( i18n( "Save Log..." ), this );
+ _save->setFixedSize( 80, _save->sizeHint().height() );
+ connect( _save, SIGNAL( clicked() ), _log, SLOT( save() ) );
+ _save->setEnabled( FALSE );
+
+ _abort = new QPushButton( i18n( "Abort" ), this );
+ _abort->setFixedSize( 80, _abort->sizeHint().height() );
+ connect( _abort, SIGNAL( clicked() ), this, SLOT( slotAbort() ) );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 8, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addStrut( 3 * lbl1->height() + 16 );
+ l1_1->addWidget( f1 );
+ l1_1->addWidget( f2 );
+
+ QVBoxLayout* l1_1_1 = new QVBoxLayout( f1, 4, 4 );
+
+ QHBoxLayout* l1_1_1_1 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_1 );
+ l1_1_1_1->addWidget( lbl1 );
+ l1_1_1_1->addWidget( _elapsedTime, 1 );
+
+ QHBoxLayout* l1_1_1_2 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_2 );
+ l1_1_1_2->addWidget( lbl3 );
+ l1_1_1_2->addWidget( _kbytesRead, 1 );
+
+ QHBoxLayout* l1_1_1_3 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_3 );
+ l1_1_1_3->addWidget( lbl5 );
+ l1_1_1_3->addWidget( _transferRate, 1 );
+
+ QVBoxLayout* l1_1_2 = new QVBoxLayout( f2, 4, 4 );
+
+ QHBoxLayout* l1_1_2_1 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_1 );
+ l1_1_2_1->addWidget( lbl2 );
+ l1_1_2_1->addWidget( _archives, 1 );
+
+ QHBoxLayout* l1_1_2_2 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_2 );
+ l1_1_2_2->addWidget( lbl4 );
+ l1_1_2_2->addWidget( _files, 1 );
+
+ QHBoxLayout* l1_1_2_3 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_3 );
+ l1_1_2_3->addWidget( lbl6 );
+ l1_1_2_3->addWidget( _totalFiles, 1 );
+
+ l1->addWidget( _log, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addStretch( 1 );
+ l1_2->addWidget( _ok );
+ l1_2->addWidget( _save );
+ l1_2->addWidget( _abort );
+}
+
+IndexDlg::~IndexDlg()
+{
+ delete _tarParser;
+}
+
+void IndexDlg::show()
+{
+ startTimer( 100 );
+
+ QDialog::show();
+}
+
+void IndexDlg::slotEntry( const QString & name, int size, int mtime, int record )
+{
+ if ( !_fileName.isEmpty() ) {
+ _archive->addFile( _fileSize, _fileMTime, _fileStartRecord, record, _fileName );
+ }
+
+ _fileName = name;
+ _fileSize = size;
+ _fileMTime = mtime;
+ _fileStartRecord = record;
+
+ /* 2002-01-28 LEW */
+ // printf("IndexDlg::slotEntry called with \"%s\", %d bytes\n", name.latin1(), size);
+ /* 2002-01-28 LEW */
+
+ QString tmp;
+ tmp.setNum( ++_numFiles );
+ _files->setText( tmp );
+ _totalFileCount++;
+ tmp.setNum( _totalFileCount );
+ _totalFiles->setText( tmp );
+
+ _log->append( name );
+}
+
+void IndexDlg::slotOK()
+{
+ if ( _aborted ) {
+ reject();
+ } else {
+ accept();
+ }
+}
+
+void IndexDlg::slotAbort()
+{
+ killTimers();
+ _aborted = TRUE;
+}
+
+void IndexDlg::timerEvent( QTimerEvent* )
+{
+ killTimers();
+
+ // Rewind tape.
+ _log->append( i18n( "Rewinding tape." ) );
+ if ( !TapeDrive::instance()->rewind() ) {
+ KMessageBox::error( this, i18n( "Cannot rewind tape. Indexing aborted." ));
+ _ok->setEnabled( TRUE );
+ _save->setEnabled( TRUE );
+ _abort->setEnabled( FALSE );
+ _log->append( i18n( "Cannot rewind tape." ) );
+ return;
+ }
+
+ // Skip tape ID.
+ if ( !TapeDrive::instance()->nextFile( 1 ) ) {
+ KMessageBox::error( this, i18n( "Failed to skip tape ID. Indexing aborted." ));
+ _ok->setEnabled( TRUE );
+ _save->setEnabled( TRUE );
+ _abort->setEnabled( FALSE );
+ _log->append( i18n( "Failed to skip tape ID." ) );
+ return;
+ }
+
+ _startTime = time( NULL );
+
+ int oldElapsed = 0;
+ QString msg;
+ int count;
+ char *buf = new char[Options::instance()->getTapeBlockSize()];
+ bool atLeastOneGoodRead = TRUE;
+ while ( ( !_aborted ) && ( atLeastOneGoodRead ) ) {
+ atLeastOneGoodRead = FALSE;
+ _archive = NULL;
+
+ delete _tarParser;
+ _tarParser = new TarParser();
+ connect( _tarParser, SIGNAL( sigEntry( const QString &, int, int, int ) ), this, SLOT( slotEntry( const QString &, int, int, int ) ) );
+
+ int endBlock = 0;
+ int leftover = 0;
+
+ while ( ( count = TapeDrive::instance()->read( buf, Options::instance()->getTapeBlockSize() ) ) > 0 ) {
+ // Is this the first block of the archive?
+ if ( !atLeastOneGoodRead ) {
+ atLeastOneGoodRead = TRUE;
+ _archiveCount++;
+ msg.setNum( _archiveCount );
+ _archives->setText( msg );
+ msg = i18n( "Indexing archive %1." ).arg( _archiveCount );
+ _log->append( msg );
+
+ msg = i18n( "Archive %1" ).arg( _archiveCount );
+ _archive = new Archive( _tape, 0, msg );
+ _fileName = QString::null;
+ _fileSize = -1;
+ _fileMTime = -1;
+ _fileStartRecord = -1;
+ _numFiles = 0;
+ }
+
+ leftover += count;
+ endBlock += leftover / Options::instance()->getTapeBlockSize();
+ leftover %= Options::instance()->getTapeBlockSize();
+
+ _tarParser->slotData( buf, count );
+ _totalKBytes += (float)count / 1024.0;
+
+ // Update stats.
+ int elapsed = time( NULL ) - _startTime;
+ if ( elapsed > oldElapsed )
+ {
+ updateStats();
+ KApplication::kApplication()->processEvents();
+ if ( _aborted ) {
+ break;
+ }
+ oldElapsed = elapsed;
+ }
+ }
+ if ( _aborted ) {
+ break;
+ }
+ if ( _archive ) {
+ _archive->setEndBlock( endBlock );
+
+ if ( _fileName.length() > 0 ) {
+ _archive->addFile( _fileSize, _fileMTime, _fileStartRecord, _archive->getEndBlock() * ( Options::instance()->getTapeBlockSize() / 512 ), _fileName );
+ }
+
+ _tape->addChild( _archive );
+ }
+ }
+
+ delete [] buf;
+
+ updateStats();
+
+ TapeDrive::instance()->rewind();
+
+ if ( !_aborted ) {
+ _tape->setName( i18n( "Reindexed Tape" ) );
+ _tape->setSize( Options::instance()->getDefaultTapeSize() );
+ }
+
+ _ok->setEnabled( TRUE );
+ _ok->setDefault( TRUE );
+ _save->setEnabled( TRUE );
+ _abort->setEnabled( FALSE );
+}
+
+void IndexDlg::updateStats()
+{
+ QString str;
+ int elapsed = time( NULL ) - _startTime;
+
+ str = QString::fromUtf8( QCString().sprintf( i18n( "%02d:%02d:%02d" ).utf8(), elapsed / 3600, elapsed / 60 % 60, elapsed % 60 ) );
+ _elapsedTime->setText( str );
+
+ str = Util::kbytesToString( (int)_totalKBytes );
+ _kbytesRead->setText( str );
+
+ if ( elapsed > 0 ) {
+ str = i18n( "%1/min" ).arg(Util::kbytesToString( (int)_totalKBytes * 60 / elapsed ) );
+ _transferRate->setText( str );
+ }
+}
diff --git a/kdat/IndexDlg.h b/kdat/IndexDlg.h
new file mode 100644
index 0000000..e624cf5
--- /dev/null
+++ b/kdat/IndexDlg.h
@@ -0,0 +1,92 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _IndexDlg_h_
+#define _IndexDlg_h_
+
+#include <qdialog.h>
+#include <qptrlist.h>
+
+#include "Range.h"
+
+class QLabel;
+class QPushButton;
+
+class Archive;
+class File;
+class LoggerWidget;
+class Tape;
+class TarParser;
+
+/**
+ * @short Status dialog for recreating a tape index.
+ */
+class IndexDlg : public QDialog {
+ Q_OBJECT
+ TarParser* _tarParser;
+ Tape* _tape;
+ Archive* _archive;
+ QString _leftover;
+ QLabel* _elapsedTime;
+ QLabel* _kbytesRead;
+ QLabel* _transferRate;
+ QLabel* _archives;
+ QLabel* _files;
+ QLabel* _totalFiles;
+ LoggerWidget* _log;
+ QPushButton* _ok;
+ QPushButton* _save;
+ QPushButton* _abort;
+ int _startTime;
+ float _totalKBytes;
+ int _archiveCount;
+ int _fileCount;
+ int _totalFileCount;
+ bool _aborted;
+ int _numFiles;
+
+ int _fileSize;
+ int _fileMTime;
+ int _fileStartRecord;
+ QString _fileName;
+
+ void updateStats();
+private slots:
+ void slotOK();
+ void slotAbort();
+ void slotEntry( const QString & name, int size, int mtime, int record );
+protected:
+ void show();
+ void timerEvent( QTimerEvent* e );
+public:
+ /**
+ * Create a new tape index dialog.
+ *
+ * @param tape A pointer to the empty tape index to fill in.
+ * @param parent The parent widget for this dialog.
+ * @param name The name of this dialog.
+ */
+ IndexDlg( Tape* tape, QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the tape index dialog.
+ */
+ ~IndexDlg();
+};
+
+#endif
diff --git a/kdat/InfoShellWidget.cpp b/kdat/InfoShellWidget.cpp
new file mode 100644
index 0000000..e7c3189
--- /dev/null
+++ b/kdat/InfoShellWidget.cpp
@@ -0,0 +1,43 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <qobjectlist.h>
+#include <qobjectdict.h>
+
+#include "InfoShellWidget.h"
+
+#include "InfoShellWidget.moc"
+
+InfoShellWidget::InfoShellWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+}
+
+InfoShellWidget::~InfoShellWidget()
+{
+}
+
+void InfoShellWidget::resizeEvent( QResizeEvent* )
+{
+ if ( children() ) {
+ QObjectListIt i( *children() );
+ for ( ; i.current(); ++i ) {
+ ((QWidget*)i.current())->resize( size() );
+ }
+ }
+}
diff --git a/kdat/InfoShellWidget.h b/kdat/InfoShellWidget.h
new file mode 100644
index 0000000..c1379ee
--- /dev/null
+++ b/kdat/InfoShellWidget.h
@@ -0,0 +1,49 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _InfoShellWidget_h_
+#define _InfoShellWidget_h_
+
+#include <qwidget.h>
+
+/**
+ * @short A suitable parent for the info widgets.
+ */
+class InfoShellWidget : public QWidget {
+ Q_OBJECT
+public:
+ /**
+ * Create a new info shell widget.
+ *
+ * @param parent The parent widget.
+ * @param name The name of this widget.
+ */
+ InfoShellWidget( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the info shell widget.
+ */
+ ~InfoShellWidget();
+protected:
+ /**
+ * Resize all children to fill all of the available space within the shell.
+ */
+ virtual void resizeEvent( QResizeEvent* e );
+};
+
+#endif
diff --git a/kdat/KDat.kdoc b/kdat/KDat.kdoc
new file mode 100644
index 0000000..7297e64
--- /dev/null
+++ b/kdat/KDat.kdoc
@@ -0,0 +1,643 @@
+.
+Archive=Archive.html
+Archive=Archive.html
+Archive::_startBlock=Archive.html#_startBlock
+Archive::_endBlock=Archive.html#_endBlock
+Archive::_timeStamp=Archive.html#_timeStamp
+Archive::_name=Archive.html#_name
+Archive::Archive=Archive.html#Archive
+Archive::~Archive=Archive.html#~Archive
+Archive::timeStamp=Archive.html#timeStamp
+Archive::startBlock=Archive.html#startBlock
+Archive::endBlock=Archive.html#endBlock
+Archive::name=Archive.html#name
+Archive::files=Archive.html#files
+Archive::children=Archive.html#children
+Archive::setEndBlock=Archive.html#setEndBlock
+Archive::setName=Archive.html#setName
+Archive::addFile=Archive.html#addFile
+ArchiveInfoDlg=ArchiveInfoDlg.html
+ArchiveInfoDlg=ArchiveInfoDlg.html
+ArchiveInfoDlg::_tape=ArchiveInfoDlg.html#_tape
+ArchiveInfoDlg::_archive=ArchiveInfoDlg.html#_archive
+ArchiveInfoDlg::_archiveName=ArchiveInfoDlg.html#_archiveName
+ArchiveInfoDlg::slotOK=ArchiveInfoDlg.html#slotOK
+ArchiveInfoDlg::slotApply=ArchiveInfoDlg.html#slotApply
+ArchiveInfoDlg::slotCancel=ArchiveInfoDlg.html#slotCancel
+ArchiveInfoDlg::ArchiveInfoDlg=ArchiveInfoDlg.html#ArchiveInfoDlg
+ArchiveInfoDlg::~ArchiveInfoDlg=ArchiveInfoDlg.html#~ArchiveInfoDlg
+BackupDlg=BackupDlg.html
+BackupDlg=BackupDlg.html
+BackupDlg::_proc=BackupDlg.html#_proc
+BackupDlg::_tarParser=BackupDlg.html#_tarParser
+BackupDlg::_archiveName=BackupDlg.html#_archiveName
+BackupDlg::_workingDir=BackupDlg.html#_workingDir
+BackupDlg::_file=BackupDlg.html#_file
+BackupDlg::_oneFileSystem=BackupDlg.html#_oneFileSystem
+BackupDlg::_incremental=BackupDlg.html#_incremental
+BackupDlg::_snapshot=BackupDlg.html#_snapshot
+BackupDlg::_archiveSize=BackupDlg.html#_archiveSize
+BackupDlg::_tape=BackupDlg.html#_tape
+BackupDlg::_totalKBytes=BackupDlg.html#_totalKBytes
+BackupDlg::_elapsedTime=BackupDlg.html#_elapsedTime
+BackupDlg::_timeRemaining=BackupDlg.html#_timeRemaining
+BackupDlg::_kbytesWritten=BackupDlg.html#_kbytesWritten
+BackupDlg::_transferRate=BackupDlg.html#_transferRate
+BackupDlg::_files=BackupDlg.html#_files
+BackupDlg::_log=BackupDlg.html#_log
+BackupDlg::_ok=BackupDlg.html#_ok
+BackupDlg::_save=BackupDlg.html#_save
+BackupDlg::_abort=BackupDlg.html#_abort
+BackupDlg::_startTime=BackupDlg.html#_startTime
+BackupDlg::_archive=BackupDlg.html#_archive
+BackupDlg::_aborted=BackupDlg.html#_aborted
+BackupDlg::toString=BackupDlg.html#toString
+BackupDlg::slotProcessExited=BackupDlg.html#slotProcessExited
+BackupDlg::slotStdout=BackupDlg.html#slotStdout
+BackupDlg::slotOK=BackupDlg.html#slotOK
+BackupDlg::slotAbort=BackupDlg.html#slotAbort
+BackupDlg::slotEntry=BackupDlg.html#slotEntry
+BackupDlg::show=BackupDlg.html#show
+BackupDlg::timerEvent=BackupDlg.html#timerEvent
+BackupDlg::BackupDlg=BackupDlg.html#BackupDlg
+BackupDlg::~BackupDlg=BackupDlg.html#~BackupDlg
+BackupOptDlg=BackupOptDlg.html
+BackupOptDlg=BackupOptDlg.html
+BackupOptDlg::_archiveName=BackupOptDlg.html#_archiveName
+BackupOptDlg::_sourceFile=BackupOptDlg.html#_sourceFile
+BackupOptDlg::_workingDir=BackupOptDlg.html#_workingDir
+BackupOptDlg::_oneFilesystem=BackupOptDlg.html#_oneFilesystem
+BackupOptDlg::_listedIncremental=BackupOptDlg.html#_listedIncremental
+BackupOptDlg::_group=BackupOptDlg.html#_group
+BackupOptDlg::_snapshotLabel=BackupOptDlg.html#_snapshotLabel
+BackupOptDlg::_snapshotFile=BackupOptDlg.html#_snapshotFile
+BackupOptDlg::_removeSnapshot=BackupOptDlg.html#_removeSnapshot
+BackupOptDlg::incrementalToggled=BackupOptDlg.html#incrementalToggled
+BackupOptDlg::BackupOptDlg=BackupOptDlg.html#BackupOptDlg
+BackupOptDlg::~BackupOptDlg=BackupOptDlg.html#~BackupOptDlg
+BackupOptDlg::archiveName=BackupOptDlg.html#archiveName
+BackupOptDlg::file=BackupOptDlg.html#file
+BackupOptDlg::workingDir=BackupOptDlg.html#workingDir
+BackupOptDlg::oneFilesystem=BackupOptDlg.html#oneFilesystem
+BackupOptDlg::incremental=BackupOptDlg.html#incremental
+BackupOptDlg::snapshotFile=BackupOptDlg.html#snapshotFile
+BackupOptDlg::removeSnapshot=BackupOptDlg.html#removeSnapshot
+File=File.html
+File=File.html
+File::_size=File.html#_size
+File::_mtime=File.html#_mtime
+File::_record=File.html#_record
+File::_name=File.html#_name
+File::File=File.html#File
+File::~File=File.html#~File
+File::size=File.html#size
+File::mtime=File.html#mtime
+File::record=File.html#record
+File::name=File.html#name
+File::children=File.html#children
+IndexDlg=IndexDlg.html
+IndexDlg=IndexDlg.html
+IndexDlg::_tarParser=IndexDlg.html#_tarParser
+IndexDlg::_tape=IndexDlg.html#_tape
+IndexDlg::_archive=IndexDlg.html#_archive
+IndexDlg::_leftover=IndexDlg.html#_leftover
+IndexDlg::_elapsedTime=IndexDlg.html#_elapsedTime
+IndexDlg::_kbytesRead=IndexDlg.html#_kbytesRead
+IndexDlg::_transferRate=IndexDlg.html#_transferRate
+IndexDlg::_archives=IndexDlg.html#_archives
+IndexDlg::_files=IndexDlg.html#_files
+IndexDlg::_totalFiles=IndexDlg.html#_totalFiles
+IndexDlg::_log=IndexDlg.html#_log
+IndexDlg::_ok=IndexDlg.html#_ok
+IndexDlg::_save=IndexDlg.html#_save
+IndexDlg::_abort=IndexDlg.html#_abort
+IndexDlg::_startTime=IndexDlg.html#_startTime
+IndexDlg::_totalKBytes=IndexDlg.html#_totalKBytes
+IndexDlg::_archiveCount=IndexDlg.html#_archiveCount
+IndexDlg::_fileCount=IndexDlg.html#_fileCount
+IndexDlg::_totalFileCount=IndexDlg.html#_totalFileCount
+IndexDlg::_aborted=IndexDlg.html#_aborted
+IndexDlg::updateStats=IndexDlg.html#updateStats
+IndexDlg::toString=IndexDlg.html#toString
+IndexDlg::slotOK=IndexDlg.html#slotOK
+IndexDlg::slotAbort=IndexDlg.html#slotAbort
+IndexDlg::slotEntry=IndexDlg.html#slotEntry
+IndexDlg::show=IndexDlg.html#show
+IndexDlg::timerEvent=IndexDlg.html#timerEvent
+IndexDlg::IndexDlg=IndexDlg.html#IndexDlg
+IndexDlg::~IndexDlg=IndexDlg.html#~IndexDlg
+KDat=KDat.html
+KDat=KDat.html
+KDat::_menu=KDat.html#_menu
+KDat::_fileMenu=KDat.html#_fileMenu
+KDat::_editMenu=KDat.html#_editMenu
+KDat::_toolbar=KDat.html#_toolbar
+KDat::_statusBar=KDat.html#_statusBar
+KDat::_localTree=KDat.html#_localTree
+KDat::_tapeTree=KDat.html#_tapeTree
+KDat::_folderOpen=KDat.html#_folderOpen
+KDat::_folderClosed=KDat.html#_folderClosed
+KDat::_file=KDat.html#_file
+KDat::_archive=KDat.html#_archive
+KDat::_online=KDat.html#_online
+KDat::_offline=KDat.html#_offline
+KDat::_tapePresent=KDat.html#_tapePresent
+KDat::_tape=KDat.html#_tape
+KDat::_instance=KDat.html#_instance
+KDat::setTapePresent=KDat.html#setTapePresent
+KDat::fillTapeTree=KDat.html#fillTapeTree
+KDat::insertNode=KDat.html#insertNode
+KDat::indexIndex=KDat.html#indexIndex
+KDat::calcBackupSize=KDat.html#calcBackupSize
+KDat::KDat=KDat.html#KDat
+KDat::localExpanding=KDat.html#localExpanding
+KDat::localExpanded=KDat.html#localExpanded
+KDat::localCollapsed=KDat.html#localCollapsed
+KDat::localSelected=KDat.html#localSelected
+KDat::tapeExpanding=KDat.html#tapeExpanding
+KDat::tapeExpanded=KDat.html#tapeExpanded
+KDat::tapeCollapsed=KDat.html#tapeCollapsed
+KDat::tapeSelected=KDat.html#tapeSelected
+KDat::fileBackup=KDat.html#fileBackup
+KDat::fileRestore=KDat.html#fileRestore
+KDat::fileVerify=KDat.html#fileVerify
+KDat::fileMountTape=KDat.html#fileMountTape
+KDat::fileIndexTape=KDat.html#fileIndexTape
+KDat::fileFormatTape=KDat.html#fileFormatTape
+KDat::fileQuit=KDat.html#fileQuit
+KDat::editTapeInfo=KDat.html#editTapeInfo
+KDat::editPreferences=KDat.html#editPreferences
+KDat::help=KDat.html#help
+KDat::slotTapeDevice=KDat.html#slotTapeDevice
+KDat::~KDat=KDat.html#~KDat
+KDat::instance=KDat.html#instance
+KDat::status=KDat.html#status
+TapeDrive=TapeDrive.html
+TapeDrive=TapeDrive.html
+TapeDrive::_fd=TapeDrive.html#_fd
+TapeDrive::_readOnly=TapeDrive.html#_readOnly
+TapeDrive::_tape=TapeDrive.html#_tape
+TapeDrive::_writeBuf=TapeDrive.html#_writeBuf
+TapeDrive::_readBuf=TapeDrive.html#_readBuf
+TapeDrive::_writeBufIdx=TapeDrive.html#_writeBufIdx
+TapeDrive::_readBufIdx=TapeDrive.html#_readBufIdx
+TapeDrive::_instance=TapeDrive.html#_instance
+TapeDrive::TapeDrive=TapeDrive.html#TapeDrive
+TapeDrive::flush=TapeDrive.html#flush
+TapeDrive::instance=TapeDrive.html#instance
+TapeDrive::isReadOnly=TapeDrive.html#isReadOnly
+TapeDrive::isTapePresent=TapeDrive.html#isTapePresent
+TapeDrive::ejectTape=TapeDrive.html#ejectTape
+TapeDrive::eraseTape=TapeDrive.html#eraseTape
+TapeDrive::rewind=TapeDrive.html#rewind
+TapeDrive::readHeader=TapeDrive.html#readHeader
+TapeDrive::getBlock=TapeDrive.html#getBlock
+TapeDrive::gotoBlock=TapeDrive.html#gotoBlock
+TapeDrive::nextFile=TapeDrive.html#nextFile
+TapeDrive::prevFile=TapeDrive.html#prevFile
+TapeDrive::nextRecord=TapeDrive.html#nextRecord
+TapeDrive::prevRecord=TapeDrive.html#prevRecord
+TapeDrive::endOfTape=TapeDrive.html#endOfTape
+TapeDrive::open=TapeDrive.html#open
+TapeDrive::close=TapeDrive.html#close
+TapeDrive::read=TapeDrive.html#read
+TapeDrive::write=TapeDrive.html#write
+TapeDrive::writeEOF=TapeDrive.html#writeEOF
+TapeDrive::seek=TapeDrive.html#seek
+TapeDrive::pastEOF=TapeDrive.html#pastEOF
+TapeDrive::lock=TapeDrive.html#lock
+TapeDrive::unlock=TapeDrive.html#unlock
+TapeDrive::setBlockSize=TapeDrive.html#setBlockSize
+TapeDrive::slotTapeBlockSize=TapeDrive.html#slotTapeBlockSize
+TapeDrive::status=TapeDrive.html#status
+Logger=Logger.html
+Logger=Logger.html
+Logger::_mle=Logger.html#_mle
+Logger::Logger=Logger.html#Logger
+Logger::~Logger=Logger.html#~Logger
+Logger::append=Logger.html#append
+Logger::save=Logger.html#save
+Node=Node.html
+Node=Node.html
+Node::_type=Node.html#_type
+Node::_archive=Node.html#_archive
+Node::_file=Node.html#_file
+Node::=Node.html#
+Node::Node=Node.html#Node
+Node::Node=Node.html#Node
+Node::Node=Node.html#Node
+Node::type=Node.html#type
+Node::archive=Node.html#archive
+Node::file=Node.html#file
+Options=Options.html
+Options=Options.html
+Options::_config=Options.html#_config
+Options::_instance=Options.html#_instance
+Options::Options=Options.html#Options
+Options::instance=Options.html#instance
+Options::sync=Options.html#sync
+Options::getDefaultTapeSize=Options.html#getDefaultTapeSize
+Options::getTapeBlockSize=Options.html#getTapeBlockSize
+Options::getTapeDevice=Options.html#getTapeDevice
+Options::getTarCommand=Options.html#getTarCommand
+Options::getRmtCommand=Options.html#getRmtCommand
+Options::getLockOnMount=Options.html#getLockOnMount
+Options::getEjectOnUnmount=Options.html#getEjectOnUnmount
+Options::setDefaultTapeSize=Options.html#setDefaultTapeSize
+Options::setTapeBlockSize=Options.html#setTapeBlockSize
+Options::setTapeDevice=Options.html#setTapeDevice
+Options::setTarCommand=Options.html#setTarCommand
+Options::setRmtCommand=Options.html#setRmtCommand
+Options::setLockOnMount=Options.html#setLockOnMount
+Options::setEjectOnUnmount=Options.html#setEjectOnUnmount
+Options::sigDefaultTapeSize=Options.html#sigDefaultTapeSize
+Options::sigTapeBlockSize=Options.html#sigTapeBlockSize
+Options::sigTapeDevice=Options.html#sigTapeDevice
+Options::sigTarCommand=Options.html#sigTarCommand
+Options::sigRmtCommand=Options.html#sigRmtCommand
+Options::sigLockOnMount=Options.html#sigLockOnMount
+Options::sigEjectOnUnmount=Options.html#sigEjectOnUnmount
+OptionsDlg=OptionsDlg.html
+OptionsDlg=OptionsDlg.html
+OptionsDlg::_defaultTapeSize=OptionsDlg.html#_defaultTapeSize
+OptionsDlg::_defaultTapeSizeUnits=OptionsDlg.html#_defaultTapeSizeUnits
+OptionsDlg::_tapeBlockSize=OptionsDlg.html#_tapeBlockSize
+OptionsDlg::_tapeDevice=OptionsDlg.html#_tapeDevice
+OptionsDlg::_tarCommand=OptionsDlg.html#_tarCommand
+OptionsDlg::_lockOnMount=OptionsDlg.html#_lockOnMount
+OptionsDlg::_ejectOnUnmount=OptionsDlg.html#_ejectOnUnmount
+OptionsDlg::OptionsDlg=OptionsDlg.html#OptionsDlg
+OptionsDlg::~OptionsDlg=OptionsDlg.html#~OptionsDlg
+OptionsDlg::slotOK=OptionsDlg.html#slotOK
+OptionsDlg::slotApply=OptionsDlg.html#slotApply
+OptionsDlg::slotCancel=OptionsDlg.html#slotCancel
+Range=Range.html
+Range=Range.html
+Range::Range=Range.html#Range
+Range::start=Range.html#start
+Range::end=Range.html#end
+RestoreDlg=RestoreDlg.html
+RestoreDlg=RestoreDlg.html
+RestoreDlg::_proc=RestoreDlg.html#_proc
+RestoreDlg::_workingDir=RestoreDlg.html#_workingDir
+RestoreDlg::_startBlock=RestoreDlg.html#_startBlock
+RestoreDlg::_leftover=RestoreDlg.html#_leftover
+RestoreDlg::_elapsedTime=RestoreDlg.html#_elapsedTime
+RestoreDlg::_timeRemaining=RestoreDlg.html#_timeRemaining
+RestoreDlg::_kbytesRead=RestoreDlg.html#_kbytesRead
+RestoreDlg::_transferRate=RestoreDlg.html#_transferRate
+RestoreDlg::_files=RestoreDlg.html#_files
+RestoreDlg::_log=RestoreDlg.html#_log
+RestoreDlg::_ok=RestoreDlg.html#_ok
+RestoreDlg::_save=RestoreDlg.html#_save
+RestoreDlg::_abort=RestoreDlg.html#_abort
+RestoreDlg::_startTime=RestoreDlg.html#_startTime
+RestoreDlg::_totalKBytes=RestoreDlg.html#_totalKBytes
+RestoreDlg::_fileCount=RestoreDlg.html#_fileCount
+RestoreDlg::_archiveSize=RestoreDlg.html#_archiveSize
+RestoreDlg::_wroteStdin=RestoreDlg.html#_wroteStdin
+RestoreDlg::_aborted=RestoreDlg.html#_aborted
+RestoreDlg::_done=RestoreDlg.html#_done
+RestoreDlg::toString=RestoreDlg.html#toString
+RestoreDlg::slotProcessExited=RestoreDlg.html#slotProcessExited
+RestoreDlg::slotStdout=RestoreDlg.html#slotStdout
+RestoreDlg::slotWroteStdin=RestoreDlg.html#slotWroteStdin
+RestoreDlg::slotOK=RestoreDlg.html#slotOK
+RestoreDlg::slotAbort=RestoreDlg.html#slotAbort
+RestoreDlg::show=RestoreDlg.html#show
+RestoreDlg::timerEvent=RestoreDlg.html#timerEvent
+RestoreDlg::RestoreDlg=RestoreDlg.html#RestoreDlg
+RestoreDlg::~RestoreDlg=RestoreDlg.html#~RestoreDlg
+RestoreOptDlg=RestoreOptDlg.html
+RestoreOptDlg=RestoreOptDlg.html
+RestoreOptDlg::_workingDir=RestoreOptDlg.html#_workingDir
+RestoreOptDlg::_entry=RestoreOptDlg.html#_entry
+RestoreOptDlg::okClicked=RestoreOptDlg.html#okClicked
+RestoreOptDlg::RestoreOptDlg=RestoreOptDlg.html#RestoreOptDlg
+RestoreOptDlg::~RestoreOptDlg=RestoreOptDlg.html#~RestoreOptDlg
+RestoreOptDlg::workingDir=RestoreOptDlg.html#workingDir
+Tape=Tape.html
+Tape=Tape.html
+Tape::_tapeID=Tape.html#_tapeID
+Tape::_createTime=Tape.html#_createTime
+Tape::_modTime=Tape.html#_modTime
+Tape::_tapeName=Tape.html#_tapeName
+Tape::_tapeSize=Tape.html#_tapeSize
+Tape::Tape=Tape.html#Tape
+Tape::~Tape=Tape.html#~Tape
+Tape::formatTape=Tape.html#formatTape
+Tape::writeIndex=Tape.html#writeIndex
+Tape::tapeName=Tape.html#tapeName
+Tape::tapeID=Tape.html#tapeID
+Tape::createTime=Tape.html#createTime
+Tape::modTime=Tape.html#modTime
+Tape::tapeSize=Tape.html#tapeSize
+Tape::numArchives=Tape.html#numArchives
+Tape::addArchive=Tape.html#addArchive
+Tape::setTapeName=Tape.html#setTapeName
+Tape::setTapeSize=Tape.html#setTapeSize
+Tape::archives=Tape.html#archives
+Tape::status=Tape.html#status
+TapeDriveIF=TapeDriveIF.html
+TapeDriveIF=TapeDriveIF.html
+TapeDriveIF::flush=TapeDriveIF.html#flush
+TapeDriveIF::nextRecord=TapeDriveIF.html#nextRecord
+TapeDriveIF::pastEOF=TapeDriveIF.html#pastEOF
+TapeDriveIF::prevFile=TapeDriveIF.html#prevFile
+TapeDriveIF::prevRecord=TapeDriveIF.html#prevRecord
+TapeDriveIF::setBlockSize=TapeDriveIF.html#setBlockSize
+TapeDriveIF::close=TapeDriveIF.html#close
+TapeDriveIF::eject=TapeDriveIF.html#eject
+TapeDriveIF::getBlock=TapeDriveIF.html#getBlock
+TapeDriveIF::isReadOnly=TapeDriveIF.html#isReadOnly
+TapeDriveIF::isTapePresent=TapeDriveIF.html#isTapePresent
+TapeDriveIF::lock=TapeDriveIF.html#lock
+TapeDriveIF::nextFile=TapeDriveIF.html#nextFile
+TapeDriveIF::open=TapeDriveIF.html#open
+TapeDriveIF::read=TapeDriveIF.html#read
+TapeDriveIF::readHeader=TapeDriveIF.html#readHeader
+TapeDriveIF::rewind=TapeDriveIF.html#rewind
+TapeDriveIF::seek=TapeDriveIF.html#seek
+TapeDriveIF::unlock=TapeDriveIF.html#unlock
+TapeDriveIF::write=TapeDriveIF.html#write
+TapeDrive=TapeDrive.html
+TapeDrive=TapeDrive.html
+TapeDrive::_tapeDrive=TapeDrive.html#_tapeDrive
+TapeDrive::_instance=TapeDrive.html#_instance
+TapeDrive::TapeDrive=TapeDrive.html#TapeDrive
+TapeDrive::flush=TapeDrive.html#flush
+TapeDrive::nextRecord=TapeDrive.html#nextRecord
+TapeDrive::pastEOF=TapeDrive.html#pastEOF
+TapeDrive::prevFile=TapeDrive.html#prevFile
+TapeDrive::prevRecord=TapeDrive.html#prevRecord
+TapeDrive::setBlockSize=TapeDrive.html#setBlockSize
+TapeDrive::instance=TapeDrive.html#instance
+TapeDrive::close=TapeDrive.html#close
+TapeDrive::eject=TapeDrive.html#eject
+TapeDrive::getBlock=TapeDrive.html#getBlock
+TapeDrive::isReadOnly=TapeDrive.html#isReadOnly
+TapeDrive::isTapePresent=TapeDrive.html#isTapePresent
+TapeDrive::lock=TapeDrive.html#lock
+TapeDrive::nextFile=TapeDrive.html#nextFile
+TapeDrive::open=TapeDrive.html#open
+TapeDrive::read=TapeDrive.html#read
+TapeDrive::readHeader=TapeDrive.html#readHeader
+TapeDrive::rewind=TapeDrive.html#rewind
+TapeDrive::seek=TapeDrive.html#seek
+TapeDrive::unlock=TapeDrive.html#unlock
+TapeDrive::write=TapeDrive.html#write
+TapeDrive::slotTapeBlockSize=TapeDrive.html#slotTapeBlockSize
+TapeDrive::slotStatus=TapeDrive.html#slotStatus
+TapeDrive::status=TapeDrive.html#status
+TapeInfoDlg=TapeInfoDlg.html
+TapeInfoDlg=TapeInfoDlg.html
+TapeInfoDlg::_tape=TapeInfoDlg.html#_tape
+TapeInfoDlg::_tapeName=TapeInfoDlg.html#_tapeName
+TapeInfoDlg::_tapeSize=TapeInfoDlg.html#_tapeSize
+TapeInfoDlg::_tapeSizeUnits=TapeInfoDlg.html#_tapeSizeUnits
+TapeInfoDlg::_archives=TapeInfoDlg.html#_archives
+TapeInfoDlg::toString=TapeInfoDlg.html#toString
+TapeInfoDlg::slotOK=TapeInfoDlg.html#slotOK
+TapeInfoDlg::slotApply=TapeInfoDlg.html#slotApply
+TapeInfoDlg::slotCancel=TapeInfoDlg.html#slotCancel
+TapeInfoDlg::slotArchiveInfo=TapeInfoDlg.html#slotArchiveInfo
+TapeInfoDlg::TapeInfoDlg=TapeInfoDlg.html#TapeInfoDlg
+TapeInfoDlg::~TapeInfoDlg=TapeInfoDlg.html#~TapeInfoDlg
+TapeNameDlg=TapeNameDlg.html
+TapeNameDlg=TapeNameDlg.html
+TapeNameDlg::_name=TapeNameDlg.html#_name
+TapeNameDlg::_size=TapeNameDlg.html#_size
+TapeNameDlg::_entry=TapeNameDlg.html#_entry
+TapeNameDlg::_tapeSize=TapeNameDlg.html#_tapeSize
+TapeNameDlg::_tapeSizeUnits=TapeNameDlg.html#_tapeSizeUnits
+TapeNameDlg::okClicked=TapeNameDlg.html#okClicked
+TapeNameDlg::TapeNameDlg=TapeNameDlg.html#TapeNameDlg
+TapeNameDlg::~TapeNameDlg=TapeNameDlg.html#~TapeNameDlg
+TapeNameDlg::name=TapeNameDlg.html#name
+TapeNameDlg::size=TapeNameDlg.html#size
+TarParser=TarParser.html
+TarParser=TarParser.html
+TarParser::_bufIdx=TarParser.html#_bufIdx
+TarParser::_blocksToSkip=TarParser.html#_blocksToSkip
+TarParser::_record=TarParser.html#_record
+TarParser::_longname=TarParser.html#_longname
+TarParser::_archnameIdx=TarParser.html#_archnameIdx
+TarParser::parseOctal=TarParser.html#parseOctal
+TarParser::parseTarBlock=TarParser.html#parseTarBlock
+TarParser::TarParser=TarParser.html#TarParser
+TarParser::slotData=TarParser.html#slotData
+TarParser::sigEntry=TarParser.html#sigEntry
+VerifyDlg=VerifyDlg.html
+VerifyDlg=VerifyDlg.html
+VerifyDlg::_proc=VerifyDlg.html#_proc
+VerifyDlg::_workingDir=VerifyDlg.html#_workingDir
+VerifyDlg::_startBlock=VerifyDlg.html#_startBlock
+VerifyDlg::_leftover=VerifyDlg.html#_leftover
+VerifyDlg::_elapsedTime=VerifyDlg.html#_elapsedTime
+VerifyDlg::_timeRemaining=VerifyDlg.html#_timeRemaining
+VerifyDlg::_kbytesRead=VerifyDlg.html#_kbytesRead
+VerifyDlg::_transferRate=VerifyDlg.html#_transferRate
+VerifyDlg::_files=VerifyDlg.html#_files
+VerifyDlg::_log=VerifyDlg.html#_log
+VerifyDlg::_ok=VerifyDlg.html#_ok
+VerifyDlg::_save=VerifyDlg.html#_save
+VerifyDlg::_abort=VerifyDlg.html#_abort
+VerifyDlg::_startTime=VerifyDlg.html#_startTime
+VerifyDlg::_totalKBytes=VerifyDlg.html#_totalKBytes
+VerifyDlg::_fileCount=VerifyDlg.html#_fileCount
+VerifyDlg::_archiveSize=VerifyDlg.html#_archiveSize
+VerifyDlg::_wroteStdin=VerifyDlg.html#_wroteStdin
+VerifyDlg::_aborted=VerifyDlg.html#_aborted
+VerifyDlg::_done=VerifyDlg.html#_done
+VerifyDlg::updateStats=VerifyDlg.html#updateStats
+VerifyDlg::toString=VerifyDlg.html#toString
+VerifyDlg::slotProcessExited=VerifyDlg.html#slotProcessExited
+VerifyDlg::slotStdout=VerifyDlg.html#slotStdout
+VerifyDlg::slotWroteStdin=VerifyDlg.html#slotWroteStdin
+VerifyDlg::slotOK=VerifyDlg.html#slotOK
+VerifyDlg::slotAbort=VerifyDlg.html#slotAbort
+VerifyDlg::show=VerifyDlg.html#show
+VerifyDlg::timerEvent=VerifyDlg.html#timerEvent
+VerifyDlg::VerifyDlg=VerifyDlg.html#VerifyDlg
+VerifyDlg::~VerifyDlg=VerifyDlg.html#~VerifyDlg
+VerifyOptDlg=VerifyOptDlg.html
+VerifyOptDlg=VerifyOptDlg.html
+VerifyOptDlg::_workingDir=VerifyOptDlg.html#_workingDir
+VerifyOptDlg::_entry=VerifyOptDlg.html#_entry
+VerifyOptDlg::okClicked=VerifyOptDlg.html#okClicked
+VerifyOptDlg::VerifyOptDlg=VerifyOptDlg.html#VerifyOptDlg
+VerifyOptDlg::~VerifyOptDlg=VerifyOptDlg.html#~VerifyOptDlg
+VerifyOptDlg::workingDir=VerifyOptDlg.html#workingDir
+KTreeViewItem=KTreeViewItem.html
+KTreeViewItem=KTreeViewItem.html
+KTreeViewItem::KTreeView=KTreeViewItem.html#KTreeView
+KTreeViewItem::KTreeViewItem=KTreeViewItem.html#KTreeViewItem
+KTreeViewItem::KTreeViewItem=KTreeViewItem.html#KTreeViewItem
+KTreeViewItem::~KTreeViewItem=KTreeViewItem.html#~KTreeViewItem
+KTreeViewItem::appendChild=KTreeViewItem.html#appendChild
+KTreeViewItem::childAt=KTreeViewItem.html#childAt
+KTreeViewItem::childCount=KTreeViewItem.html#childCount
+KTreeViewItem::childIndex=KTreeViewItem.html#childIndex
+KTreeViewItem::expandButtonClicked=KTreeViewItem.html#expandButtonClicked
+KTreeViewItem::getChild=KTreeViewItem.html#getChild
+KTreeViewItem::getParent=KTreeViewItem.html#getParent
+KTreeViewItem::getPixmap=KTreeViewItem.html#getPixmap
+KTreeViewItem::getSibling=KTreeViewItem.html#getSibling
+KTreeViewItem::getText=KTreeViewItem.html#getText
+KTreeViewItem::hasChild=KTreeViewItem.html#hasChild
+KTreeViewItem::hasParent=KTreeViewItem.html#hasParent
+KTreeViewItem::hasSibling=KTreeViewItem.html#hasSibling
+KTreeViewItem::insertChild=KTreeViewItem.html#insertChild
+KTreeViewItem::isExpanded=KTreeViewItem.html#isExpanded
+KTreeViewItem::isVisible=KTreeViewItem.html#isVisible
+KTreeViewItem::removeChild=KTreeViewItem.html#removeChild
+KTreeViewItem::setDelayedExpanding=KTreeViewItem.html#setDelayedExpanding
+KTreeViewItem::setDeleteChildren=KTreeViewItem.html#setDeleteChildren
+KTreeViewItem::setDrawExpandButton=KTreeViewItem.html#setDrawExpandButton
+KTreeViewItem::setDrawText=KTreeViewItem.html#setDrawText
+KTreeViewItem::setDrawTree=KTreeViewItem.html#setDrawTree
+KTreeViewItem::setExpanded=KTreeViewItem.html#setExpanded
+KTreeViewItem::setPixmap=KTreeViewItem.html#setPixmap
+KTreeViewItem::setText=KTreeViewItem.html#setText
+KTreeViewItem::boundingRect=KTreeViewItem.html#boundingRect
+KTreeViewItem::height=KTreeViewItem.html#height
+KTreeViewItem::height=KTreeViewItem.html#height
+KTreeViewItem::paint=KTreeViewItem.html#paint
+KTreeViewItem::paintExpandButton=KTreeViewItem.html#paintExpandButton
+KTreeViewItem::paintHighlight=KTreeViewItem.html#paintHighlight
+KTreeViewItem::paintText=KTreeViewItem.html#paintText
+KTreeViewItem::paintTree=KTreeViewItem.html#paintTree
+KTreeViewItem::synchNumChildren=KTreeViewItem.html#synchNumChildren
+KTreeViewItem::textBoundingRect=KTreeViewItem.html#textBoundingRect
+KTreeViewItem::width=KTreeViewItem.html#width
+KTreeViewItem::width=KTreeViewItem.html#width
+KTreeViewItem::owner=KTreeViewItem.html#owner
+KTreeViewItem::numChildren=KTreeViewItem.html#numChildren
+KTreeViewItem::doExpandButton=KTreeViewItem.html#doExpandButton
+KTreeViewItem::expanded=KTreeViewItem.html#expanded
+KTreeViewItem::delayedExpanding=KTreeViewItem.html#delayedExpanding
+KTreeViewItem::doTree=KTreeViewItem.html#doTree
+KTreeViewItem::doText=KTreeViewItem.html#doText
+KTreeViewItem::paint=KTreeViewItem.html#paint
+KTreeViewItem::parent=KTreeViewItem.html#parent
+KTreeViewItem::sibling=KTreeViewItem.html#sibling
+KTreeViewItem::pixmap=KTreeViewItem.html#pixmap
+KTreeViewItem::text=KTreeViewItem.html#text
+KTreeViewItem::deleteChildren=KTreeViewItem.html#deleteChildren
+KTreeView=KTreeView.html
+KTreeView=KTreeView.html
+KTreeView::KTreeViewItem=KTreeView.html#KTreeViewItem
+KTreeView::KTreeView=KTreeView.html#KTreeView
+KTreeView::~KTreeView=KTreeView.html#~KTreeView
+KTreeView::appendChildItem=KTreeView.html#appendChildItem
+KTreeView::appendChildItem=KTreeView.html#appendChildItem
+KTreeView::appendChildItem=KTreeView.html#appendChildItem
+KTreeView::appendChildItem=KTreeView.html#appendChildItem
+KTreeView::autoBottomScrollBar=KTreeView.html#autoBottomScrollBar
+KTreeView::autoScrollBar=KTreeView.html#autoScrollBar
+KTreeView::autoUpdate=KTreeView.html#autoUpdate
+KTreeView::bottomScrollBar=KTreeView.html#bottomScrollBar
+KTreeView::changeItem=KTreeView.html#changeItem
+KTreeView::changeItem=KTreeView.html#changeItem
+KTreeView::clear=KTreeView.html#clear
+KTreeView::count=KTreeView.html#count
+KTreeView::currentItem=KTreeView.html#currentItem
+KTreeView::collapseItem=KTreeView.html#collapseItem
+KTreeView::expandItem=KTreeView.html#expandItem
+KTreeView::expandLevel=KTreeView.html#expandLevel
+KTreeView::expandOrCollapseItem=KTreeView.html#expandOrCollapseItem
+KTreeView::forEveryItem=KTreeView.html#forEveryItem
+KTreeView::forEveryVisibleItem=KTreeView.html#forEveryVisibleItem
+KTreeView::*getCurrentItem=KTreeView.html#*getCurrentItem
+KTreeView::indentSpacing=KTreeView.html#indentSpacing
+KTreeView::insertItem=KTreeView.html#insertItem
+KTreeView::insertItem=KTreeView.html#insertItem
+KTreeView::insertItem=KTreeView.html#insertItem
+KTreeView::insertItem=KTreeView.html#insertItem
+KTreeView::itemAt=KTreeView.html#itemAt
+KTreeView::itemAt=KTreeView.html#itemAt
+KTreeView::itemRow=KTreeView.html#itemRow
+KTreeView::itemPath=KTreeView.html#itemPath
+KTreeView::join=KTreeView.html#join
+KTreeView::join=KTreeView.html#join
+KTreeView::lowerItem=KTreeView.html#lowerItem
+KTreeView::lowerItem=KTreeView.html#lowerItem
+KTreeView::raiseItem=KTreeView.html#raiseItem
+KTreeView::raiseItem=KTreeView.html#raiseItem
+KTreeView::removeItem=KTreeView.html#removeItem
+KTreeView::removeItem=KTreeView.html#removeItem
+KTreeView::scrollBar=KTreeView.html#scrollBar
+KTreeView::setAutoUpdate=KTreeView.html#setAutoUpdate
+KTreeView::setBottomScrollBar=KTreeView.html#setBottomScrollBar
+KTreeView::setCurrentItem=KTreeView.html#setCurrentItem
+KTreeView::setExpandButtonDrawing=KTreeView.html#setExpandButtonDrawing
+KTreeView::setExpandLevel=KTreeView.html#setExpandLevel
+KTreeView::setIndentSpacing=KTreeView.html#setIndentSpacing
+KTreeView::setScrollBar=KTreeView.html#setScrollBar
+KTreeView::setShowItemText=KTreeView.html#setShowItemText
+KTreeView::setSmoothScrolling=KTreeView.html#setSmoothScrolling
+KTreeView::setTreeDrawing=KTreeView.html#setTreeDrawing
+KTreeView::showItemText=KTreeView.html#showItemText
+KTreeView::smoothScrolling=KTreeView.html#smoothScrolling
+KTreeView::split=KTreeView.html#split
+KTreeView::split=KTreeView.html#split
+KTreeView::takeItem=KTreeView.html#takeItem
+KTreeView::takeItem=KTreeView.html#takeItem
+KTreeView::treeDrawing=KTreeView.html#treeDrawing
+KTreeView::visibleCount=KTreeView.html#visibleCount
+KTreeView::collapsed=KTreeView.html#collapsed
+KTreeView::expanded=KTreeView.html#expanded
+KTreeView::expanding=KTreeView.html#expanding
+KTreeView::highlighted=KTreeView.html#highlighted
+KTreeView::selected=KTreeView.html#selected
+KTreeView::appendChildItem=KTreeView.html#appendChildItem
+KTreeView::cellHeight=KTreeView.html#cellHeight
+KTreeView::cellWidth=KTreeView.html#cellWidth
+KTreeView::changeItem=KTreeView.html#changeItem
+KTreeView::collapseSubTree=KTreeView.html#collapseSubTree
+KTreeView::countItem=KTreeView.html#countItem
+KTreeView::expandOrCollapse=KTreeView.html#expandOrCollapse
+KTreeView::expandSubTree=KTreeView.html#expandSubTree
+KTreeView::fixChildren=KTreeView.html#fixChildren
+KTreeView::focusInEvent=KTreeView.html#focusInEvent
+KTreeView::forEveryItem=KTreeView.html#forEveryItem
+KTreeView::forEveryVisibleItem=KTreeView.html#forEveryVisibleItem
+KTreeView::getMaxItemWidth=KTreeView.html#getMaxItemWidth
+KTreeView::indentation=KTreeView.html#indentation
+KTreeView::insertItem=KTreeView.html#insertItem
+KTreeView::itemPath=KTreeView.html#itemPath
+KTreeView::join=KTreeView.html#join
+KTreeView::keyPressEvent=KTreeView.html#keyPressEvent
+KTreeView::level=KTreeView.html#level
+KTreeView::lowerItem=KTreeView.html#lowerItem
+KTreeView::mouseDoubleClickEvent=KTreeView.html#mouseDoubleClickEvent
+KTreeView::mouseMoveEvent=KTreeView.html#mouseMoveEvent
+KTreeView::mousePressEvent=KTreeView.html#mousePressEvent
+KTreeView::mouseReleaseEvent=KTreeView.html#mouseReleaseEvent
+KTreeView::paintCell=KTreeView.html#paintCell
+KTreeView::raiseItem=KTreeView.html#raiseItem
+KTreeView::recursiveFind=KTreeView.html#recursiveFind
+KTreeView::setItemExpanded=KTreeView.html#setItemExpanded
+KTreeView::setItemExpandButtonDrawing=KTreeView.html#setItemExpandButtonDrawing
+KTreeView::setItemShowText=KTreeView.html#setItemShowText
+KTreeView::setItemTreeDrawing=KTreeView.html#setItemTreeDrawing
+KTreeView::split=KTreeView.html#split
+KTreeView::takeItem=KTreeView.html#takeItem
+KTreeView::updateCellWidth=KTreeView.html#updateCellWidth
+KTreeView::updateVisibleItems=KTreeView.html#updateVisibleItems
+KTreeView::updateVisibleItemRec=KTreeView.html#updateVisibleItemRec
+KTreeView::treeRoot=KTreeView.html#treeRoot
+KTreeView::clearing=KTreeView.html#clearing
+KTreeView::current=KTreeView.html#current
+KTreeView::drawExpandButton=KTreeView.html#drawExpandButton
+KTreeView::drawTree=KTreeView.html#drawTree
+KTreeView::expansion=KTreeView.html#expansion
+KTreeView::goingDown=KTreeView.html#goingDown
+KTreeView::itemIndent=KTreeView.html#itemIndent
+KTreeView::maxItemWidth=KTreeView.html#maxItemWidth
+KTreeView::showText=KTreeView.html#showText
+KTreeView::visibleItems=KTreeView.html#visibleItems
+KTreeView::x/yOffset=KTreeView.html#x/yOffset
+KTreeView::start_rubberband=KTreeView.html#start_rubberband
+KTreeView::end_rubberband=KTreeView.html#end_rubberband
+KTreeView::move_rubberband=KTreeView.html#move_rubberband
diff --git a/kdat/KDatMainWindow.cpp b/kdat/KDatMainWindow.cpp
new file mode 100644
index 0000000..925ad92
--- /dev/null
+++ b/kdat/KDatMainWindow.cpp
@@ -0,0 +1,1381 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <assert.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include <qdatetime.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qkeycode.h>
+#include <qlayout.h>
+#include <qtextstream.h>
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kmenubar.h>
+#include <kpopupmenu.h>
+#include <ktoolbar.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kstringhandler.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "ArchiveInfoWidget.h"
+#include "BackupDlg.h"
+#include "BackupOptDlg.h"
+#include "BackupProfile.h"
+#include "BackupProfileInfoWidget.h"
+#include "BackupProfileManager.h"
+#include "FileInfoWidget.h"
+#include "FormatOptDlg.h"
+#include "ImageCache.h"
+#include "IndexDlg.h"
+#include "InfoShellWidget.h"
+#include "KDatMainWindow.h"
+#include "Node.h"
+#include "Options.h"
+#include "OptionsDlg.h"
+#include "Range.h"
+#include "Tape.h"
+#include "TapeDrive.h"
+#include "TapeFileInfoWidget.h"
+#include "TapeInfoWidget.h"
+#include "TapeManager.h"
+#include "Util.h"
+#include "VerifyDlg.h"
+#include "VerifyOptDlg.h"
+#include "kdat.h"
+#include "ktreeview.h"
+#include <klocale.h>
+#include <qsplitter.h>
+#include <kstatusbar.h>
+
+#include "KDatMainWindow.moc"
+
+KDatMainWindow* KDatMainWindow::_instance = 0;
+
+KDatMainWindow* KDatMainWindow::getInstance()
+{
+ if ( _instance == 0 ) {
+ _instance = new KDatMainWindow();
+ }
+ return _instance;
+}
+
+#define KDAT_HORIZONTAL_LAYOUT
+KDatMainWindow::KDatMainWindow()
+ : KMainWindow(0), _destroyed( FALSE )
+{
+#ifdef KDAT_HORIZONTAL_LAYOUT /* 2002-01-20 LEW */
+ resize( 600, 600 ); /* was 600 by 400 */
+#else
+ resize( 600, 600 );
+#endif /* KDAT_HORIZONTAL_LAYOUT */
+
+ setIconText( i18n( "KDat: <no tape>" ) );
+ setCaption( i18n( "KDat: <no tape>" ) );
+
+ // Create object popup menus.
+ _tapeDriveMenu = new QPopupMenu();
+ _tapeDriveMenu->insertItem( i18n( "Mount Tape" ) , this, SLOT( fileMountTape() ) );
+ _tapeDriveMenu->insertItem( i18n( "Recreate Tape Index" ), this, SLOT( fileIndexTape() ) );
+ _tapeDriveMenu->insertSeparator();
+ _tapeDriveMenu->insertItem( i18n( "Format Tape..." ), this, SLOT( fileFormatTape() ) );
+
+ _archiveMenu = new QPopupMenu();
+ _archiveMenu->insertItem( i18n( "Delete Archive" ), this, SLOT( fileDeleteArchive() ) );
+
+ _mountedArchiveMenu = new QPopupMenu();
+ _mountedArchiveMenu->insertItem( i18n( "Verify..." ) , this, SLOT( fileVerify() ) );
+ _mountedArchiveMenu->insertItem( i18n( "Restore..." ) , this, SLOT( fileRestore() ) );
+ _mountedArchiveMenu->insertSeparator();
+ _mountedArchiveMenu->insertItem( i18n( "Delete Archive" ), this, SLOT( fileDeleteArchive() ) );
+
+ _mountedTapeFileMenu = new QPopupMenu();
+ _mountedTapeFileMenu->insertItem( i18n( "Verify..." ) , this, SLOT( fileVerify() ) );
+ _mountedTapeFileMenu->insertItem( i18n( "Restore..." ), this, SLOT( fileRestore() ) );
+
+ _localFileMenu = new QPopupMenu();
+ _localFileMenu->insertItem( i18n( "Backup..." ), this, SLOT( fileBackup() ) );
+
+ _tapeMenu = new QPopupMenu();
+ _tapeMenu->insertItem( i18n( "Delete Tape Index" ), this, SLOT( fileDeleteIndex() ) );
+
+ _backupProfileRootMenu = new QPopupMenu();
+ _backupProfileRootMenu->insertItem( i18n( "Create Backup Profile" ), this, SLOT( fileNewBackupProfile() ) );
+
+ _backupProfileMenu = new QPopupMenu();
+ _backupProfileMenu->insertItem( i18n( "Backup..." ), this, SLOT( fileBackup() ) );
+ _backupProfileMenu->insertSeparator();
+ _backupProfileMenu->insertItem( i18n( "Delete Backup Profile" ), this, SLOT( fileDeleteBackupProfile() ) );
+
+ _fileMenu = new QPopupMenu;
+ _fileMenu->insertItem( i18n( "Backup..." ) , this, SLOT( fileBackup() ) );
+ _fileMenu->insertItem( i18n( "Restore..." ) , this, SLOT( fileRestore() ) );
+ _fileMenu->insertItem( i18n( "Verify..." ) , this, SLOT( fileVerify() ) );
+ _fileMenu->insertItem( i18n( "Mount Tape" ) , this, SLOT( fileMountTape() ) );
+ _fileMenu->insertItem( i18n( "Recreate Tape Index" ) , this, SLOT( fileIndexTape() ) );
+ _fileMenu->insertItem( i18n( "Create Backup Profile" ), this, SLOT( fileNewBackupProfile() ) );
+ _fileMenu->insertSeparator();
+ _fileMenu->insertItem( i18n( "Delete Archive" ) , this, SLOT( fileDeleteArchive() ) );
+ _fileMenu->insertItem( i18n( "Delete Index" ) , this, SLOT( fileDeleteIndex() ) );
+ _fileMenu->insertItem( i18n( "Delete Backup Profile" ), this, SLOT( fileDeleteBackupProfile() ) );
+ _fileMenu->insertItem( i18n( "Format Tape..." ) , this, SLOT( fileFormatTape() ) );
+ _fileMenu->insertSeparator();
+ _fileMenu->insertItem( SmallIcon("exit"), i18n( "&Quit" ) , this, SLOT( fileQuit() ), CTRL + Key_Q );
+
+ _editMenu = new QPopupMenu;
+ _editMenu->insertItem( SmallIcon("configure"), i18n( "Configure KDat..." ) , this, SLOT( editPreferences() ) );
+
+ _menu = new KMenuBar( this );
+ _menu->insertItem( i18n( "&File" ), _fileMenu );
+ _menu->insertItem( i18n( "&Settings" ), _editMenu );
+ _menu->insertSeparator();
+ QString about = i18n( "KDat Version %1\n\nKDat is a tar-based tape archiver.\n\nCopyright (c) 1998-2000 Sean Vyain\nCopyright (c) 2001-2002 Lawrence Widman\nkdat@cardiothink.com" ).arg( KDAT_VERSION );
+ _menu->insertItem( i18n( "&Help" ), helpMenu( about ) );
+
+ _toolbar = new KToolBar( this );
+
+ _toolbar->insertButton( *ImageCache::instance()->getTapeUnmounted(), 0, SIGNAL( clicked( int ) ), this, SLOT( fileMountTape() ), TRUE, i18n( "Mount/unmount tape" ) );
+
+ _toolbar->insertSeparator();
+
+ _toolbar->insertButton( *ImageCache::instance()->getBackup() , 1, SIGNAL( clicked( int ) ), this, SLOT( fileBackup() ) , TRUE, i18n( "Backup" ) );
+ _toolbar->setButtonIconSet( 1, BarIconSet("kdat_backup"));
+ _toolbar->insertButton( *ImageCache::instance()->getRestore(), 2, SIGNAL( clicked( int ) ), this, SLOT( fileRestore() ), TRUE, i18n( "Restore" ) );
+ _toolbar->setButtonIconSet( 2, BarIconSet("kdat_restore"));
+ _toolbar->insertButton( *ImageCache::instance()->getVerify() , 3, SIGNAL( clicked( int ) ), this, SLOT( fileVerify() ) , TRUE, i18n( "Verify" ) );
+ _toolbar->setButtonIconSet( 3, BarIconSet("kdat_verify"));
+ addToolBar( _toolbar );
+
+ _statusBar = new KStatusBar( this );
+ _statusBar->insertItem( i18n( "Ready." ), 0 );
+
+#ifdef KDAT_HORIZONTAL_LAYOUT /* 2002-01-20 LEW */
+ _panner = new QSplitter( QSplitter::Horizontal, this, "panner");
+#else
+ _panner = new QSplitter( QSplitter::Vertical, this, "panner");
+#endif /* KDAT_HORIZONTAL_LAYOUT */
+
+ // Create info viewers.
+ InfoShellWidget* infoShell = new InfoShellWidget( _panner );
+ _tapeInfo = new TapeInfoWidget( infoShell );
+ _archiveInfo = new ArchiveInfoWidget( infoShell );
+ _backupProfileInfo = new BackupProfileInfoWidget( infoShell );
+ _tapeFileInfo = new TapeFileInfoWidget( infoShell );
+ _fileInfo = new FileInfoWidget( infoShell );
+
+ // Now set up the tree
+ _tree = new KTreeView( _panner );
+ _tree->setExpandButtonDrawing( TRUE );
+
+#ifdef KDAT_HORIZONTAL_LAYOUT /* 2002-01-20 LEW */
+ _tree->setMinimumWidth( 300 );
+ _panner->moveToFirst( _tree );
+#else
+ _tree->setMinimumHeight( 300 );
+#endif /* KDAT_HORIZONTAL_LAYOUT */
+
+ connect( _tree, SIGNAL( expanding( KTreeViewItem*, bool& ) ), this, SLOT( localExpanding( KTreeViewItem*, bool& ) ) );
+ connect( _tree, SIGNAL( expanded( int ) ), this, SLOT( localExpanded( int ) ) );
+ connect( _tree, SIGNAL( collapsed( int ) ), this, SLOT( localCollapsed( int ) ) );
+ connect( _tree, SIGNAL( selected( int ) ), this, SLOT( localSelected( int ) ) );
+ connect( _tree, SIGNAL( highlighted( int ) ), this, SLOT( localHighlighted( int ) ) );
+ connect( _tree, SIGNAL( popupMenu( int, const QPoint& ) ), this, SLOT( localPopupMenu( int, const QPoint& ) ) );
+
+ setCentralWidget( _panner );
+
+ _tree->insertItem( _tapeDriveNode = new TapeDriveNode() );
+ _tree->insertItem( _rootNode = new RootNode() );
+ _tree->insertItem( _backupProfileRootNode = new BackupProfileRootNode() );
+ _tree->insertItem( new TapeIndexRootNode() );
+
+ connect( TapeDrive::instance(), SIGNAL( sigStatus( const QString & ) ), this, SLOT( status( const QString & ) ) );
+
+ setTapePresent( FALSE );
+
+ connect( Options::instance(), SIGNAL( sigTapeDevice() ), this, SLOT( slotTapeDevice() ) );
+
+ connect( TapeManager::instance(), SIGNAL( sigTapeMounted() ) , this, SLOT( slotTapeMounted() ) );
+ connect( TapeManager::instance(), SIGNAL( sigTapeUnmounted() ), this, SLOT( slotTapeUnmounted() ) );
+
+ configureUI( 0 );
+}
+
+KDatMainWindow::~KDatMainWindow()
+{
+ _destroyed = TRUE;
+
+ if ( Options::instance()->getLockOnMount() ) {
+ TapeDrive::instance()->unlock();
+ }
+ delete _tapeDriveMenu;
+ delete _archiveMenu;
+ delete _mountedArchiveMenu;
+ delete _mountedTapeFileMenu;
+ delete _localFileMenu;
+ delete _tapeMenu;
+ delete _backupProfileRootMenu;
+ delete _backupProfileMenu;
+
+}
+
+void KDatMainWindow::popupTapeDriveMenu( const QPoint& p )
+{
+ // Configure menu before popping up.
+ if ( TapeManager::instance()->getMountedTape() ) {
+ _tapeDriveMenu->changeItem( i18n( "Unmount Tape" ), _tapeDriveMenu->idAt( 0 ) );
+ _tapeDriveMenu->setItemEnabled( _tapeDriveMenu->idAt( 1 ), TRUE );
+ } else {
+ _tapeDriveMenu->changeItem( i18n( "Mount Tape" ), _tapeDriveMenu->idAt( 0 ) );
+ _tapeDriveMenu->setItemEnabled( _tapeDriveMenu->idAt( 1 ), FALSE );
+ }
+
+ _tapeDriveMenu->popup( p );
+}
+
+void KDatMainWindow::popupArchiveMenu( const QPoint& p )
+{
+ _archiveMenu->popup( p );
+}
+
+void KDatMainWindow::popupMountedArchiveMenu( const QPoint& p )
+{
+ _mountedArchiveMenu->popup( p );
+}
+
+void KDatMainWindow::popupMountedTapeFileMenu( const QPoint& p )
+{
+ _mountedTapeFileMenu->popup( p );
+}
+
+void KDatMainWindow::popupLocalFileMenu( const QPoint& p )
+{
+ // Configure menu before popping up.
+ _localFileMenu->setItemEnabled( _localFileMenu->idAt( 0 ), ( TapeManager::instance()->getMountedTape() != 0 ) && ( !TapeDrive::instance()->isReadOnly() ) );
+
+ _localFileMenu->popup( p );
+}
+
+void KDatMainWindow::popupTapeMenu( const QPoint& p )
+{
+ _tapeMenu->popup( p );
+}
+
+void KDatMainWindow::popupBackupProfileRootMenu( const QPoint& p )
+{
+ _backupProfileRootMenu->popup( p );
+}
+
+void KDatMainWindow::popupBackupProfileMenu( const QPoint& p )
+{
+ // Configure menu before popping up.
+ _backupProfileMenu->setItemEnabled( _backupProfileMenu->idAt( 0 ), ( TapeManager::instance()->getMountedTape() != 0 ) && ( !TapeDrive::instance()->isReadOnly() ) );
+
+ _backupProfileMenu->popup( p );
+}
+
+void KDatMainWindow::hideInfo()
+{
+ _archiveInfo->hide();
+ _backupProfileInfo->hide();
+ _tapeInfo->hide();
+ _tapeFileInfo->hide();
+ _fileInfo->hide();
+}
+
+void KDatMainWindow::showTapeInfo( Tape* tape )
+{
+ assert( tape );
+
+ hideInfo();
+
+ _tapeInfo->setTape( tape );
+ _tapeInfo->show();
+}
+
+void KDatMainWindow::showArchiveInfo( Archive* archive )
+{
+ assert( archive );
+
+ hideInfo();
+
+ _archiveInfo->setArchive( archive );
+ _archiveInfo->show();
+}
+
+void KDatMainWindow::showBackupProfileInfo( BackupProfile* backupProfile )
+{
+ assert( backupProfile );
+
+ hideInfo();
+
+ _backupProfileInfo->setBackupProfile( backupProfile );
+ _backupProfileInfo->show();
+}
+
+void KDatMainWindow::showTapeFileInfo( File* file )
+{
+ assert( file );
+
+ hideInfo();
+
+ _tapeFileInfo->setFile( file );
+ _tapeFileInfo->show();
+}
+
+void KDatMainWindow::showFileInfo( const QString & name )
+{
+ assert( !name.isNull() );
+
+ hideInfo();
+
+ _fileInfo->setFile( name );
+ _fileInfo->show();
+}
+
+void KDatMainWindow::localExpanding( KTreeViewItem* item, bool& allow )
+{
+ ((Node*)item)->expanding( allow );
+}
+
+void KDatMainWindow::localExpanded( int index )
+{
+ ((Node*)_tree->itemAt( index ))->expanded();
+}
+
+void KDatMainWindow::localCollapsed( int index )
+{
+ ((Node*)_tree->itemAt( index ))->collapsed();
+}
+
+void KDatMainWindow::localSelected( int index )
+{
+ Node* item = (Node*)_tree->itemAt( index );
+
+ /* 2002-01-30 LEW: RG and I don't like the behavior in which
+ the subtree expands or contracts when a directory is selected
+ or unselected.
+ so make the tree look the same when we are done....
+ The goal is to redraw the icon to the left of the item.
+ There's gotta be a better way to do this. */
+ if ( item->isExpanded() ) {
+ _tree->collapseItem( index );
+ _tree->expandItem( index ); // 2002-01-30 LEW
+ } else {
+ _tree->expandItem( index );
+ _tree->collapseItem( index ); // 2002-01-30 LEW
+ }
+ // repaint(); // this doesn't work 2002-01-30 LEW
+ /* 2002-01-30 LEW: RG and I don't like this behavior */
+}
+
+void KDatMainWindow::localHighlighted( int index )
+{
+ Node* item = (Node*)_tree->itemAt( index );
+
+ if ( item ) {
+ item->selected();
+ }
+
+ configureUI( TapeManager::instance()->getMountedTape() );
+}
+
+void KDatMainWindow::localPopupMenu( int index, const QPoint& p )
+{
+ Node* item = (Node*)_tree->itemAt( index );
+ item->popupMenu( p );
+}
+
+void KDatMainWindow::fileBackup()
+{
+ BackupProfile backupProfile;
+
+ /* 2002-01-28 LEW */
+ // To the i18n translator: I apologize for this long text on the last day to submit
+ // i18n changes. But, the program isn't very usable without this information. Thanks. LEW
+ // (later today): now the program works correctly! Why? Beats me!
+ QString msg = i18n("KDat will dump your files properly to tape, but may not be able\n"
+ "to restore them. To restore your files by hand, you need to know\n"
+ "the name of the *non-rewinding* version of your tape device %1.\n"
+ ).arg(Options::instance()->getTapeDevice());
+ QString msg2 = i18n("For example, if your device is /dev/st0, the non-rewinding version\n"
+ "is /dev/nst0. If your device name doesn't look like that, type\n"
+ "\"ls -l %2\" in a terminal window to see the real name of your\n"
+ "tape drive. Substitute that name for /dev/nst0 below.\n"
+ "Open a terminal window and type the following:\n"
+ " tar tfv /dev/nst0; tar tfv /dev/nst0\n"
+ " tar xfv /dev/nst0\n"
+ "The third call to \"tar\" will retrieve your data into your\n"
+ "current directory. Please let us know if this happens to you!\n"
+ " - KDat Maintenance Team\n"
+ ).arg(Options::instance()->getTapeDevice());
+ msg = msg.append(msg2);
+ KMessageBox::sorry( this, msg);
+ /* 2002-01-28 LEW */
+
+ if ( ( _tree->getCurrentItem() ) && ( ((Node*)_tree->getCurrentItem())->isType( Node::BackupProfileNodeType ) ) ) {
+ BackupProfile* bp = ((BackupProfileNode*)_tree->getCurrentItem())->getBackupProfile();
+ backupProfile.setArchiveName( bp->getArchiveName() );
+ backupProfile.setWorkingDirectory( bp->getWorkingDirectory() );
+ backupProfile.setAbsoluteFiles( bp->getAbsoluteFiles() );
+ backupProfile.setOneFilesystem( bp->isOneFilesystem() );
+ backupProfile.setIncremental( bp->isIncremental() );
+ backupProfile.setSnapshotFile( bp->getSnapshotFile() );
+ backupProfile.setRemoveSnapshot( bp->getRemoveSnapshot() );
+ } else {
+ QString name;
+ name = i18n( "Archive created on %1" ).arg( KGlobal::locale()->formatDate(QDate::currentDate(), true) );
+ name = name.stripWhiteSpace();
+
+ QStringList files;
+ getBackupFiles( files );
+
+ backupProfile.setArchiveName( name );
+ backupProfile.setAbsoluteFiles( files );
+ backupProfile.setOneFilesystem( TRUE );
+ backupProfile.setIncremental( FALSE );
+ backupProfile.setSnapshotFile( "snapshot" );
+ backupProfile.setRemoveSnapshot( FALSE );
+ }
+
+ int ret = 0;
+ BackupOptDlg dlg( &backupProfile, this );
+ if ( dlg.exec() == QDialog::Accepted ) {
+ // Begin backup.
+ status( i18n( "Performing backup..." ) );
+ int size = calcBackupSize( dlg.getWorkingDirectory(), dlg.isOneFilesystem(), dlg.getRelativeFiles(), dlg.isIncremental(), dlg.getSnapshotFile(), dlg.getRemoveSnapshot() );
+
+ // Check to see whether user aborted the backup
+ if ( size < 0) {
+ status( i18n( "Backup canceled." ) );
+ return;
+ }
+
+ // Make sure the archive will fit on the tape.
+ int tapeSize = 1;
+ QPtrListIterator<Archive> i( TapeManager::instance()->getMountedTape()->getChildren() );
+ if ( i.toLast() != NULL ) {
+ tapeSize = i.current()->getEndBlock();
+ tapeSize = (int)((float)tapeSize / 1024.0 * (float)Options::instance()->getTapeBlockSize()) + 1;
+ }
+ if ( tapeSize + size >= TapeManager::instance()->getMountedTape()->getSize() ) {
+ // Warn user that tape is probably too short.
+ QString msg;
+ msg = i18n( "WARNING: The estimated archive size is %1 KB but "
+ "the tape has only %2 KB of space!\n"
+ "Back up anyway?" )
+ .arg(KGlobal::locale()->formatNumber(size, 0))
+ .arg(KGlobal::locale()->formatNumber(TapeManager::instance()->getMountedTape()->getSize() - tapeSize, 0 ));
+ int result = KMessageBox::warningContinueCancel( this,
+ msg, i18n("Backup"), i18n("Backup") );
+ if ( result != KMessageBox::Continue) {
+ status( i18n( "Backup canceled." ) );
+ return;
+ }
+ }
+
+ if ( TapeDrive::instance()->getFile() < 0 ) {
+ // Rewind tape.
+ status( i18n( "Rewinding tape..." ) );
+ if ( !TapeDrive::instance()->rewind() ) {
+ KMessageBox::error( this,
+ i18n("Cannot rewind tape.\nBackup aborted."),
+ i18n("Backup Error"));
+ status( i18n( "Backup aborted." ) );
+ return;
+ }
+ }
+
+ // Go to end of tape.
+ status( i18n( "Skipping to end of tape..." ) );
+ if ( !TapeDrive::instance()->nextFile( TapeManager::instance()->getMountedTape()->getChildren().count() + 1 - TapeDrive::instance()->getFile() ) ) {
+ KMessageBox::error( this,
+ i18n("Cannot get to end of tape.\nBackup aborted."),
+ i18n("Backup Error"));
+ status( i18n( "Backup aborted." ) );
+ return;
+ }
+
+ status( i18n( "Backup in progress..." ) );
+ BackupDlg backupDlg( dlg.getArchiveName(), dlg.getWorkingDirectory(), dlg.getRelativeFiles(), dlg.isOneFilesystem(), dlg.isIncremental(), dlg.getSnapshotFile(), dlg.getRemoveSnapshot(), size, TapeManager::instance()->getMountedTape(), this );
+ ret = backupDlg.exec();
+
+// status( i18n( "Rewinding tape..." ) );
+// TapeDrive::instance()->rewind();
+// if ( !TapeDrive::instance()->prevFile( 1 ) ) {
+// status( i18n( "Rewinding tape..." ) );
+// TapeDrive::instance()->rewind();
+// }
+ }
+
+ // All done.
+ if ( ret == QDialog::Accepted ) {
+ status( i18n( "Backup complete." ) );
+ } else {
+ status( i18n( "Backup aborted." ) );
+ }
+}
+
+void KDatMainWindow::fileRestore()
+{
+ doVerify( TRUE );
+}
+
+void KDatMainWindow::fileVerify()
+{
+ doVerify( FALSE );
+}
+
+void KDatMainWindow::doVerify( bool restore )
+{
+ RangeableNode* rangeableNode = 0;
+ MountedArchiveNode* archiveNode = 0;
+ QStringList files;
+ Archive* archive = 0;
+ // Check for marked files first.
+ for ( int i = _tapeDriveNode->childCount() - 1; i >= 0; i-- ) {
+ if ( ( ((SelectableNode*)_tapeDriveNode->childAt( i ))->isSelected() ) ||
+ ( ((SelectableNode*)_tapeDriveNode->childAt( i ))->hasSelectedChildren() )) {
+ archiveNode = (MountedArchiveNode*)_tapeDriveNode->childAt( i );
+ archive = archiveNode->getArchive();
+ /* 2002-01-30 LEW */
+#ifdef DEBUG
+ printf("KDatMainWindow::doVerify: %d node of %s: ", i,
+ (SelectableNode*)_tapeDriveNode->getText().latin1() );
+ if( ((SelectableNode*)_tapeDriveNode->childAt( i ))->isSelected() ){
+ printf("is completely selected\n");
+ } else {
+ printf("is partially selected\n");
+ }
+#endif /* DEBUG */
+ /* 2002-01-30 LEW */
+ break;
+ }
+ }
+
+ if ( !archiveNode ) {
+ if ( ((Node*)_tree->getCurrentItem())->isType( Node::RangeableNodeType ) ) {
+ rangeableNode = (RangeableNode*)_tree->getCurrentItem();
+ Node* parent = rangeableNode;
+ for ( ; !parent->isType( Node::MountedArchiveNodeType ); parent = (Node*)parent->getParent() );
+ assert( parent );
+ archive = ((MountedArchiveNode*)parent)->getArchive();
+ }
+ }
+
+ assert( archive );
+ QPtrListIterator<Archive> it( archive->getTape()->getChildren() );
+ int fileno;
+ for ( fileno = 1; ( it.current() ) && ( it.current() != archive ); ++it, fileno++ );
+
+ assert( archiveNode || rangeableNode );
+ assert( fileno > -1 );
+
+ RangeList ranges;
+ if ( rangeableNode ) {
+ QPtrListIterator<Range> it( rangeableNode->getRanges() );
+ for ( ; it.current(); ++it ) {
+ ranges.addRange( it.current()->getStart(), it.current()->getEnd() );
+ }
+ if ( rangeableNode->isType( Node::MountedArchiveNodeType ) ) {
+ // Make sure the mounted archive node has populated its children.
+ archiveNode = (MountedArchiveNode*)rangeableNode;
+ if ( archiveNode->childCount() == 0 ) {
+ bool dummy = TRUE;
+ archiveNode->expanding( dummy );
+ }
+
+ for ( int i = rangeableNode->childCount() - 1; i >= 0; i-- ) {
+ if ( ((Node*)rangeableNode->childAt( i ))->isType( Node::MountedTapeDirectoryNodeType ) ) {
+ files.append( ((MountedTapeDirectoryNode*)rangeableNode->childAt( i ))->getFullPath() );
+ } else if ( ((Node*)rangeableNode->childAt( i ))->isType( Node::MountedTapeFileNodeType ) ) {
+ files.append( ((MountedTapeFileNode*)rangeableNode->childAt( i ))->getFullPath() );
+ } else {
+ assert( FALSE );
+ }
+ }
+ } else if ( rangeableNode->isType( Node::MountedTapeDirectoryNodeType ) ) {
+ files.append( ((MountedTapeDirectoryNode*)rangeableNode)->getFullPath() );
+ } else if ( rangeableNode->isType( Node::MountedTapeFileNodeType ) ) {
+ files.append( ((MountedTapeFileNode*)rangeableNode)->getFullPath() );
+ } else {
+ assert( FALSE );
+ }
+ } else {
+ // Compile a list of files to verify/restore.
+ QPtrStack<RangeableNode> stack;
+
+ // Make sure the mounted archive node has populated its children.
+ if ( archiveNode->childCount() == 0 ) {
+ bool dummy = TRUE;
+ archiveNode->expanding( dummy );
+ }
+
+ for ( int i = archiveNode->childCount() - 1; i >= 0; i-- ) {
+ stack.push( (RangeableNode*)archiveNode->childAt( i ) );
+ }
+ RangeableNode* sel = 0;
+ while ( stack.count() > 0 ) {
+ sel = stack.pop();
+ if ( sel->isSelected() ) {
+ QPtrListIterator<Range> it( sel->getRanges() );
+ for ( ; it.current(); ++it ) {
+ ranges.addRange( it.current()->getStart(), it.current()->getEnd() );
+ }
+
+ if ( sel->isType( Node::MountedTapeDirectoryNodeType ) ) {
+ files.append( ((MountedTapeDirectoryNode*)sel)->getFullPath() );
+ } else if ( sel->isType( Node::MountedTapeFileNodeType ) ) {
+ files.append( ((MountedTapeFileNode*)sel)->getFullPath() );
+ } else {
+ assert( FALSE );
+ }
+ } else if ( sel->hasSelectedChildren() ) {
+ for ( int i = sel->childCount() - 1; i >= 0; i-- ) {
+ stack.push( (RangeableNode*)sel->childAt( i ) );
+ }
+ }
+ }
+ }
+
+ char buf[1024];
+ VerifyOptDlg dlg( getcwd( buf, 1024 ), files, restore, this );
+ if ( dlg.exec() == QDialog::Accepted ) {
+ if ( restore ) {
+ status( i18n( "Restore in progress..." ) );
+ } else {
+ status( i18n( "Verify in progress..." ) );
+ }
+ VerifyDlg verifyDlg( dlg.getWorkingDirectory(), fileno, ranges, restore, this );
+ int ret = verifyDlg.exec();
+
+ if ( ret == QDialog::Accepted ) {
+ if ( restore ) {
+ status( i18n( "Restore complete." ) );
+ } else {
+ status( i18n( "Verify complete." ) );
+ }
+ } else {
+ if ( restore ) {
+ status( i18n( "Restore aborted." ) );
+ } else {
+ status( i18n( "Verify aborted." ) );
+ }
+ }
+ }
+}
+
+void KDatMainWindow::fileMountTape()
+{
+ static QString msg;
+
+ // construct helpful error message (same as in fileFormatTape())
+ msg = i18n("There appears to be no tape in the drive %1. Please\n"
+ "check \"Edit->Preferences\" to make sure the\n"
+ "correct device is selected as the tape drive (e.g.\n"
+ "/dev/st0). If you hear the tape drive moving, wait\n"
+ "until it stops and then try mounting it again.")
+ .arg(Options::instance()->getTapeDevice());
+
+ if ( !TapeManager::instance()->getMountedTape() ) {
+ if ( Options::instance()->getLoadOnMount() ) {
+ if ( !TapeDrive::instance()->load() ) {
+ KMessageBox::sorry( this, msg);
+ return;
+ }
+ }
+
+ if ( TapeDrive::instance()->isTapePresent() ) {
+ setTapePresent( TRUE );
+ } else {
+ KMessageBox::sorry( this, msg);
+ }
+ } else {
+ setTapePresent( FALSE );
+ }
+}
+
+void KDatMainWindow::fileIndexTape()
+{
+ int result = KMessageBox::warningContinueCancel( this,
+ i18n( "The current tape index will be overwritten, continue?" ),
+ i18n( "Index Tape"), i18n("Overwrite"));
+ if ( result == KMessageBox::Continue) {
+ TapeManager::instance()->getMountedTape()->clear();
+ IndexDlg dlg( TapeManager::instance()->getMountedTape(), this );
+ if ( dlg.exec() == QDialog::Accepted ) {
+ QString title;
+ title = i18n( "KDat: %1" ).arg( TapeManager::instance()->getMountedTape()->getName() );
+ setCaption( title );
+ setIconText( title );
+
+ status( i18n( "Index complete." ) );
+ } else {
+ status( i18n( "Index aborted." ) );
+ }
+ }
+}
+
+void KDatMainWindow::fileDeleteArchive()
+{
+ Node* sel = (Node*)_tree->getCurrentItem();
+ if ( ( !sel ) || ( !sel->isType( Node::ArchiveNodeType ) && !sel->isType( Node::MountedArchiveNodeType ) ) ) {
+ KMessageBox::sorry( this, i18n( "No archive is selected.\n"
+ "In order to delete an archive, the archive to be deleted "
+ "must be selected in the tree first." ));
+ return;
+ }
+
+ // Find the selected archive and see if it has any archives after it.
+ Archive* archive = 0;
+ if ( sel->isType( Node::ArchiveNodeType ) ) {
+ archive = ((ArchiveNode*)sel)->getArchive();
+ } else if ( sel->isType( Node::MountedArchiveNodeType ) ) {
+ archive = ((MountedArchiveNode*)sel)->getArchive();
+ }
+ assert( archive );
+
+ Tape* tape = archive->getTape();
+ QPtrListIterator<Archive> i( tape->getChildren() );
+ for ( ; i.current(); ++i ) {
+ if ( i.current() == archive ) {
+ break;
+ }
+ }
+ assert( i.current() );
+
+ ++i;
+ if ( i.current() ) {
+ // There are other archives after this one on the tape.
+ QString list;
+ for ( ; i.current(); ++i ) {
+ list.append( "\n " );
+ list.append( i.current()->getName() );
+ }
+
+ QString msg =
+ i18n( "An archive cannot be removed from the middle of the tape. If\nthe archive '%1' is deleted then\nthe following archives will also be deleted:\n%2\n\nDelete all listed archives?" ).arg(archive->getName()).arg(list);
+ int result = KMessageBox::warningContinueCancel( this,
+ msg, i18n("Delete Archive"), i18n("Delete All"));
+ if (result == KMessageBox::Continue) {
+ tape->removeChild( archive );
+ emit status( i18n( "Archives deleted." ) );
+ if ( _tree->getCurrentItem() ) {
+ ((Node*)_tree->getCurrentItem())->selected();
+ }
+ configureUI( TapeManager::instance()->getMountedTape() );
+ }
+ } else {
+ // This is the last (known) archive on the tape.
+ QString msg =
+ i18n( "Really delete the archive '%1'?" ).arg(archive->getName());
+ int result = KMessageBox::warningContinueCancel( this,
+ msg, i18n("Delete Archive"), i18n("Delete"));
+ if (result == KMessageBox::Continue) {
+ tape->removeChild( archive );
+ emit status( i18n( "Archive deleted." ) );
+ if ( _tree->getCurrentItem() ) {
+ ((Node*)_tree->getCurrentItem())->selected();
+ }
+ configureUI( TapeManager::instance()->getMountedTape() );
+ }
+ }
+}
+
+void KDatMainWindow::fileDeleteIndex()
+{
+ Node* sel = (Node*)_tree->getCurrentItem();
+ if ( ( !sel ) || ( !sel->isType( Node::TapeNodeType ) ) ) {
+ KMessageBox::sorry( this, i18n( "No tape index is selected.\n"
+ "In order to delete a tape index, the tape index to be deleted "
+ "must be selected in the tree first." ));
+ return;
+ }
+
+ Tape* tape = ((TapeNode*)sel)->getTape();
+ assert( tape );
+ if ( tape == TapeManager::instance()->getMountedTape() ) {
+ KMessageBox::sorry( this, i18n( "Tape is still mounted. "
+ "The index for a mounted tape cannot be deleted.\n"
+ "Unmount the tape and try again." ));
+ return;
+ }
+
+ QString msg =
+ i18n( "Really delete the index for '%1'?" ).arg(tape->getName());
+ int result = KMessageBox::warningContinueCancel( this,
+ msg, i18n("Delete Tape Index"), i18n("Delete"));
+ if (result == KMessageBox::Continue) {
+ TapeManager::instance()->removeTape( tape );
+ emit status( i18n( "Tape index deleted." ) );
+ if ( _tree->getCurrentItem() ) {
+ ((Node*)_tree->getCurrentItem())->selected();
+ }
+ configureUI( TapeManager::instance()->getMountedTape() );
+ }
+}
+
+void KDatMainWindow::fileFormatTape()
+{
+ static QString msg;
+
+ // construct helpful error message (same as in fileMountTape())
+ msg = i18n("There appears to be no tape in the drive %1. Please\n"
+ "check \"Edit->Preferences\" to make sure the\n"
+ "correct device is selected as the tape drive (e.g.\n"
+ "/dev/st0). If you hear the tape drive moving, wait\n"
+ "until it stops and then try mounting it again.")
+ .arg(Options::instance()->getTapeDevice());
+
+ if ( !TapeDrive::instance()->isTapePresent() ) {
+ KMessageBox::sorry( this, msg );
+ return;
+ }
+
+ if ( TapeDrive::instance()->isReadOnly() ) {
+ KMessageBox::sorry( this, i18n( "The tape in the drive is write protected.\nPlease disable write protection and try again." ));
+ return;
+ }
+
+ int result = KMessageBox::warningContinueCancel( this,
+ i18n( "All data currently on the tape will be lost.\n"
+ "Are you sure you want to continue?" ),
+ i18n("Format Tape"), i18n("Format"));
+ if (result == KMessageBox::Continue ) {
+ QString name;
+ name = i18n( "Tape created on %1" ).arg( KGlobal::locale()->formatDate(QDate::currentDate(), true) );
+ FormatOptDlg dlg( name.stripWhiteSpace(), this );
+ if ( dlg.exec() != QDialog::Accepted ) {
+ return;
+ }
+
+ // Delete old index file.
+ if ( TapeManager::instance()->getMountedTape() ) {
+ TapeManager::instance()->removeTape( TapeManager::instance()->getMountedTape() );
+ TapeManager::instance()->unmountTape();
+ }
+
+ Tape* tape = new Tape();
+ tape->setName( dlg.getName() );
+ tape->setSize( dlg.getSize() );
+
+ status( i18n( "Formatting tape..." ) );
+ tape->format();
+ TapeManager::instance()->addTape( tape );
+ status( i18n( "Format complete." ) );
+
+ setTapePresent( FALSE, FALSE );
+ setTapePresent( TRUE, FALSE );
+ }
+}
+
+void KDatMainWindow::fileNewBackupProfile()
+{
+ BackupProfile* backupProfile = new BackupProfile();
+
+ // Pick a unique name.
+ QString name;
+ for ( int i = 1; ; i++ ) {
+ name = i18n( "Backup Profile %1").arg( i );
+ QStringList list = BackupProfileManager::instance()->getBackupProfileNames();
+ QStringList::Iterator it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ if ( name == *it ) {
+ break;
+ }
+ }
+ if ( it == list.end() ) {
+ // Name is unique.
+ break;
+ }
+ }
+
+ QStringList files;
+ getBackupFiles( files );
+
+ backupProfile->setName( name );
+ backupProfile->setArchiveName( i18n( "Archive" ) );
+ backupProfile->setWorkingDirectory( Util::longestCommonPath( files ) );
+ if ( !backupProfile->getWorkingDirectory() ) {
+ backupProfile->setWorkingDirectory( "/" );
+ }
+ backupProfile->setAbsoluteFiles( files );
+ backupProfile->setOneFilesystem( TRUE );
+ backupProfile->setIncremental( FALSE );
+ backupProfile->setSnapshotFile( "snapshot" );
+ backupProfile->setRemoveSnapshot( FALSE );
+ backupProfile->save();
+
+ BackupProfileManager::instance()->addBackupProfile( backupProfile );
+
+ _backupProfileRootNode->setSelected( backupProfile );
+}
+
+void KDatMainWindow::fileDeleteBackupProfile()
+{
+ Node* sel = (Node*)_tree->getCurrentItem();
+ if ( ( !sel ) || ( !sel->isType( Node::BackupProfileNodeType ) ) ) {
+ KMessageBox::sorry( this, i18n( "In order to delete a backup profile, the backup profile to be deleted "
+ "must be selected in the tree first." ));
+ return;
+ }
+
+ BackupProfile* backupProfile = ((BackupProfileNode*)sel)->getBackupProfile();
+ assert( backupProfile );
+
+ QString msg =
+ i18n("Really delete backup profile '%1'?").arg(backupProfile->getName());
+ int result = KMessageBox::warningContinueCancel( this,
+ msg, i18n("Delete Backup Profile"), i18n("Delete"));
+ if (result == KMessageBox::Continue) {
+ BackupProfileManager::instance()->removeBackupProfile( backupProfile );
+ emit status( i18n( "Backup profile deleted." ) );
+ if ( _tree->getCurrentItem() ) {
+ ((Node*)_tree->getCurrentItem())->selected();
+ }
+ configureUI( TapeManager::instance()->getMountedTape() );
+ }
+}
+
+void KDatMainWindow::fileQuit()
+{
+ KApplication::kApplication()->quit();
+}
+
+void KDatMainWindow::editPreferences()
+{
+ OptionsDlg dlg( this );
+ dlg.exec();
+}
+
+void KDatMainWindow::help()
+{
+ KApplication::kApplication()->invokeHelp( );
+}
+
+void KDatMainWindow::setTapePresent( bool tapePresent, bool eject )
+{
+ if ( TapeManager::instance()->getMountedTape() ) {
+ if ( !tapePresent ) {
+ TapeManager::instance()->unmountTape();
+
+ if ( ( eject ) && ( Options::instance()->getLockOnMount() ) ) {
+ TapeDrive::instance()->unlock();
+ }
+
+ if ( ( eject ) && ( Options::instance()->getEjectOnUnmount() ) ) {
+ TapeDrive::instance()->eject();
+ }
+
+ status( i18n( "Tape unmounted." ) );
+ }
+ } else {
+ if ( tapePresent ) {
+ status( i18n( "Reading tape header..." ) );
+ Tape* tape = TapeDrive::instance()->readHeader();
+
+ if ( tape ) {
+ TapeManager::instance()->mountTape( tape );
+ } else {
+ if ( TapeDrive::instance()->isReadOnly() ) {
+ KMessageBox::sorry( this, i18n( "This tape has not been formatted by KDat." ));
+ } else {
+ int result = KMessageBox::questionYesNo( this,
+ i18n( "This tape has not been formatted by KDat.\n\nWould you like to format it now?" ), QString::null, i18n("Format"), i18n("Do Not Format"));
+ if (result == KMessageBox::Yes) {
+ fileFormatTape();
+ return;
+ }
+ }
+ }
+
+ if ( Options::instance()->getLockOnMount() ) {
+ TapeDrive::instance()->lock();
+ }
+
+ status( i18n( "Tape mounted." ) );
+ }
+ }
+}
+
+void KDatMainWindow::status( const QString & msg )
+{
+ _statusBar->changeItem( msg, 0 );
+ KApplication::kApplication()->processEvents();
+}
+
+void KDatMainWindow::show()
+{
+ KMainWindow::show();
+
+ hideInfo();
+}
+
+// 2002-01-21 LEW: returns backup size in KB, or -1 if user chose
+// to abort the backup.
+int KDatMainWindow::calcBackupSize( const QString& workingDir, bool local, const QStringList& files,
+ bool incremental, const QString& snapshot, bool removeSnapshot )
+{
+ int return_value;
+
+ chdir( QFile::encodeName(workingDir) );
+
+ bool useSnapshot = !snapshot.isEmpty() && !removeSnapshot;
+
+ int tmp = 0;
+ if ( incremental && !removeSnapshot ) {
+ QFile snap( snapshot );
+ if ( snap.exists() && snap.open( IO_ReadOnly ) ) {
+ QTextStream t( &snap );
+ t >> tmp;
+ } else {
+ useSnapshot = FALSE;
+ }
+ }
+ QDateTime mtime;
+ mtime.setTime_t( tmp );
+
+ int size = 0;
+
+ /* 2002-01-24 LEW: start of backup-cancel dialog */
+ create_backup_dialog();
+ stop_flag = FALSE; // initialize the flag that tells us whether use
+ // cancelled the backup via the dialog.
+ /* 2002-01-24 LEW: end of backup-cancel dialog */
+
+ QStringList filesTmp = files;
+ QStringList::Iterator ii = filesTmp.begin();
+ for ( ; ii != filesTmp.end(); ++ii ) {
+
+ // Is this a normal file, or a directory?
+ QFileInfo finfo( *ii );
+ if ( !finfo.isDir() ) {
+ if ( ( !useSnapshot ) || ( finfo.lastModified() > mtime ) ) {
+ size += finfo.size() / 512;
+ if ( finfo.size() % 512 ) {
+ size++;
+ }
+ }
+ continue;
+ }
+
+ QPtrStack<QString> dirStack;
+ dirStack.push( new QString( *ii ) );
+
+ // If stay on one file system, get device of starting directory.
+ dev_t device = 0;
+ struct stat info;
+ if ( local ) {
+ if ( lstat( QFile::encodeName(*ii), &info ) != 0 ) {
+ device = 0;
+ } else {
+ device = info.st_dev;
+ }
+ }
+
+ QString msg;
+ // msg.truncate( 4095 );
+ QDir dir;
+ const QFileInfoList* infoList;
+ while ( !dirStack.isEmpty() ) {
+ if( stop_flag == TRUE ) break;
+ QString* path = dirStack.pop();
+ msg = i18n("Estimating backup size: %1, %2" )
+ .arg(Util::kbytesToString( size / 2 ))
+ .arg(KStringHandler::csqueeze(*path, 60));
+ status( msg );
+ KApplication::kApplication()->processEvents();
+ dir.setPath( *path );
+ infoList = dir.entryInfoList( QDir::Hidden | QDir::Files | QDir::Dirs, 0 );
+ if ( infoList ) {
+ QFileInfoListIterator i( *infoList );
+ for ( ; i.current(); ++i ) {
+ if ( ( i.current()->fileName() != "." ) && ( i.current()->fileName() != ".." ) ) {
+ size++;
+ if ( i.current()->isSymLink() ) {
+ } else if ( i.current()->isDir() ) {
+ if ( local ) {
+ if ( lstat( QFile::encodeName(i.current()->absFilePath()), &info ) == 0 ) {
+ if ( device == info.st_dev ) {
+ dirStack.push( new QString( i.current()->absFilePath() ) );
+ }
+ }
+ } else {
+ dirStack.push( new QString( i.current()->absFilePath() ) );
+ }
+ } else if ( ( !useSnapshot ) || ( i.current()->lastModified() > mtime ) ) {
+ size += i.current()->size() / 512;
+ if ( i.current()->size() % 512 ) {
+ size++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ delete _backupdialog; // we're done, so zap this widget
+
+ // Convert size in tar blocks to size in kbytes.
+ return_value = size / 2;
+
+ if( stop_flag == TRUE ) return_value = -1;
+
+ return return_value;
+}
+
+void KDatMainWindow::getBackupFiles( QStringList& files )
+{
+ if ( !_rootNode->isSelected() && !_rootNode->hasSelectedChildren() ) {
+ // Backup the entire subtree.
+ if ( ( _tree->getCurrentItem() ) && ( ((Node*)_tree->getCurrentItem())->isType( Node::ArchiveableNodeType ) ) ) {
+ files.append( ((ArchiveableNode*)_tree->getCurrentItem())->getFullPath() );
+ }
+ } else {
+ // Compile a list of files to backup.
+ QPtrStack<ArchiveableNode> stack;
+ stack.push( _rootNode );
+ ArchiveableNode* sel = 0;
+ while ( stack.count() > 0 ) {
+ sel = stack.pop();
+ if ( sel->isSelected() ) {
+ files.append( sel->getFullPath() );
+ } else if ( sel->hasSelectedChildren() ) {
+ for ( int i = sel->childCount() - 1; i >= 0; i-- ) {
+ stack.push( (ArchiveableNode*)sel->childAt( i ) );
+ }
+ }
+ }
+ }
+}
+
+void KDatMainWindow::setBackupFiles( const QStringList& files )
+{
+ _rootNode->setSelected( FALSE );
+
+ QString tmp;
+ QStringList filesTmp = files;
+ QStringList::Iterator it = filesTmp.begin();
+ for ( ; it != filesTmp.end(); ++it ) {
+ ArchiveableNode* n = _rootNode;
+ while ( n ) {
+ if ( n->getFullPath() == *it ) {
+ n->setSelected( TRUE );
+ n = 0;
+ } else {
+ if ( n->childCount() == 0 ) {
+ bool dummy = TRUE;
+ n->expanding( dummy );
+ }
+ int i;
+ for ( i = n->childCount() - 1; i >=0; i-- ) {
+ tmp = ((ArchiveableNode*)n->childAt( i ))->getFullPath();
+ if ( tmp == (*it).left( tmp.length() ) ) {
+ n = (ArchiveableNode*)n->childAt( i );
+ break;
+ }
+ }
+ if ( i < 0 ) {
+ n = 0;
+ }
+ }
+ }
+ }
+}
+
+void KDatMainWindow::slotTapeDevice()
+{
+ setTapePresent( FALSE );
+}
+
+void KDatMainWindow::slotTapeMounted()
+{
+ configureUI( TapeManager::instance()->getMountedTape() );
+}
+
+void KDatMainWindow::slotTapeUnmounted()
+{
+ configureUI( 0 );
+}
+
+void KDatMainWindow::configureUI( Tape* tape )
+{
+ if ( _destroyed ) {
+ return;
+ }
+
+ Node* sel = (Node*)_tree->getCurrentItem();
+
+ // Title bar
+ if ( tape ) {
+ QString title;
+ title = i18n( "KDat: %1" ).arg(tape->getName());
+ setCaption( title );
+ setIconText( title );
+ } else {
+ setCaption( i18n( "KDat: <no tape>" ) );
+ setIconText( i18n( "KDat: <no tape >" ) );
+ }
+
+ // Backup
+ bool canBackup = ( tape ) && ( !TapeDrive::instance()->isReadOnly() ) &&
+ ( ( ( sel ) && ( sel->isType( Node::ArchiveableNodeType ) || sel->isType( Node::BackupProfileNodeType ) ) ) ||
+ ( _rootNode->isSelected() || _rootNode->hasSelectedChildren() ) );
+ _toolbar->setItemEnabled( 1, canBackup );
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 0 ), canBackup );
+
+ // Restore/verify
+ bool canRestore = ( tape ) && ( sel ) && sel->isType( Node::RangeableNodeType );
+ if ( !canRestore ) {
+ for ( int i = _tapeDriveNode->childCount() - 1; i >= 0; i-- ) {
+ if ( ( ((SelectableNode*)_tapeDriveNode->childAt( i ))->isSelected() ) ||
+ ( ((SelectableNode*)_tapeDriveNode->childAt( i ))->hasSelectedChildren() )) {
+ canRestore = TRUE;
+ break;
+ }
+ }
+ }
+ if ( canRestore ) {
+ // 2002-01-30 LEW: check Node *sel because we can have canRestore==true
+ // even if sel==NULL when a child is selected (see loop above).
+ if( sel != (Node *)0x0 )
+ {
+ for ( Node* parent = (Node*)sel->getParent();
+ ( parent ) && ( parent->getParent() );
+ parent = (Node*)parent->getParent() ) {
+ if ( parent->isType( Node::TapeNodeType ) ) {
+ canRestore = FALSE;
+ }
+ }
+ }
+ // 2002-01-30 LEW: see if we ever get here...
+ else
+ {
+ printf("Found sel==0x0 in %s %d\n", __FILE__, __LINE__);
+ }
+ // 2002-01-30 LEW
+
+ }
+ _toolbar->setItemEnabled( 2, canRestore );
+ _toolbar->setItemEnabled( 3, canRestore );
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 1 ), canRestore );
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 2 ), canRestore );
+
+ // Mount/unmount tape
+ if ( tape ) {
+ _toolbar->setButtonPixmap( 0, *ImageCache::instance()->getTapeMounted() );
+ _fileMenu->changeItem( i18n( "Unmount Tape" ), _fileMenu->idAt( 3 ) );
+ } else {
+ _toolbar->setButtonPixmap( 0, *ImageCache::instance()->getTapeUnmounted() );
+ _fileMenu->changeItem( i18n( "Mount Tape" ), _fileMenu->idAt( 3 ) );
+ }
+
+ // Index tape
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 4 ), tape != NULL );
+
+ // Delete archive
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 7 ), ( sel ) && sel->isType( Node::ArchiveNodeType ) );
+
+ // Delete index
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 8 ), ( sel ) && sel->isType( Node::TapeNodeType ) );
+
+ // Delete backup profile
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 9 ), ( sel ) && sel->isType( Node::BackupProfileNodeType ) );
+
+ // Format tape
+ _fileMenu->setItemEnabled( _fileMenu->idAt( 10 ), TapeManager::instance()->getMountedTape() && !TapeDrive::instance()->isReadOnly() );
+}
+
+void KDatMainWindow::readProperties( KConfig* config )
+{
+ QValueList<int> sizes;
+ sizes << config->readNumEntry( "panner", 50 );
+ _panner->setSizes( sizes );
+}
+
+void KDatMainWindow::saveProperties( KConfig* config )
+{
+ config->writeEntry( "panner", _panner->sizes().first());
+}
+
+// Create the dialog that lets user cancel estimation of backup size
+void KDatMainWindow::create_backup_dialog()
+{
+ /* 2002-01-24 LEW: start of backup-cancel dialog */
+ static QString stop_button_text, stop_button_caption;
+ stop_button_text =
+ i18n("Click \"CANCEL\" to stop the backup process.\n"
+ "For example, you may quickly see that the size of\n"
+ "the files you selected will exceed the size of the\n"
+ "backup tape, and may then decide to stop and remove\n"
+ "some files from your list of files to backup.\n\n"
+ "Click \"Continue\" to remove this message while\n"
+ "continuing the backup.");
+ stop_button_caption = i18n("Stop estimating backup size");
+
+ // gotta put a callback in here. Probably need to create a
+ // dialog object 2002-01-22 LEW
+ _backupdialog = new KDialog( this, "backupdialog", false );
+ _backupdialog->setCaption( stop_button_caption );
+ // _backupdialog->resize(370,200); /* 2002-01-28 LEW */
+ _backupdialog->resize(370,260);
+
+ _lbl = new QLabel( stop_button_text, _backupdialog );
+ // _lbl->setGeometry( QRect( 30, 20, 350, 140 ) ); /* 2002-01-28 LEW */
+ _lbl->setGeometry( QRect( 30, 20, 350, 200 ) );
+
+ _cancel = new KPushButton( KStdGuiItem::cancel(), _backupdialog );
+ _cancel->setFixedSize( 80, _cancel->sizeHint().height() );
+ _cancel->setEnabled( TRUE );
+ /* 2002-01-24 LEW: looks like we can't increase the button width
+ to accomodate a wider message :( */
+ // _cancel->setGeometry( QRect( 50, 170, 0, 0 ) ); /* 2002-01-28 LEW */
+ _cancel->setGeometry( QRect( 50, 230, 0, 0 ) );
+ connect( _cancel, SIGNAL( clicked() ), this, SLOT( backupCancel() ) );
+
+ _continue = new KPushButton( KStdGuiItem::cont(), _backupdialog );
+ _continue->setFixedSize( 80, _continue->sizeHint().height() );
+ _continue->setEnabled( TRUE );
+ _continue->setDefault( TRUE );
+ // _continue->setGeometry( QRect( 200, 170, 0, 0 ) ); /* 2002-01-28 LEW */
+ _continue->setGeometry( QRect( 200, 230, 0, 0 ) );
+ connect( _continue, SIGNAL( clicked() ), this, SLOT( backupContinue() ) );
+
+ _backupdialog->show();
+}
+
+// stop calculating the backup size and hide the dialog screen
+void KDatMainWindow::backupCancel()
+{
+ stop_flag = TRUE;
+ _backupdialog->hide();
+}
+
+// continue calculating the backup size and hide the dialog screen
+void KDatMainWindow::backupContinue()
+{
+ _backupdialog->hide();
+}
diff --git a/kdat/KDatMainWindow.h b/kdat/KDatMainWindow.h
new file mode 100644
index 0000000..33e6732
--- /dev/null
+++ b/kdat/KDatMainWindow.h
@@ -0,0 +1,285 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef KDat_h
+#define KDat_h
+
+#include <kmainwindow.h>
+#include <kdialog.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+
+class KMenuBar;
+class QSplitter;
+class KStatusBar;
+class KToolBar;
+class KTreeView;
+class KTreeViewItem;
+
+class QPixmap;
+class QPopupMenu;
+
+class Archive;
+class ArchiveInfoWidget;
+class BackupProfile;
+class BackupProfileInfoWidget;
+class BackupProfileRootNode;
+class File;
+class FileInfoWidget;
+class Node;
+class RootNode;
+class Tape;
+class TapeDriveNode;
+class TapeFileInfoWidget;
+class TapeInfoWidget;
+
+/**
+ * @short The KDat main window. Everything happens from here.
+ */
+class KDatMainWindow : public KMainWindow {
+ Q_OBJECT
+
+private:
+ bool _destroyed;
+ KMenuBar* _menu;
+ QPopupMenu* _fileMenu;
+ QPopupMenu* _editMenu;
+ KToolBar* _toolbar;
+ KStatusBar* _statusBar;
+ QSplitter* _panner;
+ KTreeView* _tree;
+ QPopupMenu* _tapeDriveMenu;
+ QPopupMenu* _archiveMenu;
+ QPopupMenu* _mountedArchiveMenu;
+ QPopupMenu* _mountedTapeFileMenu;
+ QPopupMenu* _localFileMenu;
+ QPopupMenu* _tapeMenu;
+ QPopupMenu* _backupProfileRootMenu;
+ QPopupMenu* _backupProfileMenu;
+ ArchiveInfoWidget* _archiveInfo;
+ BackupProfileInfoWidget* _backupProfileInfo;
+ TapeFileInfoWidget* _tapeFileInfo;
+ TapeInfoWidget* _tapeInfo;
+ FileInfoWidget* _fileInfo;
+ RootNode* _rootNode;
+ TapeDriveNode* _tapeDriveNode;
+ BackupProfileRootNode* _backupProfileRootNode;
+
+ static KDatMainWindow* _instance;
+
+ void doVerify( bool restore = FALSE );
+ void setTapePresent( bool tapePresent, bool eject = TRUE );
+ int calcBackupSize( const QString& workingDir, bool local, const QStringList& files,
+ bool incremental, const QString& snapshot, bool removeSnapshot );
+
+ KDatMainWindow();
+
+ // 2002-01-24 LEW
+ // used in calcBackupSize() to see whether user cancelled the on-going
+ // backup to tape.
+ KDialog* _backupdialog;
+ QPushButton* _cancel;
+ QPushButton* _continue;
+ QLabel* _lbl;
+ int stop_flag;
+ void create_backup_dialog();
+ // 2002-01-24 LEW
+
+private slots:
+ void localExpanding( KTreeViewItem* item, bool& allow );
+ void localExpanded( int index );
+ void localCollapsed( int index );
+ void localSelected( int index );
+ void localHighlighted( int index );
+ void localPopupMenu( int index, const QPoint& p );
+
+ void fileBackup();
+ void fileRestore();
+ void fileVerify();
+ void fileMountTape();
+ void fileIndexTape();
+ void fileDeleteArchive();
+ void fileDeleteIndex();
+ void fileFormatTape();
+ void fileNewBackupProfile();
+ void fileDeleteBackupProfile();
+ void fileQuit();
+ void editPreferences();
+ void help();
+
+ void slotTapeDevice();
+ void slotTapeMounted();
+ void slotTapeUnmounted();
+
+ // 2002-01-24 LEW
+ void backupCancel();
+ void backupContinue();
+ // 2002-01-24 LEW
+
+protected:
+ virtual void readProperties( KConfig* config );
+ virtual void saveProperties( KConfig* config );
+
+public:
+ /**
+ * Destroy the KDat main window.
+ */
+ ~KDatMainWindow();
+
+ /**
+ * Get a reference to the single instance of the KDat main window.
+ *
+ * @return A pointer to the KDat main window.
+ */
+ static KDatMainWindow* getInstance();
+
+ /**
+ * Display the tape drive node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupTapeDriveMenu( const QPoint& p );
+
+ /**
+ * Display the archive node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupArchiveMenu( const QPoint& p );
+
+ /**
+ * Display the mounted archive node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupMountedArchiveMenu( const QPoint& p );
+
+ /**
+ * Display the mounted tape file node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupMountedTapeFileMenu( const QPoint& p );
+
+ /**
+ * Display the local file node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupLocalFileMenu( const QPoint& p );
+
+ /**
+ * Display the tape index node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupTapeMenu( const QPoint& p );
+
+ /**
+ * Display the backup profile root node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupBackupProfileRootMenu( const QPoint& p );
+
+ /**
+ * Display the backup profile node popup menu.
+ *
+ * @param p The upper left corner of the menu.
+ */
+ void popupBackupProfileMenu( const QPoint& p );
+
+ /**
+ * Hide all of the info viewers.
+ */
+ void hideInfo();
+
+ /**
+ * Display the tape info widget for the given tape.
+ *
+ * @param tape The tape index to display.
+ */
+ void showTapeInfo( Tape* tape );
+
+ /**
+ * Display the archive info widget for the given archive.
+ *
+ * @param archive The archive to display.
+ */
+ void showArchiveInfo( Archive* archive );
+
+ /**
+ * Display the tape file info widget for the given file.
+ *
+ * @param file The file to display.
+ */
+ void showTapeFileInfo( File* file );
+
+ /**
+ * Display the backup profile info widget for the given backup profile.
+ *
+ * @param backupProfile The backup profile to display.
+ */
+ void showBackupProfileInfo( BackupProfile* backupProfile );
+
+ /**
+ * Display the local file info widget for the given file.
+ *
+ * @param file The full path name of the file to display.
+ */
+ void showFileInfo( const QString & name );
+
+ /**
+ * Make sure that the user interface is consistent for the given mounted
+ * tape. This method mostly just enables or disables GUI objects based on
+ * the currently mounted tape, and selections.
+ *
+ * @param tape The currently mounted tape. May be NULL.
+ */
+ void configureUI( Tape* tape );
+
+ /**
+ * Get a list of all the files selected for backup.
+ *
+ * @param files This list will be filled with the selected files.
+ */
+ void getBackupFiles( QStringList& files );
+
+ /**
+ * Set the list of all the files selected for backup.
+ *
+ * @param files This list will become the selection.
+ */
+ void setBackupFiles( const QStringList& files );
+
+public slots:
+ /**
+ * Display a text message in the status bar.
+ *
+ * @param msg The message to display.
+ */
+ void status( const QString & msg );
+
+ /**
+ * Initialize the KDat main window before displaying.
+ */
+ virtual void show();
+
+};
+
+#endif
diff --git a/kdat/LoggerWidget.cpp b/kdat/LoggerWidget.cpp
new file mode 100644
index 0000000..ac0bdc5
--- /dev/null
+++ b/kdat/LoggerWidget.cpp
@@ -0,0 +1,79 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qmultilineedit.h>
+
+#include <kapplication.h>
+#include <kfiledialog.h>
+
+#include "LoggerWidget.h"
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "LoggerWidget.moc"
+
+LoggerWidget::LoggerWidget( const QString & title, QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ QLabel* lbl1 = new QLabel( title, this );
+ lbl1->setFixedHeight( lbl1->sizeHint().height() );
+
+ _mle = new QMultiLineEdit( this );
+ _mle->setReadOnly( TRUE );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 0, 4 );
+ l1->addWidget( lbl1 );
+ l1->addWidget( _mle, 1 );
+}
+
+LoggerWidget::~LoggerWidget()
+{
+}
+
+void LoggerWidget::append( const QString & text )
+{
+ _mle->append( text );
+ _mle->setCursorPosition( _mle->numLines(), 0 );
+}
+
+void LoggerWidget::save()
+{
+ QString file = KFileDialog::getSaveFileName( QString::null, QString::null, this );
+ if ( !file.isNull() ) {
+ QFile f( file );
+ if ( f.exists() ) {
+ int result = KMessageBox::warningContinueCancel( this,
+ i18n( "Log file exists, overwrite?" ),
+ i18n( "KDat: Save Log" ),
+ i18n("&Overwrite"));
+ if (result != KMessageBox::Continue)
+ return;
+ }
+ if ( f.open( IO_WriteOnly ) ) {
+ QCString line;
+ for ( int i = 0; i < _mle->numLines(); i++ ) {
+ line = _mle->textLine( i ).utf8();
+ f.writeBlock( line, line.length() );
+ f.writeBlock( "\n", 1 );
+ }
+ f.close();
+ }
+ }
+}
diff --git a/kdat/LoggerWidget.h b/kdat/LoggerWidget.h
new file mode 100644
index 0000000..76afb78
--- /dev/null
+++ b/kdat/LoggerWidget.h
@@ -0,0 +1,62 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _LoggerWidget_h_
+#define _LoggerWidget_h_
+
+#include <qwidget.h>
+
+class QMultiLineEdit;
+
+/**
+ * @short A titled logging widget with a save option.
+ */
+class LoggerWidget : public QWidget {
+ Q_OBJECT
+ QMultiLineEdit* _mle;
+public:
+ /**
+ * Create a titled logging widget
+ *
+ * @param title The title text displayed above the logging window.
+ * @param parent The parent widget.
+ * @param name The name of this widget.
+ */
+ LoggerWidget( const QString & title, QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the logging widget.
+ */
+ ~LoggerWidget();
+
+ /**
+ * Append the given text to the end of the logging widget, and position the
+ * viewable area at the end of the text.
+ *
+ * @param text The text to append.
+ */
+ void append( const QString & text );
+public slots:
+ /**
+ * Prompt the user for a file name, and save the contents of the log to
+ * that file.
+ */
+ void save();
+};
+
+#endif
diff --git a/kdat/Makefile.am b/kdat/Makefile.am
new file mode 100644
index 0000000..846ce4c
--- /dev/null
+++ b/kdat/Makefile.am
@@ -0,0 +1,110 @@
+# KDE tags expanded automatically by am_edit - $Revision$
+
+# this 10 paths are KDE specific. Use them:
+# kde_htmldir Where your docs should go to. (contains lang subdirs)
+# kde_appsdir Where your application file (.desktop) should go to.
+# kde_icondir Where your icon should go to.
+# kde_minidir Where your mini icon should go to.
+# kde_datadir Where you install application data. (Use a subdir)
+# kde_locale Where translation files should go to.(contains lang subdirs)
+# kde_cgidir Where cgi-bin executables should go to.
+# kde_confdir Where config files should go to.
+# kde_mimedir Where mimetypes should go to.
+# kde_toolbardir Where general toolbar icons should go to.
+# kde_wallpaperdir Where general wallpapers should go to.
+
+# just set the variable
+xdg_apps_DATA = kdat.desktop
+
+# set the include path for X, qt and KDE
+INCLUDES= $(all_includes)
+# claim, which subdirectories you want to install
+SUBDIRS = pics
+
+####### This part is very kdat specific
+# you can add here more. This one gets installed
+bin_PROGRAMS = kdat
+
+# Which sources should be compiled for kdat.
+kdat_SOURCES = \
+ Archive.cpp \
+ ArchiveInfoWidget.cpp \
+ BackupDlg.cpp \
+ BackupOptDlg.cpp \
+ BackupProfile.cpp \
+ BackupProfileInfoWidget.cpp \
+ BackupProfileManager.cpp \
+ BackupProfileWidget.cpp \
+ ErrorHandler.cpp \
+ File.cpp \
+ FileInfoWidget.cpp \
+ ImageCache.cpp \
+ IndexDlg.cpp \
+ InfoShellWidget.cpp \
+ KDatMainWindow.cpp \
+ LoggerWidget.cpp \
+ Node.cpp \
+ Options.cpp \
+ OptionsDlg.cpp \
+ OptionsDlgWidget.ui \
+ Range.cpp \
+ Tape.cpp \
+ TapeDrive.cpp \
+ TapeFileInfoWidget.cpp \
+ TapeInfoWidget.cpp \
+ TapeManager.cpp \
+ FormatOptDlg.cpp \
+ TarParser.cpp \
+ Util.cpp \
+ VerifyDlg.cpp \
+ VerifyOptDlg.cpp \
+ ktreeview.cpp \
+ main.cpp
+
+
+# the library search path
+kdat_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+# the libraries to link against. Be aware of the order. First the libraries,
+# that depend on the following ones.
+kdat_LDADD = $(LIB_KFILE)
+
+# this option you can leave out. Just, if you use "make dist", you need it
+noinst_HEADERS = \
+ Archive.h \
+ ArchiveInfoWidget.h \
+ BackupDlg.h \
+ BackupOptDlg.h \
+ BackupProfile.h \
+ BackupProfileInfoWidget.h \
+ BackupProfileManager.h \
+ BackupProfileWidget.h \
+ File.h \
+ FileInfoWidget.h \
+ ImageCache.h \
+ IndexDlg.h \
+ InfoShellWidget.h \
+ KDatMainWindow.h \
+ LoggerWidget.h \
+ Node.h \
+ Options.h \
+ OptionsDlg.h \
+ Range.h \
+ Tape.h \
+ TapeDrive.h \
+ TapeFileInfoWidget.h \
+ TapeInfoWidget.h \
+ TapeManager.h \
+ FormatOptDlg.h \
+ TarParser.h \
+ Util.h \
+ VerifyDlg.h \
+ VerifyOptDlg.h \
+ kdat.h \
+ ktreeview.h
+
+# just to make sure, automake makes them
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kdat.pot
diff --git a/kdat/Node.cpp b/kdat/Node.cpp
new file mode 100644
index 0000000..828ad69
--- /dev/null
+++ b/kdat/Node.cpp
@@ -0,0 +1,1585 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <assert.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <qdir.h>
+#include <qpainter.h>
+#include <qstyle.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+
+#include "Archive.h"
+#include "BackupProfile.h"
+#include "BackupProfileManager.h"
+#include "ImageCache.h"
+#include "KDatMainWindow.h"
+#include "Node.h"
+#include "Range.h"
+#include "Tape.h"
+#include "TapeManager.h"
+#include <klocale.h>
+
+#include "Node.moc"
+
+Node::Node( int type, const QString & text, const QPixmap& pixmap )
+ : KTreeViewItem( text, pixmap ),
+ _type( type )
+{
+}
+
+Node::~Node()
+{
+}
+
+void Node::insertNode( Node* child )
+{
+ static Node* lastParent = 0;
+ static uint lastDirIndex = 0;
+
+ if ( lastParent != this ) {
+ // Recompute lastDirIndex.
+ for ( lastDirIndex = 0;
+ ( lastDirIndex < childCount() ) && ( ((Node*)childAt( lastDirIndex ))->getType() == TapeDirectoryNodeType );
+ lastDirIndex++ );
+ lastParent = this;
+ }
+
+ int min, mid, max, smin, smax;
+ if ( ( child->getType() == TapeDirectoryNodeType ) || ( child->getType() == MountedTapeDirectoryNodeType ) ) {
+ min = 0;
+ max = lastDirIndex - 1;
+ lastDirIndex++;
+ } else {
+ min = lastDirIndex;
+ max = childCount() - 1;
+ }
+
+ if ( min > max ) min = max;
+
+ smin = min;
+ smax = max;
+ //printf( "min = %d, max = %d\n", min, max );
+
+ mid = min;
+ while ( min < max ) {
+ mid = ( max - min ) / 2 + min;
+ //mid = ( min + max ) / 2;
+ if ( child->getText().compare( childAt( mid )->getText() ) < 0 ) {
+ max = mid - 1;
+ } else {
+ min = mid + 1;
+ }
+ }
+
+ if ( childCount() ) {
+ // KLUDGE!
+ mid -= 5;
+ if ( mid < smin ) mid = smin;
+ if ( ((Node*)childAt( mid ))->getType() != child->getType() ) mid++;
+ for ( ; ( mid <= smax ) && ( child->getText().compare( childAt( mid )->getText() ) > 0 ); mid++ );
+ //printf( "index = %d, text = '%s'\n", mid, child->getText().data() );
+ insertChild( mid, child );
+ } else {
+ //printf( "index = %d, text = '%s'\n", 0, child->getText().data() );
+ insertChild( 0, child );
+ }
+}
+
+int Node::getType()
+{
+ return _type;
+}
+
+bool Node::isType( int type )
+{
+ return type == NodeType;
+}
+
+void Node::expanding( bool expand )
+{
+ expand = TRUE;
+}
+
+void Node::expanded()
+{
+}
+
+void Node::collapsed()
+{
+}
+
+void Node::selected()
+{
+ KDatMainWindow::getInstance()->hideInfo();
+}
+
+void Node::popupMenu( const QPoint& )
+{
+}
+
+TapeNode::TapeNode( Tape* tape )
+ : Node( TapeNodeType, tape->getName(), *ImageCache::instance()->getTape() ),
+ _tape( tape )
+{
+ setDelayedExpanding( TRUE );
+}
+
+Tape* TapeNode::getTape()
+{
+ return _tape;
+}
+
+bool TapeNode::validate()
+{
+ bool changed = _tape->getName() != getText();
+ if ( changed ) {
+ setText( _tape->getName() );
+ }
+
+ if ( ( childCount() == 0 ) && ( !isExpanded() ) ) {
+ return changed;
+ }
+
+ // Add/update existing archives.
+ QPtrListIterator<Archive> i( _tape->getChildren() );
+ ArchiveNode* n;
+ for ( ; i.current(); ++i ) {
+ n = findArchiveNode( i.current() );
+ if ( n ) {
+ if ( n->validate() ) {
+ bool select = ( owner->getCurrentItem() == n );
+ removeChild( n );
+ insertNode( n );
+ if ( select ) {
+ owner->setCurrentItem( owner->itemRow( n ) );
+ }
+ }
+ } else {
+ insertNode( new ArchiveNode( i.current() ) );
+ }
+ }
+
+ // Remove deleted archives.
+ Archive* a;
+ for ( uint j = 0; j < childCount(); ) {
+ a = ((ArchiveNode*)childAt( j ))->getArchive();
+ for ( i.toFirst(); i.current(); ++i ) {
+ if ( i.current() == a ) {
+ break;
+ }
+ }
+ if ( !i.current() ) {
+ removeChild( childAt( j ) );
+ } else {
+ j++;
+ }
+ }
+
+ return changed;
+}
+
+bool TapeNode::isType( int type )
+{
+ if ( type == TapeNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void TapeNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ // We already have the children added
+ return;
+ }
+
+ QPtrListIterator<Archive> f( _tape->getChildren() );
+ for ( ; f.current(); ++f ) {
+ insertNode( new ArchiveNode( f.current() ) );
+ }
+}
+
+void TapeNode::selected()
+{
+ KDatMainWindow::getInstance()->showTapeInfo( _tape );
+}
+
+void TapeNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupTapeMenu( p );
+}
+
+ArchiveNode* TapeNode::findArchiveNode( Archive* archive )
+{
+ ArchiveNode* n = 0;
+ for ( uint i = 0; i < childCount(); i++ ) {
+ if ( ((ArchiveNode*)childAt( i ))->getArchive() == archive ) {
+ n = (ArchiveNode*)childAt( i );
+ break;
+ }
+ }
+
+ return n;
+}
+
+ArchiveNode::ArchiveNode( Archive* archive )
+ : Node( ArchiveNodeType, archive->getName(), *ImageCache::instance()->getArchive() ),
+ _archive( archive )
+{
+ setDelayedExpanding( TRUE );
+}
+
+Archive* ArchiveNode::getArchive()
+{
+ return _archive;
+}
+
+bool ArchiveNode::validate()
+{
+ bool changed = _archive->getName() != getText();
+ if ( changed ) {
+ setText( _archive->getName() );
+ }
+
+ return changed;
+}
+
+bool ArchiveNode::isType( int type )
+{
+ if ( type == ArchiveNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void ArchiveNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ // We already have the children added.
+ return;
+ }
+
+ QPtrListIterator<File> f( _archive->getChildren() );
+ for ( ; f.current(); ++f ) {
+ if ( f.current()->getName()[f.current()->getName().length()-1] == '/' ) {
+ insertNode( new TapeDirectoryNode( f.current() ) );
+ } else {
+ insertNode( new TapeFileNode( f.current() ) );
+ }
+ }
+}
+
+void ArchiveNode::selected()
+{
+ KDatMainWindow::getInstance()->showArchiveInfo( _archive );
+}
+
+void ArchiveNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupArchiveMenu( p );
+}
+
+TapeDirectoryNode::TapeDirectoryNode( File* file )
+ : Node( TapeDirectoryNodeType, "", *ImageCache::instance()->getFolderClosed() ),
+ _file( file )
+{
+ setDelayedExpanding( TRUE );
+
+ int len = _file->getName().length();
+ int idx1 = _file->getName().findRev( '/', len - 2 );
+ if ( idx1 < 0 ) {
+ setText( _file->getName().left( len - 1 ) );
+ } else {
+ setText( _file->getName().mid( idx1 + 1, len - idx1 - 2 ) );
+ }
+}
+
+File* TapeDirectoryNode::getFile()
+{
+ return _file;
+}
+
+bool TapeDirectoryNode::isType( int type )
+{
+ if ( type == TapeDirectoryNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void TapeDirectoryNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ // We already have the children added.
+ return;
+ }
+
+ QPtrListIterator<File> f( _file->getChildren() );
+ for ( ; f.current(); ++f ) {
+ if ( f.current()->getName()[f.current()->getName().length()-1] == '/' ) {
+ insertNode( new TapeDirectoryNode( f.current() ) );
+ } else {
+ insertNode( new TapeFileNode( f.current() ) );
+ }
+ }
+}
+
+void TapeDirectoryNode::expanded()
+{
+ setPixmap( *ImageCache::instance()->getFolderOpen() );
+}
+
+void TapeDirectoryNode::collapsed()
+{
+ setPixmap( *ImageCache::instance()->getFolderClosed() );
+}
+
+void TapeDirectoryNode::selected()
+{
+ KDatMainWindow::getInstance()->showTapeFileInfo( _file );
+}
+
+TapeFileNode::TapeFileNode( File* file )
+ : Node( TapeFileNodeType, file->getName(), *ImageCache::instance()->getFile() ),
+ _file( file )
+{
+ int len = _file->getName().length();
+ int idx1 = _file->getName().findRev( '/', len - 1 );
+ if ( idx1 < 0 ) {
+ setText( _file->getName().left( len ) );
+ } else {
+ setText( _file->getName().mid( idx1 + 1, len - idx1 - 1 ) );
+ }
+}
+
+File* TapeFileNode::getFile()
+{
+ return _file;
+}
+
+bool TapeFileNode::isType( int type )
+{
+ if ( type == TapeFileNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void TapeFileNode::selected()
+{
+ KDatMainWindow::getInstance()->showTapeFileInfo( _file );
+}
+
+SelectableNode::SelectableNode( int type, const QString & text, const QPixmap& pixmap, int state )
+ : Node( type, text, pixmap ),
+ _state( state )
+{
+}
+
+void SelectableNode::doUpdateState()
+{
+ bool oneSelected = FALSE;
+ bool hasSelected = FALSE;
+ bool allSelected = TRUE;
+ for ( uint i = 0; i < childCount(); i++ ) {
+ switch ( ((SelectableNode*)childAt( i ))->_state ) {
+ case SelAll:
+ oneSelected = TRUE;
+ hasSelected = TRUE;
+ break;
+
+ case SelSome:
+ hasSelected = TRUE;
+ allSelected = FALSE;
+ break;
+
+ case SelNone:
+ allSelected = FALSE;
+ break;
+ }
+ }
+
+ if ( allSelected ) {
+ _state = SelAll;
+ } else if ( oneSelected || hasSelected ) {
+ _state = SelSome;
+ } else {
+ _state = SelNone;
+ }
+
+ if ( ( getParent() ) && ( getParent()->getParent() ) && ( ((Node*)getParent())->isType( SelectableNodeType ) ) ) {
+ ((SelectableNode*)getParent())->doUpdateState();
+ }
+}
+
+void SelectableNode::doSetSelected( bool select )
+{
+ // All my children get the same selection state.
+ for ( uint i = 0; i < childCount(); i++ ) {
+ if ( select ) {
+ if ( !((SelectableNode*)childAt( i ))->isSelected() ) {
+ ((SelectableNode*)childAt( i ))->doSetSelected( TRUE );
+ }
+ } else {
+ if ( ((SelectableNode*)childAt( i ))->isSelected() || ((SelectableNode*)childAt( i ))->hasSelectedChildren() ) {
+ ((SelectableNode*)childAt( i ))->doSetSelected( FALSE );
+ }
+ }
+ }
+
+ if ( select ) {
+ _state = SelAll;
+ } else {
+ _state = SelNone;
+ }
+}
+
+const QPixmap* SelectableNode::getSelectPixmap() const
+{
+ switch ( _state ) {
+ case SelAll:
+ return ImageCache::instance()->getSelectAll();
+
+ case SelNone:
+ return ImageCache::instance()->getSelectNone();
+
+ case SelSome:
+ return ImageCache::instance()->getSelectSome();
+
+ default:
+ return 0;
+ }
+}
+
+bool SelectableNode::mousePressEvent( const QPoint& point )
+{
+ if ( _selectRect.contains( point ) ) {
+ switch ( _state ) {
+ case SelAll:
+ setSelected( FALSE );
+ break;
+
+ case SelNone:
+ setSelected( TRUE );
+ break;
+
+ case SelSome:
+ setSelected( TRUE );
+ break;
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+void SelectableNode::paint( QPainter* p, int indent, const QColorGroup& cg,
+ bool highlighted ) const
+{
+ assert(getParent() != 0); /* can't paint root item */
+
+ p->save();
+ p->setPen(cg.text());
+ p->setBackgroundColor(cg.base());
+
+ int cellHeight = height(p->fontMetrics());
+
+ if (doTree) {
+ paintTree(p, indent, cellHeight);
+ }
+
+ /*
+ * If this item has at least one child and expand button drawing is
+ * enabled, set the rect for the expand button for later mouse press
+ * bounds checking, and draw the button.
+ */
+ if (doExpandButton && (child || delayedExpanding)) {
+ paintExpandButton(p, indent, cellHeight);
+ }
+
+ const QPixmap* pm = getSelectPixmap();
+ p->drawPixmap( indent, ( height() - pm->height() ) / 2, *pm );
+ _selectRect.setRect( indent, ( height() - pm->height() ) / 2, 12, 12 );
+
+ // now draw the item pixmap and text, if applicable
+ int pixmapX = indent + 4 + 12;
+ int pixmapY = (cellHeight - pixmap.height()) / 2;
+ p->drawPixmap(pixmapX, pixmapY, pixmap);
+
+ if (doText) {
+ paintText(p, indent, cellHeight, cg, highlighted);
+ }
+ p->restore();
+}
+
+void SelectableNode::paintText( QPainter* p, int indent, int cellHeight,
+ const QColorGroup& cg, bool highlighted ) const
+{
+ int textX = indent + 12 + 4 + pixmap.width() + 4;
+ int textY = cellHeight - ((cellHeight - p->fontMetrics().ascent() -
+ p->fontMetrics().leading()) / 2);
+ if (highlighted) {
+ paintHighlight(p, indent, cg, owner->hasFocus(),
+ (Qt::GUIStyle)owner->style().styleHint(QStyle::SH_GUIStyle)); // Qt3 doesn't make this easy ;)
+ p->setPen(cg.base());
+ p->setBackgroundColor(cg.text());
+ }
+ else {
+ p->setPen(cg.text());
+ p->setBackgroundColor(cg.base());
+ }
+ p->drawText(textX, textY, text);
+}
+
+int SelectableNode::width( int indent, const QFontMetrics& fm ) const
+{
+ int maxWidth = pixmap.width();
+ maxWidth += (4 + 12 + 4 + fm.width(text));
+ return maxWidth == 0 ? -1 : indent + maxWidth + 3;
+}
+
+QRect SelectableNode::textBoundingRect(int indent) const
+{
+ const QFontMetrics& fm = owner->fontMetrics();
+ int cellHeight = height(fm);
+ int rectX = indent + 12 + 4 + pixmap.width() + 3;
+ int rectY = (cellHeight - fm.ascent() - fm.leading()) / 2 + 2;
+ int rectW = fm.width(text) + 1;
+ int rectH = fm.ascent() + fm.leading();
+ return QRect(rectX, rectY, rectW, rectH);
+}
+
+bool SelectableNode::isType( int type )
+{
+ if ( type == SelectableNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+bool SelectableNode::isSelected()
+{
+ return _state == SelAll;
+}
+
+bool SelectableNode::hasSelectedChildren()
+{
+ return _state == SelAll || _state == SelSome;
+}
+
+void SelectableNode::setSelected( bool select )
+{
+ doSetSelected( select );
+
+ if ( ( getParent() ) && ( getParent()->getParent() ) && ( ((Node*)getParent())->isType( SelectableNodeType ) ) ) {
+ ((SelectableNode*)getParent())->doUpdateState();
+ }
+
+ owner->repaint();
+
+ KDatMainWindow::getInstance()->configureUI( TapeManager::instance()->getMountedTape() );
+}
+
+RangeableNode::RangeableNode( int type, const QString & text, const QPixmap& pixmap, int state )
+ : SelectableNode( type, text, pixmap, state )
+{
+}
+
+bool RangeableNode::isType( int type )
+{
+ if ( type == RangeableNodeType ) {
+ return TRUE;
+ } else {
+ return SelectableNode::isType( type );
+ }
+}
+
+MountedArchiveNode::MountedArchiveNode( Archive* archive )
+ : RangeableNode( MountedArchiveNodeType, archive->getName(), *ImageCache::instance()->getArchive(), SelNone ),
+ _archive( archive )
+{
+ setDelayedExpanding( TRUE );
+}
+
+Archive* MountedArchiveNode::getArchive()
+{
+ return _archive;
+}
+
+const QPtrList<Range>& MountedArchiveNode::getRanges()
+{
+ return _archive->getRanges();
+}
+
+bool MountedArchiveNode::validate()
+{
+ bool changed = _archive->getName() != getText();
+ if ( changed ) {
+ setText( _archive->getName() );
+ }
+
+ return changed;
+}
+
+void MountedArchiveNode::setSelected( bool select )
+{
+ if ( select ) {
+ // Deselect all other archives.
+ Node* parent = (Node*)getParent();
+ for ( int i = parent->childCount() - 1; i >= 0; i-- ) {
+ if ( parent->childAt( i ) != this ) {
+ ((SelectableNode*)parent->childAt( i ))->setSelected( FALSE );
+ }
+ }
+ }
+
+ SelectableNode::setSelected( select );
+}
+
+bool MountedArchiveNode::isType( int type )
+{
+ if ( type == MountedArchiveNodeType ) {
+ return TRUE;
+ } else {
+ return RangeableNode::isType( type );
+ }
+}
+
+void MountedArchiveNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ // We already have the children added.
+ return;
+ }
+
+ QPtrListIterator<File> f( _archive->getChildren() );
+ for ( ; f.current(); ++f ) {
+ if ( f.current()->getName()[f.current()->getName().length()-1] == '/' ) {
+ insertNode( new MountedTapeDirectoryNode( f.current(), _state == SelSome ? SelNone : _state ) );
+ } else {
+ insertNode( new MountedTapeFileNode( f.current(), _state == SelSome ? SelNone : _state ) );
+ }
+ }
+}
+
+void MountedArchiveNode::selected()
+{
+ KDatMainWindow::getInstance()->showArchiveInfo( _archive );
+}
+
+void MountedArchiveNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupMountedArchiveMenu( p );
+}
+
+MountedTapeDirectoryNode::MountedTapeDirectoryNode( File* file, int state )
+ : RangeableNode( MountedTapeDirectoryNodeType, "", *ImageCache::instance()->getFolderClosed(), state ),
+ _file( file )
+{
+ assert( _file > (File*)0x1 );
+
+ setDelayedExpanding( TRUE );
+
+ int len = _file->getName().length();
+ int idx1 = _file->getName().findRev( '/', len - 2 );
+ if ( idx1 < 0 ) {
+ setText( _file->getName().left( len - 1 ) );
+ } else {
+ setText( _file->getName().mid( idx1 + 1, len - idx1 - 2 ) );
+ }
+}
+
+File* MountedTapeDirectoryNode::getFile()
+{
+ return _file;
+}
+
+QString MountedTapeDirectoryNode::getFullPath()
+{
+ if ( _fullPath.length() == 0 ) {
+ _fullPath = getText() + "/";
+ for ( Node* parent = (Node*)getParent(); !parent->isType( MountedArchiveNodeType ); parent = (Node*)parent->getParent() ) {
+ _fullPath.prepend( "/" );
+ _fullPath.prepend( parent->getText() );
+ }
+ }
+
+ return _fullPath;
+}
+
+const QPtrList<Range>& MountedTapeDirectoryNode::getRanges()
+{
+ return _file->getRanges();
+}
+
+void MountedTapeDirectoryNode::setSelected( bool select )
+{
+ if ( select ) {
+ // Deselect all other archives.
+ Node* parent = (Node*)getParent();
+ Node* arcNode = 0;
+ while ( !parent->isType( TapeDriveNodeType ) ) {
+ if ( parent->isType( MountedArchiveNodeType ) ) {
+ arcNode = parent;
+ }
+ parent = (Node*)parent->getParent();
+ }
+ for ( int i = parent->childCount() - 1; i >= 0; i-- ) {
+ if ( parent->childAt( i ) != arcNode ) {
+ ((SelectableNode*)parent->childAt( i ))->setSelected( FALSE );
+ }
+ }
+ }
+
+ SelectableNode::setSelected( select );
+}
+
+bool MountedTapeDirectoryNode::isType( int type )
+{
+ if ( type == MountedTapeDirectoryNodeType ) {
+ return TRUE;
+ } else {
+ return RangeableNode::isType( type );
+ }
+}
+
+void MountedTapeDirectoryNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ // We already have the children added.
+ return;
+ }
+
+ QPtrListIterator<File> f( _file->getChildren() );
+ for ( ; f.current(); ++f ) {
+ if ( f.current()->getName()[f.current()->getName().length()-1] == '/' ) {
+ insertNode( new MountedTapeDirectoryNode( f.current(), _state == SelSome ? SelNone : _state ) );
+ } else {
+ insertNode( new MountedTapeFileNode( f.current(), _state == SelSome ? SelNone : _state ) );
+ }
+ }
+}
+
+void MountedTapeDirectoryNode::expanded()
+{
+ setPixmap( *ImageCache::instance()->getFolderOpen() );
+}
+
+void MountedTapeDirectoryNode::collapsed()
+{
+ setPixmap( *ImageCache::instance()->getFolderClosed() );
+}
+
+void MountedTapeDirectoryNode::selected()
+{
+ KDatMainWindow::getInstance()->showTapeFileInfo( _file );
+}
+
+void MountedTapeDirectoryNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupMountedTapeFileMenu( p );
+}
+
+MountedTapeFileNode::MountedTapeFileNode( File* file, int state )
+ : RangeableNode( MountedTapeFileNodeType, file->getName(), *ImageCache::instance()->getFile(), state ),
+ _file( file )
+{
+ int len = _file->getName().length();
+ int idx1 = _file->getName().findRev( '/', len - 1 );
+ if ( idx1 < 0 ) {
+ setText( _file->getName().left( len ) );
+ } else {
+ setText( _file->getName().mid( idx1 + 1, len - idx1 - 1 ) );
+ }
+}
+
+File* MountedTapeFileNode::getFile()
+{
+ return _file;
+}
+
+QString MountedTapeFileNode::getFullPath()
+{
+ if ( _fullPath.length() == 0 ) {
+ _fullPath = getText();
+ for ( Node* parent = (Node*)getParent(); !parent->isType( MountedArchiveNodeType ); parent = (Node*)parent->getParent() ) {
+ _fullPath.prepend( "/" );
+ _fullPath.prepend( parent->getText() );
+ }
+ }
+
+ return _fullPath;
+}
+
+const QPtrList<Range>& MountedTapeFileNode::getRanges()
+{
+ return _file->getRanges();
+}
+
+void MountedTapeFileNode::setSelected( bool select )
+{
+ if ( select ) {
+ // Deselect all other archives.
+ Node* parent = (Node*)getParent();
+ Node* arcNode = 0;
+ while ( !parent->isType( TapeDriveNodeType ) ) {
+ if ( parent->isType( MountedArchiveNodeType ) ) {
+ arcNode = parent;
+ }
+ parent = (Node*)parent->getParent();
+ }
+ for ( int i = parent->childCount() - 1; i >= 0; i-- ) {
+ if ( parent->childAt( i ) != arcNode ) {
+ ((SelectableNode*)parent->childAt( i ))->setSelected( FALSE );
+ }
+ }
+ }
+
+ SelectableNode::setSelected( select );
+}
+
+bool MountedTapeFileNode::isType( int type )
+{
+ if ( type == MountedTapeFileNodeType ) {
+ return TRUE;
+ } else {
+ return RangeableNode::isType( type );
+ }
+}
+
+void MountedTapeFileNode::selected()
+{
+ KDatMainWindow::getInstance()->showTapeFileInfo( _file );
+}
+
+void MountedTapeFileNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupMountedTapeFileMenu( p );
+}
+
+ArchiveableNode::ArchiveableNode( int type, const QString & text, const QPixmap& pixmap, int state )
+ : SelectableNode( type, text, pixmap, state )
+{
+}
+
+bool ArchiveableNode::isType( int type )
+{
+ if ( type == ArchiveableNodeType ) {
+ return TRUE;
+ } else {
+ return SelectableNode::isType( type );
+ }
+}
+
+RootNode::RootNode()
+ : ArchiveableNode( RootNodeType, "/", *ImageCache::instance()->getFolderClosed(), SelNone ),
+ _mtime( -1 )
+{
+ setDelayedExpanding( TRUE );
+}
+
+QString RootNode::getFullPath()
+{
+ if ( _fullPath.length() == 0 ) {
+ _fullPath = "/";
+ }
+
+ return _fullPath;
+}
+
+bool RootNode::isType( int type )
+{
+ if ( type == RootNodeType ) {
+ return TRUE;
+ } else {
+ return ArchiveableNode::isType( type );
+ }
+}
+
+void RootNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ // If we already have some children, check to see if the directory has been modified.
+ if ( childCount() > 0 ) {
+ struct stat statinfo;
+ if ( stat( "/", &statinfo ) < 0 ) {
+ printf( "Can't stat '/'\n" );
+ expand = FALSE;
+ return;
+ }
+
+ if ( statinfo.st_mtime == _mtime ) {
+ // Directory has not been modified.
+ return;
+ }
+
+ _mtime = statinfo.st_mtime;
+
+ // Remove all the children.
+ Node* n;
+ while ( ( n = (Node*)getChild() ) ) {
+ removeChild( n );
+ delete n;
+ }
+ } else {
+ struct stat statinfo;
+ if ( stat( "/", &statinfo ) < 0 ) {
+ printf( "Can't stat '/'\n" );
+ expand = FALSE;
+ return;
+ }
+
+ _mtime = statinfo.st_mtime;
+ }
+
+ QDir dir( "/" );
+ if ( dir.exists() ) {
+ // Make sure we can read the directory.
+ if ( !dir.isReadable() ) {
+ //KMsgBox::message( this, i18n( "KDat: Error" ), i18n( "The directory cannot be read." ), KMsgBox::EXCLAMATION );
+ return;
+ }
+
+ // Fill in the child's children.
+ const QFileInfoList* list = dir.entryInfoList( QDir::Hidden | QDir::Files | QDir::Dirs, QDir::Name | QDir::DirsFirst );
+ if ( list ) {
+ QFileInfoListIterator it( *list );
+ for ( ; it.current(); ++it ) {
+ if ( ( it.current()->fileName() != "." ) && ( it.current()->fileName() != ".." ) ) {
+ if ( it.current()->isDir() ) {
+ appendChild( new DirectoryNode( it.current()->fileName(), _state == SelSome ? SelNone : _state ) );
+ } else {
+ appendChild( new FileNode( it.current()->fileName(), _state == SelSome ? SelNone : _state ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+void RootNode::expanded()
+{
+ setPixmap( *ImageCache::instance()->getFolderOpen() );
+}
+
+void RootNode::collapsed()
+{
+ setPixmap( *ImageCache::instance()->getFolderClosed() );
+}
+
+void RootNode::selected()
+{
+ KDatMainWindow::getInstance()->showFileInfo( "/" );
+}
+
+void RootNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupLocalFileMenu( p );
+}
+
+DirectoryNode::DirectoryNode( const QString & text, int state )
+ : ArchiveableNode( DirectoryNodeType, text, *ImageCache::instance()->getFolderClosed(), state ),
+ _mtime( -1 )
+{
+ setDelayedExpanding( TRUE );
+}
+
+QString DirectoryNode::getFullPath()
+{
+ if ( _fullPath.isEmpty() ) {
+ _fullPath = ((ArchiveableNode*)getParent())->getFullPath() + getText() + "/";
+ }
+
+ return _fullPath;
+}
+
+bool DirectoryNode::isType( int type )
+{
+ if ( type == DirectoryNodeType ) {
+ return TRUE;
+ } else {
+ return ArchiveableNode::isType( type );
+ }
+}
+
+void DirectoryNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ // Construct the full path.
+ QString path;
+ Node* n;
+ for ( n = this; n->getType() != RootNodeType; n = (Node*)n->getParent() ) {
+ path.prepend( "/" );
+ path.prepend( n->getText() );
+ }
+ path.prepend( "/" );
+
+ // If we already have some children, check to see if the directory has been modified.
+ if ( childCount() > 0 ) {
+ struct stat statinfo;
+ if ( stat( QFile::encodeName(path), &statinfo ) < 0 ) {
+ kdError() << "Can't stat " << path << endl;
+ expand = FALSE;
+ return;
+ }
+
+ if ( statinfo.st_mtime == _mtime ) {
+ // Directory has not been modified.
+ return;
+ }
+
+ _mtime = statinfo.st_mtime;
+
+ // Remove all the children.
+ Node* n;
+ while ( ( n = (Node*)getChild() ) ) {
+ removeChild( n );
+ delete n;
+ }
+ } else {
+ struct stat statinfo;
+ if ( stat( QFile::encodeName(path), &statinfo ) < 0 ) {
+ kdError() << "Can't stat " << path << endl;
+ expand = FALSE;
+ return;
+ }
+
+ _mtime = statinfo.st_mtime;
+ }
+
+ QDir dir( path );
+ if ( dir.exists() ) {
+ // Make sure we can read the directory.
+ if ( !dir.isReadable() ) {
+ //KMsgBox::message( this, i18n( "KDat: Error" ), i18n( "The directory cannot be read." ), KMsgBox::EXCLAMATION );
+ return;
+ }
+
+ // Fill in the child's children.
+ const QFileInfoList* list = dir.entryInfoList( QDir::Hidden | QDir::Files | QDir::Dirs, QDir::Name | QDir::DirsFirst );
+ if ( list ) {
+ QFileInfoListIterator it( *list );
+ for ( ; it.current(); ++it ) {
+ if ( ( it.current()->fileName() != "." ) && ( it.current()->fileName() != ".." ) ) {
+ if ( it.current()->isDir() ) {
+ appendChild( new DirectoryNode( it.current()->fileName(), _state == SelSome ? SelNone : _state ) );
+ } else {
+ appendChild( new FileNode( it.current()->fileName(), _state == SelSome ? SelNone : _state ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+void DirectoryNode::expanded()
+{
+ setPixmap( *ImageCache::instance()->getFolderOpen() );
+}
+
+void DirectoryNode::collapsed()
+{
+ setPixmap( *ImageCache::instance()->getFolderClosed() );
+}
+
+void DirectoryNode::selected()
+{
+ // Construct the full path.
+ QString path;
+ Node* n;
+ for ( n = this; n->getType() != RootNodeType; n = (Node*)n->getParent() ) {
+ path.prepend( "/" );
+ path.prepend( n->getText() );
+ }
+ path.prepend( "/" );
+ path = path.left( path.length() - 1 );
+
+ KDatMainWindow::getInstance()->showFileInfo( path );
+}
+
+void DirectoryNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupLocalFileMenu( p );
+}
+
+FileNode::FileNode( const QString & text, int state )
+ : ArchiveableNode( FileNodeType, text, *ImageCache::instance()->getFile(), state )
+{
+}
+
+QString FileNode::getFullPath()
+{
+ if ( _fullPath.isEmpty() ) {
+ _fullPath = ((ArchiveableNode*)getParent())->getFullPath() + getText();
+ }
+
+ return _fullPath;
+}
+
+bool FileNode::isType( int type )
+{
+ if ( type == FileNodeType ) {
+ return TRUE;
+ } else {
+ return ArchiveableNode::isType( type );
+ }
+}
+
+void FileNode::selected()
+{
+ // Construct the full path.
+ QString path;
+ Node* n;
+ for ( n = this; n->getType() != RootNodeType; n = (Node*)n->getParent() ) {
+ path.prepend( "/" );
+ path.prepend( n->getText() );
+ }
+ path.prepend( "/" );
+ path = path.left( path.length() - 1 );
+
+ KDatMainWindow::getInstance()->showFileInfo( path );
+}
+
+void FileNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupLocalFileMenu( p );
+}
+
+TapeDriveNode::TapeDriveNode()
+ : Node( TapeDriveNodeType, i18n( "<no tape>" ), *ImageCache::instance()->getTapeUnmounted() )
+{
+ setDelayedExpanding( TRUE );
+
+ connect( TapeManager::instance(), SIGNAL( sigTapeMounted() ) , this, SLOT( slotTapeMounted() ) );
+ connect( TapeManager::instance(), SIGNAL( sigTapeUnmounted() ) , this, SLOT( slotTapeUnmounted() ) );
+ connect( TapeManager::instance(), SIGNAL( sigTapeModified( Tape* ) ), this, SLOT( slotTapeModified( Tape* ) ) );
+}
+
+bool TapeDriveNode::isType( int type )
+{
+ if ( type == TapeDriveNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void TapeDriveNode::expanding( bool expand )
+{
+ if ( !TapeManager::instance()->getMountedTape() ) {
+ expand = FALSE;
+ return;
+ }
+
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ // We already have the children added
+ return;
+ }
+
+ QPtrListIterator<Archive> f( TapeManager::instance()->getMountedTape()->getChildren() );
+ for ( ; f.current(); ++f ) {
+ insertNode( new MountedArchiveNode( f.current() ) );
+ }
+}
+
+void TapeDriveNode::selected()
+{
+ if ( TapeManager::instance()->getMountedTape() ) {
+ KDatMainWindow::getInstance()->showTapeInfo( TapeManager::instance()->getMountedTape() );
+ } else {
+ KDatMainWindow::getInstance()->hideInfo();
+ }
+}
+
+void TapeDriveNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupTapeDriveMenu( p );
+}
+
+void TapeDriveNode::slotTapeMounted()
+{
+ setPixmap( *ImageCache::instance()->getTapeMounted() );
+ setText( TapeManager::instance()->getMountedTape()->getName() );
+
+ if ( this == owner->getCurrentItem() ) {
+ KDatMainWindow::getInstance()->showTapeInfo( TapeManager::instance()->getMountedTape() );
+ }
+
+ if ( isExpanded() ) {
+ bool dummy = TRUE;
+ expanding( dummy );
+ }
+}
+
+void TapeDriveNode::slotTapeUnmounted()
+{
+ setPixmap( *ImageCache::instance()->getTapeUnmounted() );
+ setText( i18n( "<no tape>" ) );
+
+ // Remove all the children.
+ Node* n;
+ while ( ( n = (Node*)getChild() ) ) {
+ Node::removeChild( n );
+ delete n;
+ }
+
+ if ( this == owner->getCurrentItem() ) {
+ KDatMainWindow::getInstance()->hideInfo();
+ }
+}
+
+void TapeDriveNode::slotTapeModified( Tape* tape )
+{
+ if ( TapeManager::instance()->getMountedTape() != tape ) {
+ return;
+ }
+
+ setText( tape->getName() );
+
+ if ( owner->getCurrentItem() == this ) {
+ KDatMainWindow::getInstance()->showTapeInfo( TapeManager::instance()->getMountedTape() );
+ }
+
+ if ( ( childCount() == 0 ) && ( !isExpanded() ) ) {
+ return;
+ }
+
+ // Add/update existing archives.
+ QPtrListIterator<Archive> i( tape->getChildren() );
+ MountedArchiveNode* n;
+ for ( ; i.current(); ++i ) {
+ n = findArchiveNode( i.current() );
+ if ( n ) {
+ if ( n->validate() ) {
+ bool select = ( owner->getCurrentItem() == n );
+ Node::removeChild( n );
+ insertNode( n );
+ if ( select ) {
+ owner->setCurrentItem( owner->itemRow( n ) );
+ }
+ }
+ } else {
+ insertNode( new MountedArchiveNode( i.current() ) );
+ }
+ }
+
+ // Remove deleted archives.
+ Archive* a;
+ for ( uint j = 0; j < childCount(); ) {
+ a = ((MountedArchiveNode*)childAt( j ))->getArchive();
+ for ( i.toFirst(); i.current(); ++i ) {
+ if ( i.current() == a ) {
+ break;
+ }
+ }
+ if ( !i.current() ) {
+ Node::removeChild( childAt( j ) );
+ } else {
+ j++;
+ }
+ }
+}
+
+MountedArchiveNode* TapeDriveNode::findArchiveNode( Archive* archive )
+{
+ MountedArchiveNode* n = 0;
+ for ( uint i = 0; i < childCount(); i++ ) {
+ if ( ((MountedArchiveNode*)childAt( i ))->getArchive() == archive ) {
+ n = (MountedArchiveNode*)childAt( i );
+ break;
+ }
+ }
+
+ return n;
+}
+
+TapeIndexRootNode::TapeIndexRootNode()
+ : Node( TapeIndexRootNodeType, i18n( "Tape Indexes" ), *ImageCache::instance()->getFolderClosed() )
+{
+ setDelayedExpanding( TRUE );
+
+ connect( TapeManager::instance(), SIGNAL( sigTapeAdded( Tape* ) ) , this, SLOT( slotTapeAdded( Tape* ) ) );
+ connect( TapeManager::instance(), SIGNAL( sigTapeRemoved( Tape* ) ) , this, SLOT( slotTapeRemoved( Tape* ) ) );
+ connect( TapeManager::instance(), SIGNAL( sigTapeModified( Tape* ) ), this, SLOT( slotTapeModified( Tape* ) ) );
+}
+
+bool TapeIndexRootNode::isType( int type )
+{
+ if ( type == TapeIndexRootNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void TapeIndexRootNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ return;
+ }
+
+ QStringList list = TapeManager::instance()->getTapeIDs();
+ QStringList::Iterator i = list.begin();
+ for ( ; i != list.end(); ++i ) {
+ Tape* tape = TapeManager::instance()->findTape( *i );
+ if ( tape ) {
+ insertNode( new TapeNode( tape ) );
+ }
+ }
+}
+
+void TapeIndexRootNode::expanded()
+{
+ setPixmap( *ImageCache::instance()->getFolderOpen() );
+}
+
+void TapeIndexRootNode::collapsed()
+{
+ setPixmap( *ImageCache::instance()->getFolderClosed() );
+}
+
+void TapeIndexRootNode::slotTapeAdded( Tape* tape )
+{
+ if ( ( childCount() > 0 ) || ( isExpanded() ) ) {
+ insertNode( new TapeNode( tape ) );
+ }
+}
+
+void TapeIndexRootNode::slotTapeRemoved( Tape* tape )
+{
+ if ( ( childCount() > 0 ) || ( isExpanded() ) ) {
+ Node* n = findTapeNode( tape );
+ if ( n ) {
+ Node::removeChild( n );
+ delete n;
+ }
+ }
+}
+
+void TapeIndexRootNode::slotTapeModified( Tape* tape )
+{
+ TapeNode* n = findTapeNode( tape );
+ if ( !n ) {
+ return;
+ }
+
+ if ( n->validate() ) {
+ bool select = ( owner->getCurrentItem() == n );
+ Node::removeChild( n );
+ insertNode( n );
+ if ( select ) {
+ owner->setCurrentItem( owner->itemRow( n ) );
+ }
+ }
+}
+
+TapeNode* TapeIndexRootNode::findTapeNode( Tape* tape )
+{
+ TapeNode* n = 0;
+ for ( uint i = 0; i < childCount(); i++ ) {
+ n = (TapeNode*)childAt( i );
+ if ( n->getTape() == tape ) {
+ return n;
+ }
+ }
+
+ return 0;
+}
+
+BackupProfileNode::BackupProfileNode( BackupProfile* backupProfile )
+ : Node( BackupProfileNodeType, backupProfile->getName(), *ImageCache::instance()->getFile() ),
+ _backupProfile( backupProfile )
+{
+}
+
+BackupProfile* BackupProfileNode::getBackupProfile()
+{
+ return _backupProfile;
+}
+
+bool BackupProfileNode::validate()
+{
+ bool changed = _backupProfile->getName() != getText();
+ if ( changed ) {
+ setText( _backupProfile->getName() );
+ }
+
+ return changed;
+}
+
+bool BackupProfileNode::isType( int type )
+{
+ if ( type == BackupProfileNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void BackupProfileNode::selected()
+{
+ KDatMainWindow::getInstance()->showBackupProfileInfo( _backupProfile );
+}
+
+void BackupProfileNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupBackupProfileMenu( p );
+}
+
+BackupProfileRootNode::BackupProfileRootNode()
+ : Node( BackupProfileRootNodeType, i18n( "Backup Profiles" ), *ImageCache::instance()->getFolderClosed() )
+{
+ setDelayedExpanding( TRUE );
+
+ connect( BackupProfileManager::instance(), SIGNAL( sigBackupProfileAdded( BackupProfile* ) ) ,
+ this, SLOT( slotBackupProfileAdded( BackupProfile* ) ) );
+ connect( BackupProfileManager::instance(), SIGNAL( sigBackupProfileRemoved( BackupProfile* ) ) ,
+ this, SLOT( slotBackupProfileRemoved( BackupProfile* ) ) );
+ connect( BackupProfileManager::instance(), SIGNAL( sigBackupProfileModified( BackupProfile* ) ),
+ this, SLOT( slotBackupProfileModified( BackupProfile* ) ) );
+}
+
+void BackupProfileRootNode::setSelected( BackupProfile* pBackupProfile )
+{
+ setExpanded( TRUE );
+ bool dummy = TRUE;
+ expanding( dummy );
+ expanded();
+
+ BackupProfileNode* pNode = findBackupProfileNode( pBackupProfile );
+ if ( pNode ) {
+ owner->setCurrentItem( owner->itemRow( pNode ) );
+ pNode->selected();
+ }
+
+ KDatMainWindow::getInstance()->configureUI( TapeManager::instance()->getMountedTape() );
+}
+
+bool BackupProfileRootNode::isType( int type )
+{
+ if ( type == BackupProfileRootNodeType ) {
+ return TRUE;
+ } else {
+ return Node::isType( type );
+ }
+}
+
+void BackupProfileRootNode::expanding( bool expand )
+{
+ expand = TRUE;
+
+ if ( childCount() > 0 ) {
+ return;
+ }
+
+ QStringList list = BackupProfileManager::instance()->getBackupProfileNames();
+ QStringList::Iterator i = list.begin();
+ for ( ; i != list.end(); ++i ) {
+ BackupProfile* backupProfile = BackupProfileManager::instance()->findBackupProfile( *i );
+ if ( backupProfile ) {
+ insertNode( new BackupProfileNode( backupProfile ) );
+ }
+ }
+}
+
+void BackupProfileRootNode::expanded()
+{
+ setPixmap( *ImageCache::instance()->getFolderOpen() );
+}
+
+void BackupProfileRootNode::collapsed()
+{
+ setPixmap( *ImageCache::instance()->getFolderClosed() );
+}
+
+void BackupProfileRootNode::popupMenu( const QPoint& p )
+{
+ KDatMainWindow::getInstance()->popupBackupProfileRootMenu( p );
+}
+
+void BackupProfileRootNode::slotBackupProfileAdded( BackupProfile* backupProfile )
+{
+ if ( ( childCount() > 0 ) || ( isExpanded() ) ) {
+ insertNode( new BackupProfileNode( backupProfile ) );
+ }
+}
+
+void BackupProfileRootNode::slotBackupProfileRemoved( BackupProfile* backupProfile )
+{
+ if ( ( childCount() > 0 ) || ( isExpanded() ) ) {
+ Node* n = findBackupProfileNode( backupProfile );
+ assert( n );
+ Node::removeChild( n );
+ delete n;
+ }
+}
+
+void BackupProfileRootNode::slotBackupProfileModified( BackupProfile* backupProfile )
+{
+ BackupProfileNode* n = findBackupProfileNode( backupProfile );
+ if ( !n ) {
+ return;
+ }
+
+ if ( n->validate() ) {
+ bool select = ( owner->getCurrentItem() == n );
+ Node::removeChild( n );
+ insertNode( n );
+ if ( select ) {
+ owner->setCurrentItem( owner->itemRow( n ) );
+ }
+ }
+}
+
+BackupProfileNode* BackupProfileRootNode::findBackupProfileNode( BackupProfile* backupProfile )
+{
+ BackupProfileNode* n = 0;
+ for ( uint i = 0; i < childCount(); i++ ) {
+ n = (BackupProfileNode*)childAt( i );
+ if ( n->getBackupProfile() == backupProfile ) {
+ return n;
+ }
+ }
+
+ return 0;
+}
diff --git a/kdat/Node.h b/kdat/Node.h
new file mode 100644
index 0000000..84dfea8
--- /dev/null
+++ b/kdat/Node.h
@@ -0,0 +1,1051 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _Node_h_
+#define _Node_h_
+
+#include <qobject.h>
+
+#include "ktreeview.h"
+
+class Archive;
+class BackupProfile;
+class File;
+class RangeList;
+class Tape;
+
+/**
+ * @short The base class for all tree nodes in KDat.
+ */
+class Node : public KTreeViewItem {
+ int _type;
+protected:
+ void insertNode( Node* child );
+public:
+ enum {
+ ArchiveableNodeType,
+ ArchiveNodeType,
+ BackupProfileNodeType,
+ BackupProfileRootNodeType,
+ DirectoryNodeType,
+ FileNodeType,
+ MountedArchiveNodeType,
+ MountedTapeDirectoryNodeType,
+ MountedTapeFileNodeType,
+ NodeType,
+ RangeableNodeType,
+ RootNodeType,
+ SelectableNodeType,
+ TapeNodeType,
+ TapeDirectoryNodeType,
+ TapeDriveNodeType,
+ TapeFileNodeType,
+ TapeIndexRootNodeType
+ };
+
+ /**
+ * Create a new tree node.
+ *
+ * @param type Should be one of the enums.
+ * @param text Text label for the node.
+ * @param pixmap A pixmap to display to the left of the text.
+ */
+ Node( int type, const QString & text, const QPixmap& pixmap );
+
+ /**
+ * There must be a virtual destructor in the base class so that all the
+ * destructors in the inherited classes get called.
+ */
+ virtual ~Node();
+
+ /**
+ * Get the node's type.
+ *
+ * @return The type of this node. This information can be used to safely
+ * downcast a Node pointer.
+ */
+ int getType();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * This method is called immediately before the node is to be expanded.
+ * This method can be used to fill in the children of this node, or
+ * prevent the node from expanding. The default implementation does
+ * nothing.
+ *
+ * @param expand The method sets this to TRUE to allow the node to be
+ * expanded or FALSE to prevent the node from being expanded.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * This method is called immediately after the node has been expanded.
+ * The default implementation does nothing.
+ */
+ virtual void expanded();
+
+ /**
+ * This method is called immediately after the node has been collapsed.
+ * The default implementation does nothing.
+ */
+ virtual void collapsed();
+
+ /**
+ * This method is called immediately after the node has been selected.
+ * The default implementation does nothing.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& );
+};
+
+class ArchiveNode;
+
+/**
+ * @short This node represents the root of a tape index.
+ */
+class TapeNode : public Node {
+ Tape* _tape;
+
+ ArchiveNode* findArchiveNode( Archive* archive );
+public:
+ /**
+ * Create a tape node.
+ *
+ * @param tape A pointer to the tape index that this node represents.
+ */
+ TapeNode( Tape* tape );
+
+ /**
+ * Get the tape index associated with this node.
+ *
+ * @return A pointer to the tape index.
+ */
+ Tape* getTape();
+
+ /**
+ * Make sure that the displayed information matches the tape index. This
+ * method recurses through child nodes.
+ *
+ * @return TRUE if the node's text has changed.
+ */
+ bool validate();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each archive in the tape index.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This node represents a single archive within a tape.
+ */
+class ArchiveNode : public Node {
+ Archive* _archive;
+public:
+ /**
+ * Create an archive node.
+ *
+ * @param archive A pointer to the archive that this node represents.
+ */
+ ArchiveNode( Archive* archive );
+
+ /**
+ * Get the archive associated with this node.
+ *
+ * @return A pointer to the archive.
+ */
+ Archive* getArchive();
+
+ /**
+ * Make sure that the displayed information matches the tape index. This
+ * method recurses through child nodes.
+ *
+ * @return TRUE if the node's text has changed.
+ */
+ bool validate();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each top-level file/directory contained in the
+ * archive.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This node represents a single directory within an archive.
+ */
+class TapeDirectoryNode : public Node {
+ File* _file;
+public:
+ /**
+ * Create a tape directory node.
+ *
+ * @param file A pointer to the file that this node represents.
+ */
+ TapeDirectoryNode( File* file );
+
+ /**
+ * Get the file associated with this node.
+ *
+ * @return A pointer to the file.
+ */
+ File* getFile();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each file contained in this directory.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * Change the node's pixmap to an open folder.
+ */
+ virtual void expanded();
+
+ /**
+ * Change the node's pixmap to a closed folder.
+ */
+ virtual void collapsed();
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+};
+
+/**
+ * @short This node represents a single file within an archive.
+ */
+class TapeFileNode : public Node {
+ File* _file;
+public:
+ /**
+ * Create a tape file node.
+ *
+ * @param file A pointer to the file that this node represents.
+ */
+ TapeFileNode( File* file );
+
+ /**
+ * Get the file associated with this node.
+ *
+ * @return A pointer to the file.
+ */
+ File* getFile();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+};
+
+/**
+ * @short This class defines an interface for managing multiple selection of tree nodes.
+ */
+class SelectableNode : public Node {
+protected:
+ mutable QRect _selectRect;
+ enum { SelAll, SelNone, SelSome };
+ int _state;
+
+ void doUpdateState();
+ void doSetSelected( bool select );
+ const QPixmap* getSelectPixmap() const;
+
+ virtual bool mousePressEvent( const QPoint& point );
+ virtual void paint( QPainter* p, int indent,
+ const QColorGroup& cg, bool highlighted ) const;
+ virtual void paintText( QPainter* p, int indent, int cellHeight,
+ const QColorGroup& cg, bool highlighted ) const;
+ virtual int width( int indent, const QFontMetrics& fm ) const;
+ virtual QRect textBoundingRect( int indent ) const;
+public:
+ /**
+ * Create a selectable node.
+ *
+ * @param type Should be one of the enums.
+ * @param text Text label for the node.
+ * @param pixmap A pixmap to display to the left of the text.
+ * @param state The initial selection state of the node.
+ */
+ SelectableNode( int type, const QString & text, const QPixmap& pixmap, int state );
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Determine whether the node and all of its children are selected.
+ *
+ * @return TRUE if the node is selected, otherwise FALSE.
+ */
+ bool isSelected();
+
+ /**
+ * Determine whether the node has at least one selected descendent.
+ *
+ * @return TRUE if at least one descendent is selected.
+ */
+ bool hasSelectedChildren();
+
+ /**
+ * Select/deselect this node and all of its children.
+ *
+ * @param selected TRUE means the node will be selected, FALSE means the
+ * node will be deselected.
+ */
+ virtual void setSelected( bool selected );
+};
+
+/**
+ * @short This class defines an interface for retrieving a list of selected tape blocks.
+ */
+class RangeableNode : public SelectableNode {
+public:
+ /**
+ * Create a new rangeable node.
+ *
+ * @param type Should be one of the enums.
+ * @param text Text label for the node.
+ * @param pixmap A pixmap to display to the left of the text.
+ * @param state The initial selection state of the node.
+ */
+ RangeableNode( int type, const QString & text, const QPixmap& pixmap, int state );
+
+ /**
+ * Get a list of all the selected ranges for the subtree rooted at this
+ * node.
+ */
+ virtual const QPtrList<Range>& getRanges() = 0;
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+};
+
+/**
+ * @short This node represents a single archive within a mounted tape.
+ */
+class MountedArchiveNode : public RangeableNode {
+ Archive* _archive;
+public:
+ /**
+ * Create an mounted archive node.
+ *
+ * @param archive A pointer to the archive that this node represents.
+ */
+ MountedArchiveNode( Archive* archive );
+
+ /**
+ * Get the archive associated with this node.
+ *
+ * @return A pointer to the archive.
+ */
+ Archive* getArchive();
+
+ /**
+ * Make sure that the displayed information matches the tape index. This
+ * method recurses through child nodes.
+ *
+ * @return TRUE if the node's text has changed.
+ */
+ bool validate();
+
+ /**
+ * Get a list of all the selected ranges for the subtree rooted at this
+ * node.
+ */
+ virtual const QPtrList<Range>& getRanges();
+
+ /**
+ * Select/deselect this node and all of its children.
+ *
+ * @param selected TRUE means the node will be selected, FALSE means the
+ * node will be deselected.
+ */
+ virtual void setSelected( bool selected );
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each top-level file/directory contained in the
+ * archive.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This node represents a single directory within a mounted archive.
+ */
+class MountedTapeDirectoryNode : public RangeableNode {
+ File* _file;
+ QString _fullPath;
+public:
+ /**
+ * Create a tape directory node.
+ *
+ * @param file A pointer to the file that this node represents.
+ * @param state The initial selection state of the node.
+ */
+ MountedTapeDirectoryNode( File* file, int state );
+
+ /**
+ * Get the file associated with this node.
+ *
+ * @return A pointer to the file.
+ */
+ File* getFile();
+
+ /**
+ * Return the "fully" qualified path name of this node. It will probably
+ * NOT begin with a '/'.
+ *
+ * @return The full path name of the directory.
+ */
+ QString getFullPath();
+
+ /**
+ * Get a list of all the selected ranges for the subtree rooted at this
+ * node.
+ */
+ virtual const QPtrList<Range>& getRanges();
+
+ /**
+ * Select/deselect this node and all of its children.
+ *
+ * @param selected TRUE means the node will be selected, FALSE means the
+ * node will be deselected.
+ */
+ virtual void setSelected( bool selected );
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each file contained in this directory.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * Change the node's pixmap to an open folder.
+ */
+ virtual void expanded();
+
+ /**
+ * Change the node's pixmap to a closed folder.
+ */
+ virtual void collapsed();
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This node represents a single file within a mounted archive.
+ */
+class MountedTapeFileNode : public RangeableNode {
+ File* _file;
+ QString _fullPath;
+public:
+ /**
+ * Create a tape file node.
+ *
+ * @param file A pointer to the file that this node represents.
+ * @param state The initial selection state of the node.
+ */
+ MountedTapeFileNode( File* file, int state );
+
+ /**
+ * Get the file associated with this node.
+ *
+ * @return A pointer to the file.
+ */
+ File* getFile();
+
+ /**
+ * Return the "fully" qualified path name of this node. It will probably
+ * NOT begin with a '/'.
+ *
+ * @return The full path name of the file.
+ */
+ QString getFullPath();
+
+ /**
+ * Get a list of all the selected ranges for the subtree rooted at this
+ * node.
+ */
+ virtual const QPtrList<Range>& getRanges();
+
+ /**
+ * Select/deselect this node and all of its children.
+ *
+ * @param selected TRUE means the node will be selected, FALSE means the
+ * node will be deselected.
+ */
+ virtual void setSelected( bool selected );
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This defines an interface for archiveable nodes.
+ */
+class ArchiveableNode : public SelectableNode {
+protected:
+ QString _fullPath;
+public:
+ /**
+ * Create a new archiveable node.
+ *
+ * @param type Should be one of the enums.
+ * @param text Text label for the node.
+ * @param pixmap A pixmap to display to the left of the text.
+ * @param state The initial selection state of the node.
+ */
+ ArchiveableNode( int type, const QString & text, const QPixmap& pixmap, int state );
+
+ /**
+ * Compute the full path name of this node. Nodes representing
+ * directories end with a '/'.
+ *
+ * @return The full path of the file that this node represents.
+ */
+ virtual QString getFullPath() = 0;
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+};
+
+/**
+ * @short This node represents the root directory of the local filesystem.
+ */
+class RootNode : public ArchiveableNode {
+ int _mtime;
+public:
+ /**
+ * Create a root directory node.
+ */
+ RootNode();
+
+ /**
+ * Compute the full path name of this node. Nodes representing
+ * directories end with a '/'.
+ *
+ * @return The full path of the file that this node represents.
+ */
+ virtual QString getFullPath();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each file contained in this directory. If the
+ * directory has been modified then all of the child nodes are recreated.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * Change the node's pixmap to an open folder.
+ */
+ virtual void expanded();
+
+ /**
+ * Change the node's pixmap to a closed folder.
+ */
+ virtual void collapsed();
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This node represents a directory on the local filesystem.
+ */
+class DirectoryNode : public ArchiveableNode {
+ int _mtime;
+public:
+ /**
+ * Create a directory node.
+ *
+ * @param text The name of the directory. The full path is determined by
+ * traversing the tree to the root node.
+ * @param state The initial selection state of the node.
+ */
+ DirectoryNode( const QString & text, int state );
+
+ /**
+ * Compute the full path name of this node. Nodes representing
+ * directories end with a '/'.
+ *
+ * @return The full path of the file that this node represents.
+ */
+ virtual QString getFullPath();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each file contained in this directory. If the
+ * directory has been modified then all of the child nodes are recreated.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * Change the node's pixmap to an open folder.
+ */
+ virtual void expanded();
+
+ /**
+ * Change the node's pixmap to a closed folder.
+ */
+ virtual void collapsed();
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This node represents a file on the local filesystem.
+ */
+class FileNode : public ArchiveableNode {
+public:
+ /**
+ * Create a file node.
+ *
+ * @param text The name of the file. The full path is determined by
+ * traversing the tree to the root node.
+ * @param state The initial selection state of the node.
+ */
+ FileNode( const QString & text, int state );
+
+ /**
+ * Compute the full path name of this node. Nodes representing
+ * directories end with a '/'.
+ *
+ * @return The full path of the file that this node represents.
+ */
+ virtual QString getFullPath();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+};
+
+/**
+ * @short This node represents a tape drive.
+ */
+class TapeDriveNode : public QObject, public Node {
+ Q_OBJECT
+
+ MountedArchiveNode* findArchiveNode( Archive* archive );
+public:
+ /**
+ * Create a tape drive node.
+ */
+ TapeDriveNode();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each archive in the tape index.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& p );
+public slots:
+ /**
+ * This slot is called when the tape is mounted.
+ */
+ void slotTapeMounted();
+
+ /**
+ * This slot is called when the tape is unmounted.
+ */
+ void slotTapeUnmounted();
+
+ /**
+ * Locate the child associated with the modified tape index, and make sure
+ * that the displayed information (including all children) is updated.
+ *
+ * @param tape A pointer to the tape index that was modified.
+ */
+ void slotTapeModified( Tape* tape );
+};
+
+/**
+ * @short This node represents the root of the tape index subtree.
+ */
+class TapeIndexRootNode : public QObject, public Node {
+ Q_OBJECT
+
+ TapeNode* findTapeNode( Tape* tape );
+public:
+ /**
+ * Create a tape index root.
+ */
+ TapeIndexRootNode();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each tape index.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * Change the node's pixmap to an open folder.
+ */
+ virtual void expanded();
+
+ /**
+ * Change the node's pixmap to a closed folder.
+ */
+ virtual void collapsed();
+public slots:
+ /**
+ * Add a new child node for the new tape index.
+ *
+ * @param tape A pointer to the new tape index.
+ */
+ void slotTapeAdded( Tape* tape );
+
+ /**
+ * Remove the child associated with the tape index.
+ *
+ * @param tape A pointer to the removed tape index.
+ */
+ void slotTapeRemoved( Tape* tape );
+
+ /**
+ * Locate the child associated with the modified tape index, and make sure
+ * that the displayed information (including all children) is updated.
+ *
+ * @param tape A pointer to the tape index that was modified.
+ */
+ void slotTapeModified( Tape* tape );
+};
+
+/**
+ * @short This node represents a backup profile.
+ */
+class BackupProfileNode : public Node {
+ BackupProfile* _backupProfile;
+public:
+ /**
+ * Create a backup profile node.
+ *
+ * @param backupProfile A pointer to the backup profile that this node represents.
+ */
+ BackupProfileNode( BackupProfile* backupProfile );
+
+ /**
+ * Get the backup profile associated with this node.
+ *
+ * @return A pointer to the backup profile.
+ */
+ BackupProfile* getBackupProfile();
+
+ /**
+ * Make sure that the displayed information matches the backup profile.
+ *
+ * @return TRUE if the node's text has changed.
+ */
+ bool validate();
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * This method is called immediately after the node has been selected.
+ */
+ virtual void selected();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& );
+};
+
+/**
+ * @short This node represents the root of the backup profile subtree.
+ */
+class BackupProfileRootNode : public QObject, public Node {
+ Q_OBJECT
+
+ BackupProfileNode* findBackupProfileNode( BackupProfile* backupProfile );
+public:
+ /**
+ * Create a backup profile root.
+ */
+ BackupProfileRootNode();
+
+ /**
+ * Select the node associated with the given backu profile.
+ *
+ * @param pBackupProfile The backup profile to select.
+ */
+ void setSelected( BackupProfile* pBackupProfile );
+
+ /**
+ * Determine whether the node is an instance of the given node type.
+ *
+ * @param type The type to compare against.
+ */
+ virtual bool isType( int type );
+
+ /**
+ * Create child nodes for each tape index.
+ *
+ * @param expand This will always be set to TRUE.
+ */
+ virtual void expanding( bool expand=TRUE );
+
+ /**
+ * Change the node's pixmap to an open folder.
+ */
+ virtual void expanded();
+
+ /**
+ * Change the node's pixmap to a closed folder.
+ */
+ virtual void collapsed();
+
+ /**
+ * This method is called when the user right-clicks the mouse over the
+ * node.
+ */
+ virtual void popupMenu( const QPoint& );
+public slots:
+ /**
+ * Add a new child node for the new backup profile.
+ *
+ * @param tape A pointer to the new backup profile.
+ */
+ void slotBackupProfileAdded( BackupProfile* backupProfile );
+
+ /**
+ * Remove the child associated with the backup profile.
+ *
+ * @param tape A pointer to the removed backup profile.
+ */
+ void slotBackupProfileRemoved( BackupProfile* backupProfile );
+
+ /**
+ * Locate the child associated with the modified backup profile, and make
+ * sure that the displayed information is updated.
+ *
+ * @param tape A pointer to the backup profile that was modified.
+ */
+ void slotBackupProfileModified( BackupProfile* backupProfile );
+};
+
+#endif
diff --git a/kdat/Options.cpp b/kdat/Options.cpp
new file mode 100644
index 0000000..71a784e
--- /dev/null
+++ b/kdat/Options.cpp
@@ -0,0 +1,165 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include "Options.h"
+
+#include "Options.moc"
+
+Options* Options::_instance = 0;
+
+Options::Options()
+{
+ _config = KApplication::kApplication()->config();
+
+ _defaultTapeSize = _config->readNumEntry( "defaultTapeSize", 2*1024*1024 );
+ _tapeBlockSize = _config->readNumEntry( "tapeBlockSize", 20*512 ); // Use tar default.
+ _tapeDevice = _config->readEntry( "tapeDevice", "/dev/tape" ).copy();
+ _tarCommand = _config->readPathEntry( "tarCommand", "tar" ).copy();
+ _loadOnMount = _config->readNumEntry( "loadOnMount", FALSE );
+ _lockOnMount = _config->readNumEntry( "lockOnMount", FALSE );
+ _ejectOnUnmount = _config->readNumEntry( "ejectOnUnmount", FALSE );
+ _variableBlockSize = _config->readNumEntry( "variableBlockSize", FALSE );
+}
+
+Options* Options::instance()
+{
+ if ( _instance == 0 ) {
+ _instance = new Options();
+ }
+ return _instance;
+}
+
+void Options::sync()
+{
+ _config->sync();
+}
+
+int Options::getDefaultTapeSize()
+{
+ return _defaultTapeSize;
+}
+
+int Options::getTapeBlockSize()
+{
+ return _tapeBlockSize;
+}
+
+QString Options::getTapeDevice()
+{
+ return _tapeDevice;
+}
+
+QString Options::getTarCommand()
+{
+ return _tarCommand;
+}
+
+bool Options::getLoadOnMount()
+{
+ return _loadOnMount;
+}
+
+bool Options::getLockOnMount()
+{
+ return _lockOnMount;
+}
+
+bool Options::getEjectOnUnmount()
+{
+ return _ejectOnUnmount;
+}
+
+bool Options::getVariableBlockSize()
+{
+ return _variableBlockSize;
+}
+
+void Options::setDefaultTapeSize( int kbytes )
+{
+ if ( kbytes != getDefaultTapeSize() ) {
+ _defaultTapeSize = kbytes;
+ _config->writeEntry( "defaultTapeSize", _defaultTapeSize );
+ emit sigDefaultTapeSize();
+ }
+}
+
+void Options::setTapeBlockSize( int bytes )
+{
+ if ( bytes != getTapeBlockSize() ) {
+ _tapeBlockSize = bytes;
+ _config->writeEntry( "tapeBlockSize", _tapeBlockSize );
+ emit sigTapeBlockSize();
+ }
+}
+
+void Options::setTapeDevice( const QString & str )
+{
+ if ( getTapeDevice() != str ) {
+ _tapeDevice = str;
+ _config->writeEntry( "tapeDevice", _tapeDevice );
+ emit sigTapeDevice();
+ }
+}
+
+void Options::setTarCommand( const QString & str )
+{
+ if ( getTarCommand() != str ) {
+ _tarCommand = str;
+ _config->writePathEntry( "tarCommand", _tarCommand );
+ emit sigTarCommand();
+ }
+}
+
+void Options::setLoadOnMount( bool b )
+{
+ if ( getLoadOnMount() != b ) {
+ _loadOnMount = b;
+ _config->writeEntry( "loadOnMount", _loadOnMount );
+ emit sigLoadOnMount();
+ }
+}
+
+void Options::setLockOnMount( bool b )
+{
+ if ( getLockOnMount() != b ) {
+ _lockOnMount = b;
+ _config->writeEntry( "lockOnMount", _lockOnMount );
+ emit sigLockOnMount();
+ }
+}
+
+void Options::setEjectOnUnmount( bool b )
+{
+ if ( getEjectOnUnmount() != b ) {
+ _ejectOnUnmount = b;
+ _config->writeEntry( "ejectOnUnmount", _ejectOnUnmount );
+ emit sigEjectOnUnmount();
+ }
+}
+
+void Options::setVariableBlockSize( bool b )
+{
+ if ( getVariableBlockSize() != b ) {
+ _variableBlockSize = b;
+ _config->writeEntry( "variableBlockSize", _variableBlockSize );
+ emit sigVariableBlockSize();
+ }
+}
diff --git a/kdat/Options.h b/kdat/Options.h
new file mode 100644
index 0000000..4f65795
--- /dev/null
+++ b/kdat/Options.h
@@ -0,0 +1,211 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _Options_h_
+#define _Options_h_
+
+#include <qobject.h>
+
+class KConfig;
+
+/**
+ * @short The central repository for user preferences.
+ */
+class Options : public QObject {
+ Q_OBJECT
+ KConfig* _config;
+ int _defaultTapeSize;
+ int _tapeBlockSize;
+ QString _tapeDevice;
+ QString _tarCommand;
+ bool _loadOnMount;
+ bool _lockOnMount;
+ bool _ejectOnUnmount;
+ bool _variableBlockSize;
+
+ static Options* _instance;
+
+ Options();
+public:
+ /**
+ * Get a reference to the single instance of the Options object.
+ *
+ * @return A pointer to the options object.
+ */
+ static Options* instance();
+
+ /**
+ * Save the current user preference settings.
+ */
+ void sync();
+
+ /**
+ * Get the default size to use when formatting a tape.
+ *
+ * @return The default size in kilobytes of a tape.
+ */
+ int getDefaultTapeSize();
+
+ /**
+ * The size of a tape block can be different from the size of a tar block.
+ * Tar blocks are always 512 bytes long. Be careful!
+ *
+ * @return the size in bytes of a single tape block
+ */
+ int getTapeBlockSize();
+
+ /**
+ * Get the full path to the tape device.
+ *
+ * @return The tape device path.
+ */
+ QString getTapeDevice();
+
+ /**
+ * Get the full path to the tar command.
+ *
+ * @return The path to the tar command.
+ */
+ QString getTarCommand();
+
+ /**
+ * Get whether to load the tape before attempting to mount it.
+ *
+ * @return TRUE if the tape should be loaded.
+ */
+ bool getLoadOnMount();
+
+ /**
+ * Get whether to lock the tape drive when a tape is mounted.
+ *
+ * @return TRUE if the tape drive should be locked, otherwise FALSE.
+ */
+ bool getLockOnMount();
+
+ /**
+ * Get whether to automatically eject the tape when it is unmounted.
+ *
+ * @return TRUE if the tape should be ejected, otherwise FALSE.
+ */
+ bool getEjectOnUnmount();
+
+ /**
+ * Get whether the tape drive supports variable block sizes.
+ *
+ * @return TRUE if the tape drive can handle the MTSETBLK command.
+ */
+ bool getVariableBlockSize();
+
+ /**
+ * Set the default size for new tapes.
+ *
+ * @param kbytes The size in kilobytes.
+ */
+ void setDefaultTapeSize( int kbytes );
+
+ /**
+ * Set the size of tape block.
+ *
+ * @param bytes The size in bytes of one tape block.
+ */
+ void setTapeBlockSize( int bytes );
+
+ /**
+ * Set the path to the tape device.
+ *
+ * @param str The full path to the tape device.
+ */
+ void setTapeDevice( const QString & str );
+
+ /**
+ * Set the path to the tar command.
+ *
+ * @param str The full path to the tar command.
+ */
+ void setTarCommand( const QString & str );
+
+ /**
+ * Set whether to load the tape before attempting to mount it.
+ *
+ * @param b TRUE if the tape should be loaded.
+ */
+ void setLoadOnMount( bool b );
+
+ /**
+ * Set whether to lock the tape drive whenever a tape is mounted.
+ *
+ * @param b TRUE means lock the drive, FALSE means don't.
+ */
+ void setLockOnMount( bool b );
+
+ /**
+ * Set whether to eject the tape drive whenever a tape is unmounted.
+ *
+ * @param b TRUE means eject the tape, FALSE means don't.
+ */
+ void setEjectOnUnmount( bool b );
+
+ /**
+ * Set whether the tape drive can support variable block sizes.
+ *
+ * @param b TRUE means the tape drive understands MTSETBLK.
+ */
+ void setVariableBlockSize( bool b );
+signals:
+ /**
+ * Emitted when the default tape size changes.
+ */
+ void sigDefaultTapeSize();
+
+ /**
+ * Emitted when the tape block size changes.
+ */
+ void sigTapeBlockSize();
+
+ /**
+ * Emitted when the path to the tape device changes.
+ */
+ void sigTapeDevice();
+
+ /**
+ * Emitted when the path to the tar command changes.
+ */
+ void sigTarCommand();
+
+ /**
+ * Emitted when the load on mount feature is enabled/disabled.
+ */
+ void sigLoadOnMount();
+
+ /**
+ * Emitted when the lock on mount feature is enabled/disabled.
+ */
+ void sigLockOnMount();
+
+ /**
+ * Emitted when the eject on umount feature is enabled/disabled.
+ */
+ void sigEjectOnUnmount();
+
+ /**
+ * Emitted when the variable block size feature is enabled/disabled.
+ */
+ void sigVariableBlockSize();
+};
+
+#endif
diff --git a/kdat/OptionsDlg.cpp b/kdat/OptionsDlg.cpp
new file mode 100644
index 0000000..ba07773
--- /dev/null
+++ b/kdat/OptionsDlg.cpp
@@ -0,0 +1,126 @@
+// $Id$
+//
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdlib.h>
+
+#include "Options.h"
+#include "OptionsDlg.h"
+#include "OptionsDlgWidget.h"
+
+#include <qcheckbox.h>
+
+#include <kcombobox.h>
+#include <klineedit.h>
+#include <knuminput.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kglobal.h>
+
+#include "OptionsDlg.moc"
+OptionsDlg::OptionsDlg( QWidget* parent, const char* name )
+ : KDialogBase( Swallow, i18n ("Options"), Ok | Apply | Cancel,
+ Ok, parent, name, true, true ), apply (0)
+{
+ _baseWidget = new OptionsDlgWidget ( 0 );
+ setMainWidget (_baseWidget);
+
+ connect( _baseWidget, SIGNAL( valueChanged () ), this, SLOT( slotChanged() ) );
+
+ connect( this, SIGNAL( okClicked () ), this, SLOT( slotOK() ) );
+ connect( this, SIGNAL( applyClicked() ), this, SLOT( slotApply() ) );
+ connect( this, SIGNAL( cancelClicked() ), this, SLOT( slotCancel() ) );
+
+ int size = Options::instance()->getDefaultTapeSize();
+ if ( ( size >= 1024*1024 ) && ( size % ( 1024*1024 ) == 0 ) ) {
+ // GB
+ size /= 1024*1024;
+ _baseWidget->_defaultTapeSizeUnits->setCurrentItem( 1 );
+ } else {
+ // MB
+ size /= 1024;
+ _baseWidget->_defaultTapeSizeUnits->setCurrentItem( 0 );
+ }
+ _baseWidget->_defaultTapeSize->setValue( size );
+
+ _baseWidget->_tapeBlockSize->setValue( Options::instance()->getTapeBlockSize() );
+
+ _baseWidget->_tapeDevice->setText( Options::instance()->getTapeDevice() );
+ _baseWidget->_tarCommand->setText( Options::instance()->getTarCommand() );
+ _baseWidget->_loadOnMount->setChecked( Options::instance()->getLoadOnMount() );
+ _baseWidget->_lockOnMount->setChecked( Options::instance()->getLockOnMount() );
+ _baseWidget->_ejectOnUnmount->setChecked( Options::instance()->getEjectOnUnmount() );
+ _baseWidget->_variableBlockSize->setChecked( Options::instance()->getVariableBlockSize() );
+
+ enableButtonApply ( false );
+ configChanged = false;
+}
+
+OptionsDlg::~OptionsDlg()
+{
+}
+
+void OptionsDlg::slotChanged()
+{
+ enableButtonApply ( true );
+ configChanged = true;
+}
+
+void OptionsDlg::slotOK()
+{
+ if( configChanged )
+ slotApply();
+ accept();
+}
+
+void OptionsDlg::slotApply()
+{
+ int size = _baseWidget->_defaultTapeSize->value();
+ if ( _baseWidget->_defaultTapeSizeUnits->currentItem() == 0 ) {
+ // MB
+ size *= 1024;
+ } else {
+ // GB
+ size *= 1024*1024;
+ }
+ Options::instance()->setDefaultTapeSize( size );
+
+ Options::instance()->setTapeBlockSize( _baseWidget->_tapeBlockSize->value() );
+
+ Options::instance()->setTapeDevice( _baseWidget->_tapeDevice->text() );
+
+ Options::instance()->setTarCommand( _baseWidget->_tarCommand->text() );
+
+ Options::instance()->setLoadOnMount( _baseWidget->_loadOnMount->isChecked() );
+
+ Options::instance()->setLockOnMount( _baseWidget->_lockOnMount->isChecked() );
+
+ Options::instance()->setEjectOnUnmount( _baseWidget->_ejectOnUnmount->isChecked() );
+
+ Options::instance()->setVariableBlockSize( _baseWidget->_variableBlockSize->isChecked() );
+
+ Options::instance()->sync();
+ enableButtonApply( false );
+ configChanged = false;
+}
+
+void OptionsDlg::slotCancel()
+{
+ reject();
+}
diff --git a/kdat/OptionsDlg.h b/kdat/OptionsDlg.h
new file mode 100644
index 0000000..9e62fd7
--- /dev/null
+++ b/kdat/OptionsDlg.h
@@ -0,0 +1,56 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _OptionsDlg_h_
+#define _OptionsDlg_h_
+
+#include <kdialogbase.h>
+
+class QPushButton;
+class OptionsDlgWidget;
+
+/**
+ * @short Display/edit user preferences.
+ */
+class OptionsDlg : public KDialogBase {
+ Q_OBJECT
+private slots:
+ void slotOK();
+ void slotApply();
+ void slotCancel();
+ void slotChanged();
+public:
+ /**
+ * Create a new options dialog.
+ *
+ * @param parent The parent widget of the dialog.
+ * @param name The name of the dialog.
+ */
+ OptionsDlg( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the options dialog.
+ */
+ ~OptionsDlg();
+private:
+ bool configChanged;
+ OptionsDlgWidget *_baseWidget;
+ QPushButton* apply;
+};
+
+#endif
diff --git a/kdat/OptionsDlgWidget.ui b/kdat/OptionsDlgWidget.ui
new file mode 100644
index 0000000..5ace94d
--- /dev/null
+++ b/kdat/OptionsDlgWidget.ui
@@ -0,0 +1,385 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>OptionsDlgWidget</class>
+<author>Michael Pyne</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>OptionsDlgWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>325</width>
+ <height>332</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Options Widget</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>_defaultTapeSize</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>96</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maxValue">
+ <number>4096</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This setting determines the capacity that KDat assumes your backup tapes to be. This is used when formatting the tapes.</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>_tapeBlockSize</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>96</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maxValue">
+ <number>262144</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Tape drives read and write data in individual blocks. This setting controls the size of each block, and should be set to your tape drive's block size. For floppy tape drives this should be set to &lt;b&gt;10240&lt;/b&gt; bytes.</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="2">
+ <item>
+ <property name="text">
+ <string>MB</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GB</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>_defaultTapeSizeUnits</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This option chooses whether the default tape size to the left is in megabytes (MB) or gigabytes (GB).</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>bytes</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Tape block size:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_tapeBlockSize</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Default tape size:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_defaultTapeSize</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>browseTarCommand</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Browse for the tar command.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>_tapeDevice</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The location in the filesystem of the &lt;em&gt;non-rewinding&lt;/em&gt; tape device. The default is &lt;b&gt;/dev/tape&lt;/b&gt;.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Tar command:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_tarCommand</cstring>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>browseTapeDevice</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Browse for the tape device.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>_tarCommand</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This setting controls the command that KDat uses to perform the tape backup. The full path should be given. The default is &lt;b&gt;tar&lt;/b&gt;.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Tape device:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>_tapeDevice</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Tape Drive Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>_loadOnMount</cstring>
+ </property>
+ <property name="text">
+ <string>Load tape on mount</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>&lt;qt&gt;Issue an &lt;tt&gt;mtload&lt;/tt&gt; command prior to mounting the tape.&lt;/qt&gt;</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This command issues an &lt;tt&gt;mtload&lt;/tt&gt; command to the tape device before trying to mount it.
+
+This is required by some tape drives.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>_lockOnMount</cstring>
+ </property>
+ <property name="text">
+ <string>Lock tape drive on mount</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Disable the eject button after mounting the tape.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This option makes KDat try to disable the eject button on the tape drive after the tape has been mounted.
+
+This doesn't work for all tape drives.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>_ejectOnUnmount</cstring>
+ </property>
+ <property name="text">
+ <string>Eject tape on unmount</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Try to eject the tape after it is unmounted. Don't use this for ftape.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Try to eject the tape after it has been unmounted.
+
+This option should not be used for floppy-tape drives.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>_variableBlockSize</cstring>
+ </property>
+ <property name="text">
+ <string>Variable block size</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enable variable-block size support in the tape drive.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Some tape drives support different sizes of the data block. With this option, KDat will attempt to enable that support.
+
+You must still specify the block size.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <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>0</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+</widget>
+<connections>
+ <connection>
+ <sender>_defaultTapeSize</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_tapeBlockSize</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_defaultTapeSizeUnits</sender>
+ <signal>activated(int)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_tapeDevice</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_tarCommand</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_loadOnMount</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_lockOnMount</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_ejectOnUnmount</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>_variableBlockSize</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotValueChanged()</slot>
+ </connection>
+ <connection>
+ <sender>browseTapeDevice</sender>
+ <signal>clicked()</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotBrowseTapeDevice()</slot>
+ </connection>
+ <connection>
+ <sender>browseTarCommand</sender>
+ <signal>clicked()</signal>
+ <receiver>OptionsDlgWidget</receiver>
+ <slot>slotBrowseTarCommand()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in implementation">kapplication.h</include>
+ <include location="global" impldecl="in implementation">kfiledialog.h</include>
+ <include location="global" impldecl="in implementation">kmessagebox.h</include>
+ <include location="global" impldecl="in implementation">kglobal.h</include>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="local" impldecl="in implementation">OptionsDlgWidget.ui.h</include>
+</includes>
+<signals>
+ <signal>doBrowseTapeDevice()</signal>
+ <signal>doBrowseTarCommand()</signal>
+ <signal>valueChanged()</signal>
+</signals>
+<slots>
+ <slot access="protected">slotValueChanged()</slot>
+ <slot access="protected">slotBrowseTapeDevice()</slot>
+ <slot access="protected">slotBrowseTarCommand()</slot>
+</slots>
+<layoutdefaults spacing="11" margin="6"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/kdat/OptionsDlgWidget.ui.h b/kdat/OptionsDlgWidget.ui.h
new file mode 100644
index 0000000..6b2d4d8
--- /dev/null
+++ b/kdat/OptionsDlgWidget.ui.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+
+void OptionsDlgWidget::slotValueChanged()
+{
+ emit valueChanged ();
+}
+
+
+void OptionsDlgWidget::slotBrowseTapeDevice()
+{
+ KURL url;
+ url = KFileDialog::getOpenURL( _tapeDevice->text() );
+
+ if ( !url.isEmpty() )
+ {
+ if( !url.isLocalFile() )
+ {
+ KMessageBox::sorry( 0L, i18n( "Only local files are supported" ) );
+ return;
+ }
+ _tapeDevice->setText( url.path() );
+ }
+}
+
+
+void OptionsDlgWidget::slotBrowseTarCommand()
+{
+ KURL url;
+ url = KFileDialog::getOpenURL( _tarCommand->text() );
+
+ if ( !url.isEmpty() )
+ {
+ if( !url.isLocalFile() )
+ {
+ KMessageBox::sorry( 0L, i18n( "Only local files are currently supported" ) );
+ return;
+ }
+ _tarCommand->setText( url.path() );
+ }
+}
diff --git a/kdat/RELEASE_NOTES b/kdat/RELEASE_NOTES
new file mode 100644
index 0000000..85314f8
--- /dev/null
+++ b/kdat/RELEASE_NOTES
@@ -0,0 +1,76 @@
+
+2002-01-31
+ - Debugging statements will be printed to stdout only if
+ -DDEBUG is included in CXXFLAGS during compilation
+ - "--nocrashhandler" will be added to the command-line
+ argument list only if -DDEBUG is included in CXXFLAGS
+ during compilation
+ - fix for bugs in which disk-based files were not being
+ updated. In particular, archive names can now be changed
+ permanently. Hopefully this will also fix the problem of
+ tape dumps not being remembered.
+
+2002-01-30
+ - The command-line argument "--nocrashhandler" is now added
+ to char **argv in main() to make sure that Dr. Konqi isn't
+ called. This is necessary to allow the user to generate
+ core dumps. Calling KCrash::setCrashHandler(0); doesn't work.
+ The contents of argv[] are written to stdout to remind the
+ user that this has been done.
+ - A null-pointer problem has been fixed. For now, when that
+ pointer is null, kdat will print
+ Found sel==0x0 in KDat.cpp 1250
+ to stdout. This message will be removed once the problem is
+ known to be solved completely.
+ - The behavior of the tree when a directory is selected or
+ unselected is changed so that the subdirectory does not
+ expand or collapse at the same time. This is currently done
+ by redrawing the entire subtree, which is probably not the
+ most efficient way to do it.
+
+2002-01-28
+ - KDat now seems to dump and restore properly.
+ - Frank Pieczynski <pieczy at knuut.de> provided larger
+ backup, restore, and verify icons.
+ - Signal hander now allows user to dump core if so desired.
+ - When user starts backups, a warning appears that instructs
+ him/her how to restore data from the tape using tar on the
+ command line. This is necessary becase sometimes the new
+ archive isn't saved so kdat can't restore the data. This
+ problem appears to have disappeared spontaneously today, and
+ was linked to the variable _stubbed=FALSE.
+
+2002-01-24
+ - Frank Pieczynski <pieczy at knuut.de> provided improved blue icons.
+ The original yellow icons are retained in the distribution with
+ ".yellow" appended to their basenames for those who want them.
+ - Added new dialog box that allows the user to cancel a backup
+ while the size of the backup is being estimated. This is useful
+ when the amount of data is clearly larger than the size of
+ the medium.
+
+2002-01-21
+ - Added signal handler so user can have a chance to figure out what
+ program was doing when it received one of the signals SIGHUP,
+ SIGINT, SIGFPE, SIGSEGV, SIGTERM. The program can always be killed
+ with "kill -9 <pid>".
+
+2002-01-20
+ - Made the selected/deselected icons more similar to the original
+ easy-to-read versions
+ - Fixed bug in which a single mouse click to select or
+ deselect would change the status but not update the
+ display. The display is now updated. Double-clicking still
+ works.
+ - Fixed bug that caused the tree widget to overlap the
+ information widget.
+ - Added compile-time option to arrange the tree widget and the
+ information widget either horizontally or vertically. The default
+ is now horizontal, and the top-level window size is
+ increased from 600x400 to 600x600 pixels.
+ - NOTE: the Backup Profiles have been moved by the KDE project from
+ $HOME/.kdat
+ to
+ $HOME/.kde/share/apps/kdat
+ If you simply copy your old Backup Profiles to the new directory,
+ they should work correctly.
diff --git a/kdat/Range.cpp b/kdat/Range.cpp
new file mode 100644
index 0000000..b2836aa
--- /dev/null
+++ b/kdat/Range.cpp
@@ -0,0 +1,132 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <assert.h>
+
+#include "Range.h"
+
+Range::Range( int start, int end )
+ : _start( start ),
+ _end( end )
+{
+}
+
+int Range::getStart()
+{
+ return _start;
+}
+
+int Range::getEnd()
+{
+ return _end;
+}
+
+void Range::setStart( int start )
+{
+ _start = start;
+}
+
+void Range::setEnd( int end )
+{
+ _end = end;
+}
+
+RangeList::RangeList()
+{
+}
+
+RangeList::~RangeList()
+{
+ while ( _ranges.first() ) {
+ delete _ranges.first();
+ _ranges.removeFirst();
+ }
+}
+
+const QPtrList<Range>& RangeList::getRanges() const
+{
+ return _ranges;
+}
+
+void RangeList::addRange( int start, int end )
+{
+ assert( end >= start );
+
+ if ( start == end ) {
+ return;
+ }
+
+ // Remove all of the ranges that are totally contained by the new range.
+ for ( _ranges.first(); _ranges.current(); ) {
+ if ( ( _ranges.current()->getStart() >= start ) && ( _ranges.current()->getEnd() <= end ) ) {
+ _ranges.remove();
+ } else if ( ( start >= _ranges.current()->getStart() ) && ( end <= _ranges.current()->getEnd() ) ) {
+ // The new range is totally contained in the current range.
+ return;
+ } else {
+ _ranges.next();
+ }
+ }
+
+ // Find the correct insertion point for the new range.
+ int idx = 0;
+ for ( _ranges.first(); _ranges.current(); _ranges.next(), idx++ ) {
+ if ( _ranges.current()->getStart() > start ) {
+ break;
+ }
+ }
+
+ if ( !_ranges.current() ) {
+ // Append new range to end of list.
+ if ( ( _ranges.last() ) && ( _ranges.last()->getEnd() >= start ) ) {
+ // Ranges overlap, merge them.
+ _ranges.last()->setEnd( end );
+ } else {
+ // Append a new range.
+ _ranges.append( new Range( start, end ) );
+ }
+ } else {
+ // Insert new range before current range.
+ if ( _ranges.current()->getStart() <= end ) {
+ // Ranges overlap, merge them.
+ _ranges.current()->setStart( start );
+ end = _ranges.current()->getEnd();
+
+ // Check previous range for overlap.
+ if ( ( _ranges.prev() ) && ( _ranges.current()->getEnd() >= start ) ) {
+ // New range overlapped both the before and after ranges.
+ _ranges.current()->setEnd( end );
+ _ranges.next();
+ _ranges.remove();
+ }
+ } else {
+ // Check previous range for overlap.
+ if ( ( _ranges.prev() ) && ( _ranges.current()->getEnd() >= start ) ) {
+ // New range overlapped the before range.
+ _ranges.current()->setEnd( end );
+ } else {
+ _ranges.insert( idx, new Range( start, end ) );
+ }
+ }
+ }
+}
+
+void RangeList::clear()
+{
+ _ranges.clear();
+}
diff --git a/kdat/Range.h b/kdat/Range.h
new file mode 100644
index 0000000..5b042c3
--- /dev/null
+++ b/kdat/Range.h
@@ -0,0 +1,107 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _Range_h_
+#define _Range_h_
+
+#include <qptrlist.h>
+
+/**
+ * @short This class represents a range of tar records.
+ */
+class Range {
+ int _start;
+ int _end;
+public:
+ /**
+ * Create a new range.
+ *
+ * @param start The first tar record in the range.
+ * @param end The last tar record in the range.
+ */
+ Range( int start = 0, int end = 0 );
+
+ /**
+ * Get the first tar record in this range.
+ *
+ * @return The starting tar record.
+ */
+ int getStart();
+
+ /**
+ * Get the last tar record in this range.
+ *
+ * @return The ending tar record.
+ */
+ int getEnd();
+
+ /**
+ * Set the first tar record in this range.
+ *
+ * @param start The starting tar record.
+ */
+ void setStart( int start );
+
+ /**
+ * Set the last tar record in this range.
+ *
+ * @param end The ending tar record.
+ */
+ void setEnd( int end );
+};
+
+/**
+ * A simple list of Ranges.
+ */
+class RangeList {
+ QPtrList<Range> _ranges;
+public:
+ /**
+ * Create an empty list of ranges.
+ */
+ RangeList();
+
+ /**
+ * Destroy each range in the list.
+ */
+ ~RangeList();
+
+ /**
+ * Get the simplified list of ranges.
+ *
+ * @return The list of ranges.
+ */
+ const QPtrList<Range>& getRanges() const;
+
+ /**
+ * Intelligently add the given range to the list of ranges. If possible,
+ * the new range is merged with one (or two) of the existing ranges in
+ * the list. Otherwise, a new range is added to the list.
+ *
+ * @param start The starting tar record.
+ * @param end The ending tar record.
+ */
+ void addRange( int start, int end );
+
+ /**
+ * Erase the list of ranges.
+ */
+ void clear();
+};
+
+#endif
diff --git a/kdat/TODO b/kdat/TODO
new file mode 100644
index 0000000..e1bf865
--- /dev/null
+++ b/kdat/TODO
@@ -0,0 +1,225 @@
+Outstanding Bugs
+
+2002-04-22
+ From Bas:
+ 1) DAT tape works with tar from command line but not within kdat when the
+ device is specified as /dev/st0. It works within kdat when a symbolic
+ link to /dev/tape is made and given to kdat, but only if the startup
+ option "mount tape at startup" is NOT checked.
+
+2002-01-31
+ From RG:
+ 1) Restore data
+ when asked for "Restore to directory:" in Dialog box "Restore Options"
+ enter a not existing directory (e.g.: /tmp/xyz ), kdat will restore, but no
+ data is written to requested place, Logfile shows success.
+ !!!! The data are restored to the place, where application kdat is started !
+ reason: file VerifyDlg.cpp line: 397
+ > void VerifyDlg::show()
+ > {
+ > chdir( QFile::encodeName(_workingDir) );
+ >
+ there is no error handling !!!
+
+ same problem for Verify !
+ How to deal with ??
+ - Restore: ask the user, if kdat should create the new directory ?
+ - Verify: a verify makes no sense, if the directory is not existing
+
+ So I think a correction should be done within the
+ VerifyOptDlg::okClicked() method !?!
+ 2) adding new data to a tape, UI is not updated, while forwarding to the end of
+ tape
+ 3) forward to the end of tape: text in status line not completely visible
+ 4) tape with 10 and more archives:
+ Tape or Tape Index: Archives not correctly ordered:
+ 1, 10, 12, 12, 2, 3, 4, 5, 6
+ Note: The reindexing run lists them in correct oder
+ 5) status line: only sunken, where text is why not complete status line ?
+
+2002-01-30
+ 1) When a dump fails with a write() error, no index is written
+ to disk. When the tape is then mounted, kdat does not
+ prompt to ask whether the index should be recreated.
+ /* 2002-01-31 LEW. This may now be fixed by adding freopen() */
+ 2) From RG:
+ - change of Archive Name is not written to file (Tape Index)
+ open Tape Index, select archive, modify Archive Name (right pane),
+ press Apply, Note: tree is updated,
+ quit kdat, restart kdat, open Tape Index, old name appears
+ /* 2002-01-31 LEW. This is now fixed by adding freopen() */
+ - kdat, mounted tape, open tree Tape, select an archive,
+ go to right pane, unmount tape via toolbar icon
+ --> right pane is still active, but useless ??
+ Do now a modification of Archive name, -> Entry under
+ Tape INdexes is updated !
+ - Tree: Click on Selected/unselected Icon opend/closes the subtree
+ /* 2002-01-30 LEW: workaround is in place */
+
+ Nice to have:
+ - System Notification (Sound, when backup/Restore/Verify is
+ finished, OK or error )
+ - Rewind on unmount ?!?
+ - kdat does not respect the user setting of the decimal seperator in
+ kcontrol -> Personalization -> Contry & Language -> Numbers
+
+ 3) From FP:
+ A.) * mount a tape with a backup on it
+ - open a directory with click on the plus sign
+ - open again a dir only with click on plus until you see a file
+ - click on the white quadrat to select this file
+ => crash
+ /* 2002-01-30 LEW: hopefully, this is fixed in the KDat.cpp:1250 patch */
+ B.) - select a single file (black x):
+ - the restore doesn't restore only that file, but also
+ the content of the directories above (they marked with the
+ grey X for "some_selected")
+ C.) * mount a tape with a backup on it
+ - open a directory with click on the plus sign
+ - click on the name of a directory
+ => "Restore" and "Verify" in Toolbar becomes active,
+ but there are no visible (x) selected dirs/files shown
+ (A restore in that situation restores that file and all
+ dirs above including there additional content - see B)
+ D.) - save log in the restore window brings up a Qt file dialog?
+ E.) - a directory containing a file (size 194byte) is not restored
+ - not with trying the file directly: startrecord: 10104 end 10109
+ or the dir above: startrecord 10103 end 10104
+ F.) * mount a tape with a backup on it
+ - open the tree, do 2 dirs deeper and select a file inside (black X)
+ - restore that file
+ the restore window comes up select a dir etc,
+ after the successful restore close the Restore window with ok
+ -> the file is still in black selected, the dirs above in grey
+ - now collapse the tree above the file with clicking on the "+"
+ of a grey marked dir
+ => crash
+ /* 2002-01-30 LEW: hopefully, this is fixed in the KDat.cpp:1250 patch */
+
+2002-01-29
+ 1) Major memory leak or very inefficient memory allocation:
+ Saving the log file to disk is very slow (158560 lines of text
+ over 50 min). The free function shows that at the end of the save()
+ function, there were 35MB of swap space left on the machine. After
+ the log file was freed from memory (again a very long process),
+ there were 361MB free (a difference of 326MB, or 2KB per line,
+ where each line has an average of 63 characters.
+ top showed that the size of kdat was 235M with RSS=215M when
+ the log file memory allocation was freed. free RAM during
+ this time was 3MB (out of 257MB). When kdat was terminated, free
+ RAM increased from 3MB to 214MB.
+
+2002-01-28
+ 1) The font size and line spacing vary from machine to machine
+ (e.g., Red Hat 7.0 and Red Hat 7.2). The dialog window has
+ been made larger until a way to size automatically is set up.
+
+2002-01-25
+
+ 1) FP notes "This part of KDat seems to need a cleanup in a
+ later version. For example the toolbar icons are in real at
+ a size at 22x22, but the filenames say 16x16. If you
+ change the names to hi22 kdat don't find them :-( In the
+ future there should be a set of 16x16, 22x22 and 32x32
+ toolbar icons, the menu and toolbar can then be created
+ with the KAction class and XMLGUI and the toolbar menu will
+ then have an effect :-)"
+
+2002-01-23
+
+ 1) FP reports: "One more problem: If you open in the tree a
+ archive and try to select some dir inside, a error handler
+ comes up and I have to kill KDat." /* 2002-01-28 LEW: this
+ problem is intermittent. A signal handler is now added
+ that allows the user to dump core when a problem occurs. */
+
+ 2) LEW can't see archives on tape. /* 2002-01-28 LEW: this
+ problem mysteriously disappeared today. Perhaps it had
+ something to do with configuration. In case it recurs, the
+ notes below showing a relationship to _stubbed are retained. */
+ /* 2002-01-31 LEW. This may now be fixed by adding freopen() */
+
+ Progress so far:
+
+ 2002-01-26 LEW: in Tape.cpp, readVersion4Index() on a recent tape dump
+ shows that numArchives is 0 even though the tape has the dumped files
+ on it (as shown by running tar tfv /dev/nst0 3 times). A problem with
+ creating the archive after the tape is dumped? In fact, the Archive
+ dialog during the dump shows that no files are being dumped when in
+ fact they are.
+
+ Also, TapeManager::findTape() shows that the newly mounted tape's ID
+ is used to retrieve the Tape* entry in _tapes, but _tapes has no
+ entries. It is supposed to contain the details from all the index
+ files in the appdata directory. But, when those files are read when
+ the TapeManager is instantiated, only their names are stored
+ (in QStringList _tapeIDs). The files themselves are not examined.
+
+ 2002-01-28 LEW: On further examination, the BackupDlg widget does in fact
+ call Tape::addChild( Archive* archive ) to add the new archive, and
+ addChild() does call read() in preparation for updating the on-disk
+ tape file. However, read() refuses to do anything because the tape
+ isn't stubbed (_stubbed==FALSE). I don't know what this means yet.
+ Forcing _stubbed=TRUE doesn't work either. It looks like _stubbed has
+ to do with whether the tape ID is recognized as belonging to an index
+ file on disk or not (see the second paragraph of 2002-01-26).
+
+2002-01-21
+
+ 1) While dumping 9.5GB to 8.3GB tape:
+ In file tools/qgarray.cpp, line 227: Out of memory
+ kdeinit: Fatal IO error: client killed
+ kdeinit: sending SIGHUP to children.
+ Mutex destroy failure: Device or resource busy
+ kdeinit: sending SIGTERM to children.
+ kdeinit: Exit.
+ /* 2002-01-21 LEW: added signal handler to KDat so it won't
+ crash when it receives SIGHUPs, SIGTERMs, etc., and that
+ allows user to dump core if (s)he wishes. */
+
+c/o rolandg at onlinehome.de:
+
+ 2) Tree Widget: Mounted Tape
+ Icon too big -> the backup sets are not visible on the screen.
+ If I select the archive, I see the upper pixel of some marked text.
+
+ 3) Tree Widget: Tape Index is empty, but I did just a few minutes ago
+ a 1st backup onto the the tape.
+ The tape index file is stored in .kde/share/apps/kdat.
+ /* 2002-01-24 RG sent patch */
+
+ 4) Backup Profiles
+ o Delete Profile does not work
+ o after creating several new profiles the directory .kde/share/apps/kdat
+ lists some with their default names, and some with the by me defined
+ profile names.
+ 5) When backup up some more files, kdat calculates the complete size
+ of the data. In the status line the filenames are running through.
+ I see no way to cancel this action. /* 2002-01-24 LEW: new dialog added */
+
+2002-01-20 Outstanding bugs
+
+ 1) The vertical line in the tree widget that shows indenting levels is not
+ drawn correctly: there is a small hole in the dir lines. (Thanks
+ to Frank Pieczynski <pieczyk at knuut.de>.) /* fixed 2002-01-24 with new
+ icons that FP sent in. */
+ 2) when files are restored, they are copied correctly from the tape to
+ disk, but their names in the log window are corrupted (this is an old
+ bug). /* reported fixed by RG 2002-01-23 */
+ 3) Verify quits early (this is an old bug).
+
+2001-08-01 These are possible sources of bugs:
+
+1) don't return 0 instead of a null QString
+ (e.g., BackupProfile::getWorkingDirectory())
+2) don't test for FALSE predicate values with
+ !(). Use == FALSE instead.
+3) don't piggyback .remove with .first:
+ _relativeFiles.remove(_relativeFiles.first())
+
+ Instead, separate the two:
+ QString my_first = _relativeFiles.first();
+ _relativeFiles.remove( my_first );
+
+ This may be important with any call to .remove()
+ as may be found with: `grep "\.remove" *.cpp`
diff --git a/kdat/Tape.cpp b/kdat/Tape.cpp
new file mode 100644
index 0000000..b015376
--- /dev/null
+++ b/kdat/Tape.cpp
@@ -0,0 +1,933 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <qfile.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+
+#include "IndexDlg.h"
+#include "KDatMainWindow.h"
+#include "Options.h"
+#include "Tape.h"
+#include "TapeDrive.h"
+#include "TapeManager.h"
+#include "kdat.h"
+
+Tape::Tape()
+ : _stubbed( FALSE ),
+ _name( i18n( "New Tape" ) ),
+ _size( Options::instance()->getDefaultTapeSize() ),
+ _fptr( 0 )
+{
+ char buffer[1024];
+ gethostname( buffer, 1024 );
+ time_t tm = time( NULL );
+ _ctime = tm;
+ _mtime = tm;
+ _id.sprintf("%s:%d", buffer, tm);
+
+ write();
+}
+
+Tape::Tape( const char * id )
+ : _stubbed( TRUE ),
+ _id( id ),
+ _ctime( -1 ),
+ _mtime( -1 ),
+ _name( "<unknown>" ),
+ _size( -1 ),
+ _fptr( 0 )
+{
+}
+
+Tape::~Tape()
+{
+ clear();
+}
+
+void Tape::format()
+{
+ // Rewind tape.
+ if ( !TapeDrive::instance()->rewind() ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Rewinding tape failed." ), i18n("Format Failed"));
+ return;
+ }
+
+ // Set block size for tape.
+ if ( !TapeDrive::instance()->setBlockSize( Options::instance()->getTapeBlockSize() ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Cannot set tape block size." ), i18n("Format Failed"));
+ return;
+ }
+
+ // TAPE HEADER
+ int iv;
+
+ // KDat magic string.
+ if ( TapeDrive::instance()->write( KDAT_MAGIC, KDAT_MAGIC_LENGTH ) < KDAT_MAGIC_LENGTH ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing magic string failed." ), i18n("Format Failed"));
+ return;
+ }
+
+ // Tape header version number.
+ iv = KDAT_TAPE_HEADER_VERSION;
+ if ( TapeDrive::instance()->write( (const char*)&iv, 4 ) < 4 ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing version number failed." ), i18n("Format Failed") );
+ return;
+ }
+
+ // Write tape ID. Tape ID is machine name + current time.
+ iv = _id.length() + 1;
+ if ( TapeDrive::instance()->write( (const char*)&iv, 4 ) < 4 ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing tape ID length failed." ), i18n("Format Failed") );
+ return;
+ }
+ if ( TapeDrive::instance()->write( _id, iv ) < iv ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Writing tape ID failed." ), i18n("Format Failed") );
+ return;
+ }
+
+ // Write end of file marker.
+ TapeDrive::instance()->close();
+ TapeDrive::instance()->open();
+
+ // Write new tape index.
+ write();
+}
+
+void Tape::read()
+{
+ if ( !_stubbed ) {
+ /* 2002-01-28 LEW */
+ // printf("Can't read tape data because tape isn't stubbed\n" );
+ /* 2002-01-28 LEW */
+ return;
+ }
+
+ _stubbed = FALSE;
+
+ /* 2002-01-28 LEW */
+ // printf("Preparing to read tape data\n" );
+ // QString filename1 = locateLocal( "appdata", _id);
+ // printf("The tape data are in \"%s\"\n", filename1.ascii() );
+ /* 2002-01-28 LEW */
+
+ if ( !_fptr ) {
+ QString filename = locateLocal( "appdata", _id);
+ _fptr = fopen( QFile::encodeName(filename), "r" );
+
+ /* 2002-01-28 LEW */
+#ifdef DEBUG
+ // printf("Opened tape archive file \"%s\". %s %d\n",
+ // filename.ascii(), __FILE__, __LINE__ );
+#endif /* DEBUG */
+ /* 2002-01-28 LEW */
+
+ }
+
+ if ( !_fptr ) {
+ // No tape index file was found.
+ int result = KMessageBox::warningContinueCancel( KDatMainWindow::getInstance(),
+ i18n( "No index file was found for this tape.\n"
+ "Recreate the index from tape?" ),
+ i18n("Tape Index"),
+ i18n("Recreate"));
+ if (result == KMessageBox::Continue ) {
+ write();
+
+ IndexDlg dlg( this, KDatMainWindow::getInstance() );
+ dlg.exec();
+ TapeManager::instance()->addTape( this );
+ return;
+ } else {
+ return;
+ }
+ }
+
+ char buf[4096];
+
+ fseek( _fptr, 0, SEEK_SET );
+
+ // Read index file version number.
+ if ( !fgets( buf, 4096, _fptr ) ) {
+ fclose( _fptr );
+ KMessageBox::error( KDatMainWindow::getInstance(),
+ i18n( "Reading version number failed." ),
+ i18n("Index File Error") );
+ return;
+ }
+ int version = atoi( buf );
+
+ switch ( version ) {
+ case 1:
+ readVersion1Index( _fptr );
+ readAll( version );
+ calcRanges();
+ fclose( _fptr );
+ _fptr = NULL;
+ write();
+ break;
+
+ case 2:
+ readVersion2Index( _fptr );
+ readAll( version );
+ calcRanges();
+ fclose( _fptr );
+ _fptr = NULL;
+ write();
+ break;
+
+ case 3:
+ readVersion3Index( _fptr );
+ readAll( version );
+ calcRanges();
+ fclose( _fptr );
+ _fptr = NULL;
+ write();
+ break;
+
+ case 4:
+ readVersion4Index( _fptr );
+ break;
+
+ default:
+ {
+ KMessageBox::sorry( KDatMainWindow::getInstance(),
+ i18n( "The tape index file format is version %d. The index cannot be read by this version of KDat. Perhaps the tape index file was created by a newer version of KDat?" ).arg(version ),
+ i18n("Tape Index") );
+ }
+ }
+}
+
+void Tape::readAll( int version )
+{
+ read();
+
+ QPtrListIterator<Archive> i( _children );
+ for ( ; i.current(); ++i ) {
+ i.current()->readAll( version );
+ }
+}
+
+void Tape::write()
+{
+ QString filename = locateLocal( "appdata", _id);
+
+ /* 2002-01-28 LEW */
+#ifdef DEBUG
+ // printf("Preparing to write the archive data to \"%s\". %s %d\n",
+ // filename.ascii(), __FILE__, __LINE__ );
+#endif /* DEBUG */
+ /* 2002-01-28 LEW */
+
+ if ( !_fptr ) {
+ _fptr = fopen( QFile::encodeName(filename), "w" );
+
+ /* 2002-01-31 LEW */
+#ifdef DEBUG
+ // printf("Opened new archive file \"%s\". %s %d\n",
+ // filename.ascii(), __FILE__, __LINE__ );
+#endif /* DEBUG */
+ /* 2002-01-31 LEW */
+
+ if ( !_fptr ) {
+ // Suck!
+ printf( "Tape::write() -- cannot open '%s' for writing!\n", filename.ascii() );
+ return;
+ }
+ } else {
+ freopen( QFile::encodeName(filename), "w", _fptr );
+ /* 2002-01-31 LEW */
+#ifdef DEBUG
+ // printf("Reopened new archive file \"%s\". %s %d\n",
+ // filename.ascii(), __FILE__, __LINE__ );
+#endif /* DEBUG */
+ /* 2002-01-31 LEW */
+ }
+
+ int zero = 0;
+
+ //===== Write the tape data =====
+
+ fprintf( _fptr, "%d\n", KDAT_INDEX_FILE_VERSION );
+ fprintf( _fptr, "%s\n", _id.data() );
+
+ fwrite( &_ctime, sizeof( _ctime ), 1, _fptr );
+ fwrite( &_mtime, sizeof( _mtime ), 1, _fptr );
+ fwrite( &_size , sizeof( _size ), 1, _fptr );
+ char buf[4096];
+ memset( buf, 0, 4096 );
+ memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
+ fwrite( buf, sizeof( char ), 4096, _fptr );
+ int ival = _children.count();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+
+ // Fill in the archive offsets later...
+ int archiveTable = ftell( _fptr );
+ for ( uint i = 0; i < MAX_NUM_ARCHIVES; i++ ) {
+ fwrite( &zero, sizeof( zero ), 1, _fptr );
+ }
+
+ //===== Write archives =====
+ QPtrListIterator<Archive> i( _children );
+ int count = 0;
+ for ( ; i.current(); ++i, count++ ) {
+ // Fill in the file offset.
+ int here = ftell( _fptr );
+ fseek( _fptr, archiveTable + 4*count, SEEK_SET );
+ fwrite( &here, sizeof( here ), 1, _fptr );
+ fseek( _fptr, here, SEEK_SET );
+
+ i.current()->write( _fptr );
+ }
+
+ freopen( QFile::encodeName(filename), "r+", _fptr );
+}
+
+QString Tape::getID()
+{
+ read();
+
+ return _id;
+}
+
+QString Tape::getName()
+{
+ read();
+
+ return _name;
+}
+
+int Tape::getCTime()
+{
+ read();
+
+ return _ctime;
+}
+
+int Tape::getMTime()
+{
+ read();
+
+ return _mtime;
+}
+
+int Tape::getSize()
+{
+ read();
+
+ return _size;
+}
+
+const QPtrList<Archive>& Tape::getChildren()
+{
+ read();
+
+ return _children;
+}
+
+void Tape::setName( const QString & name )
+{
+ /* 2002-01-31 LEW */
+ int i;
+ /* 2002-01-31 LEW */
+
+ read();
+
+ if ( !_fptr ) {
+ // Create a new empty index file.
+ write();
+ }
+
+ // change file to read-write so we can update it 2002-01-31 LEW
+ QString filename = locateLocal( "appdata", _id);
+ freopen( QFile::encodeName(filename), "r+", _fptr );
+
+ _name = name;
+
+ char buf[4096];
+ if( fseek( _fptr, 0, SEEK_SET ) < 0 )
+ {
+ clearerr( _fptr );
+#ifdef DEBUG /* Can't create new i18n strings now, so we'll save this for KDE 3.1 */
+ /* Note to translator: this error checking was added while tracking
+ down a bug that turns out to be unrelated. The errors I'm looking
+ for here haven't happened in real use, so there is no rush to add
+ these checks in KDE 3.0. Thanks. - LW */
+ QString msg = i18n("Error during fseek #1 while accessing archive: \"");
+ msg.append( getID() );
+ msg.append( "\": " );
+ msg.append( i18n(strerror( errno )) );
+ printf("%s\n", msg.latin1());
+ KMessageBox::error(NULL, msg, i18n("File Access Error"));
+#endif /* DEBUG */
+ return;
+ }
+ if( fgets( buf, 4096, _fptr ) == NULL )
+ {
+ clearerr( _fptr );
+#ifdef DEBUG /* Can't create new i18n strings now, so we'll save this for KDE 3.1 */
+ QString msg = i18n("Error while accessing string #1 in archive: \"");
+ msg.append( getID() );
+ msg.append( "\": " );
+ msg.append( i18n(strerror( errno )) );
+ printf("%s\n", msg.latin1());
+ KMessageBox::error(NULL, msg, i18n("File Access Error"));
+#endif /* DEBUG */
+ return;
+ }
+ if( fgets( buf, 4096, _fptr ) == NULL )
+ {
+ clearerr( _fptr );
+#ifdef DEBUG /* Can't create new i18n strings now, so we'll save this for KDE 3.1 */
+ QString msg = i18n("Error while accessing string #2 in archive: \"");
+ msg.append( getID() );
+ msg.append( "\": " );
+ msg.append( i18n(strerror( errno )) );
+ printf("%s\n", msg.latin1());
+ KMessageBox::error(NULL, msg, i18n("File Access Error"));
+#endif /* DEBUG */
+ return;
+ }
+ if( fseek( _fptr, 12, SEEK_CUR ) < 0 )
+ {
+ clearerr( _fptr );
+#ifdef DEBUG /* Can't create new i18n strings now, so we'll save this for KDE 3.1 */
+ QString msg = i18n("Error during fseek #2 while accessing archive: \"");
+ msg.append( getID() );
+ msg.append( "\": " );
+ msg.append( i18n(strerror( errno )) );
+ printf("%s\n", msg.latin1());
+ KMessageBox::error(NULL, msg, i18n("File Access Error"));
+#endif /* DEBUG */
+ return;
+ }
+ memset( buf, 0, 4096 );
+ memcpy( buf, _name.ascii(), _name.length() > 4095 ? 4095 : _name.length() );
+ i = fwrite( buf, sizeof( char ), 4096, _fptr );
+ /* 2002-01-31 LEW */
+ /* Note to translator: I know it's past the deadline, so don't translate this. I think
+ I fixed the bug that caused this error to occur. Thanks - LW */
+ if( ( i < 4096 ) || ( ferror( _fptr ) != 0 )){
+ clearerr( _fptr );
+ QString msg = i18n("Error while updating archive name: ");
+ msg.append( i18n(strerror( errno )) );
+ printf("%s\n", msg.latin1());
+ KMessageBox::error(NULL, msg, i18n("File Access Error"));
+ // return;
+ /* 2002-01-31 LEW */
+ }
+ fflush( _fptr );
+
+ /* 2002-01-31 LEW */
+#ifdef DEBUG
+ // printf("Tape::setName. wrote \"%s\" (%d bytes) into archive ID %s. %s %d\n",
+ // _name.ascii(), _name.length(), getID().latin1(), __FILE__, __LINE__);
+ // printf(" The buffer size is 4096. %d bytes were written\n", i);
+#endif /* DEBUG */
+ /* 2002-01-31 LEW */
+
+ // change back to read-only 2002-01-31 LEW
+ freopen( QFile::encodeName(filename), "r", _fptr );
+
+ TapeManager::instance()->tapeModified( this );
+}
+
+void Tape::setMTime( int mtime )
+{
+ read();
+
+ if ( !_fptr ) {
+ // Create a new empty index file.
+ write();
+ }
+
+ // change file to read-write so we can update it 2002-01-31 LEW
+ QString filename = locateLocal( "appdata", _id);
+ freopen( QFile::encodeName(filename), "r+", _fptr );
+
+ _mtime = mtime;
+
+ char buf[4096];
+ fseek( _fptr, 0, SEEK_SET );
+ fgets( buf, 4096, _fptr );
+ fgets( buf, 4096, _fptr );
+ fseek( _fptr, 4, SEEK_CUR );
+ fwrite( &_mtime, sizeof( _mtime ), 1, _fptr );
+ fflush( _fptr );
+
+ // change back to read-only 2002-01-31 LEW
+ freopen( QFile::encodeName(filename), "r", _fptr );
+
+ TapeManager::instance()->tapeModified( this );
+}
+
+void Tape::setSize( int size )
+{
+ read();
+
+ if ( !_fptr ) {
+ // Create a new empty index file.
+ write();
+ }
+
+ _size = size;
+
+ // change file to read-write so we can update it 2002-01-31 LEW
+ QString filename = locateLocal( "appdata", _id);
+ freopen( QFile::encodeName(filename), "r+", _fptr );
+
+ char buf[4096];
+ fseek( _fptr, 0, SEEK_SET );
+ fgets( buf, 4096, _fptr );
+ fgets( buf, 4096, _fptr );
+ fseek( _fptr, 8, SEEK_CUR );
+ fwrite( &_size, sizeof( _size ), 1, _fptr );
+ fflush( _fptr );
+
+ // change back to read-only 2002-01-31 LEW
+ freopen( QFile::encodeName(filename), "r", _fptr );
+
+ TapeManager::instance()->tapeModified( this );
+}
+
+void Tape::addChild( Archive* archive )
+{
+ /* 2002-01-28 LEW */
+ // printf("Preparing to add archive to tape file\n" );
+ /* 2002-01-28 LEW */
+
+ read();
+
+ // change file to read-write so we can update it 2002-01-31 LEW
+ QString filename = locateLocal( "appdata", _id);
+ freopen( QFile::encodeName(filename), "r+", _fptr );
+
+ archive->calcRanges();
+
+ _children.append( archive );
+
+ char buf[4096];
+ fseek( _fptr, 0, SEEK_END );
+ int here = ftell( _fptr );
+ fseek( _fptr, 0, SEEK_SET );
+ fgets( buf, 4096, _fptr );
+ fgets( buf, 4096, _fptr );
+ fseek( _fptr, 12 + 4096, SEEK_CUR );
+ int ival = _children.count();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+ fseek( _fptr, ( _children.count() - 1 ) * 4, SEEK_CUR );
+ fwrite( &here, sizeof( here ), 1, _fptr );
+ fseek( _fptr, here, SEEK_SET );
+ archive->write( _fptr );
+ fflush( _fptr );
+
+ setMTime( time( NULL ) );
+
+ // change back to read-only 2002-01-31 LEW
+ freopen( QFile::encodeName(filename), "r", _fptr );
+
+ /* 2002-01-28 LEW */
+ // printf("Done adding archive to tape file\n" );
+ /* 2002-01-28 LEW */
+}
+
+void Tape::removeChild( Archive* archive )
+{
+ read();
+
+ while ( _children.last() != archive ) {
+ _children.removeLast();
+ }
+ _children.removeLast();
+
+ char buf[4096];
+ fseek( _fptr, 0, SEEK_SET );
+ fgets( buf, 4096, _fptr );
+ fgets( buf, 4096, _fptr );
+ fseek( _fptr, 12 + 4096, SEEK_CUR );
+ int ival = _children.count();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+ int here;
+ if ( ival > 0 ) {
+ fseek( _fptr, _children.count() * 4, SEEK_CUR );
+ fread( &here, sizeof( here ), 1, _fptr );
+ } else {
+ fseek( _fptr, MAX_NUM_ARCHIVES * 4, SEEK_CUR );
+ here = ftell( _fptr );
+ }
+
+ QString filename = locateLocal( "appdata", _id);
+ truncate( QFile::encodeName(filename), here );
+ freopen( QFile::encodeName(filename), "r+", _fptr );
+ fflush( _fptr );
+
+ // change back to read-only 2002-01-31 LEW
+ freopen( QFile::encodeName(filename), "r", _fptr );
+
+ setMTime( time( NULL ) );
+}
+
+void Tape::clear()
+{
+ if ( _children.count() < 1 ) {
+ return;
+ }
+
+ while ( _children.first() ) {
+ delete _children.first();
+ _children.removeFirst();
+ }
+
+ char buf[4096];
+ fseek( _fptr, 0, SEEK_SET );
+ fgets( buf, 4096, _fptr );
+ fgets( buf, 4096, _fptr );
+ fseek( _fptr, 12 + 4096, SEEK_CUR );
+ int ival = _children.count();
+ fwrite( &ival, sizeof( ival ), 1, _fptr );
+ fseek( _fptr, MAX_NUM_ARCHIVES * 4, SEEK_CUR );
+ int here = ftell( _fptr );
+
+ QString filename = locateLocal( "appdata", _id);
+ truncate( QFile::encodeName(filename), here );
+ freopen( QFile::encodeName(filename), "r+", _fptr );
+ fflush( _fptr );
+
+ // change back to read-only 2002-01-31 LEW
+ freopen( QFile::encodeName(filename), "r", _fptr );
+
+ setMTime( time( NULL ) );
+}
+
+void Tape::readVersion1Index( FILE* fptr )
+{
+ fseek( fptr, 0, SEEK_CUR );
+
+ char buf[4096];
+
+ // Read the tapeID.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
+ return;
+ }
+ QCString tapeID = buf;
+ tapeID.truncate( tapeID.length() - 1 );
+ if ( tapeID !=_id ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
+ return;
+ }
+
+ // Read creation time.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading creation time failed." ), i18n("Index File Error") );
+ return;
+ }
+ _ctime = atoi( buf );
+
+ // Read modification time.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading modification time failed." ), i18n("Index File Error") );
+ return;
+ }
+ _mtime = atoi( buf );
+
+ // Read tape name.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape name failed." ), i18n("Index File Error") );
+ return;
+ }
+ _name = buf;
+ _name.truncate( _name.length() - 1 );
+
+ // Read tape size.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape size failed." ), i18n("Index File Error") );
+ return;
+ }
+ _size = atoi( buf );
+
+ // Read number of archives.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive count failed." ), i18n("Index File Error") );
+ return;
+ }
+ int numArchives = atoi( buf );
+
+ for ( ; numArchives; numArchives-- ) {
+ // Read archive name.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive name failed." ), i18n("Index File Error") );
+ return;
+ }
+ QString archiveName = buf;
+ archiveName.truncate( archiveName.length() - 1 );
+
+ // Read archive time stamp.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive time stamp failed." ), i18n("Index File Error") );
+ return;
+ }
+ int archiveTimeStamp = atoi( buf );
+
+ // Read archive start block.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive start block failed." ), i18n("Index File Error") );
+ return;
+ }
+ int archiveStartBlock = atoi( buf );
+
+ // Read archive end block.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive end block failed." ), i18n("Index File Error") );
+ return;
+ }
+ int archiveEndBlock = atoi( buf );
+
+ // Create the archive.
+ Archive* archive = new Archive( this, archiveTimeStamp, archiveName );
+ archive->setEndBlock( archiveEndBlock - archiveStartBlock );
+
+ _children.append( archive );
+
+ // Read the number of files.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive file count failed." ), i18n("Index File Error") );
+ return;
+ }
+ int archiveNumFiles = atoi( buf );
+
+ QString tmpFileName;
+ int tmpFileSize = -1;
+ int tmpFileMTime = -1;
+ int tmpFileStartRecord = -1;
+ for ( ; archiveNumFiles; archiveNumFiles-- ) {
+ // Read file name.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file name failed." ), i18n("Index File Error") );
+ return;
+ }
+ QString fileName = buf;
+ fileName.truncate( fileName.length() - 1 );
+
+ // Read file size.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file size failed." ), i18n("Index File Error") );
+ return;
+ }
+ int fileSize = atoi( buf );
+
+ // Read file modification time.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file modification time failed." ), i18n("Index File Error") );
+ return;
+ }
+ int fileModTime = atoi( buf );
+
+ // Read file record number.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading file record number failed." ), i18n("Index File Error") );
+ return;
+ }
+ int fileRecord = atoi( buf );
+
+ if ( tmpFileName.length() > 0 ) {
+ archive->addFile( tmpFileSize, tmpFileMTime, tmpFileStartRecord, fileRecord, tmpFileName );
+ }
+
+ tmpFileName = fileName.copy();
+ tmpFileSize = fileSize;
+ tmpFileMTime = fileModTime;
+ tmpFileStartRecord = fileRecord;
+ }
+
+ if ( tmpFileName.length() > 0 ) {
+ archive->addFile( tmpFileSize, tmpFileMTime, tmpFileStartRecord, archive->getEndBlock() * ( Options::instance()->getTapeBlockSize() / 512 ), tmpFileName );
+ }
+ }
+}
+
+void Tape::readVersion2Index( FILE* fptr )
+{
+ fseek( fptr, 0, SEEK_CUR );
+
+ char buf[4096];
+
+ // Read the tapeID.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
+ return;
+ }
+ QCString tapeID = buf;
+ tapeID.truncate( tapeID.length() - 1 );
+ if ( tapeID != _id ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
+ return;
+ }
+
+ // Read creation time.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading creation time failed." ), i18n("Index File Error") );
+ return;
+ }
+ _ctime = atoi( buf );
+
+ // Read modification time.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading modification time failed." ), i18n("Index File Error") );
+ return;
+ }
+ _mtime = atoi( buf );
+
+ // Read tape name.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape name failed." ), i18n("Index File Error") );
+ return;
+ }
+ _name = buf;
+ _name.truncate( _name.length() - 1 );
+
+ // Read tape size.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape size failed." ), i18n("Index File Error") );
+ return;
+ }
+ _size = atoi( buf );
+
+ // Read number of archives.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading archive count failed." ), i18n("Index File Error") );
+ return;
+ }
+ int numArchives = atoi( buf );
+
+ int ival;
+ for ( ; numArchives; numArchives-- ) {
+ fread( &ival, sizeof( ival ), 1, fptr );
+ _children.append( new Archive( this, fptr, ival ) );
+ }
+}
+
+void Tape::readVersion3Index( FILE* fptr )
+{
+ fseek( fptr, 0, SEEK_CUR );
+
+ char buf[4097];
+ buf[4096] = '\0';
+
+ // Read the tapeID.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
+ return;
+ }
+ QCString tapeID = buf;
+ tapeID.truncate( tapeID.length() - 1 );
+ if ( tapeID != _id ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
+ return;
+ }
+
+ // Read creation time.
+ fread( &_ctime, sizeof( _ctime ), 1, fptr );
+
+ // Read modification time.
+ fread( &_mtime, sizeof( _mtime ), 1, fptr );
+
+ // Read tape size.
+ fread( &_size, sizeof( _size ), 1, fptr );
+
+ // Read tape name.
+ fread( buf, sizeof( char ), 4096, fptr );
+ _name = buf;
+
+ // Read number of archives.
+ int numArchives;
+ fread( &numArchives, sizeof( numArchives ), 1, fptr );
+
+ int ival;
+ for ( ; numArchives; numArchives-- ) {
+ fread( &ival, sizeof( ival ), 1, fptr );
+ _children.append( new Archive( this, fptr, ival ) );
+ }
+}
+
+void Tape::readVersion4Index( FILE* fptr )
+{
+ fseek( fptr, 0, SEEK_CUR );
+
+ char buf[4097];
+ buf[4096] = '\0';
+
+ // Read the tapeID.
+ if ( !fgets( buf, 4096, fptr ) ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ), i18n("Index File Error") );
+ return;
+ }
+ QCString tapeID = buf;
+ tapeID.truncate( tapeID.length() - 1 );
+ if ( tapeID != _id ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Tape ID on tape does not match tape ID in index file." ), i18n("Index File Error") );
+ return;
+ }
+
+ // Read creation time.
+ fread( &_ctime, sizeof( _ctime ), 1, fptr );
+
+ // Read modification time.
+ fread( &_mtime, sizeof( _mtime ), 1, fptr );
+
+ // Read tape size.
+ fread( &_size, sizeof( _size ), 1, fptr );
+
+ // Read tape name.
+ fread( buf, sizeof( char ), 4096, fptr );
+ _name = buf;
+
+ // Read number of archives.
+ int numArchives;
+ fread( &numArchives, sizeof( numArchives ), 1, fptr );
+
+ int ival;
+ for ( ; numArchives; numArchives-- ) {
+ fread( &ival, sizeof( ival ), 1, fptr );
+ _children.append( new Archive( this, fptr, ival ) );
+ }
+
+ /* 2002-01-31 LEW */
+#ifdef DEBUG
+ printf("Read contents of archive file \"%s\". %s %d\n",
+ _name.latin1(), __FILE__, __LINE__ );
+#endif /* DEBUG */
+ /* 2002-01-31 LEW */
+}
+
+void Tape::calcRanges()
+{
+ QPtrListIterator<Archive> it( getChildren() );
+ for ( ; it.current(); ++it ) {
+ it.current()->calcRanges();
+ }
+}
diff --git a/kdat/Tape.h b/kdat/Tape.h
new file mode 100644
index 0000000..eab7cb3
--- /dev/null
+++ b/kdat/Tape.h
@@ -0,0 +1,156 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _Tape_h_
+#define _Tape_h_
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+#include "Archive.h"
+
+/**
+ * @short This class represents a single tape index.
+ */
+class Tape {
+ bool _stubbed;
+ QCString _id;
+ int _ctime;
+ int _mtime;
+ QString _name;
+ int _size;
+ QPtrList<Archive> _children;
+
+ FILE* _fptr;
+
+ void readVersion1Index( FILE* fptr );
+ void readVersion2Index( FILE* fptr );
+ void readVersion3Index( FILE* fptr );
+ void readVersion4Index( FILE* fptr );
+
+ void calcRanges();
+
+ void read();
+ void readAll( int version );
+ void write();
+public:
+ /**
+ * Create a new tape index, and automatically generate a unique tape ID.
+ */
+ Tape();
+
+ /**
+ * Create a new tape index for the given tape index ID.
+ *
+ * @param id The unique tape index identifier.
+ */
+ Tape( const char * id );
+
+ /**
+ * Destroy the tape index.
+ */
+ ~Tape();
+
+ /**
+ * Writes a KDat header containing the tape ID, at the beginning of the
+ * tape. All data on the tape will be lost.
+ */
+ void format();
+
+ /**
+ * Get the unique ID for the tape.
+ *
+ * @return The tape id.
+ */
+ QString getID();
+
+ /**
+ * Get the user-specified name for the tape.
+ *
+ * @return The name of the tape.
+ */
+ QString getName();
+
+ /**
+ * Get the date and time that the tape was formatted.
+ *
+ * @return The tape format time, in seconds since the Epoch.
+ */
+ int getCTime();
+
+ /**
+ * Get the last time that the tape was modified.
+ *
+ * @return The tape modification time, in seconds since the Epoch.
+ */
+ int getMTime();
+
+ /**
+ * Get the total tape capacity.
+ *
+ * @return The tape capacity in kilobytes.
+ */
+ int getSize();
+
+ /**
+ * Get the list of archives on this tape.
+ *
+ * @return The list of all archives on the tape.
+ */
+ const QPtrList<Archive>& getChildren();
+
+ /**
+ * Set the name for the tape.
+ *
+ * @param name The new name for the tape.
+ */
+ void setName( const QString & name );
+
+ /**
+ * Set the modification time for the tape to be the current time..
+ */
+ void setMTime( int mtime );
+
+ /**
+ * Set the total capacity of the tape.
+ *
+ * @param size The total size, in kilobytes, of the tape.
+ */
+ void setSize( int size );
+
+ /**
+ * Add an archive to the tape index.
+ *
+ * @param archive The archive to add.
+ */
+ void addChild( Archive* archive );
+
+ /**
+ * Remove an archive and all the archives that follow it from the index.
+ *
+ * @param archive The archive to remove.
+ */
+ void removeChild( Archive* archive );
+
+ /**
+ * Recursively destroy all children of the tape index.
+ */
+ void clear();
+};
+
+#endif
diff --git a/kdat/TapeDrive.cpp b/kdat/TapeDrive.cpp
new file mode 100644
index 0000000..64cb46f
--- /dev/null
+++ b/kdat/TapeDrive.cpp
@@ -0,0 +1,642 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mtio.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <qfile.h>
+
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <klocale.h>
+
+#include "KDatMainWindow.h"
+#include "Options.h"
+#include "Tape.h"
+#include "TapeManager.h"
+#include "TapeDrive.h"
+#include "kdat.h"
+
+#include "TapeDrive.moc"
+
+TapeDrive* TapeDrive::_instance = 0;
+
+TapeDrive* TapeDrive::instance()
+{
+ if ( !_instance ) {
+ _instance = new TapeDrive();
+ }
+
+ return _instance;
+}
+
+TapeDrive::TapeDrive()
+ : _fd ( -1 ),
+ _readOnly( TRUE ),
+ _tape( 0 ),
+ _writeBuf( 0 ),
+ _readBuf( 0 ),
+ _writeBufIdx( 0 ),
+ _readBufIdx( Options::instance()->getTapeBlockSize() )
+{
+ setBlockSize( Options::instance()->getTapeBlockSize() );
+ _writeBuf = new char[ Options::instance()->getTapeBlockSize() ];
+ _readBuf = new char[ Options::instance()->getTapeBlockSize() ];
+}
+
+TapeDrive::~TapeDrive()
+{
+ if ( Options::instance()->getLockOnMount() ) {
+ unlock();
+ }
+
+ delete [] _writeBuf;
+ delete [] _readBuf;
+}
+
+void TapeDrive::flush()
+{
+ _readBufIdx = Options::instance()->getTapeBlockSize();
+
+ if ( _writeBufIdx <= 0 ) {
+ return;
+ }
+
+ memset( _writeBuf + _writeBufIdx, 0, Options::instance()->getTapeBlockSize() - _writeBufIdx );
+ int ret = ::write( _fd, _writeBuf, Options::instance()->getTapeBlockSize() );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::flush() -- write failed!\n" );
+ }
+
+ _writeBufIdx = 0;
+}
+
+bool TapeDrive::load()
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+#ifdef MTLOAD
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTLOAD;
+ tapeOp.mt_count = 1;
+
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::lock() -- ioctl( MTLOAD ) failed!\n" );
+ }
+
+ return ret >= 0;
+#else
+ return TRUE;
+#endif
+}
+
+bool TapeDrive::lock()
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+#ifdef MTLOCK
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTLOCK;
+ tapeOp.mt_count = 1;
+
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::lock() -- ioctl( MTLOCK ) failed!\n" );
+ }
+
+ return ret >= 0;
+#else
+ return TRUE;
+#endif
+}
+
+bool TapeDrive::unlock()
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+#ifdef MTUNLOCK
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTUNLOCK;
+ tapeOp.mt_count = 1;
+
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::unlock() -- ioctl( MTUNLOCK ) failed!\n" );
+ }
+
+ return ret >= 0;
+#else
+ return TRUE;
+#endif
+}
+
+bool TapeDrive::isReadOnly()
+{
+ return _readOnly;
+}
+
+bool TapeDrive::isTapePresent()
+{
+ open();
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+ // Get tape status.
+ struct mtget tapeStatus;
+ int ret = ioctl( _fd, MTIOCGET, &tapeStatus );
+ if ( ret < 0 ) {
+ return FALSE;
+ }
+
+ // Check for the presence of a tape.
+// if ( !GMT_DR_OPEN( tapeStatus.mt_gstat ) ) {
+ if ( GMT_ONLINE( tapeStatus.mt_gstat ) ) {
+ // Lock the tape drive door.
+ //struct mtop tapeOp;
+ //tapeOp.mt_op = MTLOCK;
+ //tapeOp.mt_count = 1;
+ //int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ //if ( ret < 0 ) {
+ // printf( "TapeDrive::isTapePresent() -- ioctl( MTLOCK ) failed!\n" );
+ //}
+
+ if ( _readOnly ) {
+ emit sigStatus( i18n( "Tape mounted readonly." ) );
+ } else {
+ emit sigStatus( i18n( "Tape mounted read/write." ) );
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+void TapeDrive::eject()
+{
+ if ( _fd < 0 ) {
+ return;
+ }
+
+ flush();
+
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTOFFL;
+ tapeOp.mt_count = 1;
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::ejectTape() -- ioctl( MTOFFL ) failed!\n" );
+ }
+}
+
+Tape* TapeDrive::readHeader()
+{
+ _tape = NULL;
+
+ // Rewind tape.
+ emit sigStatus( "Rewinding tape..." );
+ if ( !rewind() ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Rewinding tape failed." ));
+ return NULL;
+ }
+
+ // KDat magic string.
+ emit sigStatus( i18n( "Reading magic string..." ) );
+ char magic[9];
+ if ( read( magic, 9 ) < 9 ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading magic string failed." ));
+ return NULL;
+ }
+ if ( strncmp( "KDatMAGIC", magic, 9 ) ) {
+ // Bad magic.
+ return NULL;
+ }
+
+ // Read version number.
+ emit sigStatus( i18n( "Reading version number..." ) );
+ int version;
+ if ( read( (char*)&version, 4 ) < 4 ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading version number failed." ));
+ return NULL;
+ }
+
+ if ( version > KDAT_TAPE_HEADER_VERSION ) {
+ KMessageBox::information( KDatMainWindow::getInstance(), i18n( "Tape was formatted by a more recent version of KDat. Consider upgrading." ));
+ }
+
+ // Read tape ID.
+ emit sigStatus( i18n( "Reading tape ID..." ) );
+ int len;
+ if ( read( (char*)&len, 4 ) < 4 ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID length failed." ));
+ return NULL;
+ }
+ char* tapeID = new char[len];
+ if ( read( tapeID, len ) < len ) {
+ KMessageBox::error( KDatMainWindow::getInstance(), i18n( "Reading tape ID failed." ));
+ delete [] tapeID;
+ return NULL;
+ }
+
+ _tape = TapeManager::instance()->findTape( tapeID );
+ delete [] tapeID;
+ return _tape;
+}
+
+bool TapeDrive::rewind()
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+ flush();
+
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTREW;
+ tapeOp.mt_count = 1;
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::rewind() -- ioctl( MTREW ) failed!\n" );
+ }
+
+ return ret >= 0;
+}
+
+int TapeDrive::getFile()
+{
+ if ( _fd < 0 ) {
+ return -1;
+ }
+
+ struct mtget tapePos;
+
+ if ( ioctl( _fd, MTIOCGET, &tapePos ) < 0 ) {
+ printf( "TapeDrive::getFile() -- ioctl( MTIOCGET ) failed!\n" );
+ return -1;
+ }
+
+ return tapePos.mt_fileno;
+}
+
+int TapeDrive::getBlock()
+{
+ if ( _fd < 0 ) {
+ return -1;
+ }
+
+ struct mtget tapePos;
+
+ if ( ioctl( _fd, MTIOCGET, &tapePos ) < 0 ) {
+ printf( "TapeDrive::getBlock() -- ioctl( MTIOCGET ) failed!\n" );
+ return -1;
+ }
+
+ //%%% I don't think this makes sense anymore because the tape buffer size == the tape block size.
+ // Need to subtract off the blocks that the application has not "read" yet.
+ //int unread = ( Options::instance()->getTapeBlockSize() - _readBufIdx ) / Options::instance()->getTapeBlockSize();
+
+ //return tapePos.mt_blkno - unread;
+
+ return tapePos.mt_blkno;
+}
+
+bool TapeDrive::nextFile( int count )
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+ flush();
+
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTFSF;
+ tapeOp.mt_count = count;
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::nextFile() -- ioctl( MTFSF ) failed!\n" );
+ }
+ return ret >= 0;
+}
+
+bool TapeDrive::prevFile( int count )
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+ flush();
+
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTBSF;
+ tapeOp.mt_count = count;
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::prevFile() -- ioctl( MTBSF ) failed!\n" );
+ }
+ return ret >= 0;
+}
+
+bool TapeDrive::nextRecord( int count )
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+ flush();
+
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTFSR;
+ tapeOp.mt_count = count;
+
+ bool status = ( ioctl( _fd, MTIOCTOP, &tapeOp ) >= 0 );
+
+ if ( !status ) {
+ // Try reading count * TapeBlockSize bytes.
+ char *buf = new char[Options::instance()->getTapeBlockSize()];
+ int bytes = count * Options::instance()->getTapeBlockSize();
+ int ret;
+ while ( bytes > 0 ) {
+ ret = read( buf, bytes > Options::instance()->getTapeBlockSize() ? Options::instance()->getTapeBlockSize() : bytes );
+ if ( ret <= 0 ) {
+ status = FALSE;
+ break;
+ }
+ bytes -= ret;
+ }
+ delete [] buf;
+ status = TRUE;
+ }
+ return status;
+}
+
+bool TapeDrive::prevRecord( int count )
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+ flush();
+
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTBSR;
+ tapeOp.mt_count = count;
+ int ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::prevRecord() -- ioctl( MTBSR ) failed!\n" );
+ }
+ return ret >= 0;
+}
+
+void TapeDrive::close()
+{
+ if ( _fd < 0 ) {
+ return;
+ }
+
+ flush();
+
+ ::close( _fd );
+}
+
+void TapeDrive::open()
+{
+ close();
+
+ // Open the tape device.
+ _fd = ::open( QFile::encodeName(Options::instance()->getTapeDevice()), O_RDWR );
+ if ( _fd < 0 ) {
+ _fd = ::open( QFile::encodeName(Options::instance()->getTapeDevice()), O_RDONLY );
+ if ( _fd < 0 ) {
+ return;
+ } else {
+ _readOnly = TRUE;
+ }
+ } else {
+ _readOnly = FALSE;
+ }
+
+ // Set the tape block size after the device is opened.
+ setBlockSize( Options::instance()->getTapeBlockSize() );
+}
+
+int TapeDrive::read( char* buf, int len )
+{
+ if ( _fd < 0 ) {
+ return -1;
+ }
+
+ //printf( "TapeDrive::read() -- _readBufIdx = %d\n", _readBufIdx );
+
+ int remain = Options::instance()->getTapeBlockSize() - _readBufIdx;
+ if ( len <= remain ) {
+ memcpy( buf, _readBuf + _readBufIdx, len );
+ _readBufIdx += len;
+ } else {
+ memcpy( buf, _readBuf + _readBufIdx, remain );
+ _readBufIdx = Options::instance()->getTapeBlockSize();
+
+ int need = Options::instance()->getTapeBlockSize();
+ int count = 0;
+ while ( need > 0 ) {
+ int ret = ::read( _fd, _readBuf + count, Options::instance()->getTapeBlockSize() );
+ if ( ret <= 0 ) return ret;
+ need -= ret;
+ count += ret;
+ }
+
+ memcpy( buf + remain, _readBuf, len - remain );
+ _readBufIdx = len - remain;
+ }
+
+ //int ret = ::read( _fd, buf, len );
+ return len;
+}
+
+int TapeDrive::write( const char* buf, int len )
+{
+ if ( _fd < 0 ) {
+ return -1;
+ }
+
+ int bufIdx = 0;
+ while ( len + _writeBufIdx - bufIdx > Options::instance()->getTapeBlockSize() ) {
+ memcpy( _writeBuf + _writeBufIdx, buf + bufIdx, Options::instance()->getTapeBlockSize() - _writeBufIdx );
+ int ret = ::write( _fd, _writeBuf, Options::instance()->getTapeBlockSize() );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::write() -- write failed!\n" );
+ return ret;
+ }
+ bufIdx += Options::instance()->getTapeBlockSize() - _writeBufIdx;
+ _writeBufIdx = 0;
+ }
+
+ if ( bufIdx < len ) {
+ memcpy( _writeBuf + _writeBufIdx, buf + bufIdx, len - bufIdx );
+ _writeBufIdx += len - bufIdx;
+ }
+
+ return len;
+}
+
+bool TapeDrive::seek( int file, int tarBlock )
+{
+// printf( "TapeDrive::seek() -- file = %d, block = %d\n", file, tarBlock );
+
+ if ( _fd < 0 ) {
+ printf( "bailing1\n" );
+ return FALSE;
+ }
+
+ flush();
+
+ // Go to the desired archive.
+ emit sigStatus( i18n( "Skipping to archive..." ) );
+
+ int curFile = getFile();
+// printf( "TapeDrive::seek() -- curFile = %d\n", curFile );
+ if ( curFile < 0 ) {
+ emit sigStatus( i18n( "Rewinding tape..." ) );
+ rewind();
+ curFile = 0;
+ }
+
+ int fileDiff = file - curFile;
+ if ( fileDiff > 0 ) {
+ nextFile( fileDiff );
+ } else if ( fileDiff < 0 ) {
+ prevFile( -fileDiff + 1 );
+ nextFile( 1 );
+ }
+
+ int tapeBlock = tarBlock / ( Options::instance()->getTapeBlockSize() / 512 );
+// printf( "TapeDrive::seek() -- desired tapeBlock = %d\n", tapeBlock );
+
+ // Go to the desired record within the archive.
+ emit sigStatus( i18n( "Skipping to block..." ) );
+ int curBlock = getBlock();
+// printf( "TapeDrive::seek() -- curBlock = %d\n", curBlock );
+ if ( curBlock < 0 ) {
+ emit sigStatus( i18n( "Rewinding tape..." ) );
+ rewind();
+ nextFile( file );
+ if ( ( curBlock = getBlock() ) < 0 ) {
+ printf( "bailing2\n" );
+ return FALSE;
+ }
+ }
+
+ if ( tapeBlock > curBlock ) {
+ if ( !nextRecord( tapeBlock - curBlock ) ) {
+ printf( "bailing3\n" );
+ return FALSE;
+ }
+ } else if ( tapeBlock < curBlock ) {
+ if ( tapeBlock == 0 ) {
+ if ( !prevFile( 1 ) ) {
+ printf( "bailing6\n" );
+ return FALSE;
+ }
+ if ( !nextFile( 1 ) ) {
+ printf( "bailing7\n" );
+ return FALSE;
+ }
+ } else {
+ if ( !prevRecord( curBlock - tapeBlock + 1 ) ) {
+ printf( "bailing4\n" );
+ return FALSE;
+ }
+ if ( !nextRecord( 1 ) ) {
+ printf( "bailing5\n" );
+ return FALSE;
+ }
+ }
+ }
+
+// printf( "TapeDrive::seek() -- now: file = %d, block = %d\n", getFile(), getBlock() );
+
+ // If tapeBlockSize > 512, we may need to skip some tar blocks.
+// printf ( "TapeDrive::seek() -- skipping %d tar blocks.\n", tarBlock - tapeBlock * ( Options::instance()->getTapeBlockSize() / 512 ) );
+ char *buf = new char[ Options::instance()->getTapeBlockSize() ];
+ read( buf, 512 * ( tarBlock - tapeBlock * ( Options::instance()->getTapeBlockSize() / 512 ) ) );
+
+ delete [] buf;
+
+ return TRUE;
+}
+
+bool TapeDrive::pastEOF()
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+ struct mtget tapeStatus;
+ if ( ioctl( _fd, MTIOCGET, &tapeStatus ) < 0 ) {
+ printf( "TapeDrive::pastEOF() -- ioctl( MTIOCGET ) failed!\n" );
+ return FALSE;
+ }
+
+ return GMT_EOF( tapeStatus.mt_gstat );
+}
+
+bool TapeDrive::setBlockSize( int blockSize )
+{
+ if ( _fd < 0 ) {
+ return FALSE;
+ }
+
+#ifdef MTSETBLK
+ flush();
+
+ int ret = 0;
+ if ( Options::instance()->getVariableBlockSize() ) {
+ struct mtop tapeOp;
+ tapeOp.mt_op = MTSETBLK;
+ tapeOp.mt_count = blockSize;
+ ret = ioctl( _fd, MTIOCTOP, &tapeOp );
+ if ( ret < 0 ) {
+ printf( "TapeDrive::setBlockSize() -- ioctl( MTSETBLK ) failed!\n" );
+ }
+ }
+
+ _readBufIdx = blockSize;
+ _writeBufIdx = 0;
+ delete [] _readBuf;
+ _readBuf = new char[ blockSize ];
+ delete [] _writeBuf;
+ _writeBuf = new char[ blockSize ];
+
+ return ret >= 0;
+#else
+ // some systems (e.g. HP-UX) encode block size into device file names
+ // so setting the block size by software does not make sense
+ return TRUE;
+#endif
+}
diff --git a/kdat/TapeDrive.h b/kdat/TapeDrive.h
new file mode 100644
index 0000000..4709eed
--- /dev/null
+++ b/kdat/TapeDrive.h
@@ -0,0 +1,247 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _TapeDrive_h_
+#define _TapeDrive_h_
+
+#include <qobject.h>
+
+class Tape;
+
+/**
+ * @short An OO interface to the tape drive.
+ */
+class TapeDrive : public QObject {
+ Q_OBJECT
+ int _fd;
+ bool _readOnly;
+ Tape* _tape;
+ char* _writeBuf;
+ char* _readBuf;
+ int _writeBufIdx;
+ int _readBufIdx;
+
+ static TapeDrive* _instance;
+
+ TapeDrive();
+public:
+ /**
+ * Destroy the tape drive (figuratively speaking, of course).
+ */
+ ~TapeDrive();
+
+ /**
+ * Get a reference to the single instance of the tape drive object.
+ *
+ * @return A pointer to the tape drive object.
+ */
+ static TapeDrive* instance();
+
+ /**
+ * Close the tape device. If data was written to the tape drive, then this
+ * will also cause a single end-of-file marker to be written out. This is
+ * the preferred way to write an end-of-file marker to the tape.
+ */
+ void close();
+
+ /**
+ * Physically eject the tape from the drive. Some tape drives do not
+ * support this operation well.
+ */
+ void eject();
+
+ /**
+ * If there is unwritten data in the buffer, it will be flushed out. This
+ * method is called when necessary by the other tape drive methods.
+ */
+ void flush();
+
+ /**
+ * Get the current tape file number. The first tape file is number 0.
+ *
+ * @return >= 0 on success, -1 on failure.
+ */
+ int getFile();
+
+ /**
+ * Get the current tape block number within the current file. The first
+ * tape block number within a file is 0.
+ *
+ * @return >= 0 on success, -1 on failure.
+ */
+ int getBlock();
+
+ /**
+ * Determine whether the tape can be written to.
+ *
+ * @return TRUE if the tape cannot be written to, otherwise FALSE.
+ */
+ bool isReadOnly();
+
+ /**
+ * Determine whether there is a tape in the drive.
+ *
+ * @return TRUE if there is a tape, otherwise FALSE.
+ */
+ bool isTapePresent();
+
+ /**
+ * Load the tape into the drive.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool load();
+
+ /**
+ * Lock the tape in the drive, so that it cannot be ejected manually by the
+ * user. Not all tape drives support this operation.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool lock();
+
+ /**
+ * Skip over one or more end-of-file markers on the tape. The tape is
+ * positioned just after the last skipped end-of-file marker.
+ *
+ * @param count The number of end-of-file markers to skip over.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool nextFile( int count );
+
+ /**
+ * Skip over one or more tape blocks within the current tape file.
+ *
+ * @param count The number of tape blocks to skip over.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool nextRecord( int count );
+
+ /**
+ * Open the tape device for reading and writing. If this fails, try
+ * opening the tape device for reading only. Check isReadOnly() to see
+ * if the tape device was opened for reading and writing.
+ *
+ * @return TRUE if the tape device was opened for reading and/or writing,
+ * otherwise FALSE.
+ */
+ void open();
+
+ /**
+ * Determine wether the tape is positioned just after an end-of-file
+ * marker.
+ *
+ * @return TRUE if the tape is positioned after an end-of-file marker,
+ * otherwise FALSE.
+ */
+ bool pastEOF();
+
+ /**
+ * Backspace over one or more end-of-file markers. The tape is positioned
+ * just before the last end-of-file marker.
+ *
+ * @param count The number of end-of-file markers to backspace over.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool prevFile( int count );
+
+ /**
+ * Backspace over one or more tape blocks.
+ *
+ * @param count The number of tape block to backspace over.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool prevRecord( int count );
+
+ /**
+ * Read data from the tape.
+ *
+ * @param buf The buffer to read into.
+ * @param len The number of bytes to read.
+ *
+ * @return The actual number of bytes read, or -1 on failure.
+ */
+ int read( char* buf, int len );
+
+ /**
+ * Read the KDat tape header (if there is one), and get the index
+ * associated with the tape.
+ *
+ * @return A pointer to the tape index, or NULL if the tape does not have
+ * a KDat header.
+ */
+ Tape* readHeader();
+
+ /**
+ * Rewind the tape.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool rewind();
+
+ /**
+ * Move the tape to the given tar block within the given tape file. This
+ * method will intelligently move the tape to the desired position.
+ *
+ * @param file The tape file number.
+ * @param tarBlock The desired tar block (NOT tape block).
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool seek( int file, int tarBlock );
+
+ /**
+ * Set the hardware tape block size.
+ *
+ * @param blockSize The new tape block size in bytes.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool setBlockSize( int blockSize );
+
+ /**
+ * Unlock the tape in the drive, so that it can be ejected manually by the
+ * user. Not all tape drives support this operation.
+ *
+ * @return TRUE on success, otherwise FALSE.
+ */
+ bool unlock();
+
+ /**
+ * Write data to the tape.
+ *
+ * @param buf The buffer to write from.
+ * @param len The number of bytes to write.
+ *
+ * @return The actual number of bytes written, or -1 on failure.
+ */
+ int write( const char* buf, int len );
+signals:
+ /**
+ * This signal is emitted for one-line, informational messages.
+ *
+ * @param msg The informational message.
+ */
+ void sigStatus( const QString & msg );
+};
+
+#endif
diff --git a/kdat/TapeFileInfoWidget.cpp b/kdat/TapeFileInfoWidget.cpp
new file mode 100644
index 0000000..de5a453
--- /dev/null
+++ b/kdat/TapeFileInfoWidget.cpp
@@ -0,0 +1,133 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <time.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kapplication.h>
+
+#include "File.h"
+#include "TapeFileInfoWidget.h"
+#include "Util.h"
+#include <klocale.h>
+
+#include "TapeFileInfoWidget.moc"
+
+TapeFileInfoWidget::TapeFileInfoWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ QLabel* lbl1 = new QLabel( i18n( "File name:" ), this );
+ QLabel* lbl2 = new QLabel( i18n( "Last modified:" ), this );
+ QLabel* lbl3 = new QLabel( i18n( "Size:" ), this );
+ QLabel* lbl4 = new QLabel( i18n( "Start record:" ), this );
+ QLabel* lbl5 = new QLabel( i18n( "End record:" ), this );
+
+ int max = lbl1->sizeHint().width();
+ if ( lbl2->sizeHint().width() > max ) max = lbl2->sizeHint().width();
+ if ( lbl3->sizeHint().width() > max ) max = lbl3->sizeHint().width();
+ if ( lbl4->sizeHint().width() > max ) max = lbl4->sizeHint().width();
+ if ( lbl5->sizeHint().width() > max ) max = lbl5->sizeHint().width();
+
+ lbl1->setFixedSize( max, lbl1->sizeHint().height() );
+ lbl2->setFixedSize( max, lbl2->sizeHint().height() );
+ lbl3->setFixedSize( max, lbl3->sizeHint().height() );
+ lbl4->setFixedSize( max, lbl4->sizeHint().height() );
+ lbl5->setFixedSize( max, lbl5->sizeHint().height() );
+
+ _fileName = new QLabel( "???", this );
+ _fileName->setFixedHeight( _fileName->sizeHint().height() );
+
+ _mtime = new QLabel( "???", this );
+ _mtime->setFixedHeight( _mtime->sizeHint().height() );
+
+ _size = new QLabel( "???", this );
+ _size->setFixedHeight( _size->sizeHint().height() );
+
+ _startRecord = new QLabel( "???", this );
+ _startRecord->setFixedHeight( _startRecord->sizeHint().height() );
+
+ _endRecord = new QLabel( "???", this );
+ _endRecord->setFixedHeight( _endRecord->sizeHint().height() );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 4, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addWidget( lbl1 );
+ l1_1->addWidget( _fileName, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addWidget( lbl2 );
+ l1_2->addWidget( _mtime, 1 );
+
+ QHBoxLayout* l1_3 = new QHBoxLayout();
+ l1->addLayout( l1_3 );
+ l1_3->addWidget( lbl3 );
+ l1_3->addWidget( _size, 1 );
+
+ QHBoxLayout* l1_4 = new QHBoxLayout();
+ l1->addLayout( l1_4 );
+ l1_4->addWidget( lbl4 );
+ l1_4->addWidget( _startRecord, 1 );
+
+ QHBoxLayout* l1_5 = new QHBoxLayout();
+ l1->addLayout( l1_5 );
+ l1_5->addWidget( lbl5 );
+ l1_5->addWidget( _endRecord, 1 );
+
+ l1->addStretch( 1 );
+}
+
+TapeFileInfoWidget::~TapeFileInfoWidget()
+{
+}
+
+void TapeFileInfoWidget::setFile( File* file )
+{
+ _file = file;
+
+ if ( !_file ) {
+ return;
+ }
+
+ _fileName->setText( _file->getName() );
+
+ QString tmp;
+ time_t tm = _file->getMTime();
+ tmp = ctime( &tm );
+ tmp = tmp.stripWhiteSpace();
+ _mtime->setText( tmp );
+
+ _startRecord->setText( Util::bytesToString( _file->getStartRecord() ) );
+
+ _endRecord->setText( Util::bytesToString( _file->getEndRecord() ) );
+
+ if ( _file->isDirectory() ) {
+ QPtrListIterator<Range> it( _file->getRanges() );
+ int records = 0;
+ for ( ; it.current(); ++it ) {
+ records += it.current()->getEnd() - it.current()->getStart();
+ }
+ _size->setText( Util::kbytesToString( records / 2 ) );
+ } else {
+ _size->setText( Util::bytesToString( _file->getSize() ) );
+ }
+}
diff --git a/kdat/TapeFileInfoWidget.h b/kdat/TapeFileInfoWidget.h
new file mode 100644
index 0000000..0eaa2a6
--- /dev/null
+++ b/kdat/TapeFileInfoWidget.h
@@ -0,0 +1,59 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _TapeFileInfoWidget_h_
+#define _TapeFileInfoWidget_h_
+
+#include <qwidget.h>
+
+class QLabel;
+
+class File;
+
+/**
+ * @short Display information about a tape file.
+ */
+class TapeFileInfoWidget : public QWidget {
+ Q_OBJECT
+ File* _file;
+ QLabel* _fileName;
+ QLabel* _mtime;
+ QLabel* _startRecord;
+ QLabel* _endRecord;
+ QLabel* _size;
+public:
+ /**
+ * Create a new tape file info widget.
+ *
+ * @param parent The parent widget.
+ * @param name The name of this widget.
+ */
+ TapeFileInfoWidget( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the tape file info widget.
+ */
+ ~TapeFileInfoWidget();
+
+ /**
+ * Display the information for the given tape file.
+ */
+ void setFile( File* file );
+};
+
+#endif
diff --git a/kdat/TapeInfoWidget.cpp b/kdat/TapeInfoWidget.cpp
new file mode 100644
index 0000000..8a22656
--- /dev/null
+++ b/kdat/TapeInfoWidget.cpp
@@ -0,0 +1,275 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "Options.h"
+#include "Tape.h"
+#include "TapeInfoWidget.h"
+#include "Util.h"
+
+#include "TapeInfoWidget.moc"
+
+TapeInfoWidget::TapeInfoWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name ),
+ _tape( 0 )
+{
+ QLabel* lbl1 = new QLabel( i18n( "Tape name:" ), this );
+ QLabel* lbl2 = new QLabel( i18n( "Tape size:" ), this );
+ QLabel* lbl3 = new QLabel( i18n( "Tape ID:" ), this );
+ QLabel* lbl4 = new QLabel( i18n( "Created on:" ), this );
+ QLabel* lbl5 = new QLabel( i18n( "Last modified:" ), this );
+ QLabel* lbl6 = new QLabel( i18n( "Archive count:" ), this );
+ QLabel* lbl7 = new QLabel( i18n( "Space used:" ), this );
+
+ int max = lbl1->sizeHint().width();
+ if ( lbl2->sizeHint().width() > max ) max = lbl2->sizeHint().width();
+ if ( lbl3->sizeHint().width() > max ) max = lbl3->sizeHint().width();
+ if ( lbl4->sizeHint().width() > max ) max = lbl4->sizeHint().width();
+ if ( lbl5->sizeHint().width() > max ) max = lbl5->sizeHint().width();
+ if ( lbl6->sizeHint().width() > max ) max = lbl6->sizeHint().width();
+ if ( lbl7->sizeHint().width() > max ) max = lbl7->sizeHint().width();
+
+ lbl1->setFixedSize( max, lbl1->sizeHint().height() );
+ lbl2->setFixedSize( max, lbl2->sizeHint().height() );
+ lbl3->setFixedSize( max, lbl3->sizeHint().height() );
+ lbl4->setFixedSize( max, lbl4->sizeHint().height() );
+ lbl5->setFixedSize( max, lbl5->sizeHint().height() );
+ lbl6->setFixedSize( max, lbl6->sizeHint().height() );
+ lbl7->setFixedSize( max, lbl7->sizeHint().height() );
+
+ _tapeName = new QLineEdit( this );
+ _tapeName->setFixedHeight( _tapeName->sizeHint().height() );
+
+ _tapeSize = new QLineEdit( this );
+ _tapeSize->setFixedSize( 48, _tapeSize->sizeHint().height() );
+
+ _tapeSizeUnits = new QComboBox( this );
+ _tapeSizeUnits->setFixedSize( 48, _tapeSizeUnits->sizeHint().height() );
+ _tapeSizeUnits->insertItem( "MB" );
+ _tapeSizeUnits->insertItem( "GB" );
+
+ _tapeID = new QLabel( "???", this );
+ _tapeID->setFixedHeight( _tapeID->sizeHint().height() );
+
+ _ctime = new QLabel( "???", this );
+ _ctime->setFixedHeight( _ctime->sizeHint().height() );
+
+ _mtime = new QLabel( "???", this );
+ _mtime->setFixedHeight( _mtime->sizeHint().height() );
+
+ _archiveCount = new QLabel( "???", this );
+ _archiveCount->setFixedHeight( _archiveCount->sizeHint().height() );
+
+ _spaceUsed = new QLabel( "???", this );
+ _spaceUsed->setFixedHeight( _spaceUsed->sizeHint().height() );
+
+ _apply = new KPushButton( KStdGuiItem::apply(), this );
+ _apply->setFixedSize( 80, _apply->sizeHint().height() );
+ _apply->setEnabled( FALSE );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 4, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addWidget( lbl1 );
+ l1_1->addWidget( _tapeName, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addWidget( lbl2 );
+ l1_2->addWidget( _tapeSize );
+ l1_2->addWidget( _tapeSizeUnits );
+ l1_2->addStretch( 1 );
+
+ QHBoxLayout* l1_3 = new QHBoxLayout();
+ l1->addLayout( l1_3 );
+ l1_3->addWidget( lbl3 );
+ l1_3->addWidget( _tapeID );
+
+ QHBoxLayout* l1_4 = new QHBoxLayout();
+ l1->addLayout( l1_4 );
+ l1_4->addWidget( lbl4 );
+ l1_4->addWidget( _ctime );
+
+ QHBoxLayout* l1_5 = new QHBoxLayout();
+ l1->addLayout( l1_5 );
+ l1_5->addWidget( lbl5 );
+ l1_5->addWidget( _mtime );
+
+ QHBoxLayout* l1_6 = new QHBoxLayout();
+ l1->addLayout( l1_6 );
+ l1_6->addWidget( lbl6 );
+ l1_6->addWidget( _archiveCount );
+
+ QHBoxLayout* l1_7 = new QHBoxLayout();
+ l1->addLayout( l1_7 );
+ l1_7->addWidget( lbl7 );
+ l1_7->addWidget( _spaceUsed );
+
+ l1->addStretch( 1 );
+
+ QHBoxLayout* l1_8 = new QHBoxLayout();
+ l1->addLayout( l1_8 );
+ l1_8->addStretch( 1 );
+ l1_8->addWidget( _apply );
+
+ connect( _tapeName , SIGNAL( textChanged( const QString & ) ), this, SLOT( slotTextChanged( const QString & ) ) );
+ connect( _tapeSize , SIGNAL( textChanged( const QString & ) ), this, SLOT( slotTextChanged( const QString & ) ) );
+ connect( _tapeSizeUnits, SIGNAL( activated( int ) ) , this, SLOT( slotActivated( int ) ) );
+ connect( _apply , SIGNAL( clicked() ) , this, SLOT( slotApply() ) );
+}
+
+TapeInfoWidget::~TapeInfoWidget()
+{
+}
+
+void TapeInfoWidget::setTape( Tape* tape )
+{
+ _tape = tape;
+
+ if ( !_tape ) {
+ return;
+ }
+
+ _tapeName->setText( _tape->getName() );
+
+ int size = _tape->getSize();
+ if ( ( size >= 1024*1024 ) && ( size % ( 1024*1024 ) == 0 ) ) {
+ // GB
+ size /= 1024*1024;
+ _tapeSizeUnits->setCurrentItem( 1 );
+ } else {
+ // MB
+ size /= 1024;
+ _tapeSizeUnits->setCurrentItem( 0 );
+ }
+ QString tmp;
+ tmp.setNum( size );
+ _tapeSize->setText( tmp );
+
+ _tapeID->setText( _tape->getID() );
+
+ time_t tm = _tape->getCTime();
+ tmp = ctime( &tm );
+ tmp = tmp.stripWhiteSpace();
+ _ctime->setText( tmp );
+
+ tm = _tape->getMTime();
+ tmp = ctime( &tm );
+ tmp = tmp.stripWhiteSpace();
+ _mtime->setText( tmp );
+
+ tmp.setNum( _tape->getChildren().count() );
+ _archiveCount->setText( tmp );
+
+ QPtrListIterator<Archive> i( _tape->getChildren() );
+ int used = 1;
+ for ( ; i.current(); ++i ) {
+ used += i.current()->getEndBlock();
+ }
+ int blockSize = Options::instance()->getTapeBlockSize();
+ if ( blockSize < 1024 ) {
+ used /= 1024 / blockSize;
+ } else if ( blockSize > 1024 ) {
+ used *= blockSize / 1024;
+ }
+ if ( _tape->getSize() > 0 ) {
+ tmp = QString::fromLatin1( "%1 / %2 (%3%)")
+ .arg(Util::kbytesToString( used ))
+ .arg(Util::kbytesToString( _tape->getSize() ))
+ .arg(used * 100 / _tape->getSize() );
+ } else {
+ tmp = Util::kbytesToString( used );
+ }
+ _spaceUsed->setText( tmp );
+}
+
+bool TapeInfoWidget::isModified()
+{
+ if ( _tape->getName() != _tapeName->text() ) {
+ return TRUE;
+ }
+
+ int size = (int)KGlobal::locale()->readNumber( _tapeSize->text() );
+ if ( _tapeSizeUnits->currentItem() == 0 ) {
+ // MB
+ size *= 1024;
+ } else {
+ // GB
+ size *= 1024*1024;
+ }
+
+ return _tape->getSize() != size;
+}
+
+void TapeInfoWidget::slotTextChanged( const QString & )
+{
+ if ( !_tape ) {
+ return;
+ }
+
+ _apply->setEnabled( isModified() );
+}
+
+void TapeInfoWidget::slotActivated( int )
+{
+ if ( !_tape ) {
+ return;
+ }
+
+ _apply->setEnabled( isModified() );
+}
+
+void TapeInfoWidget::slotApply()
+{
+ if ( !_tape ) {
+ return;
+ }
+
+ int size = (int)KGlobal::locale()->readNumber( _tapeSize->text() );
+ if ( _tapeSizeUnits->currentItem() == 0 ) {
+ // MB
+ size *= 1024;
+ } else {
+ // GB
+ size *= 1024*1024;
+ }
+
+ if ( _tape->getName() != _tapeName->text() ) {
+ _tape->setName( _tapeName->text() );
+ }
+
+ if ( size != _tape->getSize() ) {
+ _tape->setSize( size );
+ }
+
+ _apply->setEnabled( FALSE );
+}
diff --git a/kdat/TapeInfoWidget.h b/kdat/TapeInfoWidget.h
new file mode 100644
index 0000000..4b3b3a2
--- /dev/null
+++ b/kdat/TapeInfoWidget.h
@@ -0,0 +1,71 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _TapeInfoWidget_h_
+#define _TapeInfoWidget_h_
+
+#include <qwidget.h>
+
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+
+class Tape;
+
+/**
+ * @short Display/edit information about a tape index.
+ */
+class TapeInfoWidget : public QWidget {
+ Q_OBJECT
+ Tape* _tape;
+ QLineEdit* _tapeName;
+ QLineEdit* _tapeSize;
+ QComboBox* _tapeSizeUnits;
+ QLabel* _tapeID;
+ QLabel* _ctime;
+ QLabel* _mtime;
+ QLabel* _archiveCount;
+ QLabel* _spaceUsed;
+ QPushButton* _apply;
+
+ bool isModified();
+private slots:
+ void slotTextChanged( const QString & text );
+ void slotActivated( int index );
+ void slotApply();
+public:
+ /**
+ * Create a new tape info widget.
+ */
+ TapeInfoWidget( QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the tape info widget.
+ */
+ ~TapeInfoWidget();
+
+ /**
+ * Change the tape index that the widget displays/edits.
+ *
+ * @param tape The new tape index to display/edit.
+ */
+ void setTape( Tape* tape );
+};
+
+#endif
diff --git a/kdat/TapeManager.cpp b/kdat/TapeManager.cpp
new file mode 100644
index 0000000..5de218e
--- /dev/null
+++ b/kdat/TapeManager.cpp
@@ -0,0 +1,151 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qdir.h>
+#include <qregexp.h>
+#include <qfile.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#include "TapeManager.h"
+
+#include "TapeManager.moc"
+
+TapeManager::TapeManager()
+ : _mountedTape( 0 )
+{
+ _tapes.setAutoDelete( TRUE );
+
+ // Get a list of all available tape indexes.
+ QStringList relList;
+
+ // Fix 2002-01-24 c/o RG. The problem was: "Tape Index is empty, but I did
+ // just a few minutes ago a 1st backup onto the the tape."
+ // (void) KGlobal::dirs()->findAllResources( "appdata", ".*:[0-9]+", false, true, relList);
+ (void) KGlobal::dirs()->findAllResources( "appdata", "*:[0-9]*", false, true, relList);
+
+ for(QStringList::Iterator it = relList.begin();
+ it != relList.end();
+ it++)
+ {
+ QString fn = *it;
+ // Convert to outdated QStringList :-)
+ _tapeIDs.append( QFile::encodeName(fn) );
+ }
+}
+
+TapeManager::~TapeManager()
+{
+}
+
+TapeManager* TapeManager::_instance = 0;
+
+TapeManager* TapeManager::instance()
+{
+ if ( _instance == 0 ) {
+ _instance = new TapeManager();
+ }
+
+ return _instance;
+}
+
+const QStringList& TapeManager::getTapeIDs()
+{
+ return _tapeIDs;
+}
+
+Tape* TapeManager::findTape( const QString & id )
+{
+ /* 2002-01-26 LEW */
+ // printf("Contents of _tapeIDs: %d entries\n", _tapes.count());
+ // for ( QStringList::Iterator it = _tapeIDs.begin(); it != _tapeIDs.end(); ++it ) {
+ // printf("%s\n", (*it).latin1());
+ // }
+ // printf("\n");
+
+ // QDictIterator<Tape> it( _tapes );
+ // printf("Contents of _tapes: %d entries\n", _tapes.count());
+ // for( ; it.current(); ++it )
+ // printf("index ?: %s (%d)\n", it.current()->getName().latin1(),
+ // it.current()->getCTime());
+ // printf("\n");
+ /* 2002-01-26 LEW */
+
+ Tape* tape = _tapes[ id ];
+
+ if ( !tape ) {
+ tape = new Tape( id.ascii() );
+ _tapes.insert( tape->getID(), tape );
+ }
+
+ return tape;
+}
+
+void TapeManager::addTape( Tape* tape )
+{
+ Tape* old = _tapes[ tape->getID() ];
+ if ( old ) {
+ removeTape( old );
+ }
+
+ _tapeIDs.append( tape->getID() );
+ _tapes.insert( tape->getID(), tape );
+
+ emit sigTapeAdded( tape );
+}
+
+void TapeManager::removeTape( Tape* tape )
+{
+ emit sigTapeRemoved( tape );
+
+ // Remove the index file.
+ QString filename = locateLocal( "appdata", tape->getID() );
+
+ unlink( QFile::encodeName(filename) );
+
+ _tapeIDs.remove( tape->getID() );
+ _tapes.remove( tape->getID() );
+}
+
+void TapeManager::tapeModified( Tape* tape )
+{
+ emit sigTapeModified( tape );
+}
+
+void TapeManager::mountTape( Tape* tape )
+{
+ _mountedTape = tape;
+ emit sigTapeMounted();
+}
+
+void TapeManager::unmountTape()
+{
+ emit sigTapeUnmounted();
+ _mountedTape = 0;
+}
+
+Tape* TapeManager::getMountedTape()
+{
+ return _mountedTape;
+}
+
+
diff --git a/kdat/TapeManager.h b/kdat/TapeManager.h
new file mode 100644
index 0000000..bc91aab
--- /dev/null
+++ b/kdat/TapeManager.h
@@ -0,0 +1,154 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _TapeManager_h_
+#define _TapeManager_h_
+
+#include <qdict.h>
+#include <qobject.h>
+#include <qstrlist.h>
+
+#include "Tape.h"
+
+/**
+ * @short Control access to the set of tape indexes.
+ *
+ * Each user has a set of tape indexes that are stored under
+ * <TT>$HOME/.kdat/</TT>. This class provides a single point of access for
+ * reading and writing these index files.
+ *
+ * Other objects can register to be notified when a tape index is added or
+ * removed, and when a tape index is modified.
+ *
+ * A reference to the index of the currently mounted tape is maintained, and
+ * other objects can register to be notified when a tape is mounted and
+ * unmounted.
+ *
+ * The TapeManager follows the Singleton pattern.
+ */
+class TapeManager : public QObject {
+ Q_OBJECT
+
+ static TapeManager* _instance;
+
+ QDict<Tape> _tapes;
+ QStringList _tapeIDs;
+ Tape* _mountedTape;
+
+ TapeManager();
+public:
+ ~TapeManager();
+
+ /**
+ * All access to the TapeManager goes through this method.
+ *
+ * @return a pointer to the single instance of the TapeManager.
+ */
+ static TapeManager* instance();
+
+ /**
+ * Get the list of all known tape IDs.
+ *
+ * @return a QStringList containing the tape IDs.
+ */
+ const QStringList& getTapeIDs();
+
+ /**
+ * Retrieve the index for a tape.
+ *
+ * @param id the ID of the tape.
+ * @return the tape's index.
+ */
+ Tape* findTape( const QString & id );
+
+ /**
+ * Add a new tape index.
+ *
+ * @param tape a pointer to the new tape index.
+ */
+ void addTape( Tape* tape );
+
+ /**
+ * Remove a tape index. The tape index is removed from memory and from
+ * disk. A signal is emitted before the tape is actually removed.
+ *
+ * @param tape a pointer to the tape index to remove.
+ */
+ void removeTape( Tape* tape );
+
+ /**
+ * Notify anyone who cares that the tape index has been modified.
+ *
+ * @param tape a pointer to the tape index that was modified.
+ */
+ void tapeModified( Tape* tape );
+
+ /**
+ * Call this method whenever a tape is first mounted.
+ *
+ * @param tape a pointer to the newly mounted tape's index.
+ */
+ void mountTape( Tape* tape );
+
+ /**
+ * Call this method whenever the current tape is about to be unmounted.
+ */
+ void unmountTape();
+
+ /**
+ * Get a handle on the currently mounted tape's index.
+ *
+ * @return a pointer to the mounted tape's index, or NULL if no tape is
+ * mounted.
+ */
+ Tape* getMountedTape();
+signals:
+ /**
+ * Emitted after a new tape index is created.
+ *
+ * @param tape a pointer to the new tape index.
+ */
+ void sigTapeAdded( Tape* tape );
+
+ /**
+ * Emitted before a tape index is destroyed. This signal is emitted
+ * immediately before the tape index is deleted.
+ *
+ * @param tape a pointer to the tape index that is about to be destroyed.
+ */
+ void sigTapeRemoved( Tape* tape );
+
+ /**
+ * Emitted after a tape index has been changed in some way.
+ *
+ * @param tape a pointer to the tape index that has been modified.
+ */
+ void sigTapeModified( Tape* tape );
+
+ /**
+ * Emitted after a tape has been mounted.
+ */
+ void sigTapeMounted();
+
+ /**
+ * Emitted just before the current tape is unmounted.
+ */
+ void sigTapeUnmounted();
+};
+
+#endif
diff --git a/kdat/TarParser.cpp b/kdat/TarParser.cpp
new file mode 100644
index 0000000..4529d64
--- /dev/null
+++ b/kdat/TarParser.cpp
@@ -0,0 +1,117 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "TarParser.h"
+
+#include "TarParser.moc"
+
+TarParser::TarParser()
+ : _bufIdx( 0 ),
+ _blocksToSkip( 0 ),
+ _record( 0 ),
+ _longname( FALSE ),
+ _extended( FALSE ),
+ _archnameIdx( 0 )
+{
+}
+
+void TarParser::slotData( const char * data, int length )
+{
+ for ( int i = 0; i < length; i++ ) {
+ if ( _bufIdx >= 512 ) {
+ if ( _blocksToSkip > 0 ) {
+ if ( _extended ) {
+ record* rec = (record*)_buf;
+ _extended = rec->ext_hdr.isextended;
+ } else {
+ _blocksToSkip--;
+ if ( _longname ) {
+ memcpy( _archname + _archnameIdx, _buf, 512 );
+ _archnameIdx += 512;
+ }
+ }
+ } else {
+ parseTarBlock();
+ }
+ _bufIdx = 0;
+ _record++;
+ }
+ _buf[_bufIdx++] = data[i];
+ }
+}
+
+int TarParser::parseOctal( const char* buf, int length )
+{
+ int val = 0;
+
+ for ( int i = 0; i < length; i++ ) {
+ val *= 8;
+ if ( ( buf[i] >= '1' ) && ( buf[i] <= '7' ) ) {
+ val += buf[i] - '0';
+ }
+ }
+
+ return val;
+}
+
+void TarParser::parseTarBlock()
+{
+ record* rec = (record*)_buf;
+
+#if 0
+ printf( "----- parsing tar block -----\n" );
+ printf( "arch_name = '%s'\n", rec->header.arch_name );
+ printf( "mode = '%s'\n", rec->header.mode );
+ printf( "uid = %d\n", parseOctal( rec->header.uid, 6 ) );
+ printf( "gid = %d\n", parseOctal( rec->header.gid, 6 ) );
+ printf( "size = %d\n", parseOctal( rec->header.size, 11 ) );
+ printf( "mtime = %d\n", parseOctal( rec->header.mtime, 11 ) );
+ printf( "chksum = '%s'\n", rec->header.chksum );
+ printf( "linkflag = '%c'\n", rec->header.linkflag );
+ printf( "arch_linkname = '%s'\n", rec->header.arch_linkname );
+ printf( "magic = '%s'\n", rec->header.magic );
+ printf( "uname = '%s'\n", rec->header.uname );
+ printf( "gname = '%s'\n", rec->header.gname );
+ printf( "devmajor = %d\n", parseOctal( rec->header.devmajor, 8 ) );
+ printf( "devminor = %d\n", parseOctal( rec->header.devminor, 8 ) );
+ printf( "atime = %d\n", parseOctal( rec->header.atime, 11 ) );
+ printf( "ctime = %d\n", parseOctal( rec->header.ctime, 11 ) );
+ printf( "offset = %d\n", parseOctal( rec->header.offset, 11 ) );
+ printf( "longnames = '%s'\n", rec->header.longnames );
+ printf( "isextended = %d\n", rec->header.isextended );
+ printf( "realsize = %d\n", parseOctal( rec->header.realsize, 11 ) );
+#endif
+
+ if ( rec->header.magic[0] != 0 ) {
+ _blocksToSkip = ( parseOctal( rec->header.size, 11 ) + 511 ) / 512;
+ _extended = rec->header.isextended;
+
+ if ( rec->header.linkflag == LF_LONGNAME ) {
+ // The actual file name is stored in the next _blocksToSkip blocks of the tar-file.
+ _longname = TRUE;
+ _archnameIdx = 0;
+ } else {
+ if ( _longname ) {
+ _longname = FALSE;
+ emit sigEntry( _archname, parseOctal( rec->header.size, 11 ), parseOctal( rec->header.mtime, 11 ), _record );
+ } else {
+ emit sigEntry( rec->header.arch_name, parseOctal( rec->header.size, 11 ), parseOctal( rec->header.mtime, 11 ), _record );
+ }
+ }
+ }
+}
diff --git a/kdat/TarParser.h b/kdat/TarParser.h
new file mode 100644
index 0000000..b43fd35
--- /dev/null
+++ b/kdat/TarParser.h
@@ -0,0 +1,207 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _TarParser_h_
+#define _TarParser_h_
+
+#include <qobject.h>
+
+/* Standard Archive Format - Standard TAR - USTAR. */
+
+/* Header block on tape.
+
+ We use traditional DP naming conventions here. A "block" is a big chunk
+ of stuff that we do I/O on. A "record" is a piece of info that we care
+ about. Typically many "record"s fit into a "block". */
+
+#define RECORDSIZE 512
+#define NAMSIZ 100
+#define TUNMLEN 32
+#define TGNMLEN 32
+#define SPARSE_EXT_HDR 21
+#define SPARSE_IN_HDR 4
+
+struct sparse
+{
+ char offset[12];
+ char numbytes[12];
+};
+
+union record
+{
+ char charptr[RECORDSIZE];
+
+ struct header
+ {
+ char arch_name[NAMSIZ];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char arch_linkname[NAMSIZ];
+ char magic[8];
+ char uname[TUNMLEN];
+ char gname[TGNMLEN];
+ char devmajor[8];
+ char devminor[8];
+
+ /* The following fields were added for GNU and are not standard. */
+
+ char atime[12];
+ char ctime[12];
+ char offset[12];
+ char longnames[4];
+ /* Some compilers would insert the pad themselves, so pad was
+ once autoconfigured. It is simpler to always insert it! */
+ char pad;
+ struct sparse sp[SPARSE_IN_HDR];
+ char isextended;
+ char realsize[12]; /* true size of the sparse file */
+#if 0
+ char ending_blanks[12]; /* number of nulls at the end of the file,
+ if any */
+#endif
+ }
+ header;
+
+ struct extended_header
+ {
+ struct sparse sp[21];
+ char isextended;
+ }
+ ext_hdr;
+};
+
+/* The checksum field is filled with this while the checksum is computed. */
+#define CHKBLANKS " " /* 8 blanks, no null */
+
+/* The magic field is filled with this value if uname and gname are valid,
+ marking the archive as being in standard POSIX format (though GNU tar
+ itself is not POSIX conforming). */
+#define TMAGIC "ustar " /* 7 chars and a null */
+
+/* The magic field is filled with this if this is a GNU format dump entry.
+ But I suspect this is not true anymore. */
+#define GNUMAGIC "GNUtar " /* 7 chars and a null */
+
+/* The linkflag defines the type of file. */
+#define LF_OLDNORMAL '\0' /* normal disk file, Unix compat */
+#define LF_NORMAL '0' /* normal disk file */
+#define LF_LINK '1' /* link to previously dumped file */
+#define LF_SYMLINK '2' /* symbolic link */
+#define LF_CHR '3' /* character special file */
+#define LF_BLK '4' /* block special file */
+#define LF_DIR '5' /* directory */
+#define LF_FIFO '6' /* FIFO special file */
+#define LF_CONTIG '7' /* contiguous file */
+/* Further link types may be defined later. */
+
+/* Note that the standards committee allows only capital A through
+ capital Z for user-defined expansion. This means that defining
+ something as, say '8' is a *bad* idea. */
+
+/* This is a dir entry that contains the names of files that were in the
+ dir at the time the dump was made. */
+#define LF_DUMPDIR 'D'
+
+/* Identifies the NEXT file on the tape as having a long linkname. */
+#define LF_LONGLINK 'K'
+
+/* Identifies the NEXT file on the tape as having a long name. */
+#define LF_LONGNAME 'L'
+
+/* This is the continuation of a file that began on another volume. */
+#define LF_MULTIVOL 'M'
+
+/* For storing filenames that didn't fit in 100 characters. */
+#define LF_NAMES 'N'
+
+/* This is for sparse files. */
+#define LF_SPARSE 'S'
+
+/* This file is a tape/volume header. Ignore it on extraction. */
+#define LF_VOLHDR 'V'
+
+#if 0
+/* The following two blocks of #define's are unused in GNU tar. */
+
+/* Bits used in the mode field - values in octal */
+#define TSUID 04000 /* set UID on execution */
+#define TSGID 02000 /* set GID on execution */
+#define TSVTX 01000 /* save text (sticky bit) */
+
+/* File permissions */
+#define TUREAD 00400 /* read by owner */
+#define TUWRITE 00200 /* write by owner */
+#define TUEXEC 00100 /* execute/search by owner */
+#define TGREAD 00040 /* read by group */
+#define TGWRITE 00020 /* write by group */
+#define TGEXEC 00010 /* execute/search by group */
+#define TOREAD 00004 /* read by other */
+#define TOWRITE 00002 /* write by other */
+#define TOEXEC 00001 /* execute/search by other */
+
+#endif
+
+/* End of Standard Archive Format description. */
+
+/**
+ * @short A parser for GNU tar archives.
+ */
+class TarParser : public QObject {
+ Q_OBJECT
+ char _buf[512];
+ int _bufIdx;
+ int _blocksToSkip;
+ int _record;
+ bool _longname;
+ bool _extended;
+ char _archname[8192];
+ int _archnameIdx;
+
+ int parseOctal( const char* data, int length );
+ void parseTarBlock();
+public:
+ /**
+ * Create a new GNU tar archive parser.
+ */
+ TarParser();
+public slots:
+ /**
+ * This slot receives raw data that represents a GNU tar archive.
+ *
+ * @param data An array of data bytes.
+ * @param length The length of the data array.
+ */
+ void slotData( const char * data, int length );
+signals:
+ /**
+ * This signal is emitted whenever a file entry is parsed from the archive.
+ *
+ * @param name The name of the the file.
+ * @param size The size of the file, in bytes.
+ * @param mtime The last modification time for the file.
+ * @param record The tar record that this file begins on.
+ */
+ void sigEntry( const QString & name, int size, int mtime, int record );
+};
+
+#endif
diff --git a/kdat/Util.cpp b/kdat/Util.cpp
new file mode 100644
index 0000000..7fb06a3
--- /dev/null
+++ b/kdat/Util.cpp
@@ -0,0 +1,71 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <qstringlist.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "Util.h"
+
+QString Util::bytesToString( uint bytes )
+{
+ return KGlobal::locale()->formatNumber(bytes, 0);
+}
+
+QString Util::kbytesToString( uint kbytes )
+{
+ return KGlobal::locale()->formatNumber(kbytes, 0) + 'k';
+}
+
+QString Util::longestCommonPath( const QStringList& files )
+{
+ QStringList filesTmp = files;
+ QStringList::Iterator i = filesTmp.begin();
+
+ uint minLen = (*i).length();
+ for ( ; i != filesTmp.end(); ++i ) {
+ if ( minLen > (*i).length() ) {
+ minLen = (*i).length();
+ }
+ }
+ uint j;
+ for ( j = 0; j < minLen; j++ ) {
+ i = filesTmp.begin();
+ QString first = *i;
+ for ( ; i != filesTmp.end(); ++i ) {
+ if ( first.left(j) != (*i).left(j) ) {
+ // Prefixes are NOT the same.
+ break;
+ }
+ }
+ if ( i != filesTmp.end() ) {
+ // The common prefix is 0 to j-1, inclusive.
+ break;
+ }
+ }
+ i = filesTmp.begin();
+ QString prefix = *i;
+ int idx = prefix.findRev( '/', j );
+ if ( idx > -1 ) {
+ prefix = prefix.left( prefix.findRev( '/', j ) );
+ } else {
+ prefix = "";
+ }
+
+ return prefix;
+}
diff --git a/kdat/Util.h b/kdat/Util.h
new file mode 100644
index 0000000..bf761e5
--- /dev/null
+++ b/kdat/Util.h
@@ -0,0 +1,47 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _Util_h_
+#define _Util_h_
+
+#include <qstring.h>
+
+/**
+ * @short A collection of common useful methods.
+ */
+class Util {
+public:
+ /**
+ * Format the given number of bytes into a comma-separated string of
+ * digits.
+ */
+ static QString bytesToString( uint bytes );
+
+ /**
+ * Format the given number of kilobytes into a comma-separated string of
+ * digits, followed by a 'k'.
+ */
+ static QString kbytesToString( uint kbytes );
+
+ /**
+ * Find the longest common path prefix for a list of files.
+ */
+ static QString longestCommonPath( const QStringList& files );
+};
+
+#endif
diff --git a/kdat/VerifyDlg.cpp b/kdat/VerifyDlg.cpp
new file mode 100644
index 0000000..6714322
--- /dev/null
+++ b/kdat/VerifyDlg.cpp
@@ -0,0 +1,415 @@
+// $Id$
+//
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdio.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qfile.h>
+
+#include <kapplication.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "LoggerWidget.h"
+#include "Options.h"
+#include "VerifyDlg.h"
+#include "TapeDrive.h"
+#include "Util.h"
+
+#include "VerifyDlg.moc"
+
+
+VerifyDlg::VerifyDlg( const QString & workingDir, int fileno, const RangeList& ranges,
+ bool restore, QWidget* parent, const char* name )
+ : QDialog( parent, name, TRUE ),
+ _restore( restore ),
+ _proc( NULL ),
+ _workingDir( workingDir ),
+ _fileno( fileno ),
+ _ranges( ranges ),
+ _totalKBytes( 0.0 ),
+ _fileCount( 0 ),
+ _wroteStdin( TRUE ),
+ _aborted( FALSE ),
+ _done( FALSE )
+{
+ // Calculate size of verify.
+ QPtrListIterator<Range> i( _ranges.getRanges() );
+ _archiveSize = 0;
+ for ( ; i.current(); ++i ) {
+ _archiveSize += i.current()->getEnd() - i.current()->getStart();
+ }
+ _archiveSize = ( _archiveSize + 1 ) / 2;
+
+ if ( _restore ) {
+ setCaption( i18n( "KDat: Restore" ) );
+ setIconText( i18n( "KDat: Restore" ) );
+ } else {
+ setCaption( i18n( "KDat: Verify" ) );
+ setIconText( i18n( "KDat: Verify" ) );
+ }
+
+ resize( 500, 300 );
+
+ /* 2002-01-26 LEW: "Time remaining" was cut off in mid-"g"
+ in BackupDlg.cpp,
+ so we'll provide that plus some space beyond it. */
+ // const int labelWidth = 96;
+ const int labelWidth = 110;
+
+ QFrame* f1 = new QFrame( this );
+ f1->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ QFrame* f2 = new QFrame( this );
+ f2->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+
+ QLabel* lbl1 = new QLabel( i18n( "Elapsed time:" ), f1 );
+ lbl1->setFixedSize( labelWidth, lbl1->sizeHint().height() );
+
+ _elapsedTime = new QLabel( i18n( "00:00:00" ), f1 );
+ _elapsedTime->setFixedHeight( _elapsedTime->sizeHint().height() );
+
+ QLabel* lbl2 = new QLabel( i18n( "Time remaining:" ), f2 );
+ lbl2->setFixedSize( labelWidth, lbl2->sizeHint().height() );
+
+ _timeRemaining = new QLabel( i18n( "00:00:00" ), f2 );
+ _timeRemaining->setFixedHeight( _timeRemaining->sizeHint().height() );
+
+ QLabel* lbl3 = new QLabel( i18n( "Total KB:" ), f1 );
+ lbl3->setFixedSize( labelWidth, lbl3->sizeHint().height() );
+
+ QLabel* totalKbytes = new QLabel( Util::kbytesToString( _archiveSize ), f1 );
+ totalKbytes->setFixedHeight( totalKbytes->sizeHint().height() );
+
+ QLabel* lbl4 = new QLabel( i18n( "KB read:" ), f2 );
+ lbl4->setFixedSize( labelWidth, lbl4->sizeHint().height() );
+
+ _kbytesRead = new QLabel( i18n( "0KB" ), f2 );
+ _kbytesRead->setFixedHeight( _kbytesRead->sizeHint().height() );
+
+ QLabel* lbl5 = new QLabel( i18n( "Transfer rate:" ), f1 );
+ lbl5->setFixedSize( labelWidth, lbl5->sizeHint().height() );
+
+ _transferRate = new QLabel( i18n( "0KB/min" ), f1 );
+ _transferRate->setFixedHeight( _transferRate->sizeHint().height() );
+
+ QLabel* lbl6;
+ if ( _restore ) {
+ lbl6 = new QLabel( i18n( "Files:" ), f2 );
+ lbl6->setFixedSize( labelWidth, lbl6->sizeHint().height() );
+ } else {
+ lbl6 = new QLabel( i18n( "Differences:" ), f2 );
+ lbl6->setFixedSize( labelWidth, lbl6->sizeHint().height() );
+ }
+
+ _files = new QLabel( "0", f2 );
+ _files->setFixedHeight( _files->sizeHint().height() );
+
+ if ( _restore ) {
+ _log = new LoggerWidget( i18n( "Restore log:" ), this );
+ } else {
+ _log = new LoggerWidget( i18n( "Verify log:" ), this );
+ }
+
+ _ok = new KPushButton( KStdGuiItem::ok(), this );
+ _ok->setFixedSize( 80, _ok->sizeHint().height() );
+ connect( _ok, SIGNAL( clicked() ), this, SLOT( slotOK() ) );
+ _ok->setEnabled( FALSE );
+
+ _save = new QPushButton( i18n( "&Save Log..." ), this );
+ _save->setFixedSize( 80, _save->sizeHint().height() );
+ connect( _save, SIGNAL( clicked() ), _log, SLOT( save() ) );
+ _save->setEnabled( FALSE );
+
+ _abort = new QPushButton( i18n( "&Abort" ), this );
+ _abort->setFixedSize( 80, _abort->sizeHint().height() );
+ connect( _abort, SIGNAL( clicked() ), this, SLOT( slotAbort() ) );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 8, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addStrut( 3 * lbl1->height() + 16 );
+ l1_1->addWidget( f1 );
+ l1_1->addWidget( f2 );
+
+ QVBoxLayout* l1_1_1 = new QVBoxLayout( f1, 4, 4 );
+
+ QHBoxLayout* l1_1_1_1 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_1 );
+ l1_1_1_1->addWidget( lbl1 );
+ l1_1_1_1->addWidget( _elapsedTime, 1 );
+
+ QHBoxLayout* l1_1_1_2 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_2 );
+ l1_1_1_2->addWidget( lbl3 );
+ l1_1_1_2->addWidget( totalKbytes, 1 );
+
+ QHBoxLayout* l1_1_1_3 = new QHBoxLayout();
+ l1_1_1->addLayout( l1_1_1_3 );
+ l1_1_1_3->addWidget( lbl5 );
+ l1_1_1_3->addWidget( _transferRate, 1 );
+
+ QVBoxLayout* l1_1_2 = new QVBoxLayout( f2, 4, 4 );
+
+ QHBoxLayout* l1_1_2_1 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_1 );
+ l1_1_2_1->addWidget( lbl2 );
+ l1_1_2_1->addWidget( _timeRemaining, 1 );
+
+ QHBoxLayout* l1_1_2_2 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_2 );
+ l1_1_2_2->addWidget( lbl4 );
+ l1_1_2_2->addWidget( _kbytesRead, 1 );
+
+ QHBoxLayout* l1_1_2_3 = new QHBoxLayout();
+ l1_1_2->addLayout( l1_1_2_3 );
+ l1_1_2_3->addWidget( lbl6 );
+ l1_1_2_3->addWidget( _files, 1 );
+
+ l1->addWidget( _log, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2 );
+ l1_2->addStretch( 1 );
+ l1_2->addWidget( _ok );
+ l1_2->addWidget( _save );
+ l1_2->addWidget( _abort );
+}
+
+VerifyDlg::~VerifyDlg()
+{
+}
+
+void VerifyDlg::show()
+{
+ chdir( QFile::encodeName(_workingDir) );
+
+ _proc = new KProcess();
+ //_proc->setExecutable( Options::instance()->getTarCommand() );
+ *_proc << Options::instance()->getTarCommand();
+ if ( _restore ) {
+ *_proc << "-xvf" << "-";
+ } else {
+ *_proc << "-dvf" << "-";
+ }
+
+ connect( _proc, SIGNAL( processExited( KProcess* ) ), this, SLOT( slotProcessExited( KProcess* ) ) );
+ connect( _proc, SIGNAL( receivedStdout( KProcess*, char*, int ) ), this, SLOT( slotStdout( KProcess*, char*, int ) ) );
+ connect( _proc, SIGNAL( wroteStdin( KProcess* ) ), this, SLOT( slotWroteStdin( KProcess* ) ) );
+
+ _startTime = time( NULL );
+ startTimer( 100 );
+
+ _proc->start( KProcess::NotifyOnExit, KProcess::All );
+
+ QDialog::show();
+}
+
+void VerifyDlg::slotProcessExited( KProcess* )
+{
+ killTimers();
+ delete _proc;
+
+ // Set this, or we get caught in a loop.
+ _done = TRUE;
+
+ _ok->setEnabled( TRUE );
+ _ok->setDefault( TRUE );
+ _save->setEnabled( TRUE );
+ _abort->setEnabled( FALSE );
+}
+
+void VerifyDlg::slotStdout( KProcess*, char* buf, int len )
+{
+ QString data;
+ data.replace( 0, len, buf );
+ /* 2002-02-23 RG */
+ // data[len] = '\0';
+ data.truncate( len );
+ /* 2002-02-23 RG */
+ _leftover += data;
+
+ int newlineIndex;
+ while ( ( newlineIndex = _leftover.find( '\n' ) ) > -1 ) {
+ _log->append( _leftover.left( newlineIndex ) );
+
+ // Count differences.
+ if ( _restore ) {
+ _fileCount++;
+ } else {
+ int len = _lastFileName.length();
+ if ( len > 0 ) {
+ if ( _lastFileName == _leftover.left( len ) ) {
+ if ( ( _leftover[len] == ':' ) && ( _leftover[len+1] == ' ' ) ) {
+ _fileCount++;
+ } else {
+ _lastFileName = _leftover.left( newlineIndex );
+ }
+ } else {
+ _lastFileName = _leftover.left( newlineIndex );
+ }
+ } else {
+ _lastFileName = _leftover.left( newlineIndex );
+ }
+ }
+
+ _leftover.remove( 0, newlineIndex + 1 );
+ QString tmp;
+ tmp.setNum( _fileCount );
+ _files->setText( tmp );
+ }
+}
+
+void VerifyDlg::slotWroteStdin( KProcess* )
+{
+ _wroteStdin = TRUE;
+}
+
+void VerifyDlg::slotOK()
+{
+ if ( _aborted ) {
+ reject();
+ } else {
+ accept();
+ }
+}
+
+void VerifyDlg::slotAbort()
+{
+ _aborted = TRUE;
+}
+
+void VerifyDlg::timerEvent( QTimerEvent* )
+{
+ killTimers();
+
+ int oldElapsed = 0;
+
+ int bytesToRead;
+ int count;
+ char *buf = new char[Options::instance()->getTapeBlockSize()];
+ QPtrListIterator<Range> i( _ranges.getRanges() );
+ for ( ; ( !_done ) && ( !_aborted ) && ( i.current() ); ++i ) {
+ // Move to the beginning of the next range.
+ TapeDrive::instance()->seek( _fileno, i.current()->getStart() );
+
+ /* 2002-01-30 LEW */
+#ifdef DEBUG
+ printf("Seeking to next range: %d-%d\n", i.current()->getStart(), i.current()->getEnd());
+#endif /* DEBUG */
+ /* 2002-01-30 LEW */
+
+ // Read in the records and forward them to tar.
+ bytesToRead = ( i.current()->getEnd() - i.current()->getStart() ) * 512;
+ while ( bytesToRead > 0 ) {
+ count = TapeDrive::instance()->read( buf, bytesToRead > Options::instance()->getTapeBlockSize() ? Options::instance()->getTapeBlockSize() : bytesToRead );
+
+ if ( count == 0 ) {
+ // I hope this means end-of-file. Break out of the while loop, and process the next range.
+ /* 2002-01-30 LEW */
+#ifdef DEBUG
+ printf("VerifyDlg::timerEvent count==0, so I'm skipping to the next range\n");
+#endif /* DEBUG */
+ /* 2002-01-30 LEW */
+ break;
+ }
+
+ if ( count < 0 ) {
+ kdError() << i18n( "failed while reading tape data.\n" );
+ _proc->closeStdin();
+ delete [] buf;
+ return;
+ }
+
+ while ( ( !_done ) && ( !_aborted ) && ( !_wroteStdin ) )
+ KApplication::kApplication()->processEvents();
+ if ( _done || _aborted ) {
+ /* 2002-01-30 LEW */
+#ifdef DEBUG
+ printf("VerifyDlg::timerEvent done/aborted, so I'm skipping to the next range\n");
+#endif /* DEBUG */
+ /* 2002-01-30 LEW */
+ break;
+ }
+ _wroteStdin = FALSE;
+ _proc->writeStdin( buf, count );
+ bytesToRead -= count;
+ _totalKBytes += (float)count / 1024.0;
+
+ // Update stats.
+ int elapsed = time( NULL ) - _startTime;
+ if ( elapsed > oldElapsed )
+ {
+ updateStats();
+ KApplication::kApplication()->processEvents();
+ if ( _done || _aborted ) {
+ break;
+ }
+ oldElapsed = elapsed;
+ }
+ }
+ }
+
+ // Update stats.
+ updateStats();
+
+ // Send an EOF block to tar.
+ memset( buf, 0, Options::instance()->getTapeBlockSize() );
+ _proc->writeStdin( buf, Options::instance()->getTapeBlockSize() );
+
+ _proc->closeStdin();
+ delete [] buf;
+}
+
+void VerifyDlg::updateStats()
+{
+ QString str;
+ int elapsed = time( NULL ) - _startTime;
+
+ str= QString::fromUtf8( QCString().sprintf( i18n( "%02d:%02d:%02d" ).utf8(), elapsed / 3600, elapsed / 60 % 60, elapsed % 60 ) );
+ _elapsedTime->setText( str );
+
+ int remain = 0;
+ if ( (int)_totalKBytes > 0 ) {
+ remain = (int)(( (float)_archiveSize - _totalKBytes ) * (float)elapsed / _totalKBytes);
+ }
+ if ( remain < 0 ) {
+ remain = 0;
+ }
+ str = QString::fromUtf8( QCString().sprintf( i18n( "%02d:%02d:%02d" ).utf8(), remain / 3600, remain / 60 % 60, remain % 60 ) );
+ _timeRemaining->setText( str );
+
+ str = Util::kbytesToString( (int)_totalKBytes );
+ _kbytesRead->setText( str );
+
+ if ( elapsed > 0 ) {
+ str = i18n( "%1/min" ).arg(Util::kbytesToString( (int)_totalKBytes * 60 / elapsed ) );
+ _transferRate->setText( str );
+ }
+}
diff --git a/kdat/VerifyDlg.h b/kdat/VerifyDlg.h
new file mode 100644
index 0000000..0d7648e
--- /dev/null
+++ b/kdat/VerifyDlg.h
@@ -0,0 +1,94 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _VerifyDlg_h_
+#define _VerifyDlg_h_
+
+#include <qdialog.h>
+#include <qptrlist.h>
+
+#include "Range.h"
+
+class QLabel;
+class QPushButton;
+
+class KProcess;
+
+class LoggerWidget;
+class TapeDrive;
+
+/**
+ * @short Status dialog for verifying/restoring parts of an archive.
+ */
+class VerifyDlg : public QDialog {
+ Q_OBJECT
+ bool _restore;
+ KProcess* _proc;
+ QString _workingDir;
+ int _fileno;
+ const RangeList& _ranges;
+ QString _leftover;
+ QLabel* _elapsedTime;
+ QLabel* _timeRemaining;
+ QLabel* _kbytesRead;
+ QLabel* _transferRate;
+ QLabel* _files;
+ LoggerWidget* _log;
+ QPushButton* _ok;
+ QPushButton* _save;
+ QPushButton* _abort;
+ int _startTime;
+ float _totalKBytes;
+ int _fileCount;
+ int _archiveSize;
+ bool _wroteStdin;
+ bool _aborted;
+ bool _done;
+ QString _lastFileName;
+
+ void updateStats();
+private slots:
+ void slotProcessExited( KProcess* proc );
+ void slotStdout( KProcess* proc, char* buf, int len );
+ void slotWroteStdin( KProcess* proc );
+ void slotOK();
+ void slotAbort();
+protected:
+ void show();
+ void timerEvent( QTimerEvent* e );
+public:
+ /**
+ * Create a new verify/restore dialog.
+ *
+ * @param workingDir The directory to restore files to or verify files against.
+ * @param fileno The tape file number of the archive to verify/restore.
+ * @param ranges A list of tar block ranges to read.
+ * @param restore TRUE means restore, FALSE means verify.
+ * @param parent The parent widget for the dialog.
+ * @param name The name of this widget.
+ */
+ VerifyDlg( const QString & workingDir, int fileno, const RangeList& ranges,
+ bool restore = FALSE, QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the verify/restore dialog.
+ */
+ ~VerifyDlg();
+};
+
+#endif
diff --git a/kdat/VerifyOptDlg.cpp b/kdat/VerifyOptDlg.cpp
new file mode 100644
index 0000000..3eb272d
--- /dev/null
+++ b/kdat/VerifyOptDlg.cpp
@@ -0,0 +1,129 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <unistd.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qlistbox.h>
+
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "VerifyOptDlg.h"
+#include <klocale.h>
+
+#include "VerifyOptDlg.moc"
+
+VerifyOptDlg::VerifyOptDlg( const QString & def, const QStringList& files, bool restore, QWidget* parent, const char* name )
+ : QDialog( parent, name, TRUE ),
+ _restore( restore )
+{
+ if ( _restore ) {
+ setIconText( i18n( "KDat: Restore Options" ) );
+ setCaption( i18n( "KDat: Restore Options" ) );
+ } else {
+ setIconText( i18n( "KDat: Verify Options" ) );
+ setCaption( i18n( "KDat: Verify Options" ) );
+ }
+
+ QLabel* lbl1;
+ if ( _restore ) {
+ lbl1 = new QLabel( i18n( "Restore to folder:" ), this );
+ } else {
+ lbl1 = new QLabel( i18n( "Verify in folder:" ), this );
+ }
+ lbl1->setFixedSize( lbl1->sizeHint() );
+
+ _entry = new QLineEdit( this );
+ _entry->setText( def );
+ _entry->setFixedHeight( _entry->sizeHint().height() );
+
+ QPushButton* browse = new QPushButton( i18n( "..." ), this );
+ browse->setFixedSize( browse->sizeHint() );
+
+ QLabel* lbl2;
+ if ( _restore ) {
+ lbl2 = new QLabel( i18n( "Restore files:" ), this );
+ } else {
+ lbl2 = new QLabel( i18n( "Verify files:" ), this );
+ }
+ lbl2->setFixedHeight( lbl2->sizeHint().height() );
+
+ QListBox* fileList = new QListBox( this );
+ fileList->insertStringList(files);
+
+ KPushButton* ok = new KPushButton( KStdGuiItem::ok(), this );
+ ok->setFixedSize( 80, ok->sizeHint().height() );
+ KPushButton* cancel = new KPushButton( KStdGuiItem::cancel(), this );
+ cancel->setFixedSize( 80, cancel->sizeHint().height() );
+
+ QVBoxLayout* l1 = new QVBoxLayout( this, 8, 4 );
+
+ QHBoxLayout* l1_1 = new QHBoxLayout();
+ l1->addLayout( l1_1 );
+ l1_1->addWidget( lbl1 );
+ l1_1->addWidget( _entry, 1 );
+ l1_1->addWidget( browse );
+
+ l1->addWidget( lbl2 );
+ l1->addWidget( fileList, 1 );
+
+ QHBoxLayout* l1_2 = new QHBoxLayout();
+ l1->addLayout( l1_2, 0 );
+ l1_2->addStretch( 1 );
+ l1_2->addWidget( ok, 0 );
+ l1_2->addWidget( cancel, 0 );
+
+ resize( 400, 300 );
+
+ _entry->setFocus();
+ _entry->selectAll();
+
+ connect( _entry, SIGNAL( returnPressed() ), this, SLOT( okClicked() ) );
+ connect( browse, SIGNAL( clicked() ) , this, SLOT( slotBrowse() ) );
+ connect( ok , SIGNAL( clicked() ) , this, SLOT( okClicked() ) );
+ connect( cancel, SIGNAL( clicked() ) , this, SLOT( reject() ) );
+}
+
+VerifyOptDlg::~VerifyOptDlg()
+{
+}
+
+void VerifyOptDlg::okClicked()
+{
+ _workingDir = _entry->text();
+ accept();
+}
+
+QString VerifyOptDlg::getWorkingDirectory()
+{
+ return _workingDir;
+}
+
+void VerifyOptDlg::slotBrowse()
+{
+ QString tmp;
+ tmp = KFileDialog::getExistingDirectory( _entry->text() );
+ if ( tmp.length() ) {
+ _entry->setText( tmp );
+ }
+}
diff --git a/kdat/VerifyOptDlg.h b/kdat/VerifyOptDlg.h
new file mode 100644
index 0000000..f5023e4
--- /dev/null
+++ b/kdat/VerifyOptDlg.h
@@ -0,0 +1,66 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _VerifyOptDlg_h_
+#define _VerifyOptDlg_h_
+
+#include <qdialog.h>
+#include <qstring.h>
+
+class QLineEdit;
+
+/**
+ * @short Display/edit the information for performing a verify/restore operation.
+ *
+ * The verify and restore operations are similiar enough that their options
+ * have been combined into a single dialog.
+ */
+class VerifyOptDlg : public QDialog {
+ Q_OBJECT
+ bool _restore;
+ QString _workingDir;
+ QLineEdit* _entry;
+private slots:
+ void okClicked();
+ void slotBrowse();
+public:
+ /**
+ * Create a new verify/restore options dialog.
+ *
+ * @param def The default working directory.
+ * @param files The list of files that will be verified/restored.
+ * @param restore TRUE means we are doing a restore, FALSE means we are doing a verify.
+ * @param parent The parent widget for the dialog.
+ * @param name The name for the dialog.
+ */
+ VerifyOptDlg( const QString & def, const QStringList& files, bool restore = FALSE, QWidget* parent = 0, const char* name = 0 );
+
+ /**
+ * Destroy the verify/restore options dialog.
+ */
+ ~VerifyOptDlg();
+
+ /**
+ * Get thre working directory entered by the user.
+ *
+ * @return The working directory for the verify/restore operation.
+ */
+ QString getWorkingDirectory();
+};
+
+#endif
diff --git a/kdat/configure.in.in b/kdat/configure.in.in
new file mode 100644
index 0000000..9f09880
--- /dev/null
+++ b/kdat/configure.in.in
@@ -0,0 +1,10 @@
+AC_MSG_CHECKING(whether sys/mtio.h defines GMT_EOF and mtget has a member mt_gstat)
+AC_LANG_C
+AC_TRY_COMPILE(
+[#include <sys/mtio.h>],
+[struct mtget tapeStatus; GMT_EOF ( tapeStatus.mt_gstat );],
+[AC_MSG_RESULT(yes)],
+[ DO_NOT_COMPILE="$DO_NOT_COMPILE kdat"
+ AC_MSG_RESULT([no...Skipping kdat]) ]
+)
+
diff --git a/kdat/kdat.desktop b/kdat/kdat.desktop
new file mode 100644
index 0000000..3aeb7ac
--- /dev/null
+++ b/kdat/kdat.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+Name=KDat
+Name[af]=Kdat
+Name[ar]=برنامج KDat
+Name[bn]=কে-ড্যাট
+Name[eo]=Surbendigilo
+Name[hi]=के-डेट
+Name[mn]=КДЕ Дат
+Name[ne]=केडीई ड्याट
+Name[sv]=Kdat
+Name[ta]=கேடாட்
+Name[tg]=KДат
+Name[th]=เทปสำรองข้อมูล - K
+GenericName=Tape Backup Tool
+GenericName[af]=Kaset Rugsteun Program
+GenericName[ar]=أداة نسخ المحفوظات على الشريط
+GenericName[az]=Kasetə Ehtiyat Alma Vasitəsi
+GenericName[bg]=Лентов архиватор
+GenericName[bn]=টেপ ব্যাকআপ সরঞ্জাম
+GenericName[br]=Ostilh saveteiñ war seizenn
+GenericName[bs]=Alat za backup na traku
+GenericName[ca]=Utilitat per a còpies de seguretat en cintes
+GenericName[cs]=Zálohování na pásku
+GenericName[cy]=Erfyn Cefn-gopïo ar Dâp
+GenericName[da]=Værktøj til sikkerhedskopiering på bånd
+GenericName[de]=Dienstprogramm für Bandsicherungen
+GenericName[el]=Εργαλείο λήψη αντιγράφων ασφαλείας σε κασέτα
+GenericName[eo]=Bendsekurigilo
+GenericName[es]=Copia de cintas
+GenericName[et]=Varukoopiate haldamine (lindil)
+GenericName[eu]=Zinta backup tresna
+GenericName[fa]=ابزار پشتیبانی نوار
+GenericName[fi]=Nauhavarmistustyökalu
+GenericName[fo]=Trygdarritanaramboð
+GenericName[fr]=Outil de sauvegarde sur bandes
+GenericName[ga]=Uirlis Chúltaca Téipe
+GenericName[gl]=Cópia de Seguridade en Cintas
+GenericName[he]=כלי גיבוי באמצעות סרט
+GenericName[hi]=टेप बैकअप औज़ार
+GenericName[hr]=Alat za izradu sigurnosne kopije na traci
+GenericName[hu]=Szalagos mentés
+GenericName[is]=Spólu afritunartól
+GenericName[it]=Strumento per la copia di sicurezza su nastro
+GenericName[ja]=テープバックアップツール
+GenericName[ka]=სარეზერვო ასლის ხელსაწყო
+GenericName[kk]=Таспаға сақтық көшірмелеу құралы
+GenericName[km]=ឧបករណ៍​បម្រុង​ទុក​កាសែត
+GenericName[ko]=테이프 백업 도구
+GenericName[lt]=Juostinio archyvavimo priemonė
+GenericName[lv]=Lentas Rezervēšanas Rīks
+GenericName[mk]=Алатка за заштитни копии на ленти
+GenericName[mn]=Соронзон хальсанд Хадгалагч
+GenericName[ms]=Alat Ganti Sedia
+GenericName[mt]=Għodda għal backup fuq tapes
+GenericName[nb]=Verktøy for sikkerhetskopiering til magnetbånd
+GenericName[nds]=Bandsekerheitkopiewarktüüch
+GenericName[ne]=टेप जगेडा उपकरण
+GenericName[nl]=Tape backup-programma
+GenericName[nn]=Reservekopiering på band
+GenericName[pa]=ਟੇਪ ਬੈਕਅੱਪ ਸੰਦ
+GenericName[pl]=Narzędzie do kopii na taśmie
+GenericName[pt]=Ferramenta de Salvaguarda em Fita
+GenericName[pt_BR]=Ferramenta de Backup em Fita
+GenericName[ro]=Utilitar de salvare pe benzi
+GenericName[ru]=Утилита архивирования на ленту
+GenericName[se]=Liigemáŋgen báddái
+GenericName[sk]=Zálohovanie na pásku
+GenericName[sl]=Orodje za tračne rezervne kopije
+GenericName[sr]=Алат за архивирање на траку
+GenericName[sr@Latn]=Alat za arhiviranje na traku
+GenericName[sv]=Verktyg för bandsäkerhetskopiering
+GenericName[ta]=நாடா காப்பக கருவி
+GenericName[tg]=Утилита барои архив кардан ба тасма
+GenericName[th]=เครื่องมือเทปสำรองข้อมูล
+GenericName[tr]=Teyp Yedekleme Aracı
+GenericName[uk]=Засіб резервування на стрічку
+GenericName[ven]=Tshishumiswa tsha Theipi tshau Thusedza
+GenericName[vi]=Công cụ sao lưu băng
+GenericName[wa]=Usteye di copeyes di såvrité so bindes
+GenericName[xh]=Isixhobo Sokuncedisa Iteyipu
+GenericName[zh_CN]=磁带备份工具
+GenericName[zh_HK]=磁帶備份工具
+GenericName[zh_TW]=磁帶備份工具
+GenericName[zu]=Ithuluzi Yethephu Yokugcina umsebenzi uphephile
+Exec=kdat %i %m -caption "%c"
+Icon=kdat
+Type=Application
+X-KDE-StartupNotify=true
+DocPath=kdat/index.html
+Terminal=false
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;System;X-KDE-More;
diff --git a/kdat/kdat.h b/kdat/kdat.h
new file mode 100644
index 0000000..ed897ee
--- /dev/null
+++ b/kdat/kdat.h
@@ -0,0 +1,42 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _kdat_h_
+#define _kdat_h_
+
+// KDat program version.
+#define KDAT_VERSION "2.0.2"
+
+// Magic string.
+#define KDAT_MAGIC "KDatMAGIC"
+#define KDAT_MAGIC_LENGTH 9
+
+// Tape header version numbers.
+#define KDAT_TAPE_HEADER_VERSION_1_0 1
+#define KDAT_TAPE_HEADER_VERSION KDAT_TAPE_HEADER_VERSION_1_0
+
+// Index file version numbers.
+#define KDAT_INDEX_FILE_VERSION_1_0 4
+#define KDAT_INDEX_FILE_VERSION KDAT_INDEX_FILE_VERSION_1_0
+
+// Constants for tape file format.
+#define MAX_TAPE_NAME_LEN 4096
+#define MAX_ARCHIVE_NAME_LEN 4096
+#define MAX_NUM_ARCHIVES 4096
+
+#endif
diff --git a/kdat/ktreeview.cpp b/kdat/ktreeview.cpp
new file mode 100644
index 0000000..334a834
--- /dev/null
+++ b/kdat/ktreeview.cpp
@@ -0,0 +1,2074 @@
+/*
+ * $Id$
+ *
+ * KTreeView implementation
+ *
+ * Copyright (C) 1997 Johannes Sixt
+ *
+ * based on KTreeList, which is
+ * Copyright (C) 1996 Keith Brown and KtSoft
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details. You should have received a copy
+ * of the GNU General Public License along with this program; if not, write
+ * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include <ktreeview.h>
+#include "ktreeview.moc"
+#include <qapplication.h> /* used for QApplication::closingDown() */
+#include <qkeycode.h> /* used for keyboard interface */
+#include <qpainter.h> /* used to paint items */
+#include <qscrollbar.h>
+#include <qstyle.h>
+#include <assert.h>
+
+/*
+ * -------------------------------------------------------------------
+ *
+ * KTreeViewItem
+ *
+ * -------------------------------------------------------------------
+ */
+
+// constructor
+KTreeViewItem::KTreeViewItem(const QString& theText) :
+ owner(0),
+ numChildren(0),
+ doExpandButton(true),
+ expanded(false),
+ delayedExpanding(false),
+ doTree(true),
+ doText(true),
+ child(0),
+ parent(0),
+ sibling(0),
+ deleteChildren(false)
+{
+ text = theText;
+}
+
+// constructor that takes a pixmap
+KTreeViewItem::KTreeViewItem(const QString& theText,
+ const QPixmap& thePixmap) :
+ owner(0),
+ numChildren(0),
+ doExpandButton(true),
+ expanded(false),
+ delayedExpanding(false),
+ doTree(true),
+ doText(true),
+ child(0),
+ parent(0),
+ sibling(0),
+ deleteChildren(false)
+{
+ text = theText;
+ pixmap = thePixmap;
+}
+
+// destructor
+KTreeViewItem::~KTreeViewItem()
+{
+ if (deleteChildren) {
+ // remove the children
+ KTreeViewItem* i = child;
+ while (i) {
+ KTreeViewItem* d = i;
+ i = i->getSibling();
+ delete d;
+ }
+ }
+}
+
+// appends a direct child
+void KTreeViewItem::appendChild(KTreeViewItem* newChild)
+{
+ newChild->parent = this;
+ newChild->owner = owner;
+ if (!getChild()) {
+ child = newChild;
+ }
+ else {
+ KTreeViewItem* lastChild = getChild();
+ while (lastChild->hasSibling()) {
+ lastChild = lastChild->getSibling();
+ }
+ lastChild->sibling = newChild;
+ }
+ newChild->sibling = 0;
+ numChildren++;
+}
+
+// returns the bounding rectangle of the item content (not including indent
+// and branches) for hit testing
+QRect KTreeViewItem::boundingRect(int indent) const
+{
+ const QFontMetrics& fm = owner->fontMetrics();
+ int rectX = indent;
+ int rectY = 1;
+ int rectW = width(indent, fm) - rectX;
+ int rectH = height(fm) - 2;
+ return QRect(rectX, rectY, rectW, rectH);
+}
+
+// returns the child item at the specified index
+KTreeViewItem* KTreeViewItem::childAt(int index) const
+{
+ if (!hasChild())
+ return 0;
+ KTreeViewItem* item = getChild();
+ while (index > 0 && item != 0) {
+ item = item->getSibling();
+ index--;
+ }
+ return item;
+}
+
+// returns the number of children this item has
+uint KTreeViewItem::childCount() const
+{
+ return numChildren;
+}
+
+/* returns the index of the given child item in this item's branch */
+int KTreeViewItem::childIndex(KTreeViewItem* searched) const
+{
+ assert(searched != 0);
+ int index = 0;
+ KTreeViewItem* item = getChild();
+ while (item != 0 && item != searched) {
+ item = item->getSibling();
+ index++;
+ }
+ return item == 0 ? -1 : index;
+}
+
+// indicates whether mouse press is in expand button
+inline bool KTreeViewItem::expandButtonClicked(const QPoint& coord) const
+{
+ return expandButton.contains(coord);
+}
+
+bool KTreeViewItem::mousePressEvent( const QPoint& )
+{
+ return FALSE;
+}
+
+// returns a pointer to first child item
+KTreeViewItem* KTreeViewItem::getChild() const
+{
+ return child;
+}
+
+// returns the parent of this item
+KTreeViewItem* KTreeViewItem::getParent() const
+{
+ return parent;
+}
+
+// returns reference to the item pixmap
+const QPixmap& KTreeViewItem::getPixmap() const
+{
+ return pixmap;
+}
+
+// returns the sibling below this item
+KTreeViewItem* KTreeViewItem::getSibling() const
+{
+ return sibling;
+}
+
+// returns a pointer to the item text
+const QString& KTreeViewItem::getText() const
+{
+ return text;
+}
+
+// indicates whether this item has any children
+bool KTreeViewItem::hasChild() const
+{
+ return child != 0;
+}
+
+// indicates whether this item has a parent
+bool KTreeViewItem::hasParent() const
+{
+ return parent != 0;
+}
+
+// indicates whether this item has a sibling below it
+bool KTreeViewItem::hasSibling() const
+{
+ return sibling != 0;
+}
+
+int KTreeViewItem::height() const
+{
+ assert(owner != 0);
+ return height(owner->fontMetrics());
+}
+
+// returns the maximum height of text and pixmap including margins
+// or -1 if item is empty -- SHOULD NEVER BE -1!
+int KTreeViewItem::height(const QFontMetrics& fm) const
+{
+ int maxHeight = pixmap.height();
+ int textHeight = fm.ascent() + fm.leading();
+ maxHeight = textHeight > maxHeight ? textHeight : maxHeight;
+ return maxHeight == 0 ? -1 : maxHeight + 8;
+}
+
+// inserts child item at specified index in branch
+void KTreeViewItem::insertChild(int index, KTreeViewItem* newChild)
+{
+ if (index < 0) {
+ appendChild(newChild);
+ return;
+ }
+ newChild->parent = this;
+ newChild->owner = owner;
+ if (index == 0) {
+ newChild->sibling = getChild();
+ child = newChild;
+ }
+ else {
+ KTreeViewItem* prevItem = getChild();
+ KTreeViewItem* nextItem = prevItem->getSibling();
+ while (--index > 0 && nextItem) {
+ prevItem = nextItem;
+ nextItem = prevItem->getSibling();
+ }
+ prevItem->sibling = newChild;
+ newChild->sibling = nextItem;
+ }
+ numChildren++;
+
+ if ( owner ) {
+ owner->updateVisibleItems();
+ owner->update();
+ }
+}
+
+// indicates whether this item is displayed expanded
+// NOTE: a TRUE response does not necessarily indicate the item
+// has any children
+bool KTreeViewItem::isExpanded() const
+{
+ return expanded;
+}
+
+// returns true if all ancestors are expanded
+bool KTreeViewItem::isVisible() const
+{
+ for (KTreeViewItem* p = getParent(); p != 0; p = p->getParent()) {
+ if (!p->isExpanded())
+ return false;
+ }
+ return true;
+}
+
+// paint this item, including tree branches and expand button
+void KTreeViewItem::paint(QPainter* p, int indent, const QColorGroup& cg,
+ bool highlighted) const
+{
+ assert(getParent() != 0); /* can't paint root item */
+
+ p->save();
+ p->setPen(cg.text());
+ p->setBackgroundColor(cg.base());
+
+ int cellHeight = height(p->fontMetrics());
+
+ if (doTree) {
+ paintTree(p, indent, cellHeight);
+ }
+
+ /*
+ * If this item has at least one child and expand button drawing is
+ * enabled, set the rect for the expand button for later mouse press
+ * bounds checking, and draw the button.
+ */
+ if (doExpandButton && (child || delayedExpanding)) {
+ paintExpandButton(p, indent, cellHeight);
+ }
+
+ // now draw the item pixmap and text, if applicable
+ int pixmapX = indent;
+ int pixmapY = (cellHeight - pixmap.height()) / 2;
+ p->drawPixmap(pixmapX, pixmapY, pixmap);
+
+ if (doText) {
+ paintText(p, indent, cellHeight, cg, highlighted);
+ }
+ p->restore();
+}
+
+void KTreeViewItem::paintExpandButton(QPainter* p, int indent, int cellHeight) const
+{
+ int parentLeaderX = indent - (22 / 2);
+ int cellCenterY = cellHeight / 2;
+
+ expandButton.setRect(parentLeaderX - 4, cellCenterY - 4, 9, 9);
+ p->setBrush(Qt::white);
+ p->drawRect(expandButton);
+ if (expanded) {
+ p->drawLine(parentLeaderX - 2, cellCenterY,
+ parentLeaderX + 2, cellCenterY);
+ } else {
+ p->drawLine(parentLeaderX - 2, cellCenterY,
+ parentLeaderX + 2, cellCenterY);
+ p->drawLine(parentLeaderX, cellCenterY - 2,
+ parentLeaderX, cellCenterY + 2);
+ }
+ p->setBrush(Qt::NoBrush);
+}
+
+// paint the highlight
+void KTreeViewItem::paintHighlight(QPainter* p, int indent, const QColorGroup& colorGroup,
+ bool hasFocus, Qt::GUIStyle style) const
+{
+ QColor fc;
+ if (style == Qt::WindowsStyle)
+ fc = Qt::darkBlue; /* hardcoded in Qt */
+ else
+ fc = colorGroup.text();
+ QRect textRect = textBoundingRect(indent);
+ int t,l,b,r;
+ textRect.coords(&l, &t, &r, &b);
+ p->fillRect(textRect, fc); /* draw highlight background */
+ if (hasFocus) {
+ if(style == Qt::WindowsStyle) { /* draw Windows style highlight */
+ textRect.setCoords(l - 1, t - 1, r + 1, b + 1);
+ p->setPen(QPen(Qt::yellow, 0, Qt::DotLine));
+ p->setBackgroundColor(fc);
+ p->setBackgroundMode(Qt::OpaqueMode);
+ p->drawRect(textRect);
+ textRect.setCoords(l - 2, t - 2, r + 2, b + 2);
+ p->setPen(fc);
+ p->drawRect(textRect);
+ }
+ else { /* draw Motif style highlight */
+ textRect.setCoords(l - 2, t - 2, r + 2, b + 2);
+ p->drawRect(textRect);
+ }
+ }
+}
+
+// draw the text, highlighted if requested
+void KTreeViewItem::paintText(QPainter* p, int indent, int cellHeight,
+ const QColorGroup& cg, bool highlighted) const
+{
+ int textX = indent + pixmap.width() + 4;
+ int textY = cellHeight - ((cellHeight - p->fontMetrics().ascent() -
+ p->fontMetrics().leading()) / 2);
+ if (highlighted) {
+ paintHighlight(p, indent, cg, owner->hasFocus(),
+ (Qt::GUIStyle)owner->style().styleHint(QStyle::SH_GUIStyle)); // Qt3 doesn't make this easy ;)
+ p->setPen(cg.base());
+ p->setBackgroundColor(cg.text());
+ }
+ else {
+ p->setPen(cg.text());
+ p->setBackgroundColor(cg.base());
+ }
+ p->drawText(textX, textY, text);
+}
+
+// paint the tree structure
+void KTreeViewItem::paintTree(QPainter* p, int indent, int cellHeight) const
+{
+ int parentLeaderX = indent - (22 / 2);
+ int cellCenterY = cellHeight / 2;
+ int cellBottomY = cellHeight - 1;
+ int itemLeaderX = indent - 3;
+
+ /*
+ * If this is not the first item in the tree draw the line up
+ * towards parent or sibling.
+ */
+ if (parent->parent != 0 || parent->getChild() != this)
+ p->drawLine(parentLeaderX, 0, parentLeaderX, cellCenterY);
+
+ // draw the line down towards sibling
+ if (sibling)
+ p->drawLine(parentLeaderX, cellCenterY, parentLeaderX, cellBottomY);
+
+ /*
+ * If this item has children or siblings in the tree or is a child of
+ * an item other than the root item then draw the little line from the
+ * item out to the left.
+ */
+ if (sibling || (doExpandButton && (child || delayedExpanding)) ||
+ parent->parent != 0 ||
+ /*
+ * The following handles the case of an item at the end of the
+ * topmost level which doesn't have children.
+ */
+ parent->getChild() != this)
+ {
+ p->drawLine(parentLeaderX, cellCenterY, itemLeaderX, cellCenterY);
+ }
+
+ /*
+ * If there are siblings of ancestors below, draw our portion of the
+ * branches that extend through this cell.
+ */
+ KTreeViewItem* prevRoot = parent;
+ while (prevRoot->getParent() != 0) { /* while not root item */
+ if (prevRoot->hasSibling()) {
+ int sibLeaderX = owner->indentation(prevRoot) - (22 / 2);
+ p->drawLine(sibLeaderX, 0, sibLeaderX, cellBottomY);
+ }
+ prevRoot = prevRoot->getParent();
+ }
+}
+
+// removes the given (direct) child from the branch
+bool KTreeViewItem::removeChild(KTreeViewItem* theChild)
+{
+ // search item in list of children
+ KTreeViewItem* prevItem = 0;
+ KTreeViewItem* toRemove = getChild();
+ while (toRemove && toRemove != theChild) {
+ prevItem = toRemove;
+ toRemove = toRemove->getSibling();
+ }
+
+ if (toRemove) {
+ // found it!
+ if (prevItem == 0) {
+ child = toRemove->getSibling();
+ } else {
+ prevItem->sibling = toRemove->getSibling();
+ }
+ numChildren--;
+ toRemove->owner = 0;
+ }
+ assert((numChildren == 0) == (child == 0));
+
+ if ( owner ) {
+ owner->updateVisibleItems();
+ owner->update();
+ }
+
+ return toRemove != 0;
+}
+
+// sets the delayed-expanding flag
+void KTreeViewItem::setDelayedExpanding(bool flag)
+{
+ delayedExpanding = flag;
+}
+
+// tells the item whether it shall delete child items
+void KTreeViewItem::setDeleteChildren(bool flag)
+{
+ deleteChildren = flag;
+}
+
+// sets the draw expand button flag of this item
+void KTreeViewItem::setDrawExpandButton(bool doit)
+{
+ doExpandButton = doit;
+}
+
+// sets the draw text flag of this item
+void KTreeViewItem::setDrawText(bool doit)
+{
+ doText = doit;
+}
+
+// sets the draw tree branch flag of this item
+void KTreeViewItem::setDrawTree(bool doit)
+{
+ doTree = doit;
+}
+
+// sets the expanded flag of this item
+void KTreeViewItem::setExpanded(bool is)
+{
+ expanded = is;
+ if ( owner ) {
+ owner->updateVisibleItems();
+ owner->update();
+ }
+}
+
+// sets the item pixmap to the given pixmap
+void KTreeViewItem::setPixmap(const QPixmap& pm)
+{
+ pixmap = pm;
+ if ( owner ) {
+ owner->updateVisibleItems();
+ owner->update();
+ }
+}
+
+// sets the item text to the given string
+void KTreeViewItem::setText(const QString& t)
+{
+ text = t;
+ if ( owner ) {
+ owner->updateVisibleItems();
+ owner->update();
+ }
+}
+
+// counts the child items and stores the result in numChildren
+void KTreeViewItem::synchNumChildren()
+{
+ numChildren = 0;
+ KTreeViewItem* item = getChild();
+ while (item != 0) {
+ numChildren++;
+ item = item->getSibling();
+ }
+}
+
+/*
+ * returns the bounding rect of the item text in cell coordinates couldn't
+ * get QFontMetrics::boundingRect() to work right so I made my own
+ */
+QRect KTreeViewItem::textBoundingRect(int indent) const
+{
+ const QFontMetrics& fm = owner->fontMetrics();
+ int cellHeight = height(fm);
+ int rectX = indent + pixmap.width() + 3;
+ int rectY = (cellHeight - fm.ascent() - fm.leading()) / 2 + 2;
+ int rectW = fm.width(text) + 1;
+ int rectH = fm.ascent() + fm.leading();
+ return QRect(rectX, rectY, rectW, rectH);
+}
+
+// returns the total width of text and pixmap, including margins, spacing
+// and indent, or -1 if empty -- SHOULD NEVER BE -1!
+int KTreeViewItem::width(int indent) const
+{
+ return width(indent, owner->fontMetrics());
+}
+
+int KTreeViewItem::width(int indent, const QFontMetrics& fm) const
+{
+ int maxWidth = pixmap.width();
+ maxWidth += (4 + fm.width(text));
+ return maxWidth == 0 ? -1 : indent + maxWidth + 3;
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ *
+ * KTreeView
+ *
+ * -------------------------------------------------------------------
+ */
+
+// constructor
+KTreeView::KTreeView(QWidget *parent,
+ const char *name,
+ WFlags f) :
+ QGridView(parent, name, f),
+ clearing(false),
+ current(-1),
+ drawExpandButton(true),
+ drawTree(true),
+ expansion(0),
+ goingDown(false),
+ itemIndent(22),
+ showText(true),
+ itemCapacity(500),
+ visibleItems(0),
+ rubberband_mode(false)
+{
+ setCellHeight(0);
+// setCellWidth(0);
+ setNumRows(0);
+ setNumCols(1);
+ setVScrollBarMode(Auto);
+ setHScrollBarMode(Auto);
+ //switch(style().guiStyle()) {
+ //case WindowsStyle:
+ //case MotifStyle:
+ setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
+ setBackgroundColor(colorGroup().base());
+ //break;
+ /*default:
+ setFrameStyle(QFrame::Panel | QFrame::Plain);
+ setLineWidth(1);
+ }*/
+ // setAcceptFocus(true);
+ treeRoot = new KTreeViewItem;
+ treeRoot->setExpanded(true);
+ treeRoot->owner = this;
+
+ visibleItems = new KTreeViewItem*[itemCapacity];
+ // clear those pointers
+ for (int j = itemCapacity-1; j >= 0; j--) {
+ visibleItems[j] = 0;
+ }
+}
+
+// destructor
+KTreeView::~KTreeView()
+{
+ goingDown = true;
+ clear();
+ delete[] visibleItems;
+ delete treeRoot;
+}
+
+// appends a child to the item at the given index with the given text
+// and pixmap
+void KTreeView::appendChildItem(const QString & theText, const QPixmap& thePixmap,
+ int index)
+{
+ KTreeViewItem* item = new KTreeViewItem(theText, thePixmap);
+ item->setDeleteChildren(true);
+ appendChildItem(item, index);
+}
+
+// appends a child to the item at the end of the given path with
+// the given text and pixmap
+void KTreeView::appendChildItem(const QString & theText, const QPixmap& thePixmap,
+ const KPath& thePath)
+{
+ KTreeViewItem* item = new KTreeViewItem(theText, thePixmap);
+ item->setDeleteChildren(true);
+ appendChildItem(item, thePath);
+}
+
+// appends the given item to the children of the item at the given index
+void KTreeView::appendChildItem(KTreeViewItem* newItem, int index)
+{
+ /* find parent item and append new item to parent's sub tree */
+ KTreeViewItem* parentItem = itemAt(index);
+ if (!parentItem)
+ return;
+ appendChildItem(parentItem, newItem);
+}
+
+// appends the given item to the children of the item at the end of the
+// given path
+void KTreeView::appendChildItem(KTreeViewItem* newItem, const KPath& thePath)
+{
+ /* find parent item and append new item to parent's sub tree */
+ KTreeViewItem* parentItem = itemAt(thePath);
+ if (!parentItem)
+ return;
+ appendChildItem(parentItem, newItem);
+}
+
+// indicates whether horizontal scrollbar appears only when needed
+bool KTreeView::autoBottomScrollBar() const
+{
+ return (hScrollBarMode() == Auto);
+}
+
+// indicates whether vertical scrollbar appears only when needed
+bool KTreeView::autoScrollBar() const
+{
+ return (vScrollBarMode() == Auto);
+}
+
+// indicates whether display updates automatically on changes
+bool KTreeView::autoUpdate() const
+{
+ return isUpdatesEnabled();
+}
+
+// indicates whether horizontal scrollbar is present
+bool KTreeView::bottomScrollBar() const
+{
+ return !(horizontalScrollBar()->isHidden());
+}
+
+// find item at specified index and change pixmap and/or text
+void KTreeView::changeItem(const QString & newText,
+ const QPixmap *newPixmap,
+ int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item)
+ changeItem(item, index, newText, newPixmap);
+}
+
+// find item at end of specified path, and change pixmap and/or text
+void KTreeView::changeItem(const QString & newText,
+ const QPixmap* newPixmap,
+ const KPath& thePath)
+{
+ KTreeViewItem* item = itemAt(thePath);
+ if (item) {
+ int index = itemRow(item);
+ changeItem(item, index, newText, newPixmap);
+ }
+}
+
+// clear all items from list and erase display
+void KTreeView::clear()
+{
+ setCurrentItem(-1);
+
+ /* somewhat of a hack for takeItem so it doesn't update the current item... */
+ clearing = TRUE;
+
+ bool autoU = autoUpdate();
+ setAutoUpdate(FALSE);
+ QPtrStack<KTreeViewItem> stack;
+ stack.push(treeRoot);
+ while(!stack.isEmpty()) {
+ KTreeViewItem *item = stack.pop();
+ if(item->hasChild()) {
+ stack.push(item);
+ stack.push(item->getChild());
+ }
+ else if(item->hasSibling()) {
+ stack.push(item);
+ stack.push(item->getSibling());
+ }
+ else if(item->getParent() != 0) {
+ takeItem(item);
+ delete item;
+ }
+ }
+ clearing = FALSE;
+ if(goingDown || QApplication::closingDown())
+ return;
+ if(autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+}
+
+// return a count of all the items in the tree, whether visible or not
+uint KTreeView::count()
+{
+ int total = 0;
+ forEveryItem(&KTreeView::countItem, (void *)&total);
+ return total;
+}
+
+// returns the index of the current (highlighted) item
+int KTreeView::currentItem() const
+{
+ return current;
+}
+
+// only collapses the item if it is expanded. If not expanded, or
+// index invalid, does nothing
+void KTreeView::collapseItem(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item && item->isExpanded())
+ expandOrCollapse(item);
+}
+
+// only expands the item if it is collapsed. If not collapsed, or
+// index invalid, does nothing
+void KTreeView::expandItem(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item && !item->isExpanded())
+ expandOrCollapse(item);
+}
+
+// returns the depth the tree is automatically expanded to when
+// items are added
+int KTreeView::expandLevel() const
+{
+ return expansion;
+}
+
+// expands or collapses the subtree rooted at the given item,
+// as approptiate
+// if item has no children, does nothing
+void KTreeView::expandOrCollapseItem(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item)
+ expandOrCollapse(item);
+}
+
+// visits every item in the tree, visible or not and applies
+// the user supplied function with the item and user data passed as parameters
+// if user supplied function returns true, traversal ends and function returns
+bool KTreeView::forEveryItem(KForEvery func, void* user, KTreeViewItem* item)
+{
+ if (item == 0) {
+ item = treeRoot;
+ }
+ assert(item->owner == this);
+ item = item->getChild();
+
+ while (item != 0) {
+ // visit the siblings
+ if ((*func)(item, user)) {
+ return true;
+ }
+ // visit the children (recursively)
+ if (item->hasChild()) {
+ if (forEveryItem(func, user, item))
+ return true;
+ }
+ item = item->getSibling();
+ }
+ return false;
+}
+
+// visits every visible item in the tree in order and applies the
+// user supplied function with the item and user data passed as parameters
+// if user supplied function returns TRUE, traversal ends and function
+// returns
+bool KTreeView::forEveryVisibleItem(KForEvery func, void *user,
+ KTreeViewItem* item)
+{
+ if (item == 0) {
+ item = treeRoot;
+ } else {
+ // children are invisible (hence, nothing to do)
+ // if item is invisible or collapsed
+ if (!item->isVisible() || !item->isExpanded()) {
+ return false;
+ }
+ }
+ assert(item->owner == this);
+ item = item->getChild();
+
+ while (item != 0) {
+ // visit the siblings
+ if ((*func)(item, user)) {
+ return true;
+ }
+ // visit the children (recursively)
+ if (item->hasChild() && item->isExpanded()) {
+ if (forEveryVisibleItem(func, user, item))
+ return true;
+ }
+ item = item->getSibling();
+ }
+ return false;
+}
+
+// returns a pointer to the KTreeViewItem at the current index
+// or 0 if no current item
+KTreeViewItem *KTreeView::getCurrentItem()
+{
+ if(current == -1) return 0;
+ return itemAt(current);
+}
+
+// returns the current indent spacing
+int KTreeView::indentSpacing()
+{
+ return itemIndent;
+}
+
+// inserts a new item with the specified text and pixmap before
+// or after the item at the given index, depending on the value
+// of prefix
+// if index is negative, appends item to tree at root level
+bool KTreeView::insertItem(const QString & theText, const QPixmap& thePixmap,
+ int row, bool prefix)
+{
+ KTreeViewItem* refItem = itemAt(row);
+
+ KTreeViewItem* item = new KTreeViewItem(theText, thePixmap);
+ item->setDeleteChildren(true);
+
+ bool success = insertItem(refItem, item, prefix);
+ if (!success)
+ delete item;
+ return success;
+}
+
+// inserts a new item with the specified text and pixmap before
+// or after the item at the end of the given path, depending on the value
+// of prefix
+bool KTreeView::insertItem(const QString & theText, const QPixmap& thePixmap,
+ const KPath& path, bool prefix)
+{
+ KTreeViewItem* refItem = itemAt(path);
+
+ KTreeViewItem* item = new KTreeViewItem(theText, thePixmap);
+ item->setDeleteChildren(true);
+
+ bool success = insertItem(refItem, item, prefix);
+ if (!success)
+ delete item;
+ return success;
+}
+
+// inserts the given item or derived object into the tree before
+// or after the item at the given index, depending on the value
+// of prefix
+// if index is negative, appends item to tree at root level
+bool KTreeView::insertItem(KTreeViewItem* newItem,
+ int index, bool prefix)
+{
+ // find the item currently at the index, if there is one
+ KTreeViewItem* refItem = itemAt(index);
+
+ // insert new item at the appropriate place
+ return insertItem(refItem, newItem, prefix);
+}
+
+// inserts the given item or derived object into the tree before
+// or after the item at the end of the given path, depending on the value
+// of prefix
+bool KTreeView::insertItem(KTreeViewItem* newItem,
+ const KPath& thePath, bool prefix)
+{
+ // find the item currently at the end of the path, if there is one
+ KTreeViewItem* refItem = itemAt(thePath);
+
+ // insert new item at appropriate place
+ return insertItem(refItem, newItem, prefix);
+}
+
+/*
+ * returns pointer to KTreeViewItem at the specifed row or 0 if row is out
+ * of limits.
+ */
+KTreeViewItem* KTreeView::itemAt(int row)
+{
+ if (row < 0 || row >= numRows()) {
+ return 0;
+ }
+ else {
+ // lookup the item in the list of visible items
+ assert(row < itemCapacity);
+ KTreeViewItem* i = visibleItems[row];
+ assert(i != 0);
+ return i;
+ }
+}
+
+// returns pointer to KTreeViewItem at the end of the
+// path or 0 if not found
+KTreeViewItem* KTreeView::itemAt(const KPath& path)
+{
+ if (path.isEmpty())
+ return 0;
+
+ // need a copy of the path because recursiveFind will destroy it
+ KPath pathCopy;
+ pathCopy.setAutoDelete(false);
+ pathCopy = path;
+
+ return recursiveFind(pathCopy);
+}
+
+// computes the path of the item at the specified index
+// if index is invalid, nothing is done.
+void KTreeView::itemPath(int row, KPath& path)
+{
+ KTreeViewItem* item = itemAt(row);
+ if (item != 0) {
+ itemPath(item, path);
+ }
+}
+
+// returns the row in the visible tree of the given item or
+// -1 if not found
+int KTreeView::itemRow(KTreeViewItem* item)
+{
+ if (item->owner == this) {
+ // search in list of visible items
+ for (int i = numRows()-1; i >= 0; i--) {
+ if (visibleItems[i] == item) {
+ return i;
+ }
+ }
+ }
+ // not found
+ return -1;
+}
+
+/*
+ * move the subtree at the specified index up one branch level (make root
+ * item a sibling of its current parent)
+ */
+void KTreeView::join(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item)
+ join(item);
+}
+
+/*
+ * move the subtree at the specified index up one branch level (make root
+ * item a sibling of it's current parent)
+ */
+void KTreeView::join(const KPath& path)
+{
+ KTreeViewItem *item = itemAt(path);
+ if (item)
+ join(item);
+}
+
+/* move item at specified index one slot down in its parent's sub tree */
+void KTreeView::lowerItem(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item)
+ lowerItem(item);
+}
+
+/* move item at specified path one slot down in its parent's sub tree */
+void KTreeView::lowerItem(const KPath& path)
+{
+ KTreeViewItem* item = itemAt(path);
+ if (item)
+ lowerItem(item);
+}
+
+/* move item at specified index one slot up in its parent's sub tree */
+void KTreeView::raiseItem(int index)
+{
+ KTreeViewItem* item = itemAt(index);
+ if (item)
+ raiseItem(item);
+}
+
+/* move item at specified path one slot up in its parent's sub tree */
+void KTreeView::raiseItem(const KPath& path)
+{
+ KTreeViewItem* item = itemAt(path);
+ if (item)
+ raiseItem(item);
+}
+
+// remove the item at the specified index and delete it
+void KTreeView::removeItem(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item) {
+ takeItem(item);
+ delete item;
+ }
+}
+
+// remove the item at the end of the specified path and delete it
+void KTreeView::removeItem(const KPath& thePath)
+{
+ KTreeViewItem* item = itemAt(thePath);
+ if (item) {
+ takeItem(item);
+ delete item;
+ }
+}
+
+// indicates whether vertical scrollbar is present
+bool KTreeView::scrollBar() const
+{
+ return !(verticalScrollBar()->isHidden());
+}
+
+// enables/disables auto update of display
+void KTreeView::setAutoUpdate(bool enable)
+{
+ setUpdatesEnabled(enable);
+}
+
+// enables/disables horizontal scrollbar
+void KTreeView::setBottomScrollBar(bool enable)
+{
+ setHScrollBarMode(enable ? AlwaysOn : AlwaysOff);
+}
+
+// sets the current item and hightlights it, emitting signals
+void KTreeView::setCurrentItem(int row)
+{
+ if (row == current)
+ return;
+ int numVisible = numRows();
+ if (row > numVisible) {
+ emit highlighted( current );
+ return;
+ }
+ int oldCurrent = current;
+ current = row;
+ if (oldCurrent < numVisible)
+ updateCell(oldCurrent, 0);
+ if (current > -1) {
+ updateCell(current, 0);
+ }
+
+ emit highlighted( current );
+}
+
+// enables/disables drawing of expand button
+void KTreeView::setExpandButtonDrawing(bool enable)
+{
+ if(drawExpandButton == enable)
+ return;
+ drawExpandButton = enable;
+ forEveryItem(&KTreeView::setItemExpandButtonDrawing, 0);
+ if(autoUpdate() && isVisible())
+ repaint();
+}
+
+// sets depth to which subtrees are automatically expanded, and
+// redraws tree if auto update enabled
+void KTreeView::setExpandLevel(int level)
+{
+ if(expansion == level)
+ return;
+ expansion = level;
+ KTreeViewItem *item = getCurrentItem();
+ forEveryItem(&KTreeView::setItemExpanded, 0);
+ while(item) {
+ if(item->getParent()->isExpanded())
+ break;
+ item = item->getParent();
+ }
+ setCurrentItem(itemRow(item));
+ if(autoUpdate() && isVisible())
+ repaint();
+}
+
+// sets the indent margin for all branches and repaints if auto update enabled
+void KTreeView::setIndentSpacing(int spacing)
+{
+ if (itemIndent == spacing)
+ return;
+ itemIndent = spacing;
+ updateCellWidth();
+ if (autoUpdate() && isVisible())
+ repaint();
+}
+
+// enables/disables vertical scrollbar
+void KTreeView::setScrollBar(bool enable)
+{
+ setVScrollBarMode(enable? AlwaysOn : AlwaysOff );
+}
+
+// enables/disables display of item text (keys)
+void KTreeView::setShowItemText(bool enable)
+{
+ if(showText == enable)
+ return;
+ showText = enable;
+ forEveryItem(&KTreeView::setItemShowText, 0);
+ if(autoUpdate() && isVisible())
+ repaint();
+}
+
+// indicates whether vertical scrolling is by pixel or row
+void KTreeView::setSmoothScrolling(bool enable)
+{
+ verticalScrollBar()->setLineStep(enable ? 1 : cellHeight());
+}
+
+// enables/disables tree branch drawing
+void KTreeView::setTreeDrawing(bool enable)
+{
+ if(drawTree == enable)
+ return;
+ drawTree = enable;
+ forEveryItem(&KTreeView::setItemTreeDrawing, 0);
+ if(autoUpdate() && isVisible())
+ repaint();
+}
+
+// indicates whether item text keys are displayed
+bool KTreeView::showItemText() const
+{
+ return showText;
+}
+
+// indicates whether scrolling is by pixel or row
+bool KTreeView::smoothScrolling() const
+{
+ return (verticalScrollBar()->lineStep() == 1);
+}
+
+// indents the item at the given index, splitting the tree into
+// a new branch
+void KTreeView::split(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item)
+ split(item);
+}
+
+// indents the item at the given path, splitting the tree into
+// a new branch
+void KTreeView::split(const KPath& path)
+{
+ KTreeViewItem* item = itemAt(path);
+ if (item)
+ split(item);
+}
+
+// removes item at specified index from tree but does not delete it
+// returns pointer to the item or 0 if not succesful
+KTreeViewItem *KTreeView::takeItem(int index)
+{
+ KTreeViewItem *item = itemAt(index);
+ if(item)
+ takeItem(item);
+ return item;
+}
+
+// removes item at specified path from tree but does not delete it
+// returns pointer to the item or 0 if not successful
+KTreeViewItem* KTreeView::takeItem(const KPath& path)
+{
+ KTreeViewItem* item = itemAt(path);
+ if (item)
+ takeItem(item);
+ return item;
+}
+
+// indicates whether tree branches are drawn
+bool KTreeView::treeDrawing() const
+{
+ return drawTree;
+}
+
+
+// appends a child to the specified parent item (note: a child, not a sibling, is added!)
+void KTreeView::appendChildItem(KTreeViewItem* theParent,
+ KTreeViewItem* newItem)
+{
+ theParent->appendChild(newItem);
+
+ // set item state
+ newItem->setDrawExpandButton(drawExpandButton);
+ newItem->setDrawTree(drawTree);
+ newItem->setDrawText(showText);
+ if (level(newItem) < expansion) {
+ newItem->setExpanded(true);
+ }
+
+ // fix up branch levels of any children that the new item may already have
+ if(newItem->hasChild()) {
+ fixChildren(newItem);
+ }
+
+ // if necessary, adjust cell width, number of rows and repaint
+ if (newItem->isVisible() || theParent->childCount() == 1) {
+ bool autoU = autoUpdate();
+ setAutoUpdate(false);
+ updateVisibleItems();
+ if(autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+ }
+}
+
+// changes the given item with the new text and/or pixmap
+void KTreeView::changeItem(KTreeViewItem* toChange, int itemRow,
+ const QString & newText, const QPixmap* newPixmap)
+{
+ int indent = indentation(toChange);
+ int oldWidth = toChange->width(indent);
+ if(!newText.isNull())
+ toChange->setText(newText);
+ if (newPixmap)
+ toChange->setPixmap(*newPixmap);
+ if(oldWidth != toChange->width(indent))
+ updateCellWidth();
+ if(itemRow == -1)
+ return;
+ if(autoUpdate())
+ updateCell(itemRow, 0);
+}
+
+// collapses the subtree at the specified item
+void KTreeView::collapseSubTree(KTreeViewItem* subRoot)
+{
+ assert(subRoot->owner == this);
+
+ // must move the current item if it is visible
+ KTreeViewItem* cur = current >= 0 ? itemAt(current) : 0;
+
+ subRoot->setExpanded(false);
+ if (subRoot->isVisible()) {
+ updateVisibleItems();
+ // re-seat current item
+ if (cur != 0) {
+ setCurrentItem(itemRow(cur));
+ }
+ }
+ // roland
+ repaint();
+ setAutoUpdate(TRUE);
+ // roland
+}
+
+// used by count() with forEach() function to count total number
+// of items in the tree
+bool KTreeView::countItem(KTreeViewItem*, void* total)
+{
+ int* t = static_cast<int*>(total);
+ (*t)++;
+ return false;
+}
+
+// if item is expanded, collapses it or vice-versa
+void KTreeView::expandOrCollapse(KTreeViewItem* parent)
+{
+ bool autoU = autoUpdate();
+ setAutoUpdate(false);
+ int parentIndex = itemRow(parent);
+ if (parent->isExpanded()) {
+ collapseSubTree(parent);
+ emit collapsed(parentIndex);
+ }
+ else {
+ expandSubTree(parent);
+ emit expanded(parentIndex);
+ }
+ if (autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+}
+
+// expands the subtree at the given item
+void KTreeView::expandSubTree(KTreeViewItem* subRoot)
+{
+ assert(subRoot->owner == this);
+
+ // must move the current item if it is visible
+ KTreeViewItem* cur = current >= 0 ? itemAt(current) : 0;
+
+ bool allow = true;
+
+ if (subRoot->delayedExpanding) {
+ emit expanding(subRoot, allow);
+ }
+ if (!allow)
+ return;
+
+ subRoot->setExpanded(true);
+
+ if (subRoot->isVisible()) {
+ updateVisibleItems();
+ // re-seat current item
+ if (cur != 0) {
+ setCurrentItem(itemRow(cur));
+ }
+ }
+ // roland
+ repaint();
+ setAutoUpdate(TRUE);
+ // roland
+
+}
+
+// fix up branch levels out of whack from split/join operations on the tree
+void KTreeView::fixChildren(KTreeViewItem *parentItem)
+{
+ KTreeViewItem* childItem = 0;
+ KTreeViewItem* siblingItem = 0;
+// int childBranch = parentItem->getBranch() + 1;
+ if(parentItem->hasChild()) {
+ childItem = parentItem->getChild();
+// childItem->setBranch(childBranch);
+ childItem->owner = parentItem->owner;
+ fixChildren(childItem);
+ }
+ while(childItem && childItem->hasSibling()) {
+ siblingItem = childItem->getSibling();
+// siblingItem->setBranch(childBranch);
+ siblingItem->owner = parentItem->owner;
+ fixChildren(siblingItem);
+ childItem = siblingItem;
+ }
+}
+
+// handles QFocusEvent processing by setting current item to top
+// row if there is no current item, and updates cell to add or
+// delete the focus rectangle on the highlight bar
+void KTreeView::focusInEvent(QFocusEvent *)
+{
+ if(current < 0 && numRows() > 0)
+ setCurrentItem(rowAt(contentsY()));
+ updateCell(current, 0);
+}
+
+// visits every item in the tree, visible or not and applies the user
+// supplied member function with the item and user data passed as parameters
+// if the user supplied member function returns TRUE, traversal
+// ends and the function returns
+void KTreeView::forEveryItem(KForEveryM func,
+ void *user)
+{
+ KTreeViewItem *item = treeRoot->getChild();
+ QPtrStack<KTreeViewItem> stack;
+ while(item) {
+ stack.push(item);
+ while(!stack.isEmpty()) {
+ KTreeViewItem *poppedItem = stack.pop();
+ if((this->*func)(poppedItem, user))
+ return;
+ if(poppedItem->hasChild()) {
+ KTreeViewItem *childItem = poppedItem->getChild();
+ while(childItem) {
+ stack.push(childItem);
+ childItem = childItem->getSibling();
+ }
+ }
+ }
+ item = item->getSibling();
+ }
+}
+
+// visits every visible item in the tree in order and applies the user
+// supplied member function with the item and user data passed as parameters
+// if user supplied function returns TRUE, traversal ends and function
+// returns
+void KTreeView::forEveryVisibleItem(KForEveryM func,
+ void *user)
+{
+ QPtrStack<KTreeViewItem> stack;
+ KTreeViewItem *item = treeRoot->getChild();
+ do {
+ while(item) {
+ if((this->*func)(item, user)) return;
+ if(item->hasChild() && item->isExpanded()) {
+ stack.push(item);
+ item = item->getChild();
+ }
+ else
+ item = item->getSibling();
+ }
+ if(stack.isEmpty())
+ break;
+ item = stack.pop()->getSibling();
+ } while(TRUE);
+}
+
+// called by updateCellWidth() for each item in the visible list
+bool KTreeView::getMaxItemWidth(KTreeViewItem *item, void *user)
+{
+ int indent = indentation(item);
+ int* maxW = static_cast<int*>(user);
+ int w = item->width(indent);
+ if (w > *maxW)
+ *maxW = w;
+ return false;
+}
+
+int KTreeView::indentation(KTreeViewItem* item) const
+{
+ return level(item) * itemIndent + itemIndent + 3;
+}
+
+// inserts the new item before or after the reference item, depending
+// on the value of prefix
+bool KTreeView::insertItem(KTreeViewItem* referenceItem,
+ KTreeViewItem* newItem,
+ bool prefix)
+{
+ assert(newItem != 0);
+ assert(referenceItem == 0 || referenceItem->owner == this);
+
+ /* set the new item's state */
+ newItem->setDrawExpandButton(drawExpandButton);
+ newItem->setDrawTree(drawTree);
+ newItem->setDrawText(showText);
+ if (cellHeight() == 0)
+ {
+ setCellHeight(newItem->height(fontMetrics()));
+ }
+ KTreeViewItem* parentItem;
+ if (referenceItem) {
+ parentItem = referenceItem->getParent();
+ int insertIndex = parentItem->childIndex(referenceItem);
+ if (!prefix)
+ insertIndex++;
+ parentItem->insertChild(insertIndex, newItem);
+ }
+ else {
+ // no reference item, append at end of visible tree
+ // need to repaint
+ parentItem = treeRoot;
+ parentItem->appendChild(newItem);
+ }
+
+ // set item expansion
+ if (level(newItem) < expansion)
+ newItem->setExpanded(true);
+
+ // fix up branch levels of any children
+ if (newItem->hasChild())
+ fixChildren(newItem);
+
+ // if repaint necessary, do it if visible and auto update
+ // enabled
+ if (newItem->isVisible() || parentItem->childCount() == 1) {
+ bool autoU = autoUpdate();
+ setAutoUpdate(FALSE);
+ updateVisibleItems();
+ if(autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+ }
+ return true;
+}
+
+/*
+ * returns pointer to item's path
+ */
+void KTreeView::itemPath(KTreeViewItem* item, KPath& path) const
+{
+ assert(item != 0);
+ assert(item->owner == this);
+ if (item != treeRoot) {
+ itemPath(item->getParent(), path);
+ path.push(new QString(item->getText()));
+ }
+}
+
+/*
+ * joins the item's branch into the tree, making the item a sibling of its
+ * parent
+ */
+void KTreeView::join(KTreeViewItem *item)
+{
+ KTreeViewItem *itemParent = item->getParent();
+ if(itemParent->hasParent()) {
+ bool autoU = autoUpdate();
+ setAutoUpdate(FALSE);
+ takeItem(item);
+ insertItem(itemParent, item, FALSE);
+ if(autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+ }
+}
+
+// handles keyboard interface to tree list
+void KTreeView::keyPressEvent(QKeyEvent *e)
+{
+ if(numRows() == 0)
+
+ // nothing to be done
+
+ return;
+ if(currentItem() < 0)
+
+ // if no current item, make the top item current
+
+ setCurrentItem(rowAt(contentsY()));
+ int pageSize, delta;
+ switch(e->key()) {
+ case Key_Up:
+
+ // make previous item current, scroll up if necessary
+
+ if(currentItem() > 0) {
+ setCurrentItem(currentItem() - 1);
+ ensureCellVisible(currentItem(), 0);
+ }
+ break;
+ case Key_Down:
+
+ // make next item current, scroll down if necessary
+
+ if (currentItem() < numRows() - 1) {
+ setCurrentItem(currentItem() + 1);
+ ensureCellVisible(currentItem(), 0);
+ }
+ break;
+ case Key_Next:
+
+ // move highlight one page down and scroll down
+
+ delta = QMAX(1, visibleHeight() / cellHeight());
+ setCurrentItem(QMIN(currentItem() + delta, numRows() - 1));
+ ensureCellVisible(currentItem(), 0);
+ break;
+ case Key_Prior:
+
+ // move highlight one page up and scroll up
+
+ delta = QMAX(1, visibleHeight() / cellHeight());
+ setCurrentItem(QMAX(currentItem() - delta, 0));
+ ensureCellVisible(currentItem(), 0);
+ break;
+ case Key_Plus:
+
+ // if current item has subtree and is collapsed, expand it
+
+ if(currentItem() >= 0)
+ expandItem(currentItem());
+ break;
+ case Key_Minus:
+
+ // if current item has subtree and is expanded, collapse it
+
+ if(currentItem() >= 0)
+ collapseItem(currentItem());
+ break;
+ case Key_Return:
+ case Key_Enter:
+
+ // select the current item
+
+ if(currentItem() >= 0)
+ emit selected(currentItem());
+ break;
+ default:
+ break;
+ }
+}
+
+int KTreeView::level(KTreeViewItem* item) const
+{
+ assert(item != 0);
+ assert(item->owner == this);
+ assert(item != treeRoot);
+ int l = 0;
+ item = item->parent->parent; /* since item != treeRoot, there is a parent */
+ while (item != 0) {
+ item = item->parent;
+ l++;
+ }
+ return l;
+}
+
+/* move specified item down one slot in parent's subtree */
+void KTreeView::lowerItem(KTreeViewItem *item)
+{
+ KTreeViewItem *itemParent = item->getParent();
+ uint itemChildIndex = itemParent->childIndex(item);
+ if(itemChildIndex < itemParent->childCount() - 1) {
+ bool autoU = autoUpdate();
+ setAutoUpdate(FALSE);
+ takeItem(item);
+ insertItem(itemParent->childAt(itemChildIndex), item, FALSE);
+ if(autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+ }
+}
+
+// handle mouse double click events by selecting the clicked item
+// and emitting the signal
+void KTreeView::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ // find out which row has been clicked
+
+ QPoint mouseCoord = viewportToContents(e->pos());
+ int itemClicked = rowAt(mouseCoord.y());
+
+ // if a valid row was not clicked, do nothing
+
+ if(itemClicked == -1)
+ return;
+
+ KTreeViewItem *item = itemAt(itemClicked);
+ if(!item) return;
+
+ // translate mouse coord to cell coord
+
+ int cellY = cellHeight()*itemClicked;
+ int cellX = 0;
+ QPoint cellCoord(mouseCoord.x() - cellX, mouseCoord.y() - cellY);
+
+ // hit test item
+ int indent = indentation(item);
+ if(item->boundingRect(indent).contains(cellCoord))
+ emit selected(itemClicked);
+}
+
+// handle mouse movement events
+void KTreeView::mouseMoveEvent(QMouseEvent *e)
+{
+ // in rubberband_mode we actually scroll the window now
+ if (rubberband_mode)
+ {
+ move_rubberband(e->pos());
+ }
+}
+
+
+// handle single mouse presses
+void KTreeView::mousePressEvent(QMouseEvent *e)
+{
+ // first: check which button was pressed
+
+ if (e->button() == MidButton)
+ {
+ // RB: the MMB is hardcoded to the "rubberband" scroll mode
+ if (!rubberband_mode) {
+ start_rubberband(e->pos());
+ }
+ return;
+ }
+ else if ( ( rubberband_mode ) && ( e->button() != RightButton ) )
+ {
+ // another button was pressed while rubberbanding, stop the move.
+ // RB: if we allow other buttons while rubberbanding the tree can expand
+ // while rubberbanding - we then need to reclaculate and resize the
+ // rubberband rect and show the new size
+ end_rubberband();
+ return; // should we process the button press?
+ }
+
+ // find out which row has been clicked
+ QPoint mouseCoord = viewportToContents(e->pos());
+ int itemClicked = rowAt(mouseCoord.y());
+
+ // nothing to do if not on valid row
+ if (itemClicked == -1)
+ return;
+
+ KTreeViewItem* item = itemAt(itemClicked);
+ if (!item)
+ return;
+
+ // translate mouse coord to cell coord
+ int cellX = 0;
+ int cellY = cellHeight()*itemClicked;
+ QPoint cellCoord(mouseCoord.x() - cellX, mouseCoord.y() - cellY);
+
+ /* hit expand button (doesn't set currentItem) */
+ if(item->expandButtonClicked(cellCoord)) {
+ expandOrCollapse(item);
+ }
+ // hit select button (to select/deselect the item for backup)
+ // 2002-01-20 LEW: I'm adding the emit() here so that the screen gets updated,
+ // as in KTreeView::mouseDoubleClickEvent(). KTreeViewItem::mousePressEvent()
+ // returns false, so I guess some other function is being called here.
+ else if ( item->mousePressEvent( cellCoord ) ) {
+ // Item processed the button press in localSelected(itemClicked)
+ emit selected(itemClicked);
+ }
+ // hit item (to show info on the file/dir label clicked)
+ else if (item->boundingRect(indentation(item)).contains(cellCoord)) {
+ setCurrentItem(itemClicked); // highlight item
+ if ( e->button() == RightButton ) {
+ emit popupMenu( itemClicked, mapToGlobal( QPoint( e->pos().x(), e->pos().y() ) ) );
+ }
+ }
+}
+
+// handle mouse release events
+void KTreeView::mouseReleaseEvent(QMouseEvent *e)
+{
+ /* if it's the MMB end rubberbanding */
+ if (rubberband_mode && e->button()==MidButton)
+ {
+ end_rubberband();
+ }
+}
+
+// rubberband move: draw the rubberband
+void KTreeView::draw_rubberband()
+{
+#if 0
+ /*
+ * RB: I'm using a white pen because of the XorROP mode. I would prefer
+ * to draw the rectangle in red but I don't now how to get a pen which
+ * draws red in XorROP mode (this depends on the background). In fact
+ * the color should be configurable.
+ */
+
+ if (!rubberband_mode) return;
+ QPainter paint(this);
+ paint.setPen(white);
+ paint.setRasterOp(XorROP);
+ paint.drawRect(xOffset()*viewWidth()/totalWidth(),
+ yOffset()*viewHeight()/totalHeight(),
+ rubber_width+1, rubber_height+1);
+ paint.end();
+#endif
+}
+
+// rubberband move: start move
+void KTreeView::start_rubberband(const QPoint& where)
+{
+#if 0
+ if (rubberband_mode) { // Oops!
+ end_rubberband();
+ }
+ /* RB: Don't now, if this check is necessary */
+ if (!viewWidth() || !viewHeight()) return;
+ if (!totalWidth() || !totalHeight()) return;
+
+ // calculate the size of the rubberband rectangle
+ rubber_width = viewWidth()*viewWidth()/totalWidth();
+ if (rubber_width > viewWidth()) rubber_width = viewWidth();
+ rubber_height = viewHeight()*viewHeight()/totalHeight();
+ if (rubber_height > viewHeight()) rubber_height = viewHeight();
+
+ // remember the cursor position and the actual offset
+ rubber_startMouse = where;
+ rubber_startX = xOffset();
+ rubber_startY = yOffset();
+ rubberband_mode=TRUE;
+ draw_rubberband();
+#endif
+}
+
+// rubberband move: end move
+void KTreeView::end_rubberband()
+{
+#if 0
+ if (!rubberband_mode) return;
+ draw_rubberband();
+ rubberband_mode = FALSE;
+#endif
+}
+
+// rubberband move: handle mouse moves
+void KTreeView::move_rubberband(const QPoint& where)
+{
+#if 0
+ if (!rubberband_mode) return;
+
+ // look how much the mouse moved and calc the new scroll position
+ QPoint delta = where - rubber_startMouse;
+ int nx = rubber_startX + delta.x() * totalWidth() / viewWidth();
+ int ny = rubber_startY + delta.y() * totalHeight() / viewHeight();
+
+ // check the new position (and make it valid)
+ if (nx < 0) nx = 0;
+ else if (nx > maxXOffset()) nx = maxXOffset();
+ if (ny < 0) ny = 0;
+ else if (ny > maxYOffset()) ny = maxYOffset();
+
+ // redraw the rubberband at the new position
+ draw_rubberband();
+ setOffset(nx,ny);
+ draw_rubberband();
+#endif
+}
+
+
+// paints the cell at the specified row and col
+// col is ignored for now since there is only one
+void KTreeView::paintCell(QPainter* p, int row, int)
+{
+ KTreeViewItem* item = itemAt(row);
+ if (item == 0)
+ return;
+
+ p->setClipRect(cellRect(), QPainter::CoordPainter );
+ QColorGroup cg = colorGroup();
+ int indent = indentation(item);
+ item->paint(p, indent, cg,
+ current == row); /* highlighted */
+ p->setClipping(false);
+}
+
+/* raise the specified item up one slot in parent's subtree */
+void KTreeView::raiseItem(KTreeViewItem *item)
+{
+ KTreeViewItem *itemParent = item->getParent();
+ int itemChildIndex = itemParent->childIndex(item);
+ if(itemChildIndex > 0) {
+ bool autoU = autoUpdate();
+ setAutoUpdate(FALSE);
+ takeItem(item);
+ insertItem(itemParent->childAt(--itemChildIndex), item, TRUE);
+ if(autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+ }
+}
+
+// find the item at the path
+KTreeViewItem* KTreeView::recursiveFind(KPath& path)
+{
+ if (path.isEmpty())
+ return treeRoot;
+
+ // get the next key
+ QString* searchString = path.pop();
+
+ // find the parent item
+ KTreeViewItem* parent = recursiveFind(path);
+ if (parent == 0)
+ return 0;
+
+ /*
+ * Iterate through the parent's children searching for searchString.
+ */
+ KTreeViewItem* sibling = parent->getChild();
+ while (sibling != 0) {
+ if (*searchString == sibling->getText()) {
+ break; /* found it! */
+ }
+ sibling = sibling->getSibling();
+ }
+ return sibling;
+}
+
+// called by setExpandLevel for each item in tree
+bool KTreeView::setItemExpanded(KTreeViewItem *item, void *)
+{
+ if (level(item) < expansion) {
+ if(item->hasChild() && !item->isExpanded())
+ expandSubTree(item);
+ else
+ item->setExpanded(TRUE);
+ }
+ else {
+ if (item->hasChild() && item->isExpanded())
+ collapseSubTree(item);
+ else
+ item->setExpanded(FALSE);
+ }
+ return FALSE;
+}
+
+// called by setExpandButtonDrawing for every item in tree
+bool KTreeView::setItemExpandButtonDrawing(KTreeViewItem *item,
+ void *)
+{
+ item->setDrawExpandButton(drawExpandButton);
+ return FALSE;
+}
+
+// called by setShowItemText for every item in tree
+bool KTreeView::setItemShowText(KTreeViewItem *item,
+ void *)
+{
+ item->setDrawText(showText);
+ return FALSE;
+}
+
+// called by setTreeDrawing for every item in tree
+bool KTreeView::setItemTreeDrawing(KTreeViewItem *item, void *)
+{
+ item->setDrawTree(drawTree);
+ return FALSE;
+}
+
+// makes the item a child of the item above it, splitting
+// the tree into a new branch
+void KTreeView::split(KTreeViewItem *item)
+{
+ KTreeViewItem *itemParent = item->getParent();
+ int itemChildIndex = itemParent->childIndex(item);
+ if(itemChildIndex == 0)
+ return;
+ bool autoU = autoUpdate();
+ setAutoUpdate(FALSE);
+ takeItem(item);
+ appendChildItem(itemParent->childAt(--itemChildIndex), item);
+ if(autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+}
+
+// removes the item from the tree without deleting it
+void KTreeView::takeItem(KTreeViewItem* item)
+{
+ assert(item->owner == this);
+
+ // TODO: go over this function again
+
+ bool wasVisible = item->isVisible();
+ /*
+ * If we have a current item, make sure that it is not in the subtree
+ * that we are about to remove. If the current item is in the part
+ * below the taken-out subtree, we must move it up a number of rows if
+ * the taken-out subtree is at least partially visible.
+ */
+ KTreeViewItem* cur = current >= 0 ? itemAt(current) : 0;
+ if (wasVisible && cur != 0) {
+ KTreeViewItem* c = cur;
+ while (c != 0 && c != item) {
+ c = c->getParent();
+ }
+ if (c != 0) {
+ // move current item to parent
+ cur = item->getParent();
+ if (cur == treeRoot)
+ cur = 0;
+ }
+ }
+ KTreeViewItem* parentItem = item->getParent();
+ parentItem->removeChild(item);
+ item->sibling = 0;
+ if (wasVisible || parentItem->childCount() == 0) {
+ bool autoU = autoUpdate();
+ setAutoUpdate(FALSE);
+ updateVisibleItems();
+
+ if (autoU && isVisible())
+ repaint();
+ setAutoUpdate(autoU);
+ }
+
+ // re-seat the current item
+ setCurrentItem(cur != 0 ? itemRow(cur) : -1);
+}
+
+// visits each item, calculates the maximum width
+// and updates QGridView
+void KTreeView::updateCellWidth()
+{
+ // make cells at least 1 pixel wide to avoid singularities (division by zero)
+ int maxW = 1;
+ forEveryVisibleItem(&KTreeView::getMaxItemWidth, &maxW);
+ maxItemWidth = maxW;
+ setCellWidth(maxW);
+ update();
+}
+
+void KTreeView::updateVisibleItems()
+{
+ int index = 0;
+ int count = 0;
+ updateVisibleItemRec(treeRoot, index, count);
+ assert(index == count);
+ setNumRows(count);
+ updateCellWidth();
+}
+
+void KTreeView::updateVisibleItemRec(KTreeViewItem* item, int& index, int& count)
+{
+ if (!item->isExpanded()) {
+ // no visible items if not expanded
+ return;
+ }
+
+ /*
+ * Record the children of item in the list of visible items.
+ *
+ * Don't register item itself, it's already in the list. Also only
+ * allocate new space for children.
+ */
+ count += item->childCount();
+ if (count > itemCapacity) {
+ // must reallocate
+ int newCapacity = itemCapacity;
+ do {
+ newCapacity += newCapacity;
+ } while (newCapacity < count);
+ KTreeViewItem** newItems = new KTreeViewItem*[newCapacity];
+ // clear the unneeded space
+ for (int i = index; i < newCapacity; i++) {
+ newItems[i] = 0;
+ }
+ // move already accumulated items over
+ for (int i = index-1; i >= 0; i--) {
+ newItems[i] = visibleItems[i];
+ }
+ delete[] visibleItems;
+ visibleItems = newItems;
+ itemCapacity = newCapacity;
+ }
+ // insert children
+ for (KTreeViewItem* i = item->getChild(); i != 0; i = i->getSibling()) {
+ visibleItems[index++] = i;
+ updateVisibleItemRec(i, index, count);
+ }
+}
diff --git a/kdat/ktreeview.h b/kdat/ktreeview.h
new file mode 100644
index 0000000..ad1fe6b
--- /dev/null
+++ b/kdat/ktreeview.h
@@ -0,0 +1,899 @@
+/*
+ * KTreeView class interface
+ *
+ * Copyright (C) 1997 Johannes Sixt
+ *
+ * based on KTreeList, which is
+ * Copyright (C) 1996 Keith Brown and KtSoft
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details. You should have received a copy
+ * of the GNU General Public License along with this program; if not, write
+ * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef KDE_KTREE_VIEW_H
+#define KDE_KTREE_VIEW_H
+
+#include <qpixmap.h> /* used in items */
+#include <qptrstack.h> /* used to specify tree paths */
+#include <qstring.h> /* used in items */
+#include <qgridview.h> /* base class for widget */
+
+// use stack of strings to represent path information
+typedef QPtrStack<QString> KPath;
+
+class KTreeView; /* forward declaration */
+
+/** Items for the KTreeView widget */
+class KTreeViewItem
+{
+ friend class KTreeView;
+public:
+ /**
+ * Item constructor. While text defaults to a null string, and the
+ * item can be constructed this way, the text has to be non-null when
+ * the item is added to the tree, or it will not be inserted.
+ *
+ * The constructor sets the delete-children flag to false. This flag
+ * tells the item whether it shall delete the child items when it is
+ * itself deleted. By default the creator of the item is responsible to
+ * also delete the child items. (However, the versions of
+ * KTreeView::appendChildItem and KTreeView::insertChildItem that do
+ * not take a KTreeViewItem set the delete-children flag to true.)
+ */
+ KTreeViewItem(const QString& theText = QString()); // text can not be null when added to the list!
+ KTreeViewItem(const QString& theText, const QPixmap& thePixmap);
+
+ /**
+ * Destructor. It destroys its children if this item has been marked
+ * with setDeleteChildren(true).
+ */
+ virtual ~KTreeViewItem();
+
+ /**
+ * Appends a new (direct) child item at the end. It does not update
+ * administrative data in newChild except for its parent (which is this
+ * item) and owner.
+ */
+ void appendChild(KTreeViewItem* newChild);
+
+ /**
+ * Returns a pointer to the child item at the given index in this
+ * item's sub tree, or 0 if not found.
+ */
+ KTreeViewItem* childAt(int index) const;
+
+ /**
+ * Returns the number of child items in this item's sub tree.
+ */
+ uint childCount() const;
+
+ /**
+ * Returns the index in this items sub tree of the given item or -1 if
+ * not found. The specified child must not be 0.
+ */
+ int childIndex(KTreeViewItem* child) const;
+
+ /**
+ * Determines whether the specified point is inside the expand button.
+ */
+ bool expandButtonClicked(const QPoint& coord) const;
+
+ /**
+ * Give the item a chance to process the mouse event.
+ */
+ virtual bool mousePressEvent( const QPoint& coord );
+
+ /**
+ * Returns a pointer to the first child item in this item's sub tree, or
+ * 0 if none.
+ */
+ KTreeViewItem* getChild() const;
+
+ /**
+ * Returns a pointer to the parent of this item, or 0 if none.
+ */
+ KTreeViewItem* getParent() const;
+
+ /**
+ * Returns a reference to this item's pixmap. If there is no pixmap
+ * associated with this item, it will return a reference to a valid,
+ * null QPixmap.
+ */
+ const QPixmap& getPixmap() const;
+
+ /**
+ * Returns a pointer to the next item in the same branch below this
+ * one, or 0 if none.
+ */
+ KTreeViewItem* getSibling() const;
+
+ /**
+ * Returns this item's text.
+ */
+ const QString& getText() const;
+
+ /**
+ * Indicates whether this item has any children.
+ */
+ bool hasChild() const;
+
+ /**
+ * Indicates whether this item has a parent.
+ */
+ bool hasParent() const;
+
+ /**
+ * Indicates whether this item has a sibling item, that is, an item
+ * that would be displayed below it at the same level as this item.
+ */
+ bool hasSibling() const;
+
+ /**
+ * Inserts the a new (direct) child in this item before the child at
+ * the specified index (first child is index 0). If there is no child
+ * at the specified index, the item is appended. It does not update
+ * administrative data in newChild except for its parent (which is this
+ * item) and owner.
+ */
+ void insertChild(int index, KTreeViewItem* newChild);
+
+ /**
+ * Indicateds whether the item is expanded, that is, whether the child
+ * items (if any) would be visible if this item were visible.
+ *
+ * Note: If this function returns true, it does not necessarily indicate that
+ * this item is visible or that this item has any children.
+ */
+ bool isExpanded() const;
+
+ /**
+ * Returns true if the item is visible. An item is visible if all its
+ * ancestors are expanded.
+ */
+ bool isVisible() const;
+
+ /**
+ * Removes the specified (direct) child from this item and returns
+ * true. If it is not a direct child of this item, nothing happens, and
+ * false is returned. This function does not update the owning
+ * KTreeView.
+ */
+ bool removeChild(KTreeViewItem* child);
+
+ /**
+ * Sets the delayed-expanding flag. If this flag is true, the expanding
+ * signal is emitted when the item is about to be expanded. The expand
+ * button is always painted for this item, even if it doesn't have
+ * children.
+ */
+ void setDelayedExpanding(bool flag);
+
+ /**
+ * Tells the item whether it should delete its children when it is
+ * deleted. The default is false, which means that the child items must
+ * be deleted explicitly.
+ */
+ void setDeleteChildren(bool flag);
+
+ void setDrawExpandButton(bool doit);
+
+ void setDrawText(bool doit);
+
+ void setDrawTree(bool doit);
+
+ void setExpanded(bool is);
+
+ /**
+ * Sets the item pixmap to the given pixmap. It does not redraw the
+ * item or update the owning KTreeView.
+ */
+ void setPixmap(const QPixmap& pm);
+
+ /**
+ * Sets the item text. This function does not redraw the item or update
+ * the owning KTreeView.
+ */
+ void setText(const QString& t);
+
+protected:
+ /**
+ * Returns the bounding rectangle of the item.
+ */
+ virtual QRect boundingRect(int indent) const;
+
+ /**
+ * Returns the hieght of the item. The default implementation uses font
+ * metrics of the owning KTreeView widget.
+ */
+ virtual int height() const;
+
+ /*
+ * Returns the height of the item depending on the passed-in font
+ * metrics.
+ */
+ virtual int height(const QFontMetrics& fm) const;
+
+ /**
+ * Paints the item: pixmap, text, expand button, parent branches
+ */
+ virtual void paint(QPainter* p, int indent,
+ const QColorGroup& cg, bool highlighted) const;
+
+ /**
+ * paints the expand button
+ */
+ virtual void paintExpandButton(QPainter* p, int indent, int cellHeight) const;
+
+ /**
+ * paints the highlighted text
+ */
+ virtual void paintHighlight(QPainter* p, int indent,
+ const QColorGroup& cg, bool hasFocus,
+ Qt::GUIStyle style) const;
+
+ /**
+ * paints the item's text
+ */
+ virtual void paintText(QPainter* p, int indent, int cellHeight,
+ const QColorGroup& cg, bool highlighted) const;
+
+ /**
+ * paints the item's tree part.
+ */
+ virtual void paintTree(QPainter* p, int indent, int cellHeight) const;
+
+ /**
+ * Internal function that counts the number of child items.
+ */
+ void synchNumChildren();
+
+ /**
+ * Returns the bounding rectangle of the text.
+ */
+ virtual QRect textBoundingRect(int indent) const;
+
+ /**
+ * Returns the width of the item taking into account the specified
+ * indentation. The default implementation uses font metrics of the
+ * owning KTreeView widget.
+ */
+ virtual int width(int indent) const;
+
+ /**
+ * Returns the width of the item depending on the passed-in font
+ * metrics and taking into account the specified indentation.
+ */
+ virtual int width(int indent, const QFontMetrics& fm) const;
+
+protected:
+ /** The KTreeView that this item belongs to */
+ KTreeView* owner;
+ int numChildren;
+ bool doExpandButton;
+ bool expanded;
+ bool delayedExpanding;
+ bool doTree;
+ bool doText;
+ mutable QRect expandButton; /* is set in paint() */
+ KTreeViewItem* child;
+ KTreeViewItem* parent;
+ KTreeViewItem* sibling;
+ QPixmap pixmap;
+ QString text;
+ bool deleteChildren;
+};
+
+// easier declarations of function prototypes for forEvery type functions
+typedef bool (KTreeView::*KForEveryM)
+ (KTreeViewItem *, void *);
+typedef bool (*KForEvery)
+ (KTreeViewItem *, void *);
+
+/**
+ A collapsible treelist widget.
+
+ 1. Introduction
+ 2. Features
+ 3. Installation
+ 4. Public interface
+
+ 1. Introduction
+ ================================================================================
+
+ KTreeView is a class inherited from QTableView in the Qt user interface
+ library. It provides a way to display hierarchical data in a single-inheritance
+ tree, similar to tree controls in Microsoft Windows and other GUI's. It is most
+ suitable for directory trees or outlines, but I'm sure other uses will come to
+ mind. Frankly, it was designed mostly with the above two functions in mind, but
+ I have tried to make it as flexible as I know how to make it easy to adapt to
+ other uses.
+
+ In case of problems, I encourage you to read all of the other documentation
+ files in this package before contacting me as you may find the answer to your
+ question in one of them. Also read the source code if you have time. I have
+ tried to comment it adequately and make the source understandable.
+
+ 2. Features
+ ================================================================================
+
+ * Displays both text and optional pixmap supplied by the programmer. A support
+ class, KTreeViewItem, can be inherited and modified to draw items as needed
+ by the programmer.
+
+ * The list items can be returned by index or logical path and the tree
+ navigated by parent, child or sibling references contained in them. Also,
+ item information such as text, pixmap, branch level can be obtained.
+
+ * Items can be inserted, changed and removed either by index in the visible
+ structure, or by logical paths through the tree hierarchy.
+
+ * The logical path through the tree for any item can be obtained with the index
+ of the item.
+
+ * Tree structure display and expanding/collapsing of sub-trees is handled with
+ no intervention from the programmer.
+
+ * entire tree can be expanded or collapsed to a specified sub-level (handy for
+ outline views)
+
+ * Configuration as follows:
+
+ enable/disable item text display (if you only want to display pixmaps)
+
+ enable/disable drawing of expand/collapse button
+
+ enable/disable drawing of tree structure
+
+ * Keyboard support as follows:
+
+ up/down arrows move the highlight appropriately and scroll the list an item at
+ a time, if necessary
+
+ pgup/pgdn move the highlight a 'page' up or down as applicable and scroll the
+ view
+
+ +/- keys expand/collapse the highlighted item if it appropriate
+
+ enter key selects the highlighted item
+
+ * Mouse support as follows:
+
+ left click on item highlights it
+
+ left click on an item "hot button" expands or collapses its sub-tree, as
+ applicable
+
+ double click on item selects it
+
+ normal scrolling functions in conjunction with scrollbars if present
+
+ 2nd scrolling with the middle mouse button: pressing MMB inserts a
+ rubberband, showing which part of the whole tree is currently visible.
+ moving the mouse will scroll the visible part
+
+ * Signals/Slots
+
+ signal void highlighted(int) - emitted when an item in the tree is
+ highlighted; sends the index of the item
+
+ signal void selected(int) - emitted when an item in the tree is
+ selected; sends the index of the item
+
+ signal void expanded(int) - emitted when an item in the tree is expanded;
+ sends the index of the item
+
+ signal void collpased(int) - emitted when an item in the tree is collapsed;
+ sends the index of the item
+ */
+class KTreeView : public QGridView
+{
+ friend class KTreeViewItem;
+ Q_OBJECT
+public:
+ /**
+ * Widget contructor. Passes all parameters on to base QTableView, and
+ * does not use them directly. Does internal initialization, sets the
+ * current item to -1, and sets default values for scroll bars (both
+ * auto).
+ */
+ KTreeView(QWidget* parent = 0, const char* name = 0, WFlags f = 0);
+
+ /*
+ * Desctructor. Deletes all items from the topmost level that have been
+ * marked with setDeleteChildren(true).
+ */
+ virtual ~KTreeView();
+
+ /**
+ * Appends a new child item to the item at the specified row. If that
+ * item already has children, the new item is appended below these
+ * children. A KTreeViewItem is created for which the delete-children
+ * flag is set to true.
+ */
+ void appendChildItem(const QString & theText, const QPixmap& thePixmap,
+ int index);
+
+ /**
+ * Same as above except that the parent item is specified by a path.
+ */
+ void appendChildItem(const QString & theText, const QPixmap& thePixmap,
+ const KPath& thePath);
+
+ /**
+ * Appendss the specified item as a child of the item that is at the
+ * specified row. If that item already has children, the new item is
+ * appended below these children.
+ */
+ void appendChildItem(KTreeViewItem* newItem, int index);
+
+ /**
+ * Same as above except that the parent item is specified by a path.
+ */
+ void appendChildItem(KTreeViewItem* newItem, const KPath& thePath);
+
+ /**
+ Returns a bool value indicating whether the list will display a
+ horizontal scrollbar if one of the displayed items is wider than can
+ be displayed at the current width of the view.
+ */
+ bool autoBottomScrollBar() const;
+
+ /**
+ Returns a bool value indicating whether the list will display a
+ vertical scrollbar if the number of displayed items is more than can
+ be displayed at the current height of the view.
+ */
+ bool autoScrollBar() const;
+
+ /**
+ Returns a bool value indicating whether the list will update
+ immediately on changing the state of the widget in some way.
+ */
+ bool autoUpdate() const;
+
+ /**
+ Returns a bool value indicating whether the list has currently has a
+ horizontal scroll bar.
+ */
+ bool bottomScrollBar() const;
+
+ /**
+ Changes the text and/or pixmap of the given item at the specified
+ index to the given values and updates the display if auto update
+ enabled. If changing only the text or pixmap, set the other parameter
+ to 0.
+ */
+ void changeItem(const QString & newText,
+ const QPixmap *newPixmap,
+ int index);
+
+ /**
+ Same as above function, except item to change is specified by a path
+ through the tree.
+ */
+ void changeItem(const QString & newText,
+ const QPixmap *newPixmap,
+ const KPath& thePath);
+
+ /**
+ Removes all items from the tree.
+
+ */
+ void clear();
+
+ /**
+ Returns the total number of items in the tree, whether visible
+ (expanded sub-trees) or not (collapsed).
+ */
+ uint count();
+
+ /**
+ Returns the index of the current (highlighted) item. If no current
+ item, returns -1.
+ */
+ int currentItem() const;
+
+ /**
+ Collapses the sub-tree at the specified index.
+ */
+ void collapseItem(int index);
+
+ /**
+ Expands the sub-tree at the specified index.
+ */
+ void expandItem(int index);
+
+ /**
+ Returns the depth to which all parent items are automatically
+ expanded.
+ */
+ int expandLevel() const;
+
+ /**
+ Same as above functions combined into one. If sub-tree is expanded,
+ collapses it, if it is collapsed, it expands it.
+ */
+ void expandOrCollapseItem(int index);
+
+ /**
+ * Iterates every item in the tree, visible or not, and applies the
+ * function func with a pointer to each item and user data supplied as
+ * parameters. The children of the specified root item are visited
+ * (root itself is not visited!). If root is 0 all items in the tree
+ * are visited. KForEveryFunc is defined as:
+ *
+ * typedef bool (*KForEvery)(KTreeViewItem*, void*);
+ *
+ * That is, a function that returns bool and takes a pointer to a
+ * KTreeViewItem and pointer to void as parameters. The traversal ends
+ * earlier if the supplied function returns bool. In this case the
+ * return value is also true.
+ */
+ bool forEveryItem(KForEvery func, void* user,
+ KTreeViewItem* root = 0);
+
+ /**
+ * Same as above, but only iterates visible items, in order. If the
+ * specified root item is invisible no items are visited.
+ */
+ bool forEveryVisibleItem(KForEvery func, void *user,
+ KTreeViewItem* root = 0);
+
+ /**
+ Returns a pointer to the current item if there is one, or 0.
+ */
+ KTreeViewItem *getCurrentItem();
+
+ /**
+ * Returns the number of pixels an item is indented for each level. If,
+ * in a derived class, the levels are indented differently this value
+ * may be ignored.
+ */
+ int indentSpacing();
+
+ /**
+ * Inserts an item into the tree with the given text and pixmap either
+ * before or after the item currently at the given row, depending on
+ * the value of prefix. The new item is added to the same branch as the
+ * referenced item. If row is -1, the item is simply appended to the
+ * tree at the topmost level. A KTreeViewItem is created for which the
+ * delete-children flag is set to true. Returns true if the item has
+ * been successfully inserted in the tree, otherwise false.
+ */
+ bool insertItem(const QString & theText, const QPixmap& thePixmap,
+ int row = -1, bool prefix = true);
+
+ /**
+ * Same as above, but uses a path through the tree to reference the
+ * insert position. If there is no item at the specified path, the item
+ * is simply appended to the tree at the topmost level.
+ */
+ bool insertItem(const QString & theText, const QPixmap& thePixmap,
+ const KPath& thePath, bool prefix = true);
+
+ /**
+ * Same as above, but an item is specified instead of a text and a pixmap.
+ */
+ bool insertItem(KTreeViewItem *newItem,
+ int row = -1, bool prefix = true);
+
+ /**
+ * Same as above, but uses a path through the tree to reference the
+ * insert position.
+ */
+ bool insertItem(KTreeViewItem *newItem,
+ const KPath& thePath, bool prefix = true);
+
+ /**
+ * Returns a pointer to the item in the specified row, or 0 if the
+ * specified row is outside the limits. This is a cheap operation.
+ */
+ KTreeViewItem* itemAt(int row);
+
+ /**
+ * Returns a pointer to the item at the end of the path.
+ */
+ KTreeViewItem* itemAt(const KPath& path);
+
+ /**
+ * Returns the row at which the specified item is found in the visible
+ * tree or -1 if the item is not visible or not in the tree.
+ */
+ int itemRow(KTreeViewItem* item);
+
+ /**
+ * Fills path with the logical path to the item at the specified row.
+ * The specified path variable should be empty. Any strings popped from
+ * the path must be deleted by the caller. If the row is invalid, path
+ * remains unchanged (i.e. empty).
+ */
+ void itemPath(int row, KPath& path);
+
+ /**
+ * Outdents the item at the given row one level so that it becomes a
+ * sibling of its parent.
+ */
+ void join(int index);
+
+ /**
+ * Same as above but uses a path to specify the item.
+ */
+ void join(const KPath& path);
+
+ /**
+ * Moves the item at the specified row down one row in its current
+ * branch.
+ */
+ void lowerItem(int index);
+
+ /**
+ * Same as above but uses a path to specify the item.
+ */
+ void lowerItem(const KPath& path);
+
+ /**
+ * Moves the item at the specified row up one row in its current
+ * branch.
+ */
+ void raiseItem(int row);
+
+ /**
+ * Same as above but uses a path to specify the item.
+ */
+ void raiseItem(const KPath& path);
+
+ /**
+ * Removes the item at the specified row.
+ */
+ void removeItem(int row);
+
+ /**
+ * Same as above except uses path through the tree to find the item.
+ */
+ void removeItem(const KPath& thePath);
+
+ /**
+ Returns bool value indicating whether the list currently displays a
+ vertical scroll bar.
+ */
+ bool scrollBar() const;
+
+ /**
+ If enable is TRUE (default), enables auto update, else disables it.
+ */
+ void setAutoUpdate(bool enable);
+
+ /**
+ If enable is TRUE, displays a horizontal scroll bar, else hides it.
+ */
+ void setBottomScrollBar(bool enable);
+
+ /**
+ * Makes the item at row current and highlights it. The signal
+ * highlighted is emitted if the current item changes.
+ */
+ void setCurrentItem(int row);
+
+ void setExpandButtonDrawing(bool enable);
+
+ void setExpandLevel(int level);
+
+ /**
+ * Sets the indentation stepping, in pixels. If, in a derived class,
+ * the levels are indented differently this value may be ignored.
+ */
+ void setIndentSpacing(int spacing);
+
+ /**
+ If enable is TRUE, displays a vertical scroll bar, else hides it.
+ */
+ void setScrollBar(bool enable);
+
+ /**
+ If enable is TRUE (default), item text will be displayed, otherwise
+ it will not, and no highlight will be shown in the default widget.
+ */
+ void setShowItemText(bool enable);
+
+ /**
+ If enable is TRUE, enables smooth scrolling, else disables
+ it (default).
+ */
+ void setSmoothScrolling(bool enable);
+
+ /**
+ If enable is TRUE (default), lines depicting the structure of the
+ tree will be drawn, otherwise they will not.
+ */
+ void setTreeDrawing(bool enable);
+
+ /**
+ Indicates whether item text is displayed.
+ */
+ bool showItemText() const;
+
+ /**
+ Returns a bool value indicating whether smooth scrolling is enabled.
+ */
+ bool smoothScrolling() const;
+
+ /**
+ * Indents the item at the specified index, creating a new branch.
+ */
+ void split(int index);
+
+ /**
+ * Same as above but uses a path to specify the item.
+ */
+ void split(const KPath& path);
+
+ /**
+ * Removes the item at the given index from the tree, but does not
+ * delete it, returning a pointer to the removed item.
+ */
+ KTreeViewItem* takeItem(int index);
+
+ /**
+ * Same as above but uses a path to specify the item to take.
+ */
+ KTreeViewItem* takeItem(const KPath& path);
+
+ /**
+ Indicates whether the tree structure is drawn.
+ */
+ bool treeDrawing() const;
+
+ /**
+ * This function is deprecated. Use numRows() instead.
+ * Returns the number of items that are visible (their parents are
+ * expanded).
+ */
+ int visibleCount() const { return numRows(); }
+
+signals:
+ void collapsed(int index);
+ void expanded(int index);
+ /**
+ * The expanding signal is emitted when an item that has the
+ * delayedExpanding flag set is about to be expanded. The
+ * delayedExpanding flag is not reset; the slot that the signal is
+ * connected to should do so. The item being expanded is passed to the
+ * slot. The slot gets the opportunity to insert child items into that
+ * item. It should not change the item any other way. It can allow or
+ * disallow the expansion by setting the second parameter allow. If it
+ * is set to false, the item is not expanded.
+ *
+ * The signal is always emitted, regardless whether the expansion was
+ * triggered by the user or by the program.
+ */
+ void expanding(KTreeViewItem* item, bool& allow);
+ void highlighted(int index);
+ void selected(int index);
+
+ void popupMenu( int index, const QPoint& );
+protected:
+ /**
+ * Appends theChild to theParent as a new direct child. All internal
+ * state is updated and the widget is repainted as necessary. theChild
+ * remains invisible if any ancestor of theParent is collapsed.
+ */
+ void appendChildItem(KTreeViewItem* theParent,
+ KTreeViewItem* theChild);
+ void changeItem(KTreeViewItem* toChange,
+ int itemRow, const QString & newText,
+ const QPixmap* newPixmap);
+ /**
+ * Collapses the specified subtree and updates the display. subRoot
+ * need not be visible.
+ */
+ void collapseSubTree(KTreeViewItem* subRoot);
+ /** Internal function used for counting items */
+ bool countItem(KTreeViewItem* item, void* total);
+
+ void expandOrCollapse(KTreeViewItem *parentItem);
+ /**
+ * Expands the specified subtree and updates the display. subRoot need
+ * not be visible.
+ */
+ void expandSubTree(KTreeViewItem* subRoot);
+ void fixChildren(KTreeViewItem *parentItem);
+ virtual void focusInEvent(QFocusEvent *e);
+ void forEveryItem(KForEveryM func,
+ void *user);
+ void forEveryVisibleItem(KForEveryM func,
+ void *user);
+
+ /** internal function used to determine maximum item width */
+ bool getMaxItemWidth(KTreeViewItem* item, void *user);
+
+ /**
+ * Returns the indentation of the specified item in pixels.
+ */
+ virtual int indentation(KTreeViewItem* item) const;
+
+ /**
+ * Inserts the specified newItem before or after the specified
+ * referenceItem. If referenceItem is 0, the newItem is appended at the
+ * topmost level. If referenceItem is not 0, it must be an item that is
+ * already in the KTreeView. Internal data is updated and the display
+ * is refreshed as necessary. The inserted item may still be invisible
+ * if any of the parents is collapsed. newItem must not be 0.
+ */
+ bool insertItem(KTreeViewItem* referenceItem, KTreeViewItem* newItem,
+ bool prefix);
+
+ /**
+ * Finds the logical path of the specified item. The specified path
+ * variable should be empty.
+ */
+ void itemPath(KTreeViewItem* item, KPath& path) const;
+
+ void join(KTreeViewItem *item);
+ virtual void keyPressEvent(QKeyEvent *e);
+ int level(KTreeViewItem* item) const;
+ void lowerItem(KTreeViewItem *item);
+ virtual void mouseDoubleClickEvent(QMouseEvent *e);
+ virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void mouseReleaseEvent(QMouseEvent *e);
+ virtual void paintCell(QPainter *p, int row, int col);
+ /*
+ * virtual void paintItem(QPainter *p, KTreeViewItem *item,
+ * bool highlighted);
+ */
+ void raiseItem(KTreeViewItem* item);
+
+ /**
+ * Internal function that finds the item at the given path. Returns 0
+ * if the item cannot be found. The path is destroyed by this function.
+ */
+ KTreeViewItem* recursiveFind(KPath& path);
+
+ bool setItemExpanded(KTreeViewItem *item, void *);
+ bool setItemExpandButtonDrawing(KTreeViewItem *item, void *);
+ bool setItemShowText(KTreeViewItem *item, void *);
+ bool setItemTreeDrawing(KTreeViewItem *item, void *);
+ void split(KTreeViewItem *item);
+public:
+ void takeItem(KTreeViewItem *item);
+protected:
+ virtual void updateCellWidth();
+ virtual void updateVisibleItems();
+ void updateVisibleItemRec(KTreeViewItem* parent, int& count, int& width);
+
+ KTreeViewItem* treeRoot;
+ bool clearing;
+ int current;
+ bool drawExpandButton;
+ bool drawTree;
+ int expansion;
+ bool goingDown;
+ int itemIndent;
+ int maxItemWidth;
+ bool showText;
+ // list of visible items
+ int itemCapacity; /* for how many items we've space allocated */
+ KTreeViewItem** visibleItems;
+
+ // Rainer Bawidamann: move window in "rubberband" mode
+ bool rubberband_mode; // true if in "rubberband_mode"
+ QPoint rubber_startMouse; // where the user pressed the MMB
+ int rubber_height, rubber_width, // the size if the rubberband rect
+ rubber_startX, rubber_startY; // the x/yOffset() when the MMB was pressed
+ void draw_rubberband();
+ void start_rubberband(const QPoint& where);
+ void end_rubberband();
+ void move_rubberband(const QPoint& where);
+};
+
+#endif // KDE_KTREE_VIEW_H
diff --git a/kdat/large-kdat.png b/kdat/large-kdat.png
new file mode 100644
index 0000000..737972d
--- /dev/null
+++ b/kdat/large-kdat.png
Binary files differ
diff --git a/kdat/main.cpp b/kdat/main.cpp
new file mode 100644
index 0000000..0d17ce8
--- /dev/null
+++ b/kdat/main.cpp
@@ -0,0 +1,97 @@
+// KDat - a tar-based DAT archiver
+// Copyright (C) 1998-2000 Sean Vyain, svyain@mail.tds.net
+// Copyright (C) 2001-2002 Lawrence Widman, kdat@cardiothink.com
+//
+// This program is free software; you can redistribute it and/or modify
+// it under 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <qfile.h>
+#include <qdir.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kcrash.h>
+#include <kmessagebox.h>
+
+#include <signal.h>
+
+#include "kdat.h"
+#include "KDatMainWindow.h"
+
+static const char description[] =
+ I18N_NOOP("tar-based DAT archiver for KDE");
+
+/* in ErrorHandler.cpp */
+void error_handler(int err_sig);
+
+int main( int argc, char** argv )
+{
+ KAboutData aboutData( "kdat", I18N_NOOP("KDat"),
+ KDAT_VERSION, description, KAboutData::License_GPL,
+ "(c) 1999-2000, Sean Vyain; 2001-2002 Lawrence Widman");
+
+ /* 2002-01-28 LEW: so we can dump core if we want to */
+ // KCrash::setCrashHandler(0); // this is supposed to work, but it doesn't
+#ifdef DEBUG
+ {
+ char *newarg;
+ if( ( newarg = (char *)malloc( strlen("--nocrashhandler") + 1 ) ) == NULL )
+ {
+ KMessageBox::sorry(NULL, i18n("Can't allocate memory in kdat"));
+ exit(1);
+ }
+ strcpy( newarg, "--nocrashhandler" );
+ argv[ argc ] = newarg;
+ argc++;
+ }
+ {
+ int i;
+ for(i=0; i<argc; i++){
+ printf("Arg %d: %s\n", i, argv[i]);
+ }
+ }
+#endif /* DEBUG */
+ /* 2002-01-28 LEW */
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ aboutData.addAuthor( "Lawrence Widman", 0, "kdat@cardiothink.com");
+// KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+ KApplication app;
+
+ app.setMainWidget( KDatMainWindow::getInstance() );
+
+ /* set up error handler so we don't crash without notice */
+ signal(SIGHUP, error_handler);
+ signal(SIGINT, error_handler);
+ signal(SIGFPE, error_handler);
+ signal(SIGSEGV, error_handler);
+ signal(SIGTERM, error_handler);
+
+ if ( app.isRestored() && KDatMainWindow::canBeRestored( 1 ) ) {
+ KDatMainWindow::getInstance()->restore( 1 );
+ } else {
+ KDatMainWindow::getInstance()->show();
+ }
+
+ return app.exec();
+}
+
diff --git a/kdat/pics/Makefile.am b/kdat/pics/Makefile.am
new file mode 100644
index 0000000..4695907
--- /dev/null
+++ b/kdat/pics/Makefile.am
@@ -0,0 +1,3 @@
+kdaticondir = $(kde_datadir)/kdat/icons
+kdaticon_ICON = AUTO
+KDE_ICON = kdat
diff --git a/kdat/pics/cr16-app-kdat_archive.png b/kdat/pics/cr16-app-kdat_archive.png
new file mode 100644
index 0000000..6e0afc7
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_archive.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_backup.png b/kdat/pics/cr16-app-kdat_backup.png
new file mode 100644
index 0000000..58178eb
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_backup.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_eject.png b/kdat/pics/cr16-app-kdat_eject.png
new file mode 100644
index 0000000..fb14e79
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_eject.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_mounted.png b/kdat/pics/cr16-app-kdat_mounted.png
new file mode 100644
index 0000000..8fb9e64
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_mounted.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_restore.png b/kdat/pics/cr16-app-kdat_restore.png
new file mode 100644
index 0000000..0555436
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_restore.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_select_all.png b/kdat/pics/cr16-app-kdat_select_all.png
new file mode 100644
index 0000000..6016b3e
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_select_all.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_select_none.png b/kdat/pics/cr16-app-kdat_select_none.png
new file mode 100644
index 0000000..065ca56
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_select_none.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_select_some.png b/kdat/pics/cr16-app-kdat_select_some.png
new file mode 100644
index 0000000..a0ffed5
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_select_some.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_unmounted.png b/kdat/pics/cr16-app-kdat_unmounted.png
new file mode 100644
index 0000000..512d458
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_unmounted.png
Binary files differ
diff --git a/kdat/pics/cr16-app-kdat_verify.png b/kdat/pics/cr16-app-kdat_verify.png
new file mode 100644
index 0000000..e823ac2
--- /dev/null
+++ b/kdat/pics/cr16-app-kdat_verify.png
Binary files differ
diff --git a/kdat/pics/cr32-app-kdat_backup.png b/kdat/pics/cr32-app-kdat_backup.png
new file mode 100644
index 0000000..2ba1fea
--- /dev/null
+++ b/kdat/pics/cr32-app-kdat_backup.png
Binary files differ
diff --git a/kdat/pics/cr32-app-kdat_restore.png b/kdat/pics/cr32-app-kdat_restore.png
new file mode 100644
index 0000000..8638fe7
--- /dev/null
+++ b/kdat/pics/cr32-app-kdat_restore.png
Binary files differ
diff --git a/kdat/pics/cr32-app-kdat_verify.png b/kdat/pics/cr32-app-kdat_verify.png
new file mode 100644
index 0000000..8e76d2a
--- /dev/null
+++ b/kdat/pics/cr32-app-kdat_verify.png
Binary files differ
diff --git a/kdat/pics/hi16-app-kdat.png b/kdat/pics/hi16-app-kdat.png
new file mode 100644
index 0000000..214150e
--- /dev/null
+++ b/kdat/pics/hi16-app-kdat.png
Binary files differ
diff --git a/kdat/pics/hi22-app-kdat.png b/kdat/pics/hi22-app-kdat.png
new file mode 100644
index 0000000..0480297
--- /dev/null
+++ b/kdat/pics/hi22-app-kdat.png
Binary files differ
diff --git a/kdat/pics/hi32-app-kdat.png b/kdat/pics/hi32-app-kdat.png
new file mode 100644
index 0000000..8f37f56
--- /dev/null
+++ b/kdat/pics/hi32-app-kdat.png
Binary files differ
diff --git a/kdat/pics/hi48-app-kdat.png b/kdat/pics/hi48-app-kdat.png
new file mode 100644
index 0000000..737972d
--- /dev/null
+++ b/kdat/pics/hi48-app-kdat.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat.png b/kdat/pics/lo16-app-kdat.png
new file mode 100644
index 0000000..214150e
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_archive.png b/kdat/pics/lo16-app-kdat_archive.png
new file mode 100644
index 0000000..6e0afc7
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_archive.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_backup.png b/kdat/pics/lo16-app-kdat_backup.png
new file mode 100644
index 0000000..58178eb
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_backup.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_eject.png b/kdat/pics/lo16-app-kdat_eject.png
new file mode 100644
index 0000000..fb14e79
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_eject.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_mounted.png b/kdat/pics/lo16-app-kdat_mounted.png
new file mode 100644
index 0000000..8fb9e64
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_mounted.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_restore.png b/kdat/pics/lo16-app-kdat_restore.png
new file mode 100644
index 0000000..0555436
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_restore.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_select_all.png b/kdat/pics/lo16-app-kdat_select_all.png
new file mode 100644
index 0000000..6016b3e
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_select_all.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_select_none.png b/kdat/pics/lo16-app-kdat_select_none.png
new file mode 100644
index 0000000..065ca56
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_select_none.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_select_some.png b/kdat/pics/lo16-app-kdat_select_some.png
new file mode 100644
index 0000000..a0ffed5
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_select_some.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_unmounted.png b/kdat/pics/lo16-app-kdat_unmounted.png
new file mode 100644
index 0000000..512d458
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_unmounted.png
Binary files differ
diff --git a/kdat/pics/lo16-app-kdat_verify.png b/kdat/pics/lo16-app-kdat_verify.png
new file mode 100644
index 0000000..e823ac2
--- /dev/null
+++ b/kdat/pics/lo16-app-kdat_verify.png
Binary files differ
diff --git a/kdat/pics/lo32-app-kdat.png b/kdat/pics/lo32-app-kdat.png
new file mode 100644
index 0000000..74dcb14
--- /dev/null
+++ b/kdat/pics/lo32-app-kdat.png
Binary files differ
diff --git a/kdeadmin.lsm b/kdeadmin.lsm
new file mode 100644
index 0000000..ac127f1
--- /dev/null
+++ b/kdeadmin.lsm
@@ -0,0 +1,11 @@
+Begin4
+Title: kdeadmin
+Version: 3.5.10
+Entered-date: 2008-08-26
+Description: Administrative GUIs written for the K Desktop Environment (KDE)
+Keywords: KDE X11 desktop Qt
+Author: http://bugs.kde.org/ (KDE Bugtracking System)
+Primary-site: http://www.kde.org/download/
+Platforms: Unix, Qt
+Copying-policy: GPL, Artistic
+End
diff --git a/kfile-plugins/Makefile.am b/kfile-plugins/Makefile.am
new file mode 100644
index 0000000..f46ebe3
--- /dev/null
+++ b/kfile-plugins/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=rpm deb
diff --git a/kfile-plugins/deb/Makefile.am b/kfile-plugins/deb/Makefile.am
new file mode 100644
index 0000000..65e69c3
--- /dev/null
+++ b/kfile-plugins/deb/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for deb file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_deb.h
+
+kde_module_LTLIBRARIES = kfile_deb.la
+
+kfile_deb_la_SOURCES = kfile_deb.cpp
+kfile_deb_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_deb_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kfile_deb.pot
+
+services_DATA = kfile_deb.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/deb/kfile_deb.cpp b/kfile-plugins/deb/kfile_deb.cpp
new file mode 100644
index 0000000..b66e062
--- /dev/null
+++ b/kfile-plugins/deb/kfile_deb.cpp
@@ -0,0 +1,130 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Laurence Anderson <l.d.anderson@warwick.ac.uk>
+ *
+ * This program is free software; 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qbuffer.h>
+#include <kfilterdev.h>
+#include <qregexp.h>
+#include <karchive.h>
+#include <ktar.h>
+#include <kar.h>
+
+#include "kfile_deb.h"
+
+typedef KGenericFactory<KDebPlugin> DebFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_deb, DebFactory( "kfile_deb" ))
+
+KDebPlugin::KDebPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "application/x-deb" );
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+ group = addGroupInfo(info, "General", i18n("General"));
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Name", i18n("Name"), QVariant::String);
+ item = addItemInfo(group, "Version", i18n("Version"), QVariant::String);
+ item = addItemInfo(group, "Summary", i18n("Summary"), QVariant::String);
+ item = addItemInfo(group, "Size", i18n("Size"), QVariant::Int);
+}
+
+bool KDebPlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
+{
+ KAr debfile (info.path());
+
+ if ( !debfile.open( IO_ReadOnly ) ) {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ const KArchiveDirectory* debdir = debfile.directory();
+ const KArchiveEntry* controlentry = debdir->entry( "control.tar.gz" );
+ if ( !controlentry || !controlentry->isFile() ) {
+ kdWarning(7034) << "control.tar.gz not found" << endl;
+ return false;
+ }
+
+ QIODevice* filterDev = KFilterDev::device( static_cast<const KArchiveFile *>( controlentry )->device(), "application/x-gzip" );
+ if ( !filterDev ) {
+ kdWarning(7034) << "Couldn't create filter device for control.tar.gz" << endl;
+ return false;
+ }
+ KTar tarfile( filterDev );
+
+ if ( !tarfile.open( IO_ReadOnly ) ) {
+ kdWarning(7034) << "Couldn't open control.tar.gz" << endl;
+ return false;
+ }
+
+ const KArchiveDirectory* controldir = tarfile.directory();
+ Q_ASSERT( controldir );
+
+ const KArchiveEntry* controlfile = controldir->entry( "control" );
+
+ Q_ASSERT( controlfile );
+ if (controlfile) {
+ KFileMetaInfoGroup group = appendGroup(info, "General");
+ QByteArray control( static_cast<const KArchiveFile *>(controlfile)->data() );
+
+ // Now process control array
+ QBuffer controldev(control);
+ controldev.open( IO_ReadOnly );
+ while (!controldev.atEnd()) {
+ char linebuf[100];
+ controldev.readLine(linebuf, sizeof( linebuf ));
+ QString line(linebuf);
+ int fieldstart = line.find(QRegExp(":"), 0) + 2;
+ if (fieldstart == 1) break;
+ QString fieldname = line.mid(0, fieldstart - 2);
+ QString fielddata = line.mid(fieldstart, line.length() - fieldstart - 1);
+
+ if (fieldname == "Package") appendItem(group, "Name", fielddata);
+ else if (fieldname == "Version") appendItem(group, "Version", fielddata);
+ else if (fieldname == "Description") appendItem(group, "Summary", fielddata);
+ else if (fieldname == "Installed-Size") appendItem(group, "Size", int(fielddata.toInt()));
+
+ kdDebug(7034) << "Name: [" << fieldname << "] Data: [" << fielddata << "]" << endl;
+ }
+ } else {
+ kdDebug(7034) << "Couldn't read control file" << endl;
+ return false;
+ }
+
+ tarfile.close();
+ debfile.close();
+
+ return true;
+}
+
+#include "kfile_deb.moc"
diff --git a/kfile-plugins/deb/kfile_deb.desktop b/kfile-plugins/deb/kfile_deb.desktop
new file mode 100644
index 0000000..1ae6ab9
--- /dev/null
+++ b/kfile-plugins/deb/kfile_deb.desktop
@@ -0,0 +1,69 @@
+[Desktop Entry]
+Type=Service
+Name=DEB Stats
+Name[af]=Deb Statistiek
+Name[ar]=إحصائيَات DEB
+Name[az]=DEB Statistikaları
+Name[be]=Cтатыстыка DEB
+Name[bn]=ডেব পরিসংখ্যান
+Name[br]=Stadegoù gant DEB
+Name[bs]=DEB statistika
+Name[ca]=L'estat dels DEB
+Name[cs]=DEB statistiky
+Name[cy]=Ystadegau DEB
+Name[da]=DEB-stats
+Name[el]=Στατιστικά DEB
+Name[eo]=DEB statistikoj
+Name[es]=Estadísticas DEB
+Name[et]=DEB statistika
+Name[eu]=DEB estadistikak
+Name[fa]=آمار DEB
+Name[fi]=DEB-tilastot
+Name[fo]=DEB-hagtøl
+Name[fr]=État DEB
+Name[ga]=Staitistic DEB
+Name[gl]=Estatísticas DEB
+Name[he]=סטטיסטיקת DEB
+Name[hi]=डीईबी स्टेट्स
+Name[hr]=DEB statistike
+Name[hu]=DEB-statisztika
+Name[it]=Statistiche DEB
+Name[ka]=DEB სტატისტიკა
+Name[kk]=DEB статистикасы
+Name[km]=សភាព DEB
+Name[ko]=DEB 상태
+Name[lt]=DEB statistika
+Name[lv]=DEB Statusi
+Name[mn]=ДЕВ Төлөв
+Name[mt]=Statistika DEB
+Name[nb]=DEB statistikk
+Name[ne]=डीईबी तथ्याङ्क
+Name[nl]=DEB-statistieken
+Name[nn]=DEB-statistikk
+Name[pa]=DEB ਸਥਿਤੀ
+Name[pl]=Dane pakietów DEB
+Name[pt]=Informações de DEBs
+Name[pt_BR]=Estados DEB
+Name[ro]=Statistici DEB
+Name[ru]=Статистика DEB
+Name[se]=DEB-statistihkka
+Name[sk]=Štatistiky DEB
+Name[sl]=Statistike DEB
+Name[sr]=DEB Статистике
+Name[sr@Latn]=DEB Statistike
+Name[sv]=DEB-statistik
+Name[ta]=DEB புள்ளி விவரம்
+Name[tg]=Статистикаи DEB
+Name[th]=สถิติของ DEB
+Name[tr]=DEB İstatistikleri
+Name[uk]=Дані DEB
+Name[ven]=Mbalo dza DEB
+Name[vi]=Thống kê DEB
+Name[wa]=Sitatistikes DEB
+Name[zh_CN]=DEB 统计
+Name[zh_HK]=DEB 統計
+Name[zh_TW]=DEB 統計
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_deb
+MimeType=application/x-deb
+PreferredItems=Name,Version,Summary,Size
diff --git a/kfile-plugins/deb/kfile_deb.h b/kfile-plugins/deb/kfile_deb.h
new file mode 100644
index 0000000..9fd1bb0
--- /dev/null
+++ b/kfile-plugins/deb/kfile_deb.h
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Laurence Anderson <l.d.anderson@warwick.ac.uk>
+ *
+ * This program is free software; 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_DEB_H__
+#define __KFILE_DEB_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KDebPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KDebPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+
+};
+
+#endif
diff --git a/kfile-plugins/rpm/Makefile.am b/kfile-plugins/rpm/Makefile.am
new file mode 100644
index 0000000..db4e8cc
--- /dev/null
+++ b/kfile-plugins/rpm/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for rpm file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_rpm.h
+
+kde_module_LTLIBRARIES = kfile_rpm.la
+
+kfile_rpm_la_SOURCES = kfile_rpm.cpp
+kfile_rpm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_rpm_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kfile_rpm.pot
+
+services_DATA = kfile_rpm.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/rpm/kfile_rpm.cpp b/kfile-plugins/rpm/kfile_rpm.cpp
new file mode 100644
index 0000000..049b017
--- /dev/null
+++ b/kfile-plugins/rpm/kfile_rpm.cpp
@@ -0,0 +1,152 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Laurence Anderson <l.d.anderson@warwick.ac.uk>
+ *
+ * This program is free software; 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <qfile.h>
+
+#if !defined(__osf__)
+#include <inttypes.h>
+#else
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+#endif
+
+#include "kfile_rpm.h"
+
+typedef KGenericFactory<KRpmPlugin> RpmFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_rpm, RpmFactory( "kfile_rpm" ))
+
+KRpmPlugin::KRpmPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "application/x-rpm" );
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+ group = addGroupInfo(info, "General", i18n("General"));
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Name", i18n("Name"), QVariant::String);
+ item = addItemInfo(group, "Version", i18n("Version"), QVariant::String);
+ item = addItemInfo(group, "Release", i18n("Release"), QVariant::Int);
+ item = addItemInfo(group, "Summary", i18n("Summary"), QVariant::String);
+ setAttributes ( item, KFileMimeTypeInfo::Description );
+ item = addItemInfo(group, "Group", i18n("Group"), QVariant::String);
+ item = addItemInfo(group, "Size", i18n("Size"), QVariant::Int);
+ setUnit ( item, KFileMimeTypeInfo::Bytes );
+ item = addItemInfo(group, "Vendor", i18n("Vendor"), QVariant::String );
+ item = addItemInfo(group, "Packager", i18n("Packager"), QVariant::String );
+ item = addItemInfo(group, "Archive Offset", i18n("Archive Offset"), QVariant::Int);
+ item = addItemInfo(group, "Comment", i18n("Comment"), QVariant::String);
+ setAttributes( item, KFileMimeTypeInfo::MultiLine );
+
+ group = addGroupInfo(info, "All tags", i18n("All tags"));
+ addVariableInfo(group, QVariant::String, 0);
+}
+
+bool KRpmPlugin::readInfo( KFileMetaInfo& info, uint what)
+{
+ QFile file(info.path());
+ int pass;
+ KFileMetaInfoGroup general, all;
+
+ if (!file.open(IO_ReadOnly))
+ {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ QDataStream dstream(&file);
+ dstream.setByteOrder(QDataStream::BigEndian);
+ general = appendGroup(info, "General");
+ if (what == KFileMetaInfo::Everything) all = appendGroup(info, "All tags");
+
+ file.at(96); // Seek past old lead
+
+ for (pass = 0; pass < 2; pass++) { // RPMs have two headers
+ uint32_t storepos, entries, size, reserved;
+ unsigned char version;
+ char magic[3];
+
+ dstream.readRawBytes(magic, 3);
+ dstream >> version >> reserved >> entries >> size;
+ if (memcmp(magic, RPM_HEADER_MAGIC, 3)) return false;
+ if (version != 1) return false; // Only v1 headers supported
+
+ storepos = file.at() + entries * 16;
+ if (pass == 0) { // Don't need the first batch of tags - pgp etc
+ file.at(storepos + size);
+ file.at(file.at() + (8 - (file.at() % 8)) % 8); // Skip padding
+ continue;
+ }
+
+ if (entries < 500) while (entries--) { // Just in case something goes wrong, limit to 500
+ uint32_t tag, type, offset, count;
+ QString tagname;
+ dstream >> tag >> type >> offset >> count;
+ offset += storepos;
+
+ switch (tag) {
+ case RPMTAG_NAME: tagname = "Name"; break;
+ case RPMTAG_VERSION: tagname = "Version"; break;
+ case RPMTAG_SUMMARY: tagname = "Summary"; break;
+ case RPMTAG_GROUP: tagname = "Group"; break;
+ case RPMTAG_SIZE: tagname = "Size"; break;
+ case RPMTAG_RELEASE: tagname = "Release"; break;
+ case RPMTAG_VENDOR: tagname = "Vendor"; break;
+ case RPMTAG_PACKAGER: tagname = "Packager"; break;
+ case RPMTAG_DESCRIPTION: tagname = "Comment"; break;
+ }
+
+ if ( !tagname.isEmpty() || all.isValid() ) {
+ // kdDebug(7034) << "Tag number: " << tag << " Type: " << type << endl;
+ int oldPos = file.at();
+ file.at(offset); // Set file position to correct place in store
+ switch (type) {
+ case RPM_INT32_TYPE: uint32_t int32tag;
+ dstream >> int32tag;
+ if ( !tagname.isEmpty() ) appendItem(general, tagname, int(int32tag));
+ if ( all.isValid() ) appendItem(all, QString("%1").arg( tag ), QString("%1").arg( int32tag ));
+ break;
+ case RPM_INT16_TYPE: uint16_t int16tag;
+ dstream >> int16tag;
+ if ( !tagname.isEmpty() ) appendItem(general, tagname, int(int16tag));
+ if ( all.isValid() ) appendItem(all, QString("%1").arg( tag ), QString("%1").arg( int16tag ));
+ break;
+ case RPM_I18NSTRING_TYPE: // Fallthru
+ case RPM_STRING_TYPE: QString strtag; char in;
+ while ( ( in = file.getch() ) != '\0' ) strtag += in;
+ if ( !tagname.isEmpty() ) appendItem(general, tagname, strtag);
+ if( all.isValid() ) appendItem(all, QString("%1").arg( tag ), strtag);
+ break;
+ }
+ file.at(oldPos); // Restore old position
+ }
+ }
+ appendItem(general, "Archive Offset", (storepos + size) );
+ }
+
+ return true;
+}
+
+#include "kfile_rpm.moc"
diff --git a/kfile-plugins/rpm/kfile_rpm.desktop b/kfile-plugins/rpm/kfile_rpm.desktop
new file mode 100644
index 0000000..92e2140
--- /dev/null
+++ b/kfile-plugins/rpm/kfile_rpm.desktop
@@ -0,0 +1,69 @@
+[Desktop Entry]
+Type=Service
+Name=RPM Stats
+Name[af]=Rpm Statistiek
+Name[ar]=إحصائيَات RPM
+Name[az]=RPM Statistikaları
+Name[be]=Статыстыка RPM
+Name[bn]=আরপিএম পরিসংখ্যান
+Name[br]=Stadegoù gant RPM
+Name[bs]=RPM statistika
+Name[ca]=L'estat dels RPM
+Name[cs]=RPM statistiky
+Name[cy]=Ystadegau RPM
+Name[da]=RPM-stats
+Name[el]=Στατιστικά RPM
+Name[eo]=RPM statistikoj
+Name[es]=Estadísticas RPM
+Name[et]=RPM statistika
+Name[eu]=RPM estadistikak
+Name[fa]=آمار RPM
+Name[fi]=RPM-tilastot
+Name[fo]=RPM-hagtøl
+Name[fr]=État RPM
+Name[ga]=Staitistic RPM
+Name[gl]=Estatísticas RPM
+Name[he]=סטטיסטיקת RPM
+Name[hi]=आरपीएम स्टेट्स
+Name[hr]=RPM statistike
+Name[hu]=RPM-információ
+Name[it]=Statistiche RPM
+Name[ka]=RPM სტატისტიკა
+Name[kk]=RPM статистикасы
+Name[km]=សភាព RPM
+Name[ko]=RPM 상태
+Name[lt]=RPM statistika
+Name[lv]=RPM Statusi
+Name[mn]=РПМ Төлөв
+Name[mt]=Statistika RPM
+Name[nb]=RPM statistikk
+Name[ne]=आरपीएम तथ्याङ्क
+Name[nl]=RPM-statistieken
+Name[nn]=RPM-statistikk
+Name[pa]=RPM ਸਥਿਤੀ
+Name[pl]=Dane plików RPM
+Name[pt]=Informações de RPMs
+Name[pt_BR]=Estados do RPM
+Name[ro]=Statistici RPM
+Name[ru]=Статистика RPM
+Name[se]=RPM-statistihkka
+Name[sk]=Štatistiky RPM
+Name[sl]=Statistike RPM
+Name[sr]=RPM Статистике
+Name[sr@Latn]=RPM Statistike
+Name[sv]=RPM-statistik
+Name[ta]=RPM புள்ளி விவரம்
+Name[tg]=Статистикаи RPM
+Name[th]=สถิติของ RPM
+Name[tr]=RPM İstatistikleri
+Name[uk]=Дані RPM
+Name[ven]=Mbalo dza RPM
+Name[vi]=Thống kê RPM
+Name[wa]=Sitatistikes RPM
+Name[zh_CN]=RPM 统计
+Name[zh_HK]=RPM 統計
+Name[zh_TW]=RPM 統計
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_rpm
+MimeType=application/x-rpm
+PreferredItems=Name,Version,Summary,Group,Size
diff --git a/kfile-plugins/rpm/kfile_rpm.h b/kfile-plugins/rpm/kfile_rpm.h
new file mode 100644
index 0000000..797fc49
--- /dev/null
+++ b/kfile-plugins/rpm/kfile_rpm.h
@@ -0,0 +1,53 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Laurence Anderson <l.d.anderson@warwick.ac.uk>
+ *
+ * This program is free software; 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_RPM_H__
+#define __KFILE_RPM_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KRpmPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KRpmPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+
+};
+
+#define RPM_HEADER_MAGIC "\216\255\350"
+#define RPMTAG_NAME 1000
+#define RPMTAG_VERSION 1001
+#define RPMTAG_RELEASE 1002
+#define RPMTAG_SUMMARY 1004
+#define RPMTAG_DESCRIPTION 1005
+#define RPMTAG_SIZE 1009
+#define RPMTAG_VENDOR 1011
+#define RPMTAG_PACKAGER 1015
+#define RPMTAG_GROUP 1016
+#define RPM_INT16_TYPE 3
+#define RPM_INT32_TYPE 4
+#define RPM_STRING_TYPE 6
+#define RPM_I18NSTRING_TYPE 9
+
+#endif
diff --git a/knetworkconf/AUTHORS b/knetworkconf/AUTHORS
new file mode 100644
index 0000000..1fbb263
--- /dev/null
+++ b/knetworkconf/AUTHORS
@@ -0,0 +1 @@
+Juan Luis Baptiste
diff --git a/knetworkconf/COPYING b/knetworkconf/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/knetworkconf/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/knetworkconf/ChangeLog b/knetworkconf/ChangeLog
new file mode 100644
index 0000000..47af0c1
--- /dev/null
+++ b/knetworkconf/ChangeLog
@@ -0,0 +1,54 @@
+* Mon Feb 21 2005 0.6.1:
+- Ugraded network backend to GST 1.1.4
+- Support for two new platforms: Specifix and Vine Linux, being now 15 the platforms supported.
+- Parcial wireless support: Autodetection of wireless network interfaces.
+- New dialog for managing static hosts.
+- Many User Interface enhaments.
+- Lots of bug fixes
+- Lots of code cleanups
+- Updated spanish, french, german, polish and norewian translations.
+
+* Fri Aug 06 2004 0.6:
+- Ported to run as a KControl Module.
+- Major UI redesign.
+- Added support for BlackPanther OS, Conectiva Linux, Gentoo Linux, FreeBSD and Slackware Linux. Credits for Conectiva linux support goes to Helio Chissini de Castro from Conectiva.
+- Brazillian Portuguese translation by Gustavo Pichorim Boiko from Conectiva.
+- Updated german, hungarian and spanish translations.
+_ Updated english, german and spanish documentation.
+- Fixed some minor bugs.
+- Updated GST to 0.34.
+
+* Tue Feb 10 2004 0.5:
+- Added german and hungarian translations.
+- Final release.
+
+* Tue Jan 13 2004 0.5beta2:
+- Bug fixes.
+- Updated gst to 0.30.
+- Some GUI fixes.
+- Added Euskara translation and updated spanish and french ones.
+
+* Wed Oct 22 2003 0.5beta1:
+- Integrated KNetworkConf with Gnome System Tools network backend.
+ http://www.gnome.org/projects/gst/
+- Autodetection of running platform.
+- Added support for /etc/hosts file .
+- Added a enable/disable interfaces button in the main dialog.
+- Bug fixes.
+
+* Wed Oct 1 2003 0.4.2:
+- Bug fixes.
+- Added french translation, courtesy of Forian Fernandez <florian.fernandez2@wanadoo.fr>.
+
+* Sun Apr 6 2003 0.4.1:
+- Made widgets resizeable.
+- Started work for a shell script-driven distro abstraction layer.
+- Fixed crash when running KnetworkConf in a unsupported Linux distro.
+- Made all buttons of variable length (needed for other languages).
+- Added spanish translation. Thanks to Pedro Jurado Maqueda <pjmelenas@biwemail.com>
+ for this.
+- Updated rpm packages for Mandrake 9.1.
+- Bug fixes.
+
+* Fri Feb 14 2003 0.4:
+- Initial release.
diff --git a/knetworkconf/Doxyfile b/knetworkconf/Doxyfile
new file mode 100644
index 0000000..c227a40
--- /dev/null
+++ b/knetworkconf/Doxyfile
@@ -0,0 +1,232 @@
+# Doxyfile 1.3.2-Gideon
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = knetworkconf
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY =
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ALIASES =
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = /home/juancho/cvs_proyectos/knetworkconf_0.4.9
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.C \
+ *.H \
+ *.tlh \
+ *.diff \
+ *.patch \
+ *.moc \
+ *.xpm
+RECURSIVE = yes
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = yes
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+CGI_NAME = search.cgi
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH = /usr/local/bin/
+EXT_DOC_PATHS =
diff --git a/knetworkconf/INSTALL b/knetworkconf/INSTALL
new file mode 100644
index 0000000..02a4a07
--- /dev/null
+++ b/knetworkconf/INSTALL
@@ -0,0 +1,167 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 4. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/knetworkconf/LEAME b/knetworkconf/LEAME
new file mode 100644
index 0000000..8925c6c
--- /dev/null
+++ b/knetworkconf/LEAME
@@ -0,0 +1,83 @@
+KNetworkConf 0.6.1 - Un mdulo para el Centro de Control de KDE
+para configurar las propiedades de red.
+Juan Luis Baptiste M. <juan.baptiste@kdemail.net>
+Colombia 2003 - 2005
+http://www.merlinux.org/knetworkconf/
+
+------------------------------------------------------------
+
+
+1. Introduccin
+KNetworkConf es un mdulo para el Centro de Control de KDE
+(http://www.kde.org) que sirve para configurar las propiedades
+de red en una mquina GNU/Linux. Desarroll esta aplicacin debido
+a que no haba encontrado alguna que sirviera para configurar las propiedades
+de red y que fuera parte de KDE, ya que considero que una aplicacin como esta
+es muy importante en cualquier escritorio serio como lo es KDE.
+
+Caractersticas de KNetworkConf:
+
+* Configurar las interfaces de red instaladas (no se pueden agregar nuevas
+por ahora) en modos bsico y avanzado (ej. no configurar la direccin de
+difusin y mscara de red).
+* Autodeteccin de interfaces de red inalmbricas.
+* Configurar la puerta de enlace y la interfz de red por defecto.
+* Configurar el nombre de dominio y de la mquina.
+* Agregar/remover servidores de Dominio (/etc/resolv.conf).
+* Agregar/remover hosts conocidos (/etc/hosts).
+
+KNetworkConf actualmente funciona en 15 plataformas distintas:
+
+* BlackPanther OS
+* Conectiva Linux
+* Debian Linux
+* Fedora Linux
+* FreeBSD
+* Gentoo Linux
+* Mandriva Linux
+* OpenNA Linux
+* Polish Linux Distribution
+* Red Hat Linux
+* Slackware Linux
+* Specifix Linux
+* TurboLinux
+* Vine Linux
+
+Esto es posible gracias a Gnome System Tools (http://www.gnome.org/projects/gst/index.html).
+GST son un conjunto de herramientas de configuracin para Gnome. Estas
+herramientas estn divididas en frontends y backends.
+
+KNetworkConf usa el backend de red de Gnome System Tools (GST)
+(http://www.gnome.org/projects/gst/) para averiguar los valores de la red en
+las diferente plataformas. Los backends estn hechos en perl y se comunican
+con los frontends a travs de XML.
+
+NOTA: No es necesario tener instalado GNOME o GST. El backend de red viene
+includo con KNetworkConf.
+
+2. Requerimientos
+* Una distribucin compatible con Red Hat.
+* KDE 3.1.x
+* Qt 3.1.x
+* Perl
+* libxml
+* autoconf > 2.5x/automake > 1.6
+
+3. Instalacin
+Para instrucciones de instalacin por favor lea el archivo INSTALL,
+pero un arranque rpido puede hacer:
+
+./configure
+make
+su root
+make istall
+
+Usuarios de Mandriva deben agregarle la opcion --prefix=/usr al
+script configure para instalar los archivos en el directorio correcto
+y correr el comando update-menus despus de make install.
+
+4. Contacto
+Para reportar errores, o si tiene comentarios o sugerencias acerca
+de KNetworkConf, por favor escriba a las listas de correo del proyecto:
+knetworkconf-devel@lists.sourceforge.net o knetworkconf-users@lists.sourceforge.net.
+
diff --git a/knetworkconf/Makefile.am b/knetworkconf/Makefile.am
new file mode 100644
index 0000000..cb7b17e
--- /dev/null
+++ b/knetworkconf/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = knetworkconf backends pixmaps \ No newline at end of file
diff --git a/knetworkconf/README b/knetworkconf/README
new file mode 100644
index 0000000..40b11c2
--- /dev/null
+++ b/knetworkconf/README
@@ -0,0 +1,74 @@
+KNetworkConf 0.6.1 - A KDE control Center Module to confiure Network settings.
+Juan Luis Baptiste M. <juan.baptiste@kdemail.net>
+Colombia, 2003 - 2005
+http://www.merlinux.org/knetworkconf/
+
+------------------------------------------------------------
+
+
+1. Introduction
+KNetworkConf is a KDE Control Center module to configure the Network
+settings in a Linux machine. I developed it because I couldn't find any
+application to do this from within KDE, and I think this is a "must have"
+app for a serious Desktop Enviroment like KDE.
+
+KNetworkConf features:
+
+* Configure installed network devices (you can't add new ones for now)
+in basic and advanced mode (ie. don't auto configure broadcast and
+netmask values).
+* Autodetection of wireless interfaces.
+* Configure the default gateway and gateway device.
+* Configure host and domain names.
+* Add/remove DNS servers (/etc/resolv.conf).
+* Add/Remove known Hosts (/etc/hosts).
+
+KNetworkConf works now in 15 different platforms:
+
+* BlackPanther OS
+* Conectiva Linux
+* Debian Linux
+* Fedora Linux
+* FreeBSD
+* Gentoo Linux
+* Mandriva Linux
+* OpenNA Linux
+* Polish Linux Distribution
+* Red Hat Linux
+* Slackware Linux
+* Specifix Linux
+* TurboLinux
+* Vine Linux
+
+KNetworkConf uses the Gnome System Tools (gst)
+(http://www.gnome.org/projects/gst/) network backend to find out the network
+values in a platform-independient manner. This backends are a bunch of perl
+scripts that use XML files to communicate with different frontends.
+
+NOTE:You don't need to have GNOME nor GST installed AT ALL to run
+KNetworkConf. The network backend comes included.
+
+2. Requirements
+* KDE 3.1.x
+* Qt 3.1.x
+* Perl
+* libxml
+* autoconf > 2.5x/automake > 1.6
+
+3. Installation
+For installation instructions, please see the INSTALL file, but for
+a quick start you can do:
+
+./configure
+make
+su root
+make istall
+
+Mandriva users must add --prefix=/usr to the configure script to
+install the files in the correct path and run update-menus after make install.
+
+4. Contact
+To report bugs or if you have any comments or sugestions about KNetworkConf,
+please write to the mailing lists knetworkconf-devel@lists.sourceforge.net or
+knetworkconf-users@lists.sourceforge.net.
+
diff --git a/knetworkconf/TODO b/knetworkconf/TODO
new file mode 100644
index 0000000..8a4708c
--- /dev/null
+++ b/knetworkconf/TODO
@@ -0,0 +1,5 @@
+* Translation to other languajes.
+* Add/Remove network devices.
+* Autodetection of new network devices.
+* Configure routes to other hosts and networks.
+* IPv6 support.
diff --git a/knetworkconf/backends/AUTHORS b/knetworkconf/backends/AUTHORS
new file mode 100644
index 0000000..b0195bc
--- /dev/null
+++ b/knetworkconf/backends/AUTHORS
@@ -0,0 +1,5 @@
+Arturo Espinosa <arturo@ximian.com>
+Hans Petter Jansson <hpj@ximian.com>
+Tambet Ingo <tambet@ximian.com>
+Carlos Garnacho Parro <carlosg@gnome.org>
+
diff --git a/knetworkconf/backends/Makefile.am b/knetworkconf/backends/Makefile.am
new file mode 100644
index 0000000..7fc54ec
--- /dev/null
+++ b/knetworkconf/backends/Makefile.am
@@ -0,0 +1,29 @@
+backends = \
+ network-conf
+
+perl_libs = \
+ debug.pl \
+ file.pl \
+ general.pl \
+ network.pl \
+ parse.pl \
+ platform.pl \
+ process.pl \
+ replace.pl \
+ report.pl \
+ service.pl \
+ service-list.pl \
+ util.pl \
+ xml.pl
+
+scripts_SCRIPTS = $(backends) $(perl_libs)
+
+EXTRA_DIST = \
+ system-tools-backends.pc.in \
+ AUTHORS
+
+CLEANFILES = $(backends) $(perl_libs) system-tools-backends.pc
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = system-tools-backends.pc
+
diff --git a/knetworkconf/backends/NEWS b/knetworkconf/backends/NEWS
new file mode 100644
index 0000000..3ff2bd4
--- /dev/null
+++ b/knetworkconf/backends/NEWS
@@ -0,0 +1,325 @@
+System Tools Backends Version 1.4.2, 2006-01-02
+-----------------------------------------------
+
+The System Tools Backends version 1.4.1 "Radical cut" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Changes since last release
+==========================
+
+ Network
+ =======
+ - Added support for Ubuntu 5.10 and 6.04, Yoper 2.2, ArkLinux, FC4 and latest Mandrake/Mandriva (Juan Luis Baptiste)
+
+ Services
+ ========
+ - Added support for ArchLinux (Arjan Timmerman)
+
+ Time
+ ====
+ - Added support for ArchLinux (Arjan Timmerman)
+
+
+Downloading
+===========
+You can get it from :
+http://system-tools-backends.freedesktop.org/downloads/1.4/
+
+
+System Tools Backends Version 1.4.1, 2005-11-27
+-----------------------------------------------
+
+The System Tools Backends version 1.4.1 "Burning sky" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Changes since last release
+==========================
+
+ Network
+ =======
+ - Fixed network configuration in Gentoo (Christian Meyer, Florian Schricker, garnacho)
+ - Fixed WEP key detection in Slackware (garnacho)
+
+ Common
+ ======
+ - Added support for Slackware 10.2.0 (Scott J. Harmon)
+ - Changed Specifix Linux to rPath Linux (Ken VanDine)
+
+Downloading
+===========
+You can get it from :
+http://system-tools-backends.freedesktop.org/downloads/1.4/
+
+
+System Tools Backends Version 1.4.0, 2005-08-23
+-----------------------------------------------
+
+The System Tools Backends version 1.4.0 "Already there" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Downloading
+===========
+You can get it from :
+http://system-tools-backends.freedesktop.org/downloads/1.4/
+
+
+System Tools Backends Version 1.3.92, 2005-08-23
+-----------------------------------------------
+
+The System Tools Backends version 1.3.92 "Almost there" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Changes since last release
+==========================
+
+ Network
+ =======
+ - enable gateway saving under Slackware and Zenwalk (Jean-Philippe Guillemin)
+
+Downloading
+===========
+You can get it from :
+http://system-tools-backends.freedesktop.org/downloads/1.3/
+
+System Tools Backends Version 1.3.2, 2005-08-08
+-----------------------------------------------
+
+The System Tools Backends version 1.3.2 "It's not a rehearsal" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Changes since last release
+==========================
+
+ Services
+ ========
+ - Added more roles for known services (garnacho)
+
+ Users
+ =====
+ - Strings improvements in groups descriptions (Corey Burger, Guillaume Desmottes)
+
+Downloading
+===========
+You can get it from :
+http://system-tools-backends.freedesktop.org/downloads/1.3/
+
+System Tools Backends Version 1.3.1, 2005-07-05
+-----------------------------------------------
+
+The System Tools Backends version 1.3.1 "Make me laugh" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Changes since last release
+==========================
+
+ Network
+ =======
+ - do not detect irlan[0-9] interfaces as an[0-9] (garnacho)
+ - other misc fixes (garnacho)
+
+Downloading
+===========
+You can get it from :
+http://system-tools-backends.freedesktop.org/downloads/1.3/
+
+System Tools Backends Version 1.3.0, 2005-07-05
+-----------------------------------------------
+
+The System Tools Backends version 1.3.0 "Learning to hate autotools" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Changes since last release
+==========================
+
+ General
+ =======
+ - Added support for Slackware 10.1.0 (Scott J. Harmon)
+ - Added support for VidaLinux 1.2 (Christian Meyer)
+
+ Network
+ =======
+ - wireless handling improvements in Debian (me)
+ - recognize tun ifaces as dialup ones (me)
+ - fixed handling of dhclient v3 (me)
+ - fixed FreeBSD network support (Joe Marcus Clarke)
+ - fixed handling of dhcpcd (Christian Meyer)
+ - Added support for WEP key type (me)
+ - Added support for KUbuntu (Juan Luis Baptiste)
+
+ Time
+ ====
+ - update /etc/timezone in Debian systems
+
+ Services
+ ========
+ - Separate priorities for init types which support them (me)
+ - Add roles to services and runlevels (me)
+
+ Translations
+ ============
+ - el (Nikos Charonitakis)
+ - en_CA (Adam Weinberger)
+ - hu (Szabolcs Varga)
+ - id (Ahmad Riza H Nst)
+ - ne (Jyotsna, Pawan chitrakr)
+ - rw (Steve Murphy)
+ - xh (Adi Attar)
+ - zh_TW (GNOME HK Team)
+
+Downloading
+===========
+You can get it from :
+http://system-tools-backends.freedesktop.org/downloads/1.3/
+
+System Tools Backends Version 1.2.0, 2005-03-07
+-----------------------------------------------
+
+The System Tools Backends version 1.2.0 "Eleee mi niñooo!!" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+Changes since last release
+==========================
+
+ Network
+ =======
+ - Don't activate any interface after having changed if it was disabled (Garnacho)
+
+ Translations
+ ============
+ - hi (Rajesh Ranjan)
+ - hu (Szabolcs Varga)
+ - ja (Takeshi AIHANA)
+ - ro (Mişu Moldovan)
+ - sr, sr@Latn (Danilo Šegan)
+ - vi (Abel Cheung)
+ - zh_TW (GNOME HK Team)
+
+Downloading
+===========
+You can get it from :
+ftp://ftp.gnome.org/pub/GNOME/sources/system-tools-backends/1.2/
+
+System Tools Backends Version 1.1.92, 2005-03-01
+------------------------------------------------
+
+The GNOME System Tools version 1.1.92 "Tararí que te ví" have been released.
+
+The System Tools Backends are a set of cross-platform scripts for Linux and other Unix systems. The backends provide an standard XML interface for modifying the configuration regarless of the distribution that's being used.
+
+Right now the System Tools Backends fully support various distros/OS such as: Redhat, Mandriva, SuSE, Fedora, Debian (and derivations like Ubuntu, Linex, Guadalinex...), Gentoo, Slackware, FreeBSD, OpenNA, PLD, Vine and Specifix.
+
+
+Changes since last release
+==========================
+
+ General
+ =======
+ - Added support for Fedora Core 3 (Garnacho)
+ - i18n fixes (Garnacho)
+
+ Network
+ =======
+ - Added directive for changing default gateway on the fly (Garnacho)
+ - Add support for dhcpcd (Garnacho)
+ - Fixed PPP calling (Michael Vogt, Garnacho)
+
+ Shares
+ ======
+ - Avoid print$ shares (Garnacho)
+
+ Translations
+ ============
+ - bg (Alexander Shopov)
+ - ca (Josep Puigdemont i Casamajó)
+ - el (Kostas Papadimas)
+ - fi (Ilkka Tuohela)
+ - fr (Christophe Merlet)
+ - gu (Ankit Patel)
+ - it (Francesco Marletta)
+ - ko (Young-Ho Cha)
+ - lt (Žygimantas Beručka)
+ - nb (Kjartan Maraas)
+ - nl (Tino Meinen)
+ - pl (GNOME PL Team)
+ - pt (Duarte Loreto)
+ - pt_BR (Raphael Higino)
+ - th (Theppitak Karoonboonyanan)
+ - uk (Maxim Dziumanenko)
+
+Downloading
+===========
+You can get it from :
+ftp://ftp.gnome.org/pub/GNOME/sources/system-tools-backends/1.1/
+
+
+System Tools Backends Version 1.1.91, 2005-02-08
+------------------------------------------------
+
+The GNOME System Tools version 1.1.91 "Ad infinitum" have been released.
+
+The GNOME System Tools are a set of cross-platform configuration utilities for Linux and other Unix systems. The frontends knows nothing about the underlying system and provide the same user interface across the different types of systems. Internally they use the system-tools-backends package.
+
+Changes since last release
+==========================
+
+ General
+ =======
+ - Separate it from the GNOME System Tools frontends (Jeff Waugh, garnacho)
+
+ Network
+ =======
+ - Fixed hosts file parsing when there's more than one line per IP address (garnacho)
+ - Only add an empty PPP interface if it wasn't added before (garnacho)
+ - Use dhclient more reliably (garnacho)
+
+ Time
+ ====
+ - Update the correct server status in Debian (garnacho)
+
+ Users
+ =====
+ - Detect whether to use md5 or not (garnacho)
+ - Made a group description more user friendly (Ole Laursen)
+
+ Translations
+ ============
+ - cs (Miloslav Trmac)
+ - da (Ole Laursen)
+ - de (Frank Arnold)
+ - en_CA (Adam Weinberger)
+ - en_GB (David Lodge)
+ - es (Francisco Javier F. Serrador)
+ - lt (Ŝygimantas Beručka)
+ - pt (Duarte Loreto)
+ - pt_BR (Raphael Higino)
+ - sq (Elian Myftiu)
+ - sv (Christian Rose)
+
+Downloading
+===========
+You can get it from :
+ftp://ftp.gnome.org/pub/GNOME/sources/system-tools-backends/1.1/
diff --git a/knetworkconf/backends/README b/knetworkconf/backends/README
new file mode 100644
index 0000000..0618fe1
--- /dev/null
+++ b/knetworkconf/backends/README
@@ -0,0 +1,9 @@
+to extract the configuracion
+============================
+
+backend --get
+
+to restore the configuration from XML
+=====================================
+
+backend --set < file.xml
diff --git a/knetworkconf/backends/README.NEW_PLATFORMS b/knetworkconf/backends/README.NEW_PLATFORMS
new file mode 100644
index 0000000..dc2d857
--- /dev/null
+++ b/knetworkconf/backends/README.NEW_PLATFORMS
@@ -0,0 +1,5 @@
+If you patch the backends, PLEASE also make a patch with your changes and send it to the author at juan.baptiste@kdemail.net so your changes can be merged with the system-tools-backend project at freedesktop.org .
+
+Thanks.
+Juan Luis Baptiste
+
diff --git a/knetworkconf/backends/configure.in.in b/knetworkconf/backends/configure.in.in
new file mode 100644
index 0000000..44cfc14
--- /dev/null
+++ b/knetworkconf/backends/configure.in.in
@@ -0,0 +1,15 @@
+dnl ==============================================================
+dnl Set SCRIPTS_DIR, FILES_DIR & LOCALE_DIR
+dnl ==============================================================
+KDE_EXPAND_MAKEVAR(KDE_DATADIR, kde_datadir)
+scriptsdir="$KDE_DATADIR/knetworkconf/backends"
+
+AC_SUBST(scriptsdir)
+
+dnl ==============================================================
+dnl END: Set SCRIPTS_DIR, FILES_DIR & LOCALE_DIR
+dnl ==============================================================
+
+dnl Keep the comment on the line below, it works that way.
+dnl AC_OUTPUT(knetworkconf/backends/system-tools-backends.pc knetworkconf/backends/network-conf knetworkconf/backends/debug.pl knetworkconf/backends/file.pl knetworkconf/backends/general.pl knetworkconf/backends/network.pl knetworkconf/backends/parse.pl knetworkconf/backends/platform.pl knetworkconf/backends/process.pl knetworkconf/backends/replace.pl knetworkconf/backends/report.pl knetworkconf/backends/service-list.pl knetworkconf/backends/service.pl knetworkconf/backends/util.pl knetworkconf/backends/xml.pl)
+echo "Backend configured."
diff --git a/knetworkconf/backends/debug.pl.in b/knetworkconf/backends/debug.pl.in
new file mode 100644
index 0000000..1b5b5c1
--- /dev/null
+++ b/knetworkconf/backends/debug.pl.in
@@ -0,0 +1,222 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Functions for hacker debug.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+use File::Path;
+use File::Copy;
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/general.pl$DOTIN";
+require "$SCRIPTSDIR/file.pl$DOTIN";
+
+
+%gst_debug_fd_hash = ();
+
+
+sub gst_debug_open_output_file
+{
+ local *FILE;
+ my $debug_path = &gst_file_get_debug_path () . "/$gst_name/1/$_[0]";
+
+ if (!exists $gst_debug_fd_hash{$debug_path})
+ {
+ &gst_debug_rotate_try ();
+ open (FILE, ">>$debug_path");
+ $gst_debug_fd_hash{$debug_path} = *FILE;
+ }
+
+ return $gst_debug_fd_hash{$debug_path};
+}
+
+sub gst_debug_close_all
+{
+ my ($file, @files);
+
+ @files = keys %gst_debug_fd_hash;
+ foreach $file (@files)
+ {
+ &gst_file_close ($gst_debug_fd_hash{$file});
+ delete $gst_debug_fd_hash{$file};
+ }
+}
+
+sub gst_debug_print_string_to_file
+{
+ my $debug_file;
+
+ $debug_file = &gst_debug_open_output_file ($_[0]);
+ print $debug_file $_[1];
+}
+
+sub gst_debug_print_log_to_file
+{
+ my ($file, $doc) = @_;
+ my (@buff, $line, $fd);
+
+ $fd = &gst_debug_open_output_file ($file);
+
+ @buff = split ("\n", $doc);
+ foreach $line (@buff)
+ {
+ print $fd "$line\n";
+ }
+}
+
+
+sub gst_debug_print_string
+{
+ if ($gst_debug) { print STDERR $_[0]; }
+ &gst_debug_print_string_to_file ("debug", $_[0]);
+}
+
+
+sub gst_debug_print_line
+{
+ &gst_debug_print_string ($_[0] . "\n");
+}
+
+
+sub gst_debug_print_indent
+{
+ my $indent = $_[0];
+ my $indent_string = "";
+
+ $indent_string = " " x $indent;
+ &gst_debug_print_string ($indent_string);
+}
+
+
+sub gst_debug_print_indented_string
+{
+ my ($indent, @string) = @_;
+
+ &gst_debug_print_indent ($indent);
+ &gst_debug_print_string (@string);
+}
+
+
+sub gst_debug_print_indented_line
+{
+ my $indent = shift @_;
+ my @line = @_;
+
+ &gst_debug_print_indent ($indent);
+ &gst_debug_print_line (@line);
+}
+
+
+sub gst_debug_print_struct
+{
+ foreach $i (@_)
+ {
+ &gst_debug_print_struct_r (0, 0, $i);
+ }
+}
+
+
+sub gst_debug_print_struct_r
+{
+ my ($indent) = $_[0];
+ my $is_hash_value = $_[1];
+ my $a = $_[2];
+ my $type;
+ my @keys;
+ my $elem;
+ my $i;
+
+ $type = ref $a;
+
+ if (!$is_hash_value) { &gst_debug_print_indent ($indent); }
+
+ if ($type eq "SCALAR")
+ {
+ &gst_debug_print_line ($$a);
+ }
+ elsif ($type eq "ARRAY")
+ {
+ &gst_debug_print_line ("[ARRAY]");
+
+ for ($i = 0; $i <= $#$a; $i++)
+ {
+ &gst_debug_print_struct_r ($indent + 1, 0, $$a[$i]);
+ }
+ }
+ elsif ($type eq "HASH")
+ {
+ @keys = sort keys (%$a);
+
+ &gst_debug_print_line ("[HASH]");
+
+ foreach $i (@keys)
+ {
+ &gst_debug_print_indented_string ($indent + !$is_hash_value, $i . " -> ");
+ &gst_debug_print_struct_r ($indent + !$is_hash_value + 1, 1, $$a{$i});
+ }
+ }
+ else
+ {
+ &gst_debug_print_line ($a);
+ }
+}
+
+
+$gst_debug_dir_rotation_was_made = 0;
+
+sub gst_debug_rotate_try
+{
+
+ my $debug_file = $_[0];
+ my $debug_tool_dir = &gst_file_get_debug_path () . "/$gst_name";
+
+ # If this is the first debug created by this tool on this invocation,
+ # rotate the debug directories and create a new, empty one.
+
+ if (!$gst_debug_dir_rotation_was_made)
+ {
+ my $i;
+
+ $gst_debug_dir_rotation_was_made = 1;
+
+ if (-e "$debug_tool_dir/9")
+ {
+ &gst_file_rmtree ("$debug_tool_dir/9", 0, 1);
+ }
+
+ for ($i = 8; $i; $i--)
+ {
+ if (-e "$debug_tool_dir/$i")
+ {
+ move ("$debug_tool_dir/$i", "$debug_tool_dir/" . ($i + 1));
+ }
+ }
+
+ &gst_file_create_path ("$debug_tool_dir/1");
+ }
+}
+
+1;
diff --git a/knetworkconf/backends/file.pl.in b/knetworkconf/backends/file.pl.in
new file mode 100644
index 0000000..f3be154
--- /dev/null
+++ b/knetworkconf/backends/file.pl.in
@@ -0,0 +1,934 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Functions for file manipulation. Find, open, read, write, backup, etc.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Arturo Espinosa <arturo@ximian.com>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+use File::Path;
+use File::Copy;
+use File::Temp;
+use Carp;
+
+$SCRIPTSDIR = "@scriptsdir@";
+$FILESDIR = "@filesdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $FILESDIR = "files";
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/general.pl$DOTIN";
+require "$SCRIPTSDIR/report.pl$DOTIN";
+
+
+$GST_FILE_READ = 1;
+$GST_FILE_WRITE = 2;
+
+
+# --- File operations --- #
+
+
+sub gst_file_get_base_path
+{
+ my $path = "/var/cache/setup-tool-backends";
+ chmod (0755, $path);
+ return $path;
+}
+
+
+sub gst_file_get_tmp_path
+{
+ return (&gst_file_get_base_path () . "/tmp");
+}
+
+
+sub gst_file_get_backup_path
+{
+ return (&gst_file_get_base_path () . "/backup");
+}
+
+
+sub gst_file_get_debug_path
+{
+ return (&gst_file_get_base_path (). "/debug");
+}
+
+
+sub gst_file_get_data_path
+{
+ my $path = &gst_file_get_base_path (). "/data";
+ chmod (0755, $path);
+ return $path;
+}
+
+
+# Give a command, and it will put in C locale, some sane PATH values and find
+# the program to run in the path. Redirects stderr to null.
+sub get_cmd_path
+{
+ my ($cmd) = @_;
+ my ($tool_name, @argline, $command, $tool_path);
+
+ ($tool_name, @argline) = split("[ \t]+", $cmd);
+
+ $tool_path = &gst_file_locate_tool ($tool_name);
+ return -1 if ($tool_path eq "");
+
+
+ $command = "$tool_path @argline";
+ $command =~ s/\"/\\\"/g;
+
+ return $command;
+}
+
+sub gst_file_get_cmd_path
+{
+ my ($cmd) = @_;
+
+ my $command = &get_cmd_path ($cmd);
+ return ("LC_ALL=C PATH=\$PATH:/sbin:/usr/sbin $command 2> /dev/null");
+}
+
+# necessary for some programs that output info through stderr
+sub gst_file_get_cmd_path_with_stderr
+{
+ my ($cmd) = @_;
+
+ my $command = &get_cmd_path ($cmd);
+ return ("LC_ALL=C PATH=\$PATH:/sbin:/usr/sbin $command 2>&1");
+}
+
+
+sub gst_file_create_path
+{
+ my ($path, $perms) = @_;
+ $prems = $perms || 0770;
+ my @pelem;
+
+ $path =~ tr/\///s;
+ @pelem = split(/\//, $path); # 'a/b/c/d/' -> 'a', 'b', 'c', 'd', ''
+
+ for ($path = ""; @pelem; shift @pelem)
+ {
+ $path = "$path$pelem[0]";
+ mkdir($path, $perms);
+ $path = "$path/";
+ }
+
+ &gst_report_enter ();
+ &gst_report ("file_create_path", $_[0]);
+ &gst_report_leave ();
+}
+
+
+sub gst_file_create_path_for_file
+{
+ my ($path, $perms) = @_;
+ $prems = $perms || 0770;
+ my @pelem;
+
+ $path =~ tr/\///s;
+ @pelem = split(/\//, $path); # 'a/b/c/d/' -> 'a', 'b', 'c', 'd', ''
+
+ for ($path = ""; @pelem; shift @pelem)
+ {
+ if ($pelem[1] ne "")
+ {
+ $path = "$path$pelem[0]";
+ mkdir($path, $perms);
+ $path = "$path/";
+ }
+ }
+
+ &gst_report_enter ();
+ &gst_report ("file_create_path", $_[0]);
+ &gst_report_leave ();
+}
+
+
+$gst_file_backup_dir_rotation_was_made = 0;
+
+# If this is the first backup created by this tool on this invocation,
+# rotate the backup directories and create a new, empty one.
+sub gst_file_backup_rotate_dirs
+{
+ my $backup_tool_dir = $_[0];
+
+ &gst_report_enter ();
+
+ if (!$gst_file_backup_dir_rotation_was_made)
+ {
+ my $i;
+
+ $gst_file_backup_dir_rotation_was_made = 1;
+ if (-e "$backup_tool_dir/9")
+ {
+ if (-s "$backup_tool_dir/9")
+ {
+ unlink ("$backup_tool_dir/9");
+ }
+ else
+ {
+ &gst_file_rmtree ("$backup_tool_dir/9");
+ }
+ }
+
+ for ($i = 8; $i; $i--)
+ {
+ if (stat ("$backup_tool_dir/$i"))
+ {
+ move ("$backup_tool_dir/$i", "$backup_tool_dir/" . ($i+1));
+ }
+ }
+
+ if (!stat ("$backup_tool_dir/First"))
+ {
+ &gst_file_create_path ("$backup_tool_dir/First");
+ &gst_file_run ("ln -s First $backup_tool_dir/1");
+ }
+ else
+ {
+ &gst_file_create_path_for_file ("$backup_tool_dir/1/");
+ }
+
+ &gst_report ("file_backup_rotate", $backup_tool_dir);
+ }
+
+ &gst_report_enter ();
+}
+
+sub gst_file_backup
+{
+ my $backup_file = $_[0];
+ my $backup_tool_dir;
+
+ &gst_report_enter ();
+
+ $backup_tool_dir = &gst_file_get_backup_path () . "/$gst_name/";
+
+ &gst_file_backup_rotate_dirs ($backup_tool_dir);
+
+ # If the file hasn't already been backed up on this invocation, copy the
+ # file to the backup directory.
+
+ if (!stat ("$backup_tool_dir/1/$backup_file"))
+ {
+ &gst_file_create_path_for_file ("$backup_tool_dir/1/$backup_file");
+ copy ($backup_file, "$backup_tool_dir/1/$backup_file");
+ &gst_report ("file_backup_success", $backup_tool_dir);
+ }
+
+ &gst_report_leave ();
+}
+
+# Return 1/0 depending on file existance.
+sub gst_file_exists
+{
+ my ($file) = @_;
+
+ return (-f "$gst_prefix/$file")? 1: 0;
+}
+
+sub gst_file_open_read_from_names
+{
+ local *FILE;
+ my $fname = "";
+
+ &gst_report_enter ();
+
+ foreach $name (@_)
+ {
+ if (open (FILE, "$gst_prefix/$name"))
+ {
+ $fname = $name;
+ last;
+ }
+ }
+
+ (my $fullname = "$gst_prefix/$fname") =~ tr/\//\//s; # '//' -> '/'
+
+ if ($fname eq "")
+ {
+ &gst_report ("file_open_read_failed", "@_");
+ return undef;
+ }
+
+ &gst_report ("file_open_read_success", $fullname);
+ &gst_report_leave ();
+
+ return *FILE;
+}
+
+
+sub gst_file_open_write_from_names
+{
+ local *FILE;
+ my $name;
+ my $fullname;
+
+ &gst_report_enter ();
+
+ # Find out where it lives.
+
+ foreach $elem (@_) { if (stat($elem) ne "") { $name = $elem; last; } }
+
+ if ($name eq "")
+ {
+ $name = $_[0];
+ (my $fullname = "$gst_prefix/$name") =~ tr/\//\//s;
+ &gst_report ("file_open_write_create", "@_", $fullname);
+ }
+ else
+ {
+ (my $fullname = "$gst_prefix/$name") =~ tr/\//\//s;
+ &gst_report ("file_open_write_success", $fullname);
+ }
+
+ ($name = "$gst_prefix/$name") =~ tr/\//\//s; # '//' -> '/'
+ &gst_file_create_path_for_file ($name);
+
+ # Make a backup if the file already exists - if the user specified a prefix,
+ # it might not.
+
+ if (stat ($name))
+ {
+ &gst_file_backup ($name);
+ }
+
+ &gst_report_leave ();
+
+ # Truncate and return filehandle.
+
+ if (!open (FILE, ">$name"))
+ {
+ &gst_report ("file_open_write_failed", $name);
+ return undef;
+ }
+
+ return *FILE;
+}
+
+sub gst_file_open_filter_write_from_names
+{
+ local *INFILE;
+ local *OUTFILE;
+ my ($filename, $name, $elem);
+
+ &gst_report_enter ();
+
+ # Find out where it lives.
+
+ foreach $coin (@_)
+ {
+ if (-e $coin) { $name = $coin; last; }
+ }
+
+ if (! -e $name)
+ {
+ # If we couldn't locate the file, and have no prefix, give up.
+
+ # If we have a prefix, but couldn't locate the file relative to '/',
+ # take the first name in the array and let that be created in $prefix.
+
+ if ($prefix eq "")
+ {
+ &gst_report ("file_open_filter_failed", "@_");
+ return(0, 0);
+ }
+ else
+ {
+ $name = $_[0];
+ (my $fullname = "$gst_prefix/$name") =~ tr/\//\//s;
+ &gst_report ("file_open_filter_create", "@_", $fullname);
+ }
+ }
+ else
+ {
+ (my $fullname = "$gst_prefix/$name") =~ tr/\//\//s;
+ &gst_report ("file_open_filter_success", $name, $fullname);
+ }
+
+ ($filename) = $name =~ /.*\/(.+)$/;
+ ($name = "$gst_prefix/$name") =~ tr/\//\//s; # '//' -> '/'
+ &gst_file_create_path_for_file ($name);
+
+ # Make a backup if the file already exists - if the user specified a prefix,
+ # it might not.
+
+ if (-e $name)
+ {
+ &gst_file_backup ($name);
+ }
+
+ # Return filehandles. Make a copy to use as filter input. It might be
+ # invalid (no source file), in which case the caller should just write to
+ # OUTFILE without bothering with INFILE filtering.
+
+ my $tmp_path = &gst_file_get_tmp_path ();
+
+ &gst_file_create_path ("$tmp_path");
+ unlink ("$tmp_path/$gst_name-$filename");
+ copy ($name, "$tmp_path/$gst_name-$filename");
+
+ open (INFILE, "$tmp_path/$gst_name-$filename");
+
+ if (!open (OUTFILE, ">$name"))
+ {
+ &gst_report ("file_open_filter_failed", $name);
+ return;
+ }
+
+ &gst_report_leave ();
+
+ return (*INFILE, *OUTFILE);
+}
+
+
+sub gst_file_open_write_compressed
+{
+ local *FILE;
+ my ($name, $fullname, $gzip);
+
+ $gzip = &gst_file_locate_tool ("gzip");
+ return undef if (!$gzip);
+
+ &gst_report_enter ();
+
+ # Find out where it lives.
+
+ foreach $elem (@_) { if (stat($elem) ne "") { $name = $elem; last; } }
+
+ if ($name eq "")
+ {
+ $name = $_[0];
+ (my $fullname = "$gst_prefix/$name") =~ tr/\//\//s;
+ &gst_report ("file_open_write_create", "@_", $fullname);
+ }
+ else
+ {
+ (my $fullname = "$gst_prefix/$name") =~ tr/\//\//s;
+ &gst_report ("file_open_write_success", $fullname);
+ }
+
+ ($name = "$gst_prefix/$name") =~ tr/\//\//s; # '//' -> '/'
+ &gst_file_create_path_for_file ($name);
+
+ # Make a backup if the file already exists - if the user specified a prefix,
+ # it might not.
+
+ if (stat ($name))
+ {
+ &gst_file_backup ($name);
+ }
+
+ &gst_report_leave ();
+
+ # Truncate and return filehandle.
+
+ if (!open (FILE, "| $gzip -c > $name"))
+ {
+ &gst_report ("file_open_write_failed", $name);
+ return;
+ }
+
+ return *FILE;
+}
+
+
+sub gst_file_run_pipe
+{
+ my ($cmd, $mode_mask, $stderr) = @_;
+ my ($command);
+ local *PIPE;
+
+ $mode_mask = $GST_FILE_READ if $mode_mask eq undef;
+
+ &gst_report_enter ();
+
+ if ($stderr)
+ {
+ $command = &gst_file_get_cmd_path_with_stderr ($cmd);
+ }
+ else
+ {
+ $command = &gst_file_get_cmd_path ($cmd);
+ }
+
+ if ($command == -1)
+ {
+ &gst_report ("file_run_pipe_failed", $command);
+ &gst_report_leave ();
+ return undef;
+ }
+
+ $command .= " |" if $mode_mask & $GST_FILE_READ;
+ $command = "| $command > /dev/null" if $mode_mask & $GST_FILE_WRITE;
+
+ open PIPE, $command;
+ &gst_report ("file_run_pipe_success", $command);
+ &gst_report_leave ();
+ return *PIPE;
+}
+
+
+sub gst_file_run_pipe_read
+{
+ my ($cmd) = @_;
+
+ return &gst_file_run_pipe ($cmd, $GST_FILE_READ);
+}
+
+sub gst_file_run_pipe_read_with_stderr
+{
+ my ($cmd) = @_;
+
+ return &gst_file_run_pipe ($cmd, $GST_FILE_READ, 1);
+}
+
+sub gst_file_run_pipe_write
+{
+ my ($cmd) = @_;
+
+ return &gst_file_run_pipe ($cmd, $GST_FILE_WRITE);
+}
+
+
+sub gst_file_run_backtick
+{
+ my ($cmd, $stderr) = @_;
+ my ($fd, $res);
+
+ if ($stderr)
+ {
+ $fd = &gst_file_run_pipe_read_with_stderr ($cmd);
+ }
+ else
+ {
+ $fd = &gst_file_run_pipe_read ($cmd);
+ }
+
+ $res = join ('', <$fd>);
+ &gst_file_close ($fd);
+
+ return $res;
+}
+
+
+sub gst_file_close
+{
+ my ($fd) = @_;
+
+ close $fd if (ref \$fd eq "GLOB");
+}
+
+
+sub gst_file_remove
+{
+ my ($name) = @_;
+
+ &gst_report_enter ();
+ &gst_report ("file_remove", $name);
+
+ if (stat ($name))
+ {
+ &gst_file_backup ($name);
+ }
+
+ unlink $name;
+ &gst_report_leave ();
+}
+
+sub gst_file_rmtree
+{
+ my($roots, $verbose, $safe) = @_;
+ my(@files);
+ my($count) = 0;
+ $verbose ||= 0;
+ $safe ||= 0;
+
+ if ( defined($roots) && length($roots) ) {
+ $roots = [$roots] unless ref $roots;
+ }
+ else {
+ carp "No root path(s) specified\n";
+ return 0;
+ }
+
+ my($root);
+ foreach $root (@{$roots}) {
+ $root =~ s#/\z##;
+ (undef, undef, my $rp) = lstat $root or next;
+ $rp &= 07777; # don't forget setuid, setgid, sticky bits
+
+ if ( -d $root ) { # $root used to be _, which is a bug.
+ # this is why we are replicating this function.
+
+ # notabene: 0777 is for making readable in the first place,
+ # it's also intended to change it to writable in case we have
+ # to recurse in which case we are better than rm -rf for
+ # subtrees with strange permissions
+ chmod(0777, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
+ or carp "Can't make directory $root read+writeable: $!"
+ unless $safe;
+
+ local *DIR;
+ if (opendir DIR, $root) {
+ @files = readdir DIR;
+ closedir DIR;
+ }
+ else {
+ carp "Can't read $root: $!";
+ @files = ();
+ }
+
+ # Deleting large numbers of files from VMS Files-11 filesystems
+ # is faster if done in reverse ASCIIbetical order
+ @files = reverse @files if $Is_VMS;
+ ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS;
+ @files = map("$root/$_", grep $_!~/^\.{1,2}\z/s,@files);
+ $count += &gst_file_rmtree(\@files,$verbose,$safe);
+ if ($safe &&
+ ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
+ print "skipped $root\n" if $verbose;
+ next;
+ }
+ chmod 0777, $root
+ or carp "Can't make directory $root writeable: $!"
+ if $force_writeable;
+ print "rmdir $root\n" if $verbose;
+ if (rmdir $root) {
+ ++$count;
+ }
+ else {
+ carp "Can't remove directory $root: $!";
+ chmod($rp, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
+ or carp("and can't restore permissions to "
+ . sprintf("0%o",$rp) . "\n");
+ }
+ }
+ else {
+ if ($safe &&
+ ($Is_VMS ? !&VMS::Filespec::candelete($root)
+ : !(-l $root || -w $root)))
+ {
+ print "skipped $root\n" if $verbose;
+ next;
+ }
+ chmod 0666, $root
+ or carp "Can't make file $root writeable: $!"
+ if $force_writeable;
+ print "unlink $root\n" if $verbose;
+ # delete all versions under VMS
+ for (;;) {
+ unless (unlink $root) {
+ carp "Can't unlink file $root: $!";
+ if ($force_writeable) {
+ chmod $rp, $root
+ or carp("and can't restore permissions to "
+ . sprintf("0%o",$rp) . "\n");
+ }
+ last;
+ }
+ ++$count;
+ last unless $Is_VMS && lstat $root;
+ }
+ }
+ }
+
+ $count;
+}
+
+# --- Buffer operations --- #
+
+
+# Open $file and put it into @buffer, for in-line editting.
+# \@buffer on success, undef on error.
+
+sub gst_file_buffer_load
+{
+ my ($file) = @_;
+ my @buffer;
+ my $fd;
+
+ &gst_report_enter ();
+ &gst_report ("file_buffer_load", $file);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ return [] unless $fd;
+
+ @buffer = (<$fd>);
+
+ &gst_report_leave ();
+
+ return \@buffer;
+}
+
+# Same with an already open fd.
+sub gst_file_buffer_load_fd
+{
+ my ($fd) = @_;
+ my (@buffer);
+
+ &gst_report_enter ();
+ &gst_report ("file_buffer_load", $file);
+
+ @buffer = (<$fd>);
+
+ &gst_report_leave ();
+
+ return \@buffer;
+}
+
+# Take a $buffer and save it in $file. -1 is error, 0 success.
+
+sub gst_file_buffer_save
+{
+ my ($buffer, $file) = @_;
+ my ($fd, $i);
+
+ &gst_report_enter ();
+ &gst_report ("file_buffer_save", $file);
+
+ foreach $i (@$buffer)
+ {
+ &gst_debug_print_string ("|" . $i);
+ }
+
+ $fd = &gst_file_open_write_from_names ($file);
+ return -1 if !$fd;
+
+ if (@$buffer < 1)
+ {
+ # We want to write single line.
+ # Print only if $buffer is NOT a reference (it'll print ARRAY(0x412493) for example).
+ print $fd $buffer if (!ref ($buffer));
+ }
+
+ else
+ {
+ # Let's print array
+
+ foreach $i (@$buffer)
+ {
+ print $fd $i;
+ }
+ }
+
+ &gst_file_close ($fd);
+
+ &gst_report_leave ();
+
+ return 0;
+}
+
+
+# Erase all empty string elements from the $buffer.
+
+sub gst_file_buffer_clean
+{
+ my $buffer = $_[0];
+ my $i;
+
+ for ($i = 0; $i <= $#$buffer; $i++)
+ {
+ splice (@$buffer, $i, 1) if $$buffer[$i] eq "";
+ }
+}
+
+
+sub gst_file_buffer_join_lines
+{
+ my $buffer = $_[0];
+ my $i;
+
+ for ($i = 0; $i <= $#$buffer; $i++)
+ {
+ while ($$buffer[$i] =~ /\\$/)
+ {
+ chomp $$buffer[$i];
+ chop $$buffer[$i];
+ $$buffer[$i] .= $$buffer[$i + 1];
+ splice (@$buffer, $i + 1, 1);
+ }
+ }
+}
+
+
+# --- Command-line utilities --- #
+
+
+# &gst_file_run (<command line>)
+#
+# Assumes the first word on the command line is the command-line utility
+# to run, and tries to locate it, replacing it with its full path. The path
+# is cached in a hash, to avoid searching for it repeatedly. Output
+# redirection is appended, to make the utility perfectly silent. The
+# preprocessed command line is run, and its exit value is returned.
+#
+# Example: "mkswap /dev/hda3" -> 'PATH=$PATH:/sbin:/usr/sbin /sbin/mkswap /dev/hda3 2>/dev/null >/dev/null'.
+
+sub gst_file_run
+{
+ my ($cmd, $background) = @_;
+ my ($command, $tool_name, $tool_path, @argline);
+
+ &gst_report_enter ();
+
+ $command = &gst_file_get_cmd_path ($cmd);
+ return -1 if $command == -1;
+ $command .= " > /dev/null";
+ $command .= " &" if $background;
+
+ &gst_report ("file_run", $command);
+ &gst_report_leave ();
+
+ # As documented in perlfunc, divide by 256.
+ return (system ($command) / 256);
+}
+
+sub gst_file_run_bg
+{
+ my ($cmd) = @_;
+
+ return &gst_file_run ($cmd, 1);
+}
+
+# &gst_file_locate_tool
+#
+# Tries to locate a command-line utility from a set of built-in paths
+# and a set of user paths (found in the environment). The path (or a negative
+# entry) is cached in a hash, to avoid searching for it repeatedly.
+
+@gst_builtin_paths = ( "/sbin", "/usr/sbin", "/usr/local/sbin",
+ "/bin", "/usr/bin", "/usr/local/bin" );
+
+%gst_tool_paths = ();
+
+sub gst_file_locate_tool
+{
+ my ($tool) = @_;
+ my $found = "";
+ my @user_paths;
+
+ # We don't search absolute paths. Arturo.
+ if ($tool =~ /^\//)
+ {
+ if (! (-x $tool))
+ {
+ &gst_report ("file_locate_tool_failed", $tool);
+ return "";
+ }
+
+ return $tool;
+ }
+
+ &gst_report_enter ();
+
+ $found = $gst_tool_paths{$tool};
+ if ($found eq "0")
+ {
+ # Negative cache hit. At this point, the failure has already been reported
+ # once.
+ return "";
+ }
+
+ if ($found eq "")
+ {
+ # Nothing found in cache. Look for real.
+
+ # Extract user paths to try.
+
+ @user_paths = ($ENV{PATH} =~ /([^:]+):/mg);
+
+ # Try user paths.
+
+ foreach $path (@user_paths)
+ {
+ if (-x "$path/$tool" || -u "$path/$tool") { $found = "$path/$tool"; last; }
+ }
+
+ if (!$found)
+ {
+ # Try builtin paths.
+ foreach $path (@gst_builtin_paths)
+ {
+ if (-x "$path/$tool" || -u "$path/$tool") { $found = "$path/$tool"; last; }
+ }
+ }
+
+ # Report success/failure and update cache.
+
+ if ($found)
+ {
+ $gst_tool_paths{$tool} = $found;
+ &gst_report ("file_locate_tool_success", $tool);
+ }
+ else
+ {
+ $gst_tool_paths{$tool} = "0";
+ &gst_report ("file_locate_tool_failed", $tool);
+ }
+ }
+
+ &gst_report_leave ();
+
+ return ($found);
+}
+
+sub gst_file_tool_installed
+{
+ my ($tool) = @_;
+
+ $tool = &gst_file_locate_tool ($tool);
+ return 0 if $tool eq "";
+ return 1;
+}
+
+sub gst_file_copy
+{
+ my ($orig, $dest) = @_;
+
+ return if (!gst_file_exists ($orig));
+ copy ("$gst_prefix/$orig", "$gst_prefix/$dest");
+}
+
+sub gst_file_get_temp_name
+{
+ my ($prefix) = @_;
+
+ return mktemp ($prefix);
+}
+
+sub gst_file_copy_from_stock
+{
+ my ($orig, $dest) = @_;
+
+ if (!copy ("$FILESDIR/$orig", $dest))
+ {
+ &gst_report ("file_copy_failed", "$FILESDIR/$orig", $dest);
+ return -1;
+ }
+
+ return 0;
+}
+
+1;
diff --git a/knetworkconf/backends/general.pl.in b/knetworkconf/backends/general.pl.in
new file mode 100644
index 0000000..809c77a
--- /dev/null
+++ b/knetworkconf/backends/general.pl.in
@@ -0,0 +1,644 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Common stuff for the ximian-setup-tools backends.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/report.pl$DOTIN";
+require "$SCRIPTSDIR/platform.pl$DOTIN";
+require "$SCRIPTSDIR/xml.pl$DOTIN";
+
+eval "use Locale::gettext";
+$eval_gettext = $@;
+eval "use POSIX";
+$eval_posix = $@;
+eval "use Encode";
+$eval_encode = $@;
+
+$has_i18n = (($eval_gettext eq "") && ($eval_posix eq "") && ($eval_encode eq ""));
+
+if ($has_i18n)
+{
+ # set up i18n stuff
+ &setlocale (LC_MESSAGES, "");
+ &bindtextdomain ("@GETTEXT_PACKAGE@", "@localedir@");
+
+ # Big stupid hack, but it's the best I can do until
+ # distros switch to perl's gettext 1.04...
+ eval "&bind_textdomain_codeset (\"@GETTEXT_PACKAGE@\", \"UTF-8\")";
+ &textdomain ("@GETTEXT_PACKAGE@");
+
+ eval "sub _ { return gettext (shift); }";
+}
+else
+{
+ # fake the gettext calls
+ eval "sub _ { return shift; }";
+}
+
+# --- Operation modifying variables --- #
+
+
+# Variables are set to their default value, which may be overridden by user. Note
+# that a $prefix of "" will cause the configurator to use '/' as the base path,
+# and disables creation of directories and writing of previously non-existent
+# files.
+
+# We should get rid of all these globals.
+
+$gst_name = ""; # Short name of tool.
+# $gst_version = ""; # Version of tool - [major.minor.revision]. Deprecated: now in hash
+# structure generated by &gst_init.
+# $gst_operation = ""; # Major operation user wants to perform - [get | set | filter]. Same as gst_version.
+
+$gst_prefix = "";
+$gst_do_verbose = 0;
+$gst_do_report = 0;
+
+$gst_debug = 0;
+$gst_do_immediate = 1;
+
+
+# Location management stuff
+$gst_location = "";
+$gst_no_archive = 0;
+
+sub gst_print_usage_synopsis
+{
+ my ($tool) = @_;
+ my ($ops_syn, $i);
+ my @ops = qw (get set filter);
+
+ foreach $i (@ops)
+ {
+ $ops_syn .= "--$i | " if exists $ {$$tool{"directives"}}{$i};
+ }
+
+ print STDERR "Usage: $$tool{name}-conf <${ops_syn}--interface | --directive | --help | --version>\n";
+
+ print STDERR " " x length $$tool{"name"};
+ print STDERR " [--disable-immediate] [--prefix <location>]\n";
+
+ print STDERR " " x length $$tool{"name"};
+ print STDERR " [--progress] [--report] [--verbose]\n\n";
+}
+
+sub gst_print_usage_generic
+{
+ my ($tool) = @_;
+ my (%usage, $i);
+ my @ops = qw (get set filter);
+
+ my $usage_generic_head =<< "end_of_usage_generic;";
+ Major operations (specify one of these):
+
+end_of_usage_generic;
+
+ my $usage_generic_tail =<< "end_of_usage_generic;";
+ -i --interface Shows the available backend directives for interactive mode,
+ in XML format.
+
+ Interactive mode is set when no -g, -s or -f arguments are
+ given.
+
+ -d --directive <directive> Takes a \'name::arg1::arg2...::argN\' directive
+ value as comming from standard input in interactive mode.
+
+ -h --help Prints this page to standard error.
+
+ --version Prints version information to standard output.
+
+ Modifiers (specify any combination of these):
+
+ --platform <name-ver> Overrides the detection of your platform\'s
+ name and version, e.g. redhat-6.2. Use with care. See the
+ documentation for a full list of supported platforms.
+
+ --disable-immediate With --set, prevents the configurator from
+ running any commands that make immediate changes to
+ the system configuration. Use with --prefix to make a
+ dry run that won\'t affect your configuration.
+
+ With --get, suppresses running of non-vital external
+ programs that might take a long time to finish.
+
+ -p --prefix <location> Specifies a directory prefix where the
+ configuration is looked for or stored. When storing
+ (with --set), directories and files may be created.
+
+ --progress Prints machine-readable progress information to standard
+ output, before any XML, consisting of three-digit
+ percentages always starting with \'0\'.
+
+ --report Prints machine-readable diagnostic messages to standard
+ output, before any XML. Each message has a unique
+ three-digit ID. The report ends in a blank line.
+
+ -v --verbose Prints human-readable diagnostic messages to standard
+ error.
+end_of_usage_generic;
+
+ $usage{"get"} =<< "end_of_usage_generic;";
+ -g --get Prints the current configuration to standard output, as
+ a standalone XML document. The configuration is read from
+ the host\'s system config files.
+
+end_of_usage_generic;
+ $usage{"set"} =<< "end_of_usage_generic;";
+ -s --set Updates the current configuration from a standalone XML
+ document read from standard input. The format is the same
+ as for the document generated with --get.
+
+end_of_usage_generic;
+ $usage{"filter"} =<< "end_of_usage_generic;";
+ -f --filter Reads XML configuration from standard input, parses it,
+ and writes the configurator\'s impression of it back to
+ standard output. Good for debugging and parsing tests.
+
+end_of_usage_generic;
+
+ print STDERR $usage_generic_head;
+
+ foreach $i (@ops)
+ {
+ print STDERR $usage{$i} if exists $ {$$tool{"directives"}}{$i};
+ }
+
+ print STDERR $usage_generic_tail;
+}
+
+# if $exit_code is provided (ne undef), exit with that code at the end.
+sub gst_print_usage
+{
+ my ($tool, $exit_code) = @_;
+
+ &gst_print_usage_synopsis ($tool);
+ print STDERR $$tool{"description"} . "\n";
+ &gst_print_usage_generic ($tool);
+
+ exit $exit_code if $exit_code ne undef;
+}
+
+sub gst_print_version
+{
+ my ($tool, $exit_code) = @_;
+
+ print "$$tool{name} $$tool{version}\n";
+
+ exit $exit_code if $exit_code ne undef;
+}
+
+# --- Initialization and finalization --- #
+
+
+sub gst_set_operation
+{
+ my ($tool, $operation) = @_;
+
+ if ($tool{"operation"} ne "")
+ {
+ print STDERR "Error: You may specify only one major operation.\n\n";
+ &gst_print_usage ($tool, 1);
+ exit (1);
+ }
+
+ $$tool{"operation"} = $operation;
+}
+
+sub gst_set_with_param
+{
+ my ($tool, $arg_name, $value) = @_;
+
+ if ($$tool{$arg_name} ne "")
+ {
+ print STDERR "Error: You may specify --$arg_name only once.\n\n";
+ &gst_print_usage ($tool, 1);
+ }
+
+ if ($value eq "")
+ {
+ print STDERR "Error: You must specify an argument to the --$arg_name option.\n\n";
+ &gst_print_usage ($tool, 1);
+ }
+
+ $$tool{$arg_name} = $value;
+}
+
+sub gst_set_op_directive
+{
+ my ($tool, $directive) = @_;
+
+ &gst_set_with_param ($tool, "directive", $directive);
+ &gst_set_operation ($tool, "directive");
+}
+
+sub gst_set_prefix
+{
+ my ($tool, $prefix) = @_;
+
+ &gst_set_with_param ($tool, "prefix", $prefix);
+ $gst_prefix = $prefix;
+}
+
+sub gst_set_dist
+{
+ my ($tool, $dist) = @_;
+
+ &gst_set_with_param ($tool, "platform", $dist);
+ $gst_dist = $dist;
+}
+
+sub gst_set_location
+{
+ my ($tool, $location) = @_;
+
+ &gst_set_with_param ($tool, "location", $location);
+ $gst_location = $location;
+}
+
+sub gst_merge_std_directives
+{
+ my ($tool) = @_;
+ my ($directives, $i);
+ my %std_directives =
+ (
+# platforms directive to do later.
+ "platforms" => [ \&gst_platform_list, [],
+ "Print XML showing platforms supported by backend." ],
+ "platform_set" => [ \&gst_platform_set, ["platform"],
+ "Force the selected platform. platform arg must be one of the listed in the" .
+ "reports." ],
+ "interface" => [ \&gst_interface_directive, [],
+ "Print XML showing backend capabilities." ],
+ "end" => [ \&gst_end_directive, [],
+ "Finish gracefuly and exit with success." ]
+ );
+
+ $directives = $$tool{"directives"};
+ # Standard directives may be overriden.
+ foreach $i (keys %std_directives)
+ {
+ $$directives{$i} = $std_directives{$i} if !exists $$directives{$i};
+ }
+}
+
+sub gst_is_tool
+{
+ my ($tool) = @_;
+
+ if ((ref $tool eq "HASH") &&
+ (exists $$tool{"is_tool"}) &&
+ ($$tool{"is_tool"} == 1))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+sub gst_init
+{
+ my ($name, $version, $description, $directives, @args) = @_;
+ my (%tool, $arg);
+
+ # print a CR for synchronysm with the frontend
+ print "\n";
+
+ # Set the output autoflush.
+ $old_fh = select (STDOUT); $| = 1; select ($old_fh);
+ $old_fh = select (STDERR); $| = 1; select ($old_fh);
+
+ $tool{"is_tool"} = 1;
+
+ # Set backend descriptors.
+
+ $tool{"name"} = $gst_name = $name;
+ $tool{"version"} = $version;
+ $tool{"description"} = $description;
+ $tool{"directives"} = $directives;
+
+ &gst_merge_std_directives (\%tool);
+
+ # Parse arguments.
+
+ while ($arg = shift (@args))
+ {
+ if ($arg eq "--get" || $arg eq "-g") { &gst_set_operation (\%tool, "get"); }
+ elsif ($arg eq "--set" || $arg eq "-s") { &gst_set_operation (\%tool, "set"); }
+ elsif ($arg eq "--filter" || $arg eq "-f") { &gst_set_operation (\%tool, "filter"); }
+ elsif ($arg eq "--directive" || $arg eq "-d") { &gst_set_op_directive (\%tool, shift @args); }
+ elsif ($arg eq "--interface" || $arg eq "-i") { &gst_interface_print (\%tool, 0); }
+ elsif ($arg eq "--help" || $arg eq "-h") { &gst_print_usage (\%tool, 0); }
+ elsif ($arg eq "--version") { &gst_print_version (\%tool, 0); }
+ elsif ($arg eq "--prefix" || $arg eq "-p") { &gst_set_prefix (\%tool, shift @args); }
+ elsif ($arg eq "--platform") { &gst_set_dist (\%tool, shift @args); }
+ elsif ($arg eq "--progress") { $tool{"progress"} = $gst_progress = 1; }
+ elsif ($arg eq "--location") { &gst_set_location (\%tool, shift @args); }
+ elsif ($arg eq "--no-archive") { $tool{"no_archive"} = $gst_no_archive = 1; }
+ elsif ($arg eq "--debug") { $tool{"debug"} = $gst_debug = 1; }
+ elsif ($arg eq "--verbose" || $arg eq "-v")
+ {
+ $tool{"do_verbose"} = $gst_do_verbose = 1;
+ &gst_report_set_threshold (99);
+ }
+ elsif ($arg eq "--report")
+ {
+ $tool{"do_report"} = $gst_do_report = 1;
+ &gst_report_set_threshold (99);
+ }
+ else
+ {
+ print STDERR "Error: Unrecognized option '$arg'.\n\n";
+ &gst_print_usage (\%tool, 1);
+ }
+ }
+
+ # See if debug requested in env.
+
+ $tool{"debug"} = $gst_debug = 1 if ($ENV{"SET_ME_UP_HARDER"});
+
+ # Set up subsystems.
+
+ &gst_platform_get_system (\%tool);
+ &gst_platform_guess (\%tool) if !$tool{"platform"};
+ &gst_report_begin ();
+
+ return \%tool;
+}
+
+sub gst_terminate
+{
+ &gst_report_set_threshold (-1);
+ &gst_debug_close_all ();
+ exit (0);
+}
+
+sub gst_end_directive
+{
+ my ($tool) = @_;
+
+ &gst_report_end ();
+ &gst_xml_print_request_end ();
+ &gst_terminate ();
+}
+
+
+sub gst_interface_print_comment
+{
+ my ($name, $directive) = @_;
+ my %std_comments =
+ ("get" =>
+ "Prints the current configuration to standard output, as " .
+ "a standalone XML document. The configuration is read from " .
+ "the host\'s system config files.",
+
+ "set" =>
+ "Updates the current configuration from a standalone XML " .
+ "document read from standard input. The format is the same " .
+ "as for the document generated with --get.",
+
+ "filter" =>
+ "Reads XML configuration from standard input, parses it, " .
+ "and writes the configurator\'s impression of it back to " .
+ "standard output. Good for debugging and parsing tests."
+ );
+
+ $comment = $$directive[2];
+ $comment = $std_comments{$name} if (exists $std_comments{$name});
+
+ if ($comment)
+ {
+ &gst_xml_print_line ("<comment>");
+ &gst_xml_print_line ($comment);
+ &gst_xml_print_line ("</comment>");
+ }
+}
+
+# if $exit_code is provided (ne undef), exit with that code at the end.
+sub gst_interface_print
+{
+ my ($tool, $exit_code) = @_;
+ my ($directives, $key);
+
+ $directives = $$tool{"directives"};
+
+ &gst_xml_print_begin ("interface");
+ foreach $key (sort keys %$directives)
+ {
+ my $comment = $ {$$directives{$key}}[2];
+ my @args = @{ $ {$$directives{$key}}[1]};
+ my $arg;
+
+ &gst_xml_container_enter ("directive");
+ &gst_xml_print_line ("<name>$key</name>");
+ &gst_interface_print_comment ($key, $$directives{$key});
+
+ while ($arg = shift (@args))
+ {
+ if ($arg =~ /\*$/)
+ {
+ my $tmp = $arg;
+
+ &gst_report ("directive_invalid", $key) if ($#args != -1);
+ chop $tmp;
+ &gst_xml_print_line ("<var-arguments>$tmp</var-arguments>");
+ }
+ else
+ {
+ &gst_xml_print_line ("<argument>$arg</argument>");
+ }
+ }
+
+ &gst_xml_container_leave ();
+ }
+ &gst_xml_print_end ("interface");
+
+ exit $exit_code if $exit_code ne undef;
+}
+
+
+sub gst_interface_directive
+{
+ my ($tool) = @_;
+
+ &gst_report_end ();
+ &gst_interface_print ($tool);
+}
+
+
+sub gst_directive_fail
+{
+ my (@report_args) = @_;
+
+ &gst_report (@report_args);
+ &gst_report_end ();
+ &gst_xml_print_request_end ();
+ &gst_debug_close_all ();
+}
+
+# This sepparates a line in args by the directive line format,
+# doing the necessary escape sequence manipulations.
+sub gst_directive_parse_line
+{
+ my ($line) = @_;
+ my ($arg, @args);
+
+ chomp $line;
+ $line =~ s/\\\\/___escape\\___/g;
+ $line =~ s/\\::/___escape2:___/g;
+ @args = split ("::", $line);
+
+ foreach $arg (@args)
+ {
+ $arg =~ s/___escape2:___/::/g;
+ $arg =~ s/___escape\\___/\\/g;
+ }
+
+ return @args;
+}
+
+# Normal use for the direcives hash in the backends is:
+#
+# "name" => [ \&sub, [ "arg1", "arg2", "arg3",... "argN" ], "comment" ]
+#
+# name name of the directive that will be used in interactive mode.
+# sub is the function that runs the directive.
+# arg1...argN show the number of arguments that the function may use. The
+# name of the argument is used for documentation purposes for
+# the interfaces XML (dumped by the "interfaces" directive).
+# An argument ending with * means that 0 or more arguments
+# may be given.
+# comment documents the directive in a brief way, for the interface XML.
+#
+# Example:
+#
+# "install_font" => [ \&gst_font_install, [ "directory", "file", "morefiles*" ], "Installs fonts." ]
+#
+# This means that when an interactive mode directive is given, such as:
+#
+# install_font::/usr/share/fonts::/tmp/myfile::/tmp/myfile2
+#
+# the function gst_font_install will be called, with the tool structure, /usr/share/fonts,
+# /tmp/myfile and /tmp/myfile2 as arguments. Directives with 1 or 0 arguments
+# would be rejected, as we are requiring 2, and optionaly allowing more.
+# Check enable_iface in network-conf.in for an example of a directive handler.
+#
+# The generated interface XML piece for this entry would be:
+#
+# <directive>
+# <name>gst_font_install</name>
+# <comment>
+# Installs fonts.
+# </comment>
+# <argument>directory</argument>
+# <argument>file</argument>
+# <var-arguments>morefiles</var-arguments>
+# </directive>
+
+
+sub gst_directive_run
+{
+ my ($tool, $line) = @_;
+ my ($key, @args, $directives, $proc, $reqargs, $i);
+
+ ($key, @args) = &gst_directive_parse_line ($line);
+ $directives = $$tool{"directives"};
+
+ &gst_report_begin ();
+
+ if (!exists $$directives{$key})
+ {
+ &gst_directive_fail ("directive_unsup", $key);
+ return;
+ }
+
+ $reqargs = [];
+ foreach $i (@{$ {$$directives{$key}}[1]})
+ {
+ push @$reqargs, $i if not ($i =~ /\*$/);
+ }
+
+ if (scalar @args < scalar @$reqargs)
+ {
+ &gst_directive_fail ("directive_lowargs", $key, scalar (@$reqargs), join (',', $key, @args));
+ return;
+ }
+
+ $reqargs = $ {$$directives{$key}}[1];
+ if ((scalar @args != scalar @$reqargs) &&
+ !($$reqargs[$#$reqargs] =~ /\*$/))
+ {
+ &gst_directive_fail ("directive_badargs", $key, scalar (@$reqargs), join (',', $key, @args));
+ return;
+ }
+
+ &gst_report ("directive_run", $key, join (',', @args));
+
+ $proc = $ {$$directives{$key}}[0];
+ &$proc ($tool, @args);
+
+ &gst_xml_print_request_end ();
+ &gst_debug_close_all ();
+}
+
+
+sub gst_run
+{
+ my ($tool) = @_;
+ my ($line);
+
+ if ($$tool{"operation"} ne "directive")
+ {
+ my @stdops = qw (get set filter);
+ my ($op);
+
+ foreach $op (@stdops)
+ {
+ if ($$tool{"operation"} eq $op)
+ {
+ $$tool{"operation"} = "directive";
+ $$tool{"directive"} = $op;
+ }
+ }
+ }
+
+ &gst_report_end ();
+
+ if ($$tool{"directive"})
+ {
+ &gst_directive_run ($tool, $$tool{"directive"});
+ &gst_terminate ();
+ }
+
+ while ($line = <STDIN>)
+ {
+ &gst_directive_run ($tool, $line);
+ }
+}
+
+1;
diff --git a/knetworkconf/backends/guess_system.sh b/knetworkconf/backends/guess_system.sh
new file mode 100755
index 0000000..e1b5871
--- /dev/null
+++ b/knetworkconf/backends/guess_system.sh
@@ -0,0 +1,1121 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
+# Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under 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.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+# Please send patches to <autoconf-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# Use $HOST_CC if defined. $CC may point to a cross-compiler
+if test x"$CC_FOR_BUILD" = x; then
+ if test x"$HOST_CC" != x; then
+ CC_FOR_BUILD="$HOST_CC"
+ else
+ if test x"$CC" != x; then
+ CC_FOR_BUILD="$CC"
+ else
+ CC_FOR_BUILD=cc
+ fi
+ fi
+fi
+
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .globl main
+ .ent main
+main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-cbm-sysv4
+ exit 0;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ arc64:OpenBSD:*:*)
+ echo mips64el-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hkmips:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ arm32:NetBSD:*:*)
+ echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ SR2?01:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:NetBSD:*:*)
+ echo powerpc-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i?86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ sed 's/^ //' << EOF >$dummy.c
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+ rm -f $dummy.c $dummy
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i?86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ hppa*:OpenBSD:*:*)
+ echo hppa-unknown-openbsd
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F300:UNIX_System_V:*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ F301:UNIX_System_V:*:*)
+ echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ if test -x /usr/bin/objformat; then
+ if test "elf" = "`/usr/bin/objformat`"; then
+ echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
+ exit 0
+ fi
+ fi
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_help_string=`cd /; ld --help 2>&1`
+ ld_supported_emulations=`echo $ld_help_string \
+ | sed -ne '/supported emulations:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported emulations: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_emulations" in
+ *ia64)
+ echo "${UNAME_MACHINE}-unknown-linux"
+ exit 0
+ ;;
+ i?86linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0
+ ;;
+ i?86coff)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0
+ ;;
+ sparclinux)
+ echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+ exit 0
+ ;;
+ armlinux)
+ echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+ exit 0
+ ;;
+ elf32arm*)
+ echo "${UNAME_MACHINE}-unknown-linux-gnu"
+ exit 0
+ ;;
+ armelf_linux*)
+ echo "${UNAME_MACHINE}-unknown-linux-gnu"
+ exit 0
+ ;;
+ m68klinux)
+ echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+ exit 0
+ ;;
+ elf32ppc)
+ # Determine Lib Version
+ cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#if defined(__GLIBC__)
+ printf("%s %s\n", __libc_version, __libc_release);
+#else
+ printf("unkown\n");
+#endif
+ return 0;
+}
+EOF
+ LIBC=""
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy | grep 1\.99 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f $dummy.c $dummy
+ echo powerpc-unknown-linux-gnu${LIBC}
+ exit 0
+ ;;
+ esac
+
+ if test "${UNAME_MACHINE}" = "alpha" ; then
+ sed 's/^ //' <<EOF >$dummy.s
+ .globl main
+ .ent main
+ main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ LIBC=""
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./$dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+
+ objdump --private-headers $dummy | \
+ grep ld.so.1 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+ elif test "${UNAME_MACHINE}" = "mips" ; then
+ cat >$dummy.c <<EOF
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __MIPSEB__
+ printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+ printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ else
+ # Either a pre-BFD a.out linker (linux-gnuoldld)
+ # or one that does not give us useful --help.
+ # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+ # If ld does not provide *any* "supported emulations:"
+ # that means it is gnuoldld.
+ echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+ test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+ case "${UNAME_MACHINE}" in
+ i?86)
+ VENDOR=pc;
+ ;;
+ *)
+ VENDOR=unknown;
+ ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i?86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i?86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i?86:*:5:7*)
+ # Fixed at (any) Pentium or better
+ UNAME_MACHINE=i586
+ if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+ echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i?86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ pc:*:*:*)
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:*:6*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-qnx-qnx${UNAME_VERSION}
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/knetworkconf/backends/mkinstalldirs b/knetworkconf/backends/mkinstalldirs
new file mode 100755
index 0000000..d2d5f21
--- /dev/null
+++ b/knetworkconf/backends/mkinstalldirs
@@ -0,0 +1,111 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+errstatus=0
+dirmode=""
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
+
+# process command line arguments
+while test $# -gt 0 ; do
+ case $1 in
+ -h | --help | --h*) # -h for help
+ echo "$usage" 1>&2
+ exit 0
+ ;;
+ -m) # -m PERM arg
+ shift
+ test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+ dirmode=$1
+ shift
+ ;;
+ --) # stop option processing
+ shift
+ break
+ ;;
+ -*) # unknown option
+ echo "$usage" 1>&2
+ exit 1
+ ;;
+ *) # first non-opt arg
+ break
+ ;;
+ esac
+done
+
+for file
+do
+ if test -d "$file"; then
+ shift
+ else
+ break
+ fi
+done
+
+case $# in
+ 0) exit 0 ;;
+esac
+
+case $dirmode in
+ '')
+ if mkdir -p -- . 2>/dev/null; then
+ echo "mkdir -p -- $*"
+ exec mkdir -p -- "$@"
+ fi
+ ;;
+ *)
+ if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
+ echo "mkdir -m $dirmode -p -- $*"
+ exec mkdir -m "$dirmode" -p -- "$@"
+ fi
+ ;;
+esac
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case $pathcomp in
+ -*) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ else
+ if test ! -z "$dirmode"; then
+ echo "chmod $dirmode $pathcomp"
+ lasterr=""
+ chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+ if test ! -z "$lasterr"; then
+ errstatus=$lasterr
+ fi
+ fi
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# End:
+# mkinstalldirs ends here
diff --git a/knetworkconf/backends/network-conf.in b/knetworkconf/backends/network-conf.in
new file mode 100755
index 0000000..104eb88
--- /dev/null
+++ b/knetworkconf/backends/network-conf.in
@@ -0,0 +1,639 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Network configurator. Designed to be architecture and distribution independent.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Michael Vogt <mvo@debian.org> (Debian Support)
+# Arturo Espinosa <arturo@ximian.com>
+# Grzegorz Golawski <grzegol@pld-linux.org> (PLD Support)
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+# Best viewed with 100 columns of width.
+
+# Configuration files affected:
+#
+# /etc/resolv.conf
+# /etc/host.conf
+# /etc/hosts
+# /etc/sysconfig/network
+# /etc/rc.config
+# /etc/smb.conf
+
+# Running programs affected:
+#
+# smbd
+# nmbd
+# ifconfig: check current interfaces and activate/deactivate.
+
+BEGIN {
+ $SCRIPTSDIR = "@scriptsdir@";
+ if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+ {
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+ }
+
+ require "$SCRIPTSDIR/general.pl$DOTIN";
+ require "$SCRIPTSDIR/platform.pl$DOTIN";
+ require "$SCRIPTSDIR/util.pl$DOTIN";
+ require "$SCRIPTSDIR/file.pl$DOTIN";
+ require "$SCRIPTSDIR/xml.pl$DOTIN";
+ require "$SCRIPTSDIR/network.pl$DOTIN";
+}
+
+# --- Tool information --- #
+
+$name = "network";
+$version = "@VERSION@";
+@platforms = ("redhat-5.2", "redhat-6.0", "redhat-6.1", "redhat-6.2", "redhat-7.0", "redhat-7.1",
+ "redhat-7.2", "redhat-8.0", "redhat-9",
+ "openna-1.0",
+ "mandrake-7.1", "mandrake-7.2", "mandrake-9.0", "mandrake-9.1", "mandrake-9.2",
+ "mandrake-10.0", "mandrake-10.1","mandrake-10.2", "mandriva-2006.0",
+ "mandriva-2006.1", "mandriva-2007.0", "mandriva-2007.1",
+ "yoper-2.2",
+ "blackpanther-4.0",
+ "debian-2.2", "debian-3.0", "debian-3.1", "debian-4.0", "debian-5.0", "debian-testing",
+ "ubuntu-5.04", "ubuntu-5.10", "ubuntu-6.06", "ubuntu-6.10", "ubuntu-7.04", "ubuntu-7.10", "ubuntu-8.04",
+ "suse-7.0", "suse-9.0", "suse-9.1",
+ "turbolinux-7.0", "fedora-1", "fedora-2", "fedora-3", "fedora-4", "fedora-5", "rpath",
+ "pld-1.0", "pld-1.1", "pld-1.99",
+ "conectiva-9", "conectiva-10",
+ "vine-3.0", "vine-3.1",
+ "ark",
+ "slackware-9.1.0", "slackware-10.0.0", "slackware-10.1.0", "slackware-10.2.0",
+ "gentoo", "vlos-1.2", "freebsd-5", "freebsd-6");
+
+$description =<<"end_of_description;";
+ Configures all network parameters and interfaces.
+end_of_description;
+
+$progress_max = 10;
+
+$profile_file = "profiles.xml";
+
+
+# --- XML parsing ---
+
+# Scan XML from standard input to an internal tree.
+sub xml_parse
+{
+ my ($tree, %hash, $elem);
+ # Scan XML to tree.
+
+ $tree = &gst_xml_scan ();
+
+ # Walk the tree recursively and extract configuration parameters.
+ # This is the top level - find and enter the "network" tag.
+
+ while ($elem = shift @$tree)
+ {
+ if ($elem eq "network") { &xml_parse_network (shift @$tree, \%hash); }
+ else { &gst_report ("xml_unexp_tag", $elem); shift @$tree; }
+ }
+
+ return(\%hash);
+}
+
+# <network>...</network>
+
+sub push_unique
+{
+ my ($arr, $val) = @_;
+ my $i;
+
+ foreach $i (@$arr)
+ {
+ return if $i eq $val;
+ }
+
+ push @$arr, $val;
+}
+
+sub xml_parse_network
+{
+ my ($tree, $hash) = @_;
+ my ($elem);
+ my (@searchdomain, @nameserver, @order, %statichost, %interface, %dialing);
+
+ shift @$tree; # Skip attributes.
+
+ while ($elem = shift @$tree)
+ {
+ if ($elem eq "auto") { $$hash{"auto"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "hostname") { $$hash{"hostname"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "gateway") { $$hash{"gateway"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "gatewaydev") { $$hash{"gatewaydev"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "domain") { $$hash{"domain"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "workgroup") { $$hash{"workgroup"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "smbdesc") { $$hash{"smbdesc"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "name") { $$hash{"name"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "description") { $$hash{"description"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "winsserver") { $$hash{"winsserver"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "winsuse") { $$hash{"winsuse"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "smbuse") { $$hash{"smbuse"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "hostmatch") { $$hash{"hostmatch"} = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "nameserver") { &push_unique (\@nameserver, &gst_xml_get_pcdata (shift @$tree)); }
+ elsif ($elem eq "searchdomain") { &push_unique (\@searchdomain, &gst_xml_get_pcdata (shift @$tree)); }
+ elsif ($elem eq "order") { push (@order, &gst_xml_get_pcdata (shift @$tree)); }
+ elsif ($elem eq "statichost") { &xml_parse_statichost (shift @$tree, \%statichost); }
+ elsif ($elem eq "interface") { &gst_network_xml_parse_interface (shift @$tree, \%interface); }
+ elsif ($elem eq "dialing") { &xml_parse_dialing (shift @$tree, \%dialing); }
+ elsif ($elem eq "dialinstalled") { shift @$tree; }
+ elsif ($elem eq "smbinstalled") { shift @$tree; }
+ elsif ($elem eq "smartdhcpcd") { shift @$tree; }
+ elsif ($elem eq "gwdevunsup") { shift @$tree; }
+ elsif ($elem eq "wireless_device") { shift @$tree; }
+ elsif ($elem eq "profiledb") { &xml_parse_profiledb (shift @$tree, $hash); }
+ else { &gst_report ("xml_unexp_tag", $elem); shift @$tree; }
+ }
+
+ $$hash{"order"} = \@order unless $#order < 0;
+ $$hash{"searchdomain"} = \@searchdomain unless $#searchdomain < 0;
+ $$hash{"nameserver"} = \@nameserver unless $#nameserver < 0;
+ $$hash{"statichost"} = \%statichost unless scalar keys %statichost == 0;
+ $$hash{"interface"} = \%interface unless scalar keys %interface == 0;
+ $$hash{"dialing"} = \%dialing unless scalar keys %dialing == 0;
+}
+
+# <network><statichost>...</statichost></network>
+sub xml_parse_statichost
+{
+ my ($tree, $statichost) = @_;
+ my ($ip, @alias, $elem);
+
+ shift @$tree;
+
+ while ($elem = shift @$tree)
+ {
+ if ($elem eq "ip") { $ip = &gst_xml_get_pcdata (shift @$tree); }
+ elsif ($elem eq "alias") { push(@alias, &gst_xml_get_pcdata (shift @$tree)); }
+ else { &gst_report ("xml_unexp_tag", $elem); shift @$tree; }
+ }
+
+ # common regexp for IPv4 and IPv6
+ if ($ip =~ /([0-9a-fA-F\.:])+/)
+ {
+ $$statichost{$ip} = \@alias;
+ }
+}
+
+sub xml_parse_dialing
+{
+ my ($tree, $dialing) = @_;
+ my (%hash, $name, $elem);
+
+ shift @$tree;
+
+ while ($elem = shift @$tree)
+ {
+ $hash{$elem} = &gst_xml_get_pcdata (shift @$tree);
+ }
+
+ $name = $hash{"name"};
+ $$dialing{$name} = \%hash;
+}
+
+# couple of functions for fixing profiles format
+sub fix_profile_modem_iface
+{
+ my ($configuration, $section, $dialing) = @_;
+ my ($s, $key, %h);
+
+ foreach $s (keys %$dialing)
+ {
+ if ($s eq $section)
+ {
+ $h = $$dialing{$s};
+
+ foreach $key (keys %$h)
+ {
+ $$configuration{$key} = $$h{$key};
+ }
+ }
+ }
+}
+
+sub fix_profile_interface_format
+{
+ my ($interface, $dialing) = @_;
+ my (%configuration, $key, $section);
+
+ return if (exists $$interface{"configuration"});
+
+ foreach $key (keys %$interface)
+ {
+ if ($key !~ /^(dev|enabled|hwaddr)$/)
+ {
+ if ($key eq 'wvsection')
+ {
+ &fix_profile_modem_iface (\%configuration, $$interface{$key}, $dialing);
+ $configuration{"section"} = $$interface{$key};
+ }
+ else
+ {
+ $dest_key = $key;
+ $configuration{$key} = $$interface{$key};
+ }
+
+ delete $$interface{$key};
+ }
+ }
+
+ $$interface{"type"} = &gst_network_get_interface_type ($$interface{"dev"});
+
+ if (%configuration)
+ {
+ $$interface{"configuration"} = \%configuration;
+ }
+}
+
+sub fix_profile_format
+{
+ my ($hash) = @_;
+ my ($interfaces, $dialing, $iface);
+
+ $interfaces = $$hash{"interface"};
+ $dialing = $$hash{"dialing"};
+
+ foreach $iface (keys %$interfaces)
+ {
+ &fix_profile_interface_format ($$interfaces{$iface}, $dialing);
+ }
+}
+
+sub xml_parse_profile
+{
+ my ($tree, $hash) = @_;
+ my (%profile);
+
+ &xml_parse_network ($tree, \%profile);
+
+ # We've got to translate the old profiles format
+ &fix_profile_format (\%profile);
+
+ push @{$hash->{"profiledb"}{"profile"}}, \%profile;
+}
+
+sub xml_parse_profiledb
+{
+ my ($tree, $hash) = @_;
+
+ shift @$tree; # Skip attributes.
+
+ while (@$tree)
+ {
+ if ($$tree[0] eq "profile") { &xml_parse_profile ($$tree[1], $hash); }
+ else
+ {
+ &gst_report ("xml_unexp_tag", $$tree[0]);
+ }
+
+ shift @$tree;
+ shift @$tree;
+ }
+}
+
+# --- XML printing --- #
+
+sub xml_print_configuration
+{
+ my ($h) = @_;
+ my @scalar_keys =
+ qw(auto hostname gateway gatewaydev gwdevunsup domain
+ hostmatch workgroup smbdesc winsserver winsuse smbuse
+ smartdhcpcd smbinstalled dialinstalled name);
+ my @array_keys =
+ qw(nameserver searchdomain order);
+
+ # Hostname, domain, search domains, nameservers.
+
+ &gst_xml_print_scalars ($h, @scalar_keys);
+ &gst_xml_print_arrays ($h, @array_keys);
+ &network_xml_print_statichost ($h);
+
+ &xml_print_interfaces ($$h{"interface"});
+}
+
+sub xml_print_profiledb
+{
+ my ($h) = @_;
+
+ &gst_xml_print_vspace ();
+
+ &gst_xml_print_line ("<profiledb>\n");
+ &gst_xml_enter ();
+ foreach $i (@{$$h{"profiledb"}{"profile"}})
+ {
+ gst_xml_print_line ("<profile>\n");
+ gst_xml_enter ();
+
+ &xml_print_configuration ($i);
+
+ gst_xml_leave ();
+ gst_xml_print_line ("</profile>\n");
+ }
+ gst_xml_leave ();
+ gst_xml_print_line ("</profiledb>\n");
+}
+
+sub xml_print_interfaces
+{
+ my ($h) = @_;
+ my ($dev, $type);
+
+ foreach $dev (keys %$h)
+ {
+ if ($$h{$dev}{"type"})
+ {
+ $type = $$h{$dev}{"type"};
+ delete $$h{$dev}{"type"};
+ }
+ else
+ {
+ $type = &gst_network_get_interface_type ($dev);
+ }
+
+ &gst_xml_print_vspace ();
+ &gst_xml_print_line ("<interface type='$type'>");
+ &gst_xml_enter ();
+ &gst_xml_print_hash ($$h{$dev});
+
+ &gst_xml_leave ();
+ &gst_xml_print_line ("</interface>");
+ }
+}
+
+sub xml_print
+{
+ my ($h) = @_;
+
+ &gst_xml_print_begin ();
+
+ &xml_print_configuration ($h);
+ &xml_print_profiledb ($h);
+
+ &gst_xml_print_end ();
+}
+
+
+# Reading profiles
+sub read_profiledb
+{
+ my ($hash) = @_;
+ my ($path);
+ my ($tree);
+
+ $path = gst_file_get_data_path () . "/" . $main::tool->{"name"} . "/";
+ chmod (0755, $path);
+ chmod (0644, $path . $profile_file);
+
+ $tree = &gst_xml_scan ($path . $profile_file, $tool);
+ if ($tree && scalar @$tree)
+ {
+ if ($$tree[0] eq 'profiledb')
+ {
+ xml_parse_profiledb ($$tree[1], $hash);
+ }
+ else
+ {
+ gst_report ('xml_unexp_tag', $$tree[0]);
+ }
+ }
+}
+
+# Writing profiles
+sub write_profiledb
+{
+ my ($hash) = @_;
+ my $profiledb = $hash->{'profiledb'};
+ my $path = &gst_file_get_data_path () . "/" . $main::tool->{'name'} . "/";
+ chmod (0755, $path);
+
+ if ($profiledb) {
+ # Write our profiles.
+ my $fh = &gst_file_open_write_from_names ($path . $profile_file);
+ if ($fh)
+ {
+ local *STDOUT = $fh;
+ &xml_print_profiledb ($hash);
+ close ($fh);
+
+ delete $hash->{'profiledb'};
+ }
+ }
+ else
+ {
+ gst_file_remove ($path . $profile_file);
+ }
+
+ chmod (0644, $path . $profile_file);
+}
+
+
+# Top-level actions.
+sub get
+{
+ my $hash;
+
+ # network interface stuff
+ $hash = &gst_network_conf_get ();
+ &read_profiledb (\%$hash);
+ &gst_network_ensure_loopback ($hash);
+
+ &gst_report_end ();
+ &xml_print ($hash);
+}
+
+
+sub set
+{
+ my $hash;
+
+ $hash = &xml_parse ();
+ &write_profiledb ($hash);
+ &gst_network_conf_set ($hash);
+ &gst_report_end ();
+}
+
+sub set_profile
+{
+ my ($tool, $profile_name) = @_;
+ my ($hash, $profiles, $profile);
+
+ &read_profiledb (\%$hash);
+ $profiles = $$hash{"profiledb"}{"profile"};
+
+ foreach $profile (@$profiles)
+ {
+ if ($$profile{"name"} eq $profile_name)
+ {
+ &gst_network_conf_set ($profile);
+ }
+ }
+
+ &gst_report_end ();
+}
+
+sub save_profiles
+{
+ my $hash;
+
+ $hash = &xml_parse ();
+ &write_profiledb ($hash);
+ &gst_report_end ();
+}
+
+
+# --- Filter config: XML in, XML out --- #
+
+
+sub filter
+{
+ my $hash;
+
+ $hash = &xml_parse ();
+ &gst_report_end ();
+ &xml_print ($hash);
+}
+
+sub enable_iface
+{
+ my ($tool, $iface, $enabled) = @_;
+ my (%dist_attrib, $iface_set);
+ my %hash = ("configuration" => {"file" => $iface});
+
+ %dist_attrib = &gst_network_get_interface_replace_table ();
+ $iface_set = $dist_attrib{"iface_set"};
+ &$iface_set (\%hash, undef, $enabled, 1);
+
+ # small hack for ensuring that the interface is really down
+ # when messing ifup/ifdown/ifconfig calls
+ if ($enabled == 0)
+ {
+ gst_file_run ("ifconfig $iface down");
+ &drop_dhcp_connection ($iface);
+ &drop_pppd_connection ($iface);
+ }
+
+ # Don't forget to do gst_end when the reports are over!
+ &gst_report_end ();
+ # XML output would come here, but this directive returns no XML.
+}
+
+sub enable_iface_with_config
+{
+ my ($tool) = @_;
+ my ($tree, $hash, $ret, $str);
+
+ # Scan XML to tree.
+ $tree = &gst_xml_scan ();
+
+ if (shift @$tree eq "interface")
+ {
+ $hash = &gst_network_xml_parse_interface (shift @$tree);
+ }
+
+ $ret = &gst_network_enable_iface_with_config ($hash);
+ &gst_report_end ();
+
+ &gst_xml_print_begin ("enable-iface");
+ &gst_xml_print_pcdata ("success", ($ret == 0) ? "1" : "0");
+ &gst_xml_print_end ("enable-iface");
+}
+
+sub list_ifaces
+{
+ my ($tool) = @_;
+ my ($ifaces, $iface, @arr);
+
+ $ifaces = &gst_network_interfaces_get_info ();
+
+ foreach $iface (keys %$ifaces)
+ {
+ push @arr, $$ifaces{$iface};
+ }
+
+ &gst_report_end ();
+ &gst_xml_print_begin ("network-ifaces");
+ &gst_xml_print_structure (\@arr, "interface");
+ &gst_xml_print_end ("network-ifaces");
+}
+
+sub detect_modem
+{
+ my ($tool) = @_;
+ my ($device);
+
+ $device = &gst_network_autodetect_modem ();
+ &gst_report_end ();
+
+ &gst_xml_print_begin ("network-modem-device");
+ &gst_xml_print_pcdata ("device", $device) if ($device ne undef);
+ &gst_xml_print_end ("network-modem-device");
+}
+
+sub detect_essids
+{
+ my ($tool, $iface) = @_;
+ my (@essids);
+
+ $essids = &gst_network_detect_essids ($iface);
+ &gst_report_end ();
+
+ &gst_xml_print_begin ("essids");
+ &gst_xml_print_structure ($essids, "network");
+ &gst_xml_print_end ("essids");
+}
+
+sub set_gateway
+{
+ my ($tool, $iface, $address) = @_;
+
+ &gst_network_route_set_default_gw ($iface, $address);
+ &gst_report_end ();
+}
+
+# --- Main --- #
+
+# get, set and filter are special cases that don't need more parameters than a ref to their function.
+# Read general.pl.in:gst_run_directive to know about the format of this hash.
+
+$directives = {
+ "get" => [ \&get, [], "" ],
+ "set" => [ \&set, [], "" ],
+ "filter" => [ \&filter, [], "" ],
+ "list_ifaces" => [ \&list_ifaces, [],
+ "List interfaces and active/inactive status." ],
+ "save_profiles" => [ \&save_profiles, [], "Save the profiles list" ],
+ "set_profile" => [ \&set_profile, [ "profile_name" ],
+ "Set a profile as the default configuration" ],
+ "enable_iface" => [ \&enable_iface, [ "interface", "enabled" ],
+ "Immediatly enable or disable a given interface. " .
+ "interface is the file tag value, enabled is 1 or 0." ],
+ "enable_iface_with_config" => [ \&enable_iface_with_config, [],
+ "Enable an interface with a given configuration" ],
+ "detect_modem" => [ \&detect_modem, [], "Detects the modem device." ],
+ "detect_essids" => [ \&detect_essids, [ "interface" ], "Detects active wireless networks" ],
+ "set_gateway" => [ \&set_gateway, [ "interface", "address" ], "Sets the default gateway" ]
+};
+
+$tool = &gst_init ($name, $version, $description, $directives, @ARGV);
+&gst_platform_ensure_supported ($tool, @platforms);
+&gst_run ($tool);
diff --git a/knetworkconf/backends/network.pl.in b/knetworkconf/backends/network.pl.in
new file mode 100644
index 0000000..0e8b12c
--- /dev/null
+++ b/knetworkconf/backends/network.pl.in
@@ -0,0 +1,6605 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Common network stuff for the ximian-setup-tools backends.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Arturo Espinosa <arturo@ximian.com>
+# Michael Vogt <mvo@debian.org> - Debian 2.[2|3] support.
+# David Lee Ludwig <davidl@wpi.edu> - Debian 2.[2|3] support.
+# Grzegorz Golawski <grzegol@pld-linux.org> - PLD support
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+use Socket;
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/general.pl$DOTIN";
+require "$SCRIPTSDIR/file.pl$DOTIN";
+require "$SCRIPTSDIR/parse.pl$DOTIN";
+require "$SCRIPTSDIR/replace.pl$DOTIN";
+require "$SCRIPTSDIR/service.pl$DOTIN";
+require "$SCRIPTSDIR/util.pl$DOTIN";
+require "$SCRIPTSDIR/xml.pl$DOTIN";
+require "$SCRIPTSDIR/process.pl$DOTIN";
+
+
+# Shared XML printing function
+sub network_xml_print_statichost
+{
+ my ($h) = $_[0];
+ my ($statichost, $i, $j, $val);
+
+ &gst_xml_print_vspace ();
+ foreach $i (keys %{$$h{"statichost"}})
+ {
+ $statichost = $ {$$h{"statichost"}}{$i};
+ &gst_xml_container_enter ("statichost");
+ $val = &gst_xml_quote ($i);
+ &gst_xml_print_pcdata ("ip", $val);
+ foreach $j (@$statichost)
+ {
+ $val = &gst_xml_quote ($j);
+ &gst_xml_print_pcdata ("alias", $val);
+ }
+ &gst_xml_container_leave ("statichost");
+ }
+}
+
+sub gst_network_get_linux_wireless_ifaces
+{
+ my ($fd, $line);
+ my (@ifaces, $command);
+
+ $command = &gst_file_get_cmd_path ("iwconfig");
+ open $fd, "$command |";
+ return @ifaces if $fd eq undef;
+
+ while (<$fd>)
+ {
+ if (/^([a-zA-Z0-9]+)[\t ].*$/)
+ {
+ push @ifaces, $1;
+ }
+ }
+
+ &gst_file_close ($fd);
+
+ &gst_report_leave ();
+ return \@ifaces;
+}
+
+sub gst_network_get_freebsd_wireless_ifaces
+{
+ my ($fd, $line, $iface);
+ my (@ifaces, $command);
+
+ $command = &gst_file_get_cmd_path ("iwconfig");
+ open $fd, "$command |";
+ return @ifaces if $fd eq undef;
+
+ while (<$fd>)
+ {
+ if (/^([a-zA-Z]+[0-9]+):/)
+ {
+ $iface = $1;
+ }
+
+ if (/media:.*wireless.*/i)
+ {
+ push @ifaces, $iface;
+ }
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+
+ return \@ifaces;
+}
+
+# Returns an array with the wireless devices found
+sub gst_network_get_wireless_ifaces
+{
+ my ($plat) = $$tool{"system"};
+
+ return &gst_network_get_linux_wireless_ifaces if ($plat eq "Linux");
+ return &gst_network_get_freebsd_wireless_ifaces if ($plat eq "FreeBSD");
+}
+
+# set of functions for enabling an interface
+sub gst_network_config_wireless
+{
+ my ($hash, $dev, $command_iwconfig, $command_ifconfig) = @_;
+ my ($essid, $key, $command);
+
+ $essid = $$hash{"configuration"}{"essid"};
+ $key = $$hash{"configuration"}{"key"};
+ $key_type = $$hash{"configuration"}{"key_type"};
+
+ if ($essid)
+ {
+ $command = $command_iwconfig if ($$tool{"system"} eq "Linux");
+ $command = $command_ifconfig if ($$tool{"system"} eq "FreeBSD");
+
+ $command .= " $dev";
+ $command .= " essid '$essid'" if ($essid);
+
+ if ($key)
+ {
+ $key = &gst_network_get_full_key ($key, $key_type);
+ $command .= " key '$key'";
+ }
+ else
+ {
+ $command .= " key off";
+ }
+
+ &gst_file_run ($command);
+ }
+}
+
+sub gst_network_enable_iface
+{
+ my ($hash, $dev, $command_ifconfig) = @_;
+ my ($address, $netmask, $bootproto, $remote_address);
+
+ $address = $$hash{"configuration"}{"address"};
+ $netmask = $$hash{"configuration"}{"netmask"};
+ $bootproto = $$hash{"configuration"}{"bootproto"};
+ $remote_address = $$hash{"configuration"}{"remote_address"};
+
+ if ($bootproto eq "dhcp")
+ {
+ if (&gst_file_locate_tool ("dhclient3"))
+ {
+ $command = "dhclient3 -pf /var/run/dhclient.$dev.pid $dev";
+ }
+ elsif (&gst_file_locate_tool ("dhclient"))
+ {
+ $command = "dhclient -pf /var/run/dhclient.$dev.pid -e $dev";
+ }
+ else
+ {
+ $command = "dhcpcd -n $dev";
+ }
+ }
+ else
+ {
+ $command = $command_ifconfig;
+ $command .= " $dev";
+ $command .= " $address" if ($address);
+ $command .= " netmask $netmask" if ($netmask);
+ $command .= " dstaddr $remote_address" if ($remote_address);
+ $command .= " up";
+ }
+
+ return &gst_file_run ($command);
+}
+
+sub gst_network_get_chat_file
+{
+ my ($hash) = @_;
+ my ($volume, $phone_number, $external_line, $dial_command);
+ my ($dial, $tmp_file, $filename, $arr);
+
+ $volume = $$hash{"configuration"}{"volume"};
+ $phone_number = $$hash{"configuration"}{"phone_number"};
+ $external_line = $$hash{"configuration"}{"external_line"};
+ $dial_command = $$hash{"configuration"}{"dial_command"};
+
+ $filename = gst_file_get_temp_name ("network-admin-chat-script-XXXXXXXXX");
+ $tmp_file = "/tmp/$filename";
+
+ $dial = $dial_command;
+ $dial .= $external_line . "W" if ($external_line);
+ $dial .= $phone_number;
+
+ &gst_network_create_pppscript ($tmp_file);
+ chmod (0600, $tmp_file);
+ &gst_replace_chat ($tmp_file, "atd[tp][0-9wW]+", $dial);
+ &gst_network_set_modem_volume ($tmp_file, $volume);
+
+
+ return $tmp_file;
+}
+
+sub gst_network_enable_modem
+{
+ my ($hash, $dev, $command_pppd, $command_chat) = @_;
+ my ($config, $chat_file, $command, $ret);
+
+ $config = $$hash{"configuration"};
+ $chat_file = &gst_network_get_chat_file ($hash);
+
+ $command = $command_pppd;
+ $command .= " " . $$config{"serial_port"};
+ $command .= " debug" if ($$config{"debug"});
+ $command .= ($$config{"noauth"}) ? " noauth" : " auth";
+ $command .= ($$config{"persist"}) ? " persist" : " nopersist";
+ $command .= ($$config{"serial_hwctl"}) ? " crtscts" : " nocrtscts";
+ $command .= ($$config{"set_default_gw"}) ? " defaultroute" : " nodefaultroute";
+ $command .= " usepeerdns" if ($$config{"update_dns"});
+ $command .= " user " . $$config{"login"};
+ $command .= " connect \'$command_chat -v -f $chat_file\'";
+
+ $ret = &gst_file_run ($command);
+
+ return $ret;
+}
+
+sub gst_network_enable_isdn
+{
+ my ($hash, $dev, $command_pppd) = @_;
+ my ($config, $command);
+
+ $config = $$hash{"configuration"};
+
+ $command = $command_pppd;
+ $command .= " debug" if ($$config{"debug"});
+ $command .= ($$config{"noauth"}) ? " noauth" : " auth";
+ $command .= ($$config{"persist"}) ? " persist" : " nopersist";
+ $command .= ($$config{"serial_hwctl"}) ? " crtscts" : " nocrtscts";
+ $command .= ($$config{"set_default_gw"}) ? " defaultroute" : " nodefaultroute";
+ $command .= " usepeerdns" if ($$config{"update_dns"});
+ $command .= " sync plugin userpass.so ipcp-accept-local ipcp-accept-remote";
+ $command .= " plugin capiplugin.so";
+ $command .= " /dev/null";
+ $command .= " user " . $$config{"login"};
+ $command .= " number " . $$config{"phone_number"};
+
+ return &gst_file_run ($command);
+}
+
+sub drop_dhcp_connection
+{
+ my ($dev) = @_;
+ &gst_process_kill_by_pidfile ("dhclient.$dev.pid");
+ &gst_process_kill_by_pidfile ("/etc/dhcpc/dhcpcd-$dev.pid");
+}
+
+sub drop_pppd_connection
+{
+ my ($dev) = @_;
+ &gst_process_kill_by_pidfile ("$dev.pid");
+}
+
+sub gst_network_enable_iface_with_config
+{
+ my ($hash) = @_;
+ my ($command_ifconfig, $command_iwconfig);
+ my ($command_pppd, $command_chat);
+ my ($dev, $command, $ret);
+
+ $command_ifconfig = "ifconfig";
+ $command_iwconfig = "iwconfig";
+ $command_pppd = "pppd";
+ $command_chat = gst_file_locate_tool ("chat");
+
+ $dev = $$hash{"dev"};
+
+ $command = "$command_ifconfig $dev down";
+ $ret = &gst_file_run ($command);
+
+ &drop_dhcp_connection ($dev);
+ &drop_pppd_connection ($dev);
+
+ if (exists ($$hash{"configuration"}))
+ {
+ if (exists ($$hash{"configuration"}{"phone_number"}))
+ {
+ $login = $$hash{"configuration"}{"login"};
+ $pw = $$hash{"configuration"}{"password"};
+
+ &gst_network_set_pap_passwd ("/etc/ppp/pap-secrets", $login, $pw);
+ &gst_network_set_pap_passwd ("/etc/ppp/chap-secrets", $login, $pw);
+
+ if (&gst_network_check_pppd_plugin ("capiplugin"))
+ {
+ $ret = &gst_network_enable_isdn ($hash, $dev, $command_pppd);
+ }
+ else
+ {
+ $ret = &gst_network_enable_modem ($hash, $dev, $command_pppd, $command_chat);
+ }
+ }
+ else
+ {
+ # if it's a wireless interface, put first the essid
+ &gst_network_config_wireless ($hash, $dev, $command_iwconfig, $command_ifconfig);
+ $ret = &gst_network_enable_iface ($hash, $dev, $command_ifconfig);
+ }
+ }
+
+ return $ret;
+}
+
+# Tries to detect modem in a closed list of devices
+sub gst_network_autodetect_modem
+{
+ my (@arr);
+
+ if ($$tool{"system"} eq "Linux")
+ {
+ @arr = ("/dev/modem", "/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3");
+
+ $pid = `pidof pppd 2>/dev/null`;
+
+ if ($pid =~ /\d/) {
+ return;
+ }
+ }
+ elsif ($$tool{"system"} eq "FreeBSD")
+ {
+ @arr = ("/dev/modem", "/dev/cuaa0", "/dev/cuaa1", "/dev/cuaa2", "/dev/cuaa3");
+ }
+
+ foreach $tty (@arr) {
+ $temp = `pppd lcp-max-configure 1 nodetach noauth nocrtscts $tty connect \"chat -t1 \'\' AT OK\" 2>/dev/null`;
+
+ if ($temp =~ /established/) {
+ return $tty;
+ }
+ }
+}
+
+# Parse <interface>...</interface>. Put here so it can be shared with internetsharing.
+sub gst_network_xml_parse_interface_config
+{
+ my ($tree) = @_;
+ my (%config);
+
+ shift @$tree;
+
+ while ($elem = shift @$tree)
+ {
+ $config{$elem} = &gst_xml_get_pcdata (shift @$tree);
+ }
+
+ return \%config;
+}
+
+sub gst_network_xml_parse_interface
+{
+ my ($tree, $interface) = @_;
+ my (%hash, $aux, $dev, $elem);
+
+ shift @$tree;
+
+ while ($elem = shift @$tree)
+ {
+ if ($elem eq "configuration")
+ {
+ $aux = &gst_network_xml_parse_interface_config (shift @$tree);
+ $hash{$elem} = $aux if ($aux ne undef);
+ }
+ else
+ {
+ $hash{$elem} = &gst_xml_get_pcdata (shift @$tree);
+ }
+ }
+
+ if (($hash{"configuration"} ne undef) &&
+ ($hash{"configuration"}{"file"} ne undef))
+ {
+ $dev = $hash{"configuration"}{"file"};
+ }
+ else
+ {
+ $dev = &gst_network_get_file (\%hash);
+ $hash{"configuration"}{"file"} = $dev if ($hash{"configuration"} ne undef);
+ }
+
+ $$interface{$dev} = \%hash;
+ return \%hash;
+}
+
+# Expects something like "132.248.10.2" and returns 4 bytes.
+sub gst_network_ipv4_str2vec
+{
+ my ($str) = @_;
+
+ return pack ('C4', split ('\.', $str));
+}
+
+# Converse
+sub gst_network_ipv4_vec2str
+{
+ my ($vec) = @_;
+
+ return join ('.', unpack ('C4', $vec));
+}
+
+# Gets the subnet, in bitmap.
+sub gst_network_ipv4_calc_subnet_vec
+{
+ my ($addr, $mask) = @_;
+ my ($addrvec, $maskvec);
+
+ $addrvec = &gst_network_ipv4_str2vec ($addr);
+ $maskvec = &gst_network_ipv4_str2vec ($mask);
+
+ return $addrvec & $maskvec;
+}
+
+# What you're looking for.
+sub gst_network_ipv4_calc_subnet
+{
+ my ($addr, $mask) = @_;
+
+ return &gst_network_ipv4_vec2str (&gst_network_ipv4_calc_subnet_vec);
+}
+
+# The broadcast, bitmap.
+sub gst_network_ipv4_calc_bcast_vec
+{
+ my ($addr, $mask) = @_;
+
+ $addrvec = &gst_network_ipv4_str2vec ($addr);
+ $maskvec = &gst_network_ipv4_str2vec ($mask);
+
+ return $addrvec | ~$maskvec;
+}
+
+# And this returning the quad-dot notation.
+sub gst_network_ipv4_calc_bcast
+{
+ my ($addr, $mask) = @_;
+
+ return &gst_network_ipv4_vec2str (&gst_network_ipv4_calc_bcast_vec);
+}
+
+
+# Selects a ping command, which must ping just twice, with
+# one second interval, returning numeric IPs to the given
+# broadcast address.
+sub gst_network_get_broadcast_ping_cmd
+{
+ my ($bcast) = @_;
+ my ($tool_ping);
+
+ my %cmd_map =
+ (
+ "debian-2.2" => "ping -c 2 -i 1 -n $bcast",
+ "redhat-6.2" => "ping -c 2 -i 1 -n -b $bcast"
+ );
+ my %dist_map =
+ (
+ "redhat-6.0" => "redhat-6.2",
+ "redhat-6.1" => "redhat-6.2",
+ "redhat-6.2" => "redhat-6.2",
+ "redhat-7.0" => "redhat-6.2",
+ "redhat-7.1" => "redhat-6.2",
+ "redhat-7.2" => "redhat-6.2",
+ "redhat-8.0" => "redhat-6.2",
+ "redhat-9" => "redhat-6.2",
+ "openna-1.0" => "redhat-6.2",
+ "debian-2.2" => "debian-2.2",
+ "debian-3.0" => "debian-2.2",
+ "debian-3.1" => "debian-2.2",
+ "debian-4.0" => "debian-2.2",
+ "debian-5.0" => "debian-2.2",
+ "debian-testing" => "debian-2.2",
+ "ubuntu-5.04" => "debian-2.2",
+ "ubuntu-5.10" => "debian-2.2",
+ "ubuntu-6.06" => "debian-2.2",
+ "ubuntu-6.10" => "debian-2.2",
+ "ubuntu-7.04" => "debian-2.2",
+ "ubuntu-7.10" => "debian-2.2",
+ "ubuntu-8.04" => "debian-2.2",
+ "mandrake-7.1" => "debian-2.2",
+ "mandrake-7.2" => "debian-2.2",
+ "mandrake-9.0" => "debian-2.2",
+ "mandrake-9.1" => "debian-2.2",
+ "mandrake-9.2" => "debian-2.2",
+ "mandrake-10.0" => "debian-2.2",
+ "mandrake-10.1" => "redhat-6.2",
+ "mandrake-10.2" => "redhat-6.2",
+ "mandriva-2006.0" => "redhat-6.2",
+ "mandriva-2006.1" => "redhat-6.2",
+ "mandriva-2007.0" => "redhat-6.2",
+ "mandriva-2007.1" => "redhat-6.2",
+ "yoper-2.2" => "redhat-6.2",
+ "blackpanther-4.0" => "debian-2.2",
+ "suse-7.0" => "debian-2.2",
+ "suse-9.0" => "redhat-6.2",
+ "suse-9.1" => "redhat-6.2",
+ "pld-1.0" => "redhat-6.2",
+ "pld-1.1" => "redhat-6.2",
+ "pld-1.99" => "redhat-6.2",
+ "conectiva-9" => "debian-2.2",
+ "conectiva-10" => "debian-2.2",
+ "fedora-1" => "redhat-6.2",
+ "fedora-2" => "redhat-6.2",
+ "fedora-3" => "redhat-6.2",
+ "fedora-4" => "redhat-6.2",
+ "fedora-5" => "redhat-6.2",
+ "rpath" => "redhat-6.2",
+ "vine-3.0" => "redhat-6.2",
+ "vine-3.1" => "redhat-6.2",
+ "ark" => "redhat-6.2",
+ "slackware-9.1.0" => "redhat-6.2",
+ "slackware-10.0.0" => "redhat-6.2",
+ "slackware-10.1.0" => "redhat-6.2",
+ "slackware-10.2.0" => "redhat-6.2",
+ "gentoo" => "debian-2.2",
+ "vlos-1.2" => "debian-2.2",
+ "freebsd-5" => "debian-2.2",
+ "freebsd-6" => "debian-2.2",
+ );
+
+ return $cmd_map{$dist_map{$gst_dist}};
+}
+
+
+# Run ping, taking what looks like the replying host addresses, return
+# colon-sepparated (:) string. To be used with gst_process_fork.
+sub gst_network_ping_broadcast_call
+{
+ my ($bcast) = @_;
+ my ($cmd, %hosts, $fd);
+
+ $cmd = &gst_network_get_broadcast_ping_cmd ($bcast);
+ $fd = &gst_file_run_pipe_read ($cmd);
+ return undef if $fd eq undef;
+ while (<$fd>)
+ {
+ if (/([0-9.]+):?[ \t]+icmp_seq/)
+ {
+ # If it already exists, it is the second count, and we can return then.
+ last if exists $hosts{$1};
+ $hosts{$1} = 1 ;
+ }
+ }
+ &gst_file_close ($fd);
+
+ return join (':', keys (%hosts));
+}
+
+
+# Return an array of IPs of the hosts in all the adjacent local networks.
+sub gst_network_find_hosts
+{
+ my ($iface, $ifaces, $dev, $hosts_str, @hosts, $proc, @procs);
+
+ $ifaces = &gst_network_interfaces_get_info ();
+
+ foreach $dev (keys %$ifaces)
+ {
+ $iface = $$ifaces{$dev};
+ if ($$iface{"active"} && exists $$iface{"bcast"})
+ {
+ push @procs, &gst_process_fork (\&gst_network_ping_broadcast_call, $$iface{"bcast"});
+ }
+ }
+
+ &gst_process_list_check_ready (3, \@procs);
+
+ foreach $proc (@procs)
+ {
+ if ($$proc{"ready"})
+ {
+ sysread ($$proc{"fd"}, $hosts_str, 4096);
+ push @hosts, split (':', $hosts_str);
+ }
+ }
+
+ return @hosts;
+}
+
+
+# like, &gst_network_lookup_address_block ("132.248.10.2") returns 'dns2.unam.mx'
+# but watch it: it will block until libc timeouts or a result is found. If
+# nothing found, returns the address.
+sub gst_network_lookup_address_block
+{
+ my ($addr) = @_;
+ my $name;
+
+ $name = (gethostbyaddr (&gst_network_ipv4_str2vec ($addr), AF_INET))[0];
+ return $addr if length ($name) == 0;
+ return $name;
+}
+
+
+# To be called from gst_process_fork by the child.
+sub gst_network_address_lookup_call
+{
+ my ($addr) = @_;
+
+ return &gst_network_lookup_address_block ($addr);
+}
+
+
+# Fork a lookup process for every passed address, return ref to
+# array with info on every proc.
+sub gst_network_lookup_address_start
+{
+ my (@addrs) = @_;
+ my ($addr, $proc, @procs);
+
+ # Fork a lookup for every address.
+ foreach $addr (@addrs)
+ {
+ $proc = &gst_process_fork (\&gst_network_address_lookup_call, $addr);
+ $$proc{"addr"} = $addr;
+ push @procs, $proc;
+ }
+
+ return \@procs;
+}
+
+# Take a ref to a list of forked lookup processes,
+# and collect the information from those ready.
+sub gst_network_lookup_address_collect
+{
+ my ($procs) = @_;
+ my ($name, @names, $proc);
+
+ # For every process, if the "ready" flag is on, read info.
+ # Else, populate with the given address. Then kill child and wait for it to die.
+ foreach $proc (@$procs)
+ {
+ if ($$proc{"ready"})
+ {
+ sysread ($$proc{"fd"}, $name, 4096);
+ push @names, $name;
+ }
+ else
+ {
+ push @names, $$proc{"addr"};
+ }
+ &gst_process_kill ($proc);
+ }
+
+ return @names;
+}
+
+
+# like, &gst_network_lookup_address (10, "132.248.10.2", "132.248.29.8") returns
+# 'dns2.unam.mx', 'sphinx.nuclecu.unam.mx' after 10 seconds, in the worst case.
+# If any of the given addresses is not resolved before timeout, the address will
+# be returned as its name. Timeout of 0 or undef blocks.
+# Timeout may be a decimal (0.5, half a second). You can split this process in
+# two, so you can collect the information at the last moment, giving more time for
+# the lookups to take place. Use the two functions above for this, as shown here.
+sub gst_network_lookup_address
+{
+ my ($timeout, @addrs) = @_;
+ my $procs;
+
+ $procs = &gst_network_lookup_address_start (@addrs);
+ &gst_process_list_check_ready ($timeout, $procs);
+ return &gst_network_lookup_address_collect ($procs);
+}
+
+
+# This code is not under the portable table style because it is supposed to
+# depend on wvdial.
+sub gst_network_dialing_get
+{
+ my %vars =
+ (
+ "Inherits" => "inherits",
+ "Modem" => "device",
+ "Baud" => "speed",
+ "Init1" => "init1",
+ "Init2" => "init2",
+ "Phone" => "phone",
+ "Username" => "login",
+ "Password" => "password",
+ "Dial Command" => "dialcmd",
+ "SetVolume" => "volume",
+ "Stupid mode" => "stupid",
+ "Auto Reconnect" => "persist",
+ "Force Address" => "address",
+ "Auto DNS" => "update_dns",
+ "Check Def Route" => "set_default_gw",
+ "GST Device" => "gst_dev",
+ "Dial Command" => "dial_command"
+ );
+ my %title2type =
+ (
+ "Dialer (.*)" => "dialer",
+ "Modem(.*)" => "modem"
+ );
+
+ my ($file) = @_;
+ my (%ret, @sections);
+ my ($i, $j, $name, $val);
+
+ &gst_report_enter ();
+ &gst_report ("network_dialing_get");
+
+ @sections = &gst_parse_ini_sections ($file);
+ foreach $i (@sections)
+ {
+ my %hash;
+
+ $hash{"type"} = "unknown";
+ foreach $j (keys %title2type)
+ {
+ if ($i =~ /$j/)
+ {
+ $hash{"name"} = $1;
+ $hash{"type"} = $title2type{$j};
+ }
+ }
+
+ $ret{$hash{"name"}} = \%hash;
+
+ foreach $j (keys %vars)
+ {
+ $val = &gst_parse_ini ($file, $i, $j);
+ $hash{$vars{$j}} = $val if ($val ne undef);
+ }
+
+ # we add the volume label, it's not a line in the wvdial config,
+ # it's a hayes command in the init2 string, it can be ATM0 or ATL[1-3]
+ if ($hash{"init2"} =~ /M0/)
+ {
+ $hash{"volume"} = 0;
+ }
+ elsif ($hash{"init2"} =~ /L[1-3]/)
+ {
+ $hash{"init2"} =~ /.*L([1-3]).*/;
+ $volume = ($1);
+ $hash{"volume"} = $volume;
+ }
+ else
+ {
+ $hash{"volume"} = 3;
+ }
+
+ # add the external line access number
+ if ($hash{"phone"} =~ /(^.*)[wW]/)
+ {
+ $hash{"external_line"} = $1;
+ $hash{"phone"} =~ s/^.*[wW]//;
+ }
+ }
+
+ &gst_report_leave ();
+ return \%ret;
+}
+
+# returns interface type depending on it's interface name
+# types_cache is a global var for caching interface types
+sub gst_network_get_interface_type
+{
+ my ($dev) = @_;
+ my (@wireless_ifaces, $wi, $type);
+
+ return $types_cache{$dev} if (exists $types_cache{$dev});
+
+ #check whether interface is wireless
+ $wireless_ifaces = &gst_network_get_wireless_ifaces ();
+ foreach $wi (@$wireless_ifaces)
+ {
+ if ($dev eq $wi)
+ {
+ $types_cache{$dev} = "wireless";
+ return $types_cache{$dev};
+ }
+ }
+
+ if ($dev =~ /^(ppp|tun)/)
+ {
+ # check whether the proper plugin exists
+ if (&gst_network_check_pppd_plugin ("capiplugin"))
+ {
+ $types_cache{$dev} = "isdn";
+ }
+ else
+ {
+ $types_cache{$dev} = "modem";
+ }
+ }
+ elsif ($dev =~ /^(eth|dc|ed|bfe|em|fxp|bge|de|xl|ixgb|txp|vx|lge|nge|pcn|re|rl|sf|sis|sk|ste|ti|tl|tx|vge|vr|wb|cs|ex|ep|fe|ie|lnc|sn|xe|le|an|awi|wi|ndis|wlaue|axe|cue|kue|rue|fwe|nve)[0-9]/)
+ {
+ $types_cache{$dev} = "ethernet";
+ }
+ elsif ($dev =~ /^irlan[0-9]/)
+ {
+ $types_cache{$dev} = "irlan";
+ }
+ elsif ($dev =~ /^plip[0-9]/)
+ {
+ $types_cache{$dev} = "plip";
+ }
+ elsif ($dev =~ /^lo[0-9]?/)
+ {
+ $types_cache{$dev} = "loopback";
+ }
+
+ return $types_cache{$dev};
+}
+
+sub gst_network_freebsd_interfaces_get_info
+{
+ my ($dev, %ifaces, $fd);
+
+ &gst_report_enter ();
+ &gst_report ("network_iface_active_get");
+
+ $fd = &gst_file_run_pipe_read ("ifconfig");
+ return {} if $fd eq undef;
+
+ while (<$fd>)
+ {
+ chomp;
+ if (/^([^ \t:]+):.*(<.*>)/)
+ {
+ $dev = $1;
+ $ifaces{$dev}{"dev"} = $dev;
+ $ifaces{$dev}{"enabled"} = 1 if ($2 =~ /[<,]UP[,>]/);
+ }
+
+ s/^[ \t]+//;
+ if ($dev)
+ {
+ $ifaces{$dev}{"hwaddr"} = $1 if /ether[ \t]+([^ \t]+)/i;
+ $ifaces{$dev}{"addr"} = $1 if /inet[ \t]+([^ \t]+)/i;
+ $ifaces{$dev}{"mask"} = $1 if /netmask[ \t]+([^ \t]+)/i;
+ $ifaces{$dev}{"bcast"} = $1 if /broadcast[ \t]+([^ \t]+)/i;
+ }
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+ return \%ifaces;
+}
+
+sub gst_network_linux_interfaces_get_info
+{
+ my ($dev, %ifaces, $fd);
+
+ &gst_report_enter ();
+ &gst_report ("network_iface_active_get");
+
+ $fd = &gst_file_run_pipe_read ("ifconfig -a");
+ return {} if $fd eq undef;
+
+ while (<$fd>)
+ {
+ chomp;
+ if (/^([^ \t:]+)/)
+ {
+ $dev = $1;
+ $ifaces{$dev}{"enabled"} = 0;
+ $ifaces{$dev}{"dev"} = $dev;
+ }
+
+ s/^[ \t]+//;
+ if ($dev)
+ {
+ $ifaces{$dev}{"hwaddr"} = $1 if /HWaddr[ \t]+([^ \t]+)/i;
+ $ifaces{$dev}{"addr"} = $1 if /addr:([^ \t]+)/i;
+ $ifaces{$dev}{"mask"} = $1 if /mask:([^ \t]+)/i;
+ $ifaces{$dev}{"bcast"} = $1 if /bcast:([^ \t]+)/i;
+ $ifaces{$dev}{"enabled"} = 1 if /^UP[ \t]/i;
+ }
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+ return \%ifaces;
+}
+
+sub gst_network_interfaces_get_info
+{
+ my (%ifaces);
+
+ $ifaces = &gst_network_linux_interfaces_get_info if ($$tool{"system"} eq "Linux");
+ $ifaces = &gst_network_freebsd_interfaces_get_info if ($$tool{"system"} eq "FreeBSD");
+
+ foreach $dev (keys %$ifaces)
+ {
+ #$$ifaces{$dev}{"enabled"} = 0 if $$ifaces{$dev}{"addr"} eq undef;
+ $$ifaces{$dev}{"type"} = &gst_network_get_interface_type ($dev);
+
+ #delete unknown ifaces
+ if ($$ifaces{$dev}{"type"} eq undef)
+ {
+ delete $$ifaces{$dev};
+ }
+ }
+
+ return $ifaces;
+}
+
+sub gst_network_active_interfaces_get
+{
+ my $fd;
+ my @ret = ();
+
+ &gst_report_enter ();
+ &gst_report ("network_iface_active_get");
+
+ $fd = &gst_file_run_pipe_read ("ifconfig");
+ return undef if $fd eq undef;
+
+ while (<$fd>)
+ {
+ chomp;
+ s/:? .*//;
+ next if /^$/;
+ push @ret, $_;
+ }
+
+ &gst_file_close ($fd);
+
+ &gst_report_leave ();
+ return @ret;
+}
+
+sub gst_network_freebsd5_active_interfaces_get
+{
+ my ($fd, @ret);
+
+ &gst_report_enter ();
+ &gst_report ("network_iface_active_get");
+
+ $fd = &gst_file_run_pipe_read ("ifconfig");
+ return undef if ($fd eq undef);
+
+ while (<$fd>)
+ {
+ chomp;
+ if (/^([\w\d]*):.*[<,]UP[,>]/)
+ {
+ push @ret, $1;
+ }
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+
+ return @ret;
+}
+
+sub gst_network_suse70_active_interfaces_get
+{
+ my (@devs, $dev, @ret, $num);
+
+ @devs = &gst_network_active_interfaces_get ();
+
+ foreach $dev (@devs)
+ {
+ if ($dev ne "lo")
+ {
+ $num = &gst_network_suse70_parse_iface_num ("$gst_prefix/etc/rc.config", $dev);
+ push @ret, $num if $num != -1;
+ }
+ }
+
+ return @ret;
+}
+
+sub gst_network_interface_active
+{
+ my ($search_iface, $proc) = @_;
+ my @ifaces;
+
+ &gst_report_enter ();
+ &gst_report ("network_iface_is_active", $search_iface);
+
+ @ifaces = &$proc ();
+ while ($ifaces[0] ne "")
+ {
+ return 1 if (shift (@ifaces) eq $search_iface);
+ }
+
+ &gst_report_leave ();
+ return 0;
+}
+
+sub gst_network_interface_ensure_broadcast_and_network
+{
+ my ($iface) = @_;
+
+ if (exists $$iface{"netmask"} &&
+ exists $$iface{"address"})
+ {
+ if (! exists $$iface{"broadcast"})
+ {
+ $$iface{"broadcast"} = &gst_network_ipv4_calc_bcast ($$iface{"address"}, $$iface{"netmask"});
+ }
+
+ if (! exists $$iface{"network"})
+ {
+ $$iface{"network"} = &gst_network_ipv4_calc_subnet ($$iface{"address"}, $$iface{"netmask"});
+ }
+ }
+}
+
+sub gst_network_sysconfig_dir_ifaces_get_existing
+{
+ my ($dir) = @_;
+ my (@ret, $i, $name);
+ local *IFACE_DIR;
+
+ if (opendir IFACE_DIR, "$gst_prefix/$dir")
+ {
+ foreach $i (readdir (IFACE_DIR))
+ {
+ push @ret, $1 if ($i =~ /^ifcfg-(.+)$/);
+ }
+
+ closedir (IFACE_DIR);
+ }
+
+ return \@ret;
+}
+
+sub gst_network_sysconfig_rh62_ifaces_get_existing
+{
+ return @{&gst_network_sysconfig_dir_ifaces_get_existing ("/etc/sysconfig/network-scripts")};
+}
+
+sub gst_network_sysconfig_rh72_ifaces_get_existing
+{
+ my ($ret);
+
+ # This syncs /etc/sysconfig/network-scripts and /etc/sysconfig/networking
+ &gst_file_run ("redhat-config-network-cmd");
+
+ $ret = &gst_network_sysconfig_dir_ifaces_get_existing
+ ("/etc/sysconfig/networking/profiles/default");
+
+ &gst_arr_merge ($ret,
+ &gst_network_sysconfig_dir_ifaces_get_existing
+ ("/etc/sysconfig/networking/devices"));
+
+ return @$ret;
+}
+
+sub gst_network_debian_ifaces_get_existing
+{
+ my (@ret, @stanzas, $stanza);
+
+ @stanzas = &gst_parse_interfaces_stanzas ("$gst_prefix/etc/network/interfaces", "iface");
+
+ foreach $stanza (@stanzas)
+ {
+ if ($$stanza[1] eq "inet")
+ {
+ push @ret, $$stanza[0];
+ }
+ }
+
+ return @ret;
+}
+
+sub gst_network_suse70_ifaces_get_existing
+{
+ my $file = "$gst_prefix/etc/rc.config";
+ my ($i, $dev, @ret, $fd);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ return @ret if !$fd;
+
+ while ($i = <$fd>)
+ {
+ if ($i =~ /^[ \t]*NETDEV_([0-9]+)=/)
+ {
+ push @ret, $1 if &gst_parse_sh ($file, "NETDEV_$1") ne "";
+ }
+ }
+
+ &gst_file_close ($fd);
+ return @ret;
+}
+
+sub gst_network_suse90_ifaces_get_existing
+{
+ return @{&gst_network_sysconfig_dir_ifaces_get_existing ("/etc/sysconfig/network")};
+}
+
+sub gst_network_sysconfig_pld10_ifaces_get_existing
+{
+ return @{&gst_network_sysconfig_dir_ifaces_get_existing ("/etc/sysconfig/interfaces")};
+}
+
+sub gst_network_slackware91_ifaces_get_existing
+{
+ my $file = "/etc/rc.d/rc.inet1.conf";
+ my $pppscript = "/etc/ppp/pppscript";
+ my ($fd, $i, @ret);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ return @ret if !$fd;
+
+ while ($i = <$fd>)
+ {
+ if ($i =~ /^[ \t]*(IPADDR|USE_DHCP)\[([0-9]+)\][ \t]*=[ \t]*"(.*)"/)
+ {
+ push @ret, "eth$2" if ($3 ne "");
+ }
+ }
+
+ &gst_file_close ($fd);
+
+ if (&gst_file_exists ($pppscript))
+ {
+ push @ret, "ppp0";
+ }
+
+ return @ret;
+}
+
+sub gst_network_gentoo_ifaces_get_existing
+{
+ my $file = "/etc/conf.d/net";
+ my ($fd, $i, @ret, $ppp);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ return @ret if !$fd;
+
+ while ($i = <$fd>)
+ {
+ if ($i =~ /^config_([a-zA-Z0-9]*)[ \t]*=/)
+ {
+ push @ret, $1;
+ }
+ }
+
+ #now the PPP ifaces
+ foreach $ppp (</etc/conf.d/net.*>)
+ {
+ $ppp =~ s#^/etc/conf.d/net\.##;
+ push @ret, $ppp if ($ppp =~ /^ppp[0-9]$/);
+ }
+
+ return @ret;
+}
+
+sub gst_network_freebsd_ifaces_get_existing
+{
+ my $file = "/etc/rc.conf";
+ my ($fd, $i, @ret);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ return @ret if !$fd;
+
+ while ($i = <$fd>)
+ {
+ if ($i =~ /^ifconfig_(.*)[ \t]*=/)
+ {
+ push @ret, $1;
+ }
+ }
+
+ return @ret;
+}
+
+sub gst_network_suse70_parse_iface_num
+{
+ my ($file, $dev) = @_;
+ my ($i, $ret);
+
+ foreach $i (&gst_network_suse70_ifaces_get_existing ())
+ {
+ $ret = &gst_parse_sh ($file, "NETDEV_$i");
+ return $i if $ret eq $dev;
+ }
+
+ &gst_debug_print_string ("\n\nWarning: gst_network_suse70_parse_iface_num: num for $dev not found.\n\n");
+ return -1;
+}
+
+sub gst_network_suse70_parse_iface_auto
+{
+ my ($file, $iface, $key) = @_;
+ my ($val, $i);
+
+ $val = &gst_parse_sh_split ($file, $key, "[ \t]+");
+
+ foreach $i (@$val)
+ {
+ return 1 if $i eq "_$iface";
+ }
+
+ return 0;
+}
+
+sub gst_network_suse70_replace_iface_auto
+{
+ my ($file, $iface, $key, $value) = @_;
+ my ($val, $i, $found, @ret);
+
+ $val = &gst_parse_sh_split ($file, $key, "[ \t]+");
+
+ foreach $i (@$val)
+ {
+ $found = 1 if $i eq "_$iface";
+ push @ret, $i unless ($i eq "_$iface" && !$value);
+ }
+
+ return 0 if ($found == $value);
+ push @ret, "_$iface" if (!$found && $value);
+
+ return &gst_replace_sh ($file, $key, join (" ", @ret));
+}
+
+sub gst_network_suse70_parse_iface_sh
+{
+ my ($file, $iface, $key) = @_;
+ my ($val, $num);
+
+ return &gst_parse_sh ($file, "${key}_$iface");
+}
+
+sub gst_network_suse70_replace_iface_sh
+{
+ my ($file, $iface, $key, $value) = @_;
+ my ($val, $num);
+
+ return &gst_replace_sh ($file, "${key}_$iface", $value);
+}
+
+sub gst_network_suse70_get_ifconfig_arg
+{
+ my ($file, $iface, $key) = @_;
+ my ($val);
+
+ $val = &gst_network_suse70_parse_iface_sh ($file, $iface, "IFCONFIG");
+ $val =~ /[ \t]+$key[ \t]+([^ \t]+)/;
+ return $1;
+}
+
+sub gst_network_suse70_set_ifconfig_arg
+{
+ my ($file, $iface, $key, $value) = @_;
+ my ($val);
+
+ $val = &gst_network_suse70_parse_iface_sh ($file, $iface, "IFCONFIG");
+
+ return 0 if $val =~ /^dhcpclient$/ || $val =~ /^bootp$/;
+
+ if (! ($val =~ s/([ \t]+$key[ \t]+)[^ \t]+/$1$value/))
+ {
+ $val =~ s/[ \t]+up$//;
+ $val .= " " if $val =~ /[^ \t]$/;
+ $val .= "$key $value up";
+ }
+
+ return &gst_network_suse70_replace_iface_sh ($file, $iface, "IFCONFIG", $val);
+}
+
+sub gst_network_suse70_set_ifconfig_ip
+{
+ my ($file, $iface, $value) = @_;
+
+ $val = &gst_network_suse70_parse_iface_sh ($file, $iface, "IFCONFIG");
+
+ return 0 if $val =~ /^dhcpclient$/ || $val =~ /^bootp$/;
+
+ if (! ($val =~ s/^[0-9\.]+([ \t])/$value$1/))
+ {
+ $val = "$value $val";
+ $val =~ s/[ \t]+/ /;
+ }
+
+ return &gst_network_suse70_replace_iface_sh ($file, $iface, "IFCONFIG", $val);
+}
+
+sub gst_network_get_new_dialing_dev
+{
+ my ($dial_hash, $type) = @_;
+ my ($dial, $dev, $maxdev);
+
+ $maxdev = -1;
+ foreach $dial (keys %$dial_hash)
+ {
+ $dev = $ {$$dial_hash{$dial}}{"gst_dev"};
+ if ($dev ne "")
+ {
+ if ($dev =~ s/^$type//)
+ {
+ $maxdev = $dev if $dev > $maxdev;
+ }
+ }
+ }
+
+ $maxdev ++;
+ return "$type$maxdev";
+}
+
+sub gst_network_dial2iface
+{
+ my ($dial_hash, $name) = @_;
+ my ($dial, %iface, $i);
+
+ my %map = ("address" => "address",
+ "update_dns" => "update_dns",
+ "login" => "login",
+ "password" => "password",
+ "serial_port" => "device",
+ "serial_speed" => "speed",
+ "set_default_gw" => "set_default_gw",
+ "persist" => "persist",
+ "phone_number" => "phone",
+ "dev" => "gst_dev"
+ );
+
+ $dial = $$dial_hash{$name};
+ if ($$dial{"gst_dev"} eq "")
+ {
+ $$dial{"gst_dev"} = "ppp0";
+ # = &gst_network_get_new_dialing_dev ($dial_hash, "ppp");
+ }
+ else
+ {
+ $iface{"enabled"} = &gst_network_interface_active ($$dial{"gst_dev"},
+ \&gst_network_active_interfaces_get)? 1: 0;
+ }
+
+ foreach $i (keys %map)
+ {
+ $iface{$i} = $$dial{$map{$i}} if exists $$dial{$map{$i}};
+ }
+
+ $iface{"file"} = $iface{"name"} = $iface{"section"} = $name;
+ $iface{"update_dns"} = 1 if ($iface{"update_dns"} eq "");
+ $iface{"set_default_gw"} = 1 if ($iface{"set_default_gw"} eq "");
+
+ return \%iface;
+}
+
+sub gst_network_iface2dial
+{
+ my ($dial_hash, $iface) = @_;
+ my ($dial, $i);
+
+ my %map = ("address" => "address",
+ "update_dns" => "update_dns",
+ "device" => "serial_port",
+ "speed" => "serial_speed",
+ "set_default_gw" => "set_default_gw",
+ "persist" => "persist",
+ "gst_dev" => "dev"
+ );
+
+ $dial = $$dial_hash{$$iface{"name"}};
+
+ foreach $i (keys %map)
+ {
+ $$dial{$i} = $$iface{$map{$i}} if exists $$iface{$map{$i}};
+ }
+
+ $$dial{"type"} = "dialer";
+}
+
+sub gst_network_suse70_get_ppp
+{
+ my ($dial, $iface) = @_;
+ my ($d);
+
+ foreach $d (keys %$dial)
+ {
+ $$iface{$d} = &gst_network_dial2iface ($dial, $d);
+ }
+
+ return $iface;
+}
+
+sub gst_network_suse70_set_ppp
+{
+ my ($wvfile, $dial, $iface) = @_;
+ my ($d, $i, @ppp_devs, $section);
+
+ foreach $d (keys %$iface)
+ {
+ $i = $$iface{$d};
+ if ($$i{"dev"} =~ /^ppp/)
+ {
+ my ($tmp, $wv, $name);
+
+ push @ppp_devs, $i;
+
+ # This takes care of connection name changes.
+ $wv = $$i{"section"};
+ $name = $$i{"name"};
+
+ if ($wv ne $name)
+ {
+ $tmp = $$dial{$wv};
+ delete $$dial{$wv};
+ $$tmp{"name"} = $name;
+ $$dial{$name} = $tmp;
+ }
+
+ # Then merges interface with dialing.
+ &gst_network_iface2dial ($dial, $i);
+ }
+ }
+
+ # Delete any wvdial sections that are no longer present as ifaces.
+ OUTER: foreach $d (keys %$dial)
+ {
+ foreach $i (@ppp_devs)
+ {
+ next OUTER if $$i{"name"} eq $ {$$dial{$d}}{"name"};
+ }
+
+ # Don't delete the defaults: that's not very polite.
+ delete $$dial{$d} unless $ {$$dial{$d}}{"name"} eq "Defaults";
+ }
+
+ return 0;
+}
+
+sub gst_network_suse70_ppp_iface_activate
+{
+ my ($name, $enabled);
+ my ($wvdial_dod, $tool_ifconfig, @paths);
+
+ @paths = &gst_service_sysv_get_paths ();
+ $wvdial_dod = $paths[1] . "/wvdial.dod";
+ $tool_ifconfig = &gst_file_locate_tool ("ifconfig");
+
+ if ($enabled)
+ {
+ &gst_debug_print_string ("\n\nifup ppp iface $name\n\n");
+ return -1 if &gst_file_run_bg ("$wvdial_dod start \"$name\"");
+ }
+ else
+ {
+ # Hmm... you'd better not have more than one ppp connection active:
+ # this is the only SuSE way of doing it.
+ &gst_debug_print_string ("\n\nifdown ppp iface $name\n\n");
+ return -1 if &gst_file_run ("$wvdial_dod stop");
+ }
+
+ return 0;
+}
+
+sub gst_network_suse70_activate_ppp
+{
+ my ($iface) = @_;
+ my ($d, $i);
+
+ foreach $d (keys %$iface)
+ {
+ $i = $$iface{$d};
+ if ($$i{"dev"} =~ /^ppp/ && (! $$i{"enabled"}))
+ {
+ &gst_network_suse70_ppp_iface_activate ($$i{"name"}, 0);
+ # deleted, so interfaces_set doesn't handle them.
+ delete $$iface{$d};
+ }
+ }
+
+ foreach $d (keys %$iface)
+ {
+ $i = $$iface{$d};
+ if ($$i{"dev"} =~ /^ppp/ && $$i{"enabled"})
+ {
+ &gst_network_suse70_ppp_iface_activate ($$i{"name"}, 1);
+ delete $$iface{$d};
+ }
+ }
+
+ return 0;
+}
+
+sub gst_network_slackware91_create_pppgo
+{
+ my ($pppgo) = "/usr/sbin/ppp-go";
+ my ($contents, $pppd, $chat);
+ local *FILE;
+
+ if (!&gst_file_exists ($pppgo))
+ {
+ $pppd = &gst_file_locate_tool ("pppd");
+ $chat = &gst_file_locate_tool ("chat");
+
+ # create a simple ppp-go from scratch
+ # this script is based on the one that's created by pppsetup
+ $contents = "killall -INT pppd 2>/dev/null \n";
+ $contents .= "rm -f /var/lock/LCK* /var/run/ppp*.pid \n";
+ $contents .= "( $pppd connect \"$chat -v -f /etc/ppp/pppscript\") || exit 1 \n";
+ $contents .= "exit 0 \n";
+
+ &gst_file_buffer_save ($contents, $pppgo);
+ chmod 0777, "$gst_prefix/$pppgo";
+ }
+}
+
+sub gst_network_get_modem_volume
+{
+ my ($file) = @_;
+ my ($volume);
+
+ $volume = &gst_parse_chat ($file, "AT.*(M0|L[1-3])");
+
+ return 3 if ($volume eq undef);
+
+ $volume =~ s/^[ml]//i;
+ return $volume;
+}
+
+sub gst_network_set_modem_volume_string
+{
+ my ($file, $key, $volume) = @_;
+ my ($vol);
+
+ if ($volume == 0) { $vol = "ATM0" }
+ elsif ($volume == 1) { $vol = "ATL1" }
+ elsif ($volume == 2) { $vol = "ATL2" }
+ else { $vol = "ATL3" }
+
+ return &gst_replace_sh ($file, $key, $vol);
+}
+
+sub gst_network_set_modem_volume
+{
+ my ($file, $volume) = @_;
+ my $line;
+
+ $line = &gst_parse_chat ($file, "AT([^DZ][a-z0-9&]+)");
+ $line =~ s/(M0|L[1-3])//g;
+
+ if ($volume == 0) { $line .= "M0"; }
+ elsif ($volume == 1) { $line .= "L1"; }
+ elsif ($volume == 2) { $line .= "L2"; }
+ else { $line .= "L3"; }
+
+ return &gst_replace_chat ($file, "AT([^DZ][a-z0-9&]+)", $line);
+}
+
+sub gst_network_create_pppscript
+{
+ my ($pppscript) = @_;
+ my ($contents);
+
+ if (!&gst_file_exists ($pppscript))
+ {
+ # create a template file from scratch
+ $contents = 'TIMEOUT 60' . "\n";
+ $contents .= 'ABORT ERROR' . "\n";
+ $contents .= 'ABORT BUSY' . "\n";
+ $contents .= 'ABORT VOICE' . "\n";
+ $contents .= 'ABORT "NO CARRIER"' . "\n";
+ $contents .= 'ABORT "NO DIALTONE"' . "\n";
+ $contents .= 'ABORT "NO DIAL TONE"' . "\n";
+ $contents .= 'ABORT "NO ANSWER"' . "\n";
+ $contents .= '"" "ATZ"' . "\n";
+ $contents .= '"" "AT&FH0"' . "\n";
+ $contents .= 'OK-AT-OK "ATDT000000000"' . "\n";
+ $contents .= 'TIMEOUT 75' . "\n";
+ $contents .= 'CONNECT' . "\n";
+
+ &gst_file_buffer_save ($contents, $pppscript);
+ }
+}
+
+sub gst_network_create_isdn_options
+{
+ my ($file) = @_;
+
+ if (!&gst_file_exists ($file))
+ {
+ &gst_file_copy_from_stock ("general_isdn_ppp_options", $file);
+ }
+}
+
+sub gst_network_check_pppd_plugin
+{
+ my ($plugin) = @_;
+ my ($version, $output);
+
+ $version = &gst_file_run_backtick ("pppd --version", 1);
+ $version =~ s/.*version[ \t]+//;
+ chomp $version;
+
+ return 0 if !version;
+ return &gst_file_exists ("/usr/lib/pppd/$version/$plugin.so");
+}
+
+sub gst_network_gentoo_parse_gateway
+{
+ my ($file, $iface) = @_;
+ my ($str);
+
+ $str = &gst_parse_confd_net ($file, "routes_$iface");
+
+ if ($str =~ /default[ \t]+(via|gw)[ \t]+([0-9\.\:]*)/)
+ {
+ return $2;
+ }
+}
+
+sub gst_network_interfaces_get
+{
+ my (%dist_attrib, %config_hash, %hash, %fn);
+ my (@config_ifaces, $iface, $dev);
+ my ($dist, $value, $file, $proc);
+ my ($i, $j);
+ my ($modem_settings);
+
+ $hash = &gst_network_interfaces_get_info ();
+ %dist_attrib = &gst_network_get_interface_parse_table ();
+ %fn = %{$dist_attrib{"fn"}};
+ $proc = $dist_attrib{"ifaces_get"};
+ @ifaces = &$proc ();
+
+ # clear unneeded hash elements
+ foreach $i (keys %$hash)
+ {
+ delete $$hash{$i}{"addr"};
+ delete $$hash{$i}{"bcast"};
+ delete $$hash{$i}{"mask"};
+ }
+
+ foreach $i (@ifaces)
+ {
+ foreach $j (keys (%fn))
+ {
+ $ {$dist_attrib{"fn"}}{$j} = &gst_parse_expand ($fn{$j}, "iface", $i);
+ }
+
+ $iface = &gst_parse_from_table ($dist_attrib{"fn"},
+ $dist_attrib{"table"});
+ &gst_network_interface_ensure_broadcast_and_network ($iface);
+ $$iface{"file"} = $i if ($$iface{"file"} eq undef);
+
+ $dev = $$iface{"dev"};
+ delete $$iface{"dev"};
+
+ if (exists $$hash{$dev})
+ {
+ $$hash{$dev}{"configuration"} = $iface;
+ }
+ elsif (($dev eq "ppp0") || ($dev eq "tun0"))
+ {
+ $modem_settings = $iface;
+ }
+ }
+
+ # only show PPP and ISDN devices if pppd exists
+ # and they aren't configured yet
+ $dev = "ppp0" if ($$tool{"system"} eq "Linux");
+ $dev = "tun0" if ($$tool{"system"} eq "FreeBSD");
+
+ if (!exists $$hash{$dev} && &gst_file_locate_tool ("pppd"))
+ {
+ $$hash{$dev}{"dev"} = $dev;
+ $$hash{$dev}{"enabled"} = 0;
+ $$hash{$dev}{"type"} = &gst_network_get_interface_type ($dev);
+ $$hash{$dev}{"configuration"} = $modem_settings if ($modem_settings);
+ }
+
+ return \%$hash;
+}
+
+sub gst_network_conf_get
+{
+ my %dist_attrib;
+ my $hash;
+
+ %dist_attrib = &gst_network_get_parse_table ();
+
+ $hash = &gst_parse_from_table ($dist_attrib{"fn"},
+ $dist_attrib{"table"});
+ return $hash;
+}
+
+sub gst_network_rh_get_smb_desc
+{
+ my ($file, $section, $var, $hostname) = @_;
+ my $val;
+
+ $val = &gst_parse_ini ($file, $section, $var);
+ if (($val =~ /^Samba Server/) && ($hostname ne undef))
+ {
+ return $hostname;
+ }
+
+ return $val;
+}
+
+sub gst_network_rh62_get_file
+{
+ my ($iface) = @_;
+ my ($pre, $i, $dev);
+
+ $dev = $$iface{"dev"};
+ $pre = "$gst_prefix/etc/sysconfig/network-scripts/ifcfg-";
+
+ return $dev if ! -e "$pre$dev";
+
+ $dev =~ s/[0-9]*$//;
+
+ $i = 0;
+ $i ++ while (-e "$pre$dev$i");
+
+ return "$dev$i";
+}
+
+sub gst_network_rh72_get_file
+{
+ my ($iface) = @_;
+ my ($pre, $i, $dev);
+
+ $dev = $$iface{"dev"};
+ $pre = "$gst_prefix/etc/sysconfig/networking/devices/ifcfg-";
+
+ return $dev if ! -e "$pre$dev";
+
+ $i = 0;
+ $i ++ while (-e "$pre$dev.$i");
+
+ return "$dev.$i";
+}
+
+sub gst_network_deb22_get_file
+{
+ my ($iface) = @_;
+
+ return $$iface{"dev"};
+}
+
+sub gst_network_suse70_get_file
+{
+ my ($i, $file);
+
+ $file = "$gst_prefix/etc/rc.config";
+
+ $i = 0;
+ $i ++ while (&gst_parse_sh ($file, "NETDEV_$i") ne "");
+
+ return $i;
+}
+
+sub gst_network_pld10_get_file
+{
+ my ($iface) = @_;
+ my ($pre, $i, $dev);
+
+ $dev = $$iface{"dev"};
+ $pre = "$gst_prefix/etc/sysconfig/interfaces/ifcfg-";
+
+ return $dev if ! -e "$pre$dev";
+
+ $dev =~ s/[0-9]*$//;
+
+ $i = 0;
+ $i ++ while (-e "$pre$dev$i");
+
+ return "$dev$i";
+}
+
+sub gst_network_get_file
+{
+ my ($iface) = @_;
+ my $proc;
+
+ my %dist_map =
+ (
+ "redhat-6.0" => \&gst_network_rh62_get_file,
+ "redhat-6.1" => \&gst_network_rh62_get_file,
+ "redhat-6.2" => \&gst_network_rh62_get_file,
+ "redhat-7.0" => \&gst_network_rh62_get_file,
+ "redhat-7.1" => \&gst_network_rh62_get_file,
+ "redhat-7.2" => \&gst_network_rh72_get_file,
+ "redhat-8.0" => \&gst_network_rh72_get_file,
+ "redhat-9" => \&gst_network_rh72_get_file,
+ "openna-1.0" => \&gst_network_rh62_get_file,
+ "mandrake-7.2" => \&gst_network_rh62_get_file,
+ "mandrake-7.1" => \&gst_network_rh62_get_file,
+ "mandrake-9.0" => \&gst_network_rh62_get_file,
+ "mandrake-9.1" => \&gst_network_rh62_get_file,
+ "mandrake-9.2" => \&gst_network_rh62_get_file,
+ "mandrake-10.0" => \&gst_network_rh62_get_file,
+ "mandrake-10.1" => \&gst_network_rh62_get_file,
+ "mandrake-10.2" => \&gst_network_rh62_get_file,
+ "mandriva-2006.0" => \&gst_network_rh62_get_file,
+ "mandriva-2006.1" => \&gst_network_rh62_get_file,
+ "mandriva-2007.0" => \&gst_network_rh62_get_file,
+ "mandriva-2007.1" => \&gst_network_rh62_get_file,
+ "yoper-2.2" => \&gst_network_rh62_get_file,
+ "blackpanther-4.0" => \&gst_network_rh62_get_file,
+ "conectiva-9" => \&gst_network_rh62_get_file,
+ "conectiva-10" => \&gst_network_rh62_get_file,
+ "debian-2.2" => \&gst_network_deb22_get_file,
+ "debian-3.0" => \&gst_network_deb22_get_file,
+ "debian-3.1" => \&gst_network_deb22_get_file,
+ "debian-4.0" => \&gst_network_deb22_get_file,
+ "debian-5.0" => \&gst_network_deb22_get_file,
+ "debian-testing" => \&gst_network_deb22_get_file,
+ "ubuntu-5.04" => \&gst_network_deb22_get_file,
+ "ubuntu-5.10" => \&gst_network_deb22_get_file,
+ "ubuntu-6.06" => \&gst_network_deb22_get_file,
+ "ubuntu-6.10" => \&gst_network_deb22_get_file,
+ "ubuntu-7.04" => \&gst_network_deb22_get_file,
+ "ubuntu-7.10" => \&gst_network_deb22_get_file,
+ "ubuntu-8.04" => \&gst_network_deb22_get_file,
+ "suse-7.0" => \&gst_network_suse70_get_file,
+ "suse-9.0" => \&gst_network_deb22_get_file,
+ "suse-9.1" => \&gst_network_deb22_get_file,
+ "turbolinux-7.0" => \&gst_network_rh62_get_file,
+ "pld-1.0" => \&gst_network_pld10_get_file,
+ "pld-1.1" => \&gst_network_pld10_get_file,
+ "pld-1.99" => \&gst_network_pld10_get_file,
+ "fedora-1" => \&gst_network_rh72_get_file,
+ "fedora-2" => \&gst_network_rh72_get_file,
+ "fedora-3" => \&gst_network_rh72_get_file,
+ "fedora-4" => \&gst_network_rh72_get_file,
+ "fedora-5" => \&gst_network_rh72_get_file,
+ "rpath" => \&gst_network_rh72_get_file,
+ "vine-3.0" => \&gst_network_rh62_get_file,
+ "vine-3.1" => \&gst_network_rh62_get_file,
+ "ark" => \&gst_network_rh62_get_file,
+ "slackware-9.1.0" => \&gst_network_deb22_get_file,
+ "slackware-10.0.0" => \&gst_network_deb22_get_file,
+ "slackware-10.1.0" => \&gst_network_deb22_get_file,
+ "slackware-10.2.0" => \&gst_network_deb22_get_file,
+ "gentoo" => \&gst_network_deb22_get_file,
+ "freebsd-5" => \&gst_network_deb22_get_file,
+ "freebsd-6" => \&gst_network_deb22_get_file,
+ );
+
+ $proc = $dist_map{$gst_dist};
+
+ return &$proc ($iface) if $proc;
+
+ # FIXME: should make us bail.
+ &gst_debug_print_string ("\n\nWarning: No network_get_file proc for dist $gst_dist.\n\n");
+ return undef;
+}
+
+sub gst_network_get_gateway_data
+{
+ my ($fd, $gateway, $dev);
+
+ $fd = &gst_file_run_pipe_read ("route -n");
+ while (<$fd>)
+ {
+ if (/^0\.0\.0\.0[\t ]+([^\t ]+).*[ \t]([a-zA-Z0-9]*)/)
+ {
+ $gateway = $1;
+ $dev = $2;
+ last;
+ }
+ }
+
+ &gst_file_close ($fd);
+ return ($gateway, $dev);
+}
+
+sub gst_network_get_default_gatewaydev
+{
+ my ($gateway, $dev) = &gst_network_get_gateway_data ();
+
+ return $dev;
+}
+
+sub gst_network_get_default_gateway
+{
+ my ($gateway, $dev) = &gst_network_get_gateway_data ();
+
+ return $gateway;
+}
+
+sub gst_network_route_set_default_gw
+{
+ my ($gatewaydev, $gateway) = @_;
+ my ($tool_route, $curr_gateway, $curr_gatewaydev, $fd);
+
+ # Just in case. This means that no static gateway is needed.
+ return if $gateway eq "";
+
+ $fd = &gst_file_run_pipe_read ("route -n");
+ while (<$fd>)
+ {
+ if (/^0\.0\.0\.0[ \t]+([0-9.]+) /)
+ {
+ $curr_gateway = $1;
+ if ($gatewaydev ne "")
+ {
+ /([a-z0-9]+)$/;
+ $curr_gatewaydev = $1;
+ }
+
+ last;
+ }
+ }
+ &gst_file_close ($fd);
+
+ if (($curr_gateway ne $gateway) ||
+ ($curr_gatewaydev ne $gatewaydev))
+ {
+ &gst_file_run ("route del default gw $curr_gateway");
+ &gst_file_run ("route add default gw $gateway $gatewaydev");
+ }
+}
+
+sub gst_network_run_hostname
+{
+ my ($hostname) = @_;
+
+ &gst_report_enter ();
+ &gst_report ("network_hostname_set", $hostname);
+ &gst_file_run ("hostname $hostname");
+ &gst_report_leave ();
+}
+
+sub gst_network_dialing_get_section_name
+{
+ my ($dial) = @_;
+
+ my %type2title =
+ (
+ "dialer" => "Dialer ",
+ "modem" => "Modem ",
+ "unknown" => ""
+ );
+
+ return $type2title{$$dial{"type"}} . $$dial{"name"};
+}
+
+sub gst_network_dialing_set
+{
+ my ($file, $old_hash, $values_hash) = @_;
+ my %vars =
+ (
+ "inherits" => "Inherits",
+ "device" => "Modem",
+ "speed" => "Baud",
+ "init1" => "Init1",
+ "init2" => "Init2",
+ "phone" => "Phone",
+ "login" => "Username",
+ "password" => "Password",
+ "dialcmd" => "Dial Command",
+ "setvol" => "SetVolume",
+ "stupid" => "Stupid mode",
+ "persist" => "Auto Reconnect",
+ "address" => "Force Address",
+ "update_dns" => "Auto DNS",
+ "set_default_gw" => "Check Def Route",
+ "gst_dev" => "GST Device",
+ "dial_command" => "Dial Command"
+ );
+
+ my (%hash, $section);
+ my $ret;
+ my ($i, $j);
+
+ &gst_report_enter ();
+ &gst_report ("network_dialing_set");
+ &gst_file_run ("wvdialconf $gst_prefix/$file") if (!-e "$gst_prefix/$file");
+
+ # Remove those that are in old, but not in values.
+ $old_hash = $$old_hash{"dialing"};
+ OUTER: foreach $i (keys %$old_hash)
+ {
+ foreach $j (keys %$values_hash)
+ {
+ next OUTER if ($j eq $i) && ($ {$$values_hash{$j}}{"type"} eq $ {$$old_hash{$i}}{"type"});
+ }
+
+ $section = gst_network_dialing_get_section_name ($$old_hash{$i});
+ $ret = -1 if &gst_replace_remove_ini_section ($file, $section);
+ }
+
+ # Now save the current stuff.
+ foreach $i (keys %$values_hash)
+ {
+ %hash = %{$$values_hash{$i}};
+
+ $section = gst_network_dialing_get_section_name (\%hash);
+ delete $hash{"type"};
+ delete $hash{"name"};
+
+ # if init1 doesnt exist add one with ATZ
+ if (!$hash{"init1"})
+ {
+ $hash{"init1"} = "ATZ";
+ }
+
+ # add the volume settings to init2
+ if ($hash{"init2"} !~ /^(AT)/)
+ {
+ $hash{"init2"} = "AT";
+ }
+ $hash {"init2"} =~ s/L[1-3]//;
+ $hash {"init2"} =~ s/M[0-2]//;
+ if ($hash{"volume"} == 0)
+ {
+ $hash{"init2"} .= "M0";
+ }
+ else
+ {
+ $volume = $hash{"volume"};
+ $hash {"init2"} .= "L$volume";
+ }
+ delete $hash {"volume"};
+
+ # join again the "external_line" and "phone" tags
+ if ($hash{"external_line"} ne undef)
+ {
+ $hash{"phone"} = $hash{"external_line"} . "W" . $hash{"phone"};
+ delete $hash{"external_line"};
+ }
+
+ foreach $j (keys %hash)
+ {
+ $ret = -1 if &gst_replace_ini ($file, $section, $vars{$j}, $hash{$j});
+ }
+ }
+
+ &gst_report_leave ();
+
+ chmod (0600, $file) if !$ret;
+
+ return $ret;
+}
+
+# This works for all systems that have ifup/ifdown scripts.
+sub gst_network_rh62_interface_activate_by_dev
+{
+ my ($dev, $enabled) = @_;
+
+ &gst_report_enter ();
+
+ if ($enabled)
+ {
+ &gst_report ("network_iface_activate", $dev);
+ return -1 if &gst_file_run ("ifup $dev");
+ }
+ else
+ {
+ &gst_report ("network_iface_deactivate", $dev);
+ return -1 if &gst_file_run ("ifdown $dev");
+ }
+
+ &gst_report_leave ();
+
+ return 0;
+}
+
+sub gst_network_rh62_interface_activate
+{
+ my ($hash, $old_hash, $enabled, $force) = @_;
+ my $dev;
+
+ if ($force || &gst_network_interface_changed ($hash, $old_hash))
+ {
+ if (exists $$hash{"configuration"}{"file"})
+ {
+ $dev = $$hash{"configuration"}{"file"};
+ }
+ else
+ {
+ $dev = $$hash{"dev"};
+ }
+
+ &gst_network_rh62_interface_activate_by_dev ($dev, $enabled);
+ }
+}
+
+sub gst_network_suse9_interface_activate
+{
+ my ($hash, $old_hash, $enabled, $force) = @_;
+ my ($iface, $dev);
+
+ if ($force || &gst_network_interface_changed ($hash, $old_hash))
+ {
+ if (exists $$hash{"configuration"}{"file"})
+ {
+ $iface = $$hash{"configuration"}{"file"};
+ $dev = &gst_network_suse9_get_dev_name ($iface);
+ }
+ else
+ {
+ $dev = $$hash{"dev"};
+ }
+
+ &gst_network_rh62_interface_activate_by_dev ($dev, $enabled);
+ }
+}
+
+sub gst_network_suse70_interface_activate_by_dev
+{
+ my ($dev, $enabled) = @_;
+ my ($network, @paths);
+
+ @paths = &gst_service_sysv_get_paths ();
+ $network = $paths[1] . "/network";
+
+ &gst_report_enter ();
+
+ if ($enabled)
+ {
+ &gst_report ("network_iface_deactivate", $hash{"dev"});
+ return -1 if &gst_file_run_bg ("$network start $dev");
+ }
+ else
+ {
+ &gst_report ("network_iface_activate", $hash{"dev"});
+ return -1 if &gst_file_run ("$network stop $dev");
+ }
+
+ &gst_report_leave ();
+
+ return 0;
+}
+
+sub gst_network_suse70_interface_activate
+{
+ my ($hash, $old_hash, $enabled, $force) = @_;
+
+ if ($force || &gst_network_interface_changed ($hash, $old_hash))
+ {
+ &gst_network_rh62_interface_activate_by_dev ($$hash{"dev"}, $enabled);
+ }
+}
+
+sub gst_network_slackware91_interface_activate_by_dev
+{
+ my ($dev, $enabled) = @_;
+ my ($address, $netmask, $gateway);
+ my ($file) = "/etc/rc.d/rc.inet1.conf";
+ my ($ret) = 0;
+
+ &gst_report_enter ();
+
+ if ($enabled)
+ {
+ &gst_report ("network_iface_activate", $dev);
+
+ if ($dev =~ /^ppp/)
+ {
+ $ret = &gst_file_run ("ppp-go");
+ }
+ else
+ {
+ if (&gst_parse_rcinet1conf_bool ($file, $dev, USE_DHCP))
+ {
+ # Use DHCP
+ $ret = &gst_file_run ("dhclient $dev");
+ }
+ else
+ {
+ $address = &gst_parse_rcinet1conf ($file, $dev, "IPADDR");
+ $netmask = &gst_parse_rcinet1conf ($file, $dev, "NETMASK");
+ $gateway = &gst_network_get_gateway ($file, "GATEWAY", $address, $netmask);
+
+ $ret = &gst_file_run ("ifconfig $dev $address netmask $netmask up");
+
+ # Add the gateway if necessary
+ if ($gateway ne undef)
+ {
+ &gst_file_run ("route add default gw $gateway");
+ }
+ }
+ }
+ }
+ else
+ {
+ &gst_report ("network_iface_deactivate", $dev);
+
+ $ret = &gst_file_run ("ifconfig $dev down") if ($dev =~ /^eth/);
+ $ret = &gst_file_run ("ppp-off") if ($dev =~ /^ppp/);
+ }
+
+ &gst_report_leave ();
+ return -1 if ($ret != 0);
+ return 0;
+}
+
+sub gst_network_slackware91_interface_activate
+{
+ my ($hash, $old_hash, $enabled, $force) = @_;
+ my $dev = $$hash{"configuration"}{"file"};
+
+ if ($force || &gst_network_interface_changed ($hash, $old_hash))
+ {
+ &gst_network_slackware91_interface_activate_by_dev ($dev, $enabled);
+ }
+}
+
+sub gst_network_gentoo_interface_activate_by_dev
+{
+ my ($dev, $enabled) = @_;
+ my $file = "/etc/init.d/net.$dev";
+ my $action = ($enabled == 1)? "start" : "stop";
+
+ return &gst_file_run ("$file $action");
+}
+
+sub gst_network_gentoo_interface_activate
+{
+ my ($hash, $old_hash, $enabled, $force) = @_;
+ my $dev = $$hash{"configuration"}{"file"};
+
+ if ($force || &gst_network_interface_changed ($hash, $old_hash))
+ {
+ &gst_network_gentoo_interface_activate_by_dev ($dev, $enabled);
+ }
+}
+
+sub gst_network_freebsd_interface_activate_by_dev
+{
+ my ($hash, $enabled) = @_;
+ my ($dev) = $$hash{"configuration"}{"file"};
+ my ($startif) = "/etc/start_if.$dev";
+ my ($file) = "/etc/rc.conf";
+ my ($command, $dhcp_flags, $defaultroute, $fd);
+
+ if ($enabled)
+ {
+ # Run the /etc/start_if.$dev commands
+ $fd = &gst_file_open_read_from_names ($startif);
+
+ while (<$fd>)
+ {
+ `$_`;
+ }
+
+ &gst_file_close ($fd);
+ $command = &gst_parse_sh ($file, "ifconfig_$dev");
+
+ # Bring up the interface
+ if ($command =~ /DHCP/i)
+ {
+ $dhcp_flags = &gst_parse_sh ($file, "dhcp_flags");
+ &gst_file_run ("dhclient $dhcp_flags $dev");
+ }
+ else
+ {
+ &gst_file_run ("ifconfig $dev $command");
+ }
+
+ # Add the default route
+ $default_route = &gst_parse_sh ($file, "defaultrouter");
+ &gst_file_run ("route add default $default_route") if ($default_route !~ /^no$/i);
+ }
+ else
+ {
+ &gst_file_run ("ifconfig $dev down");
+ }
+}
+
+sub gst_network_freebsd_interface_activate
+{
+ my ($hash, $old_hash, $enabled, $force) =@_;
+
+ if ($force || &gst_network_interface_changed ($hash, $old_hash))
+ {
+ &gst_network_freebsd_interface_activate_by_dev ($hash, $enabled);
+ }
+}
+
+sub gst_network_remove_pap_entry
+{
+ my ($file, $login) = @_;
+ my ($i, $buff);
+
+ &gst_report_enter ();
+ &gst_report ("network_remove_pap", $file, $login);
+
+ $buff = &gst_file_buffer_load ($file);
+
+ foreach $i (@$buff)
+ {
+ $i = "" if ($i =~ /^[ \t]*$login[ \t]/);
+ }
+
+ &gst_file_buffer_clean ($buff);
+ &gst_report_leave ();
+ return &gst_file_buffer_save ($buff, $file);
+}
+
+sub gst_network_rh62_interface_delete
+{
+ my ($old_hash) = @_;
+ my $dev = $$old_hash{"configuration"}{"file"};
+ my $file = "$gst_prefix/etc/sysconfig/network-scripts/ifcfg-$dev";
+ my $login;
+
+ &gst_network_rh62_interface_activate_by_dev ($dev, 0);
+
+ $login = $old_hash{"configuration"}{"login"};
+ if ($login ne "")
+ {
+ &gst_network_remove_pap_entry ("/etc/ppp/pap-secrets", $login);
+ &gst_network_remove_pap_entry ("/etc/ppp/chap-secrets", $login);
+ }
+
+ &gst_file_remove ($file);
+}
+
+sub gst_network_rh72_interface_delete
+{
+ my ($old_hash) = @_;
+ my ($dev, $login);
+
+ $filedev = $$old_hash{"configuration"}{"file"};
+ $dev = $$old_hash{"dev"};
+ $login = $$old_hash{"configuration"}{"login"};
+
+ &gst_network_rh62_interface_activate_by_dev ($filedev, 0);
+
+ if ($login ne "")
+ {
+ &gst_network_remove_pap_entry ("/etc/ppp/pap-secrets", $login);
+ &gst_network_remove_pap_entry ("/etc/ppp/chap-secrets", $login);
+ }
+
+ &gst_file_remove ("$gst_prefix/etc/sysconfig/networking/devices/ifcfg-$filedev");
+ &gst_file_remove ("$gst_prefix/etc/sysconfig/networking/profiles/default/ifcfg-$filedev");
+ &gst_file_remove ("$gst_prefix/etc/sysconfig/network-scripts/ifcfg-$dev");
+
+ &gst_file_run ("redhat-config-network-cmd");
+}
+
+sub gst_network_deb22_interface_delete
+{
+ my ($old_hash) = @_;
+ my $dev = $$old_hash{"dev"};
+
+ &gst_network_rh62_interface_activate_by_dev ($dev, 0);
+ &gst_replace_interfaces_iface_stanza_delete ("$gst_prefix/etc/network/interfaces", $dev);
+
+ $login = $old_hash{"configuration"}{"login"};
+ if ($login ne "")
+ {
+ &gst_network_remove_pap_entry ("/etc/ppp/pap-secrets", $login);
+ &gst_network_remove_pap_entry ("/etc/ppp/chap-secrets", $login);
+ }
+}
+
+sub gst_network_suse70_interface_delete
+{
+ my ($old_hash) = @_;
+ my $dev = $$old_hash{"configuration"}{"file"};
+ my $file = "$gst_prefix/etc/rc.config";
+ my $login;
+
+ &gst_network_suse70_interface_activate_by_dev ($$old_hash{"dev"}, 0);
+
+# Commented until I know what to do with ppp connections.
+# $login = $old_hash{"login"};
+# if ($login ne "")
+# {
+# &gst_network_remove_pap_entry ("/etc/ppp/pap-secrets", $login);
+# &gst_network_remove_pap_entry ("/etc/ppp/chap-secrets", $login);
+# }
+
+ &gst_replace_sh ($file, "IPADDR_$dev", "");
+ &gst_replace_sh ($file, "NETDEV_$dev", "");
+ &gst_replace_sh ($file, "IFCONFIG_$dev", "");
+}
+
+sub gst_network_suse90_interface_delete
+{
+ my ($old_hash) = @_;
+ my $file = $$old_hash{"configuration"}{"file"};
+ my $provider = &gst_parse_sh ("$gst_prefix/etc/sysconfig/network/ifcfg-$file", PROVIDER);
+ my $dev = &gst_network_suse9_get_dev_name ($file);
+
+ &gst_network_rh62_interface_activate_by_dev ($dev, 0);
+
+ &gst_file_remove ("$gst_prefix/etc/sysconfig/network/ifroute-$file");
+ &gst_file_remove ("$gst_prefix/etc/sysconfig/network/ifcfg-$file");
+ &gst_file_remove ("$gst_prefix/etc/sysconfig/network/providers/$provider");
+}
+
+sub gst_network_pld10_interface_delete
+{
+ my ($old_hash) = @_;
+ my $dev = $$old_hash{"configuration"}{"file"};
+ my $file = "$gst_prefix/etc/sysconfig/interfaces/ifcfg-$dev";
+ my $login;
+
+ &gst_network_rh62_interface_activate_by_dev ($dev, 0);
+
+ $login = $old_hash{"configuration"}{"login"};
+ if ($login ne "")
+ {
+ &gst_network_remove_pap_entry ("/etc/ppp/pap-secrets", $login);
+ &gst_network_remove_pap_entry ("/etc/ppp/chap-secrets", $login);
+ }
+
+ &gst_file_remove ($file);
+}
+
+sub gst_network_slackware91_interface_delete
+{
+ my ($old_hash) = @_;
+ my $rcinetconf = "$gst_prefix/etc/rc.d/rc.inet1.conf";
+ my $rcinet = "$gst_prefix/etc/rc.d/rc.inet1";
+ my $pppscript = "$gst_prefix/etc/ppp/pppscript";
+ my $dev = $$old_hash {"dev"};
+
+ # remove ifup/ppp-go at startup if existing
+ &gst_network_slackware91_set_auto ($rcinet, $dev);
+
+ if ($dev =~ /^eth/)
+ {
+ # empty the values
+ &gst_replace_rcinet1conf ($rcinetconf, $dev, "IPADDR", "");
+ &gst_replace_rcinet1conf ($rcinetconf, $dev, "NETMASK", "");
+ &gst_replace_rcinet1conf ($rcinetconf, $dev, "USE_DHCP", "");
+ &gst_replace_rcinet1conf ($rcinetconf, $dev, "DHCP_HOSTNAME", "");
+ }
+ elsif ($dev =~ /^ppp/)
+ {
+ &gst_file_remove ($pppscript);
+ }
+}
+
+sub gst_network_gentoo_interface_delete
+{
+ my ($old_hash) = @_;
+ my ($dev) = $$old_hash {"dev"};
+ my ($gateway) = $$old_hash {"configuration"}{"gateway"};
+ my ($initfile) = "$gst_prefix/etc/init.d/net.$dev";
+ my ($netconf);
+
+ # bring down the interface and remove from init
+ &gst_service_gentoo_set_status ($initfile, 1, 0);
+
+ if ($dev =~ /^ppp/)
+ {
+ $netconf = "/etc/conf.d/net.$dev";
+ gst_file_remove ($netconf);
+ }
+ else
+ {
+ $netconf = "/etc/conf.d/net";
+ &gst_replace_sh ($netconf, "config_$dev", "");
+ }
+}
+
+sub gst_network_freebsd_interface_delete
+{
+ my ($old_hash) = @_;
+ my ($dev) = $$old_hash{"dev"};
+ my ($startif) = "/etc/start_if.$dev";
+ my ($file) = "/etc/rc.conf";
+ my ($pppconf) = "/etc/ppp/ppp.conf";
+ my ($buff, $line_no, $end_line_no, $i);
+
+ &gst_file_run ("ifconfig $dev down");
+
+ if ($dev =~ /^tun[0-9]+/)
+ {
+ # Delete the ppp.conf section
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+
+ $buff = &gst_file_buffer_load ($pppconf);
+
+ $line_no = &gst_parse_pppconf_find_stanza ($buff, $section);
+ $end_line_no = &gst_parse_pppconf_find_next_stanza ($buff, $line_no + 1);
+ $end_line_no = scalar @$buff + 1 if ($end_line_no == -1);
+ $end_line_no--;
+
+ for ($i = $line_no; $i <= $end_line_no; $i++)
+ {
+ delete $$buff[$i];
+ }
+
+ &gst_file_buffer_clean ($buff);
+ &gst_file_buffer_save ($buff, $pppconf);
+ }
+
+ &gst_replace_sh ($file, "ifconfig_$dev", "");
+ &gst_file_remove ($startif);
+}
+
+sub gst_network_interface_changed
+{
+ my ($iface, $iface_old) = @_;
+
+ delete $$iface{"type"};
+ delete $$iface_old{"type"};
+ return !&gst_util_struct_eq ($iface, $iface_old);
+}
+
+# silly function for leveling the configuration hash
+# with the interface hash
+sub level_interface_hash
+{
+ my ($hash) = @_;
+ my (%config, $i);
+
+ $config = $$hash{"configuration"};
+
+ foreach $i (keys %$config)
+ {
+ $$hash{$i} = $$config{$i};
+ }
+}
+
+sub gst_network_interface_set
+{
+ my ($dev, $values_hash, $old_hash) = @_;
+ my (%dist_attrib, %fn);
+ my ($proc, $i, $res);
+
+ &gst_report_enter ();
+ &gst_report ("network_iface_set", $dev);
+ %dist_attrib = &gst_network_get_interface_replace_table ();
+ $proc = $dist_attrib{"iface_set"};
+ %fn = %{$dist_attrib{"fn"}};
+
+ level_interface_hash (\%$values_hash);
+ level_interface_hash (\%$old_hash);
+
+ foreach $i (keys (%fn))
+ {
+ $ {$dist_attrib{"fn"}}{$i} = &gst_parse_expand ($fn{$i}, "iface", $dev);
+ }
+
+ $res = &gst_replace_from_table ($dist_attrib{"fn"}, $dist_attrib{"table"},
+ $values_hash, $old_hash);
+
+ # if success saving the settings for the interface, set up immediatly.
+ &$proc ($values_hash, $old_hash, $$values_hash{"enabled"}, 0) if !$res;
+
+ &gst_report_leave ();
+
+ return $res;
+}
+
+sub gst_network_interfaces_set
+{
+ my ($old_hash, $values_hash) = @_;
+ my (%dist_attrib, @ifaces, %fn);
+ my ($value, $proc);
+ my ($i, $j);
+ my ($tmp, $res);
+ my ($delete_proc, $set_proc);
+ my ($was_active);
+
+ &gst_report_enter ();
+ &gst_report ("network_ifaces_set");
+
+ %dist_attrib = &gst_network_get_interface_replace_table ();
+ $old_hash = $$old_hash{"interface"};
+
+ $delete_proc = $dist_attrib{"iface_delete"};
+ $set_proc = $dist_attrib{"iface_set"};
+
+ foreach $i (keys %$values_hash)
+ {
+ # delete it if it's no longer configured
+ if (exists $$old_hash{$i}{"configuration"} &&
+ not exists $$values_hash{$i}{"configuration"})
+ {
+ &$set_proc ($$values_hash{$i}, $$old_hash{$i}, 0, 1);
+ &$delete_proc ($$old_hash{$i});
+ }
+ elsif (exists $$values_hash{$i}{"configuration"})
+ {
+ if (&gst_network_interface_changed ($$values_hash{$i}, $$old_hash{$i}))
+ {
+ $was_active = $$values_hash{$i}{"enabled"};
+
+ &$set_proc ($$values_hash{$i}, $$old_hash{$i}, 0, 1);
+ $tmp = &gst_network_interface_set ($i, $$values_hash{$i}, $$old_hash{$i});
+ $res = $tmp if !$res;
+
+ if ($was_active == 1)
+ {
+ &$set_proc ($$values_hash{$i}, $$old_hash{$i}, 1, 1);
+ }
+ }
+ }
+ }
+
+ &gst_report_leave ();
+ return $res;
+}
+
+sub gst_network_conf_set
+{
+ my $values_hash = $_[0];
+ my $old_hash;
+ my %dist_attrib;
+
+ $old_hash = &gst_network_conf_get ();
+
+ &gst_network_ensure_loopback ($values_hash, $old_hash);
+
+ %dist_attrib = &gst_network_get_replace_table ();
+ $res = &gst_replace_from_table ($dist_attrib{"fn"}, $dist_attrib{"table"},
+ $values_hash, $old_hash);
+ return $res;
+}
+
+sub gst_network_get_pap_passwd
+{
+ my ($file, $login) = @_;
+ my (@arr, $passwd);
+
+ $login = '"?' . $login . '"?';
+ &gst_report_enter ();
+ &gst_report ("network_get_pap_passwd", $login, $file);
+ $arr = &gst_parse_split_first_array ($file, $login, "[ \t]+", "[ \t]+");
+
+ $passwd = $$arr[1];
+ &gst_report_leave ();
+
+ $passwd =~ s/^\"([^\"]*)\"$/$1/;
+
+ return $passwd;
+}
+
+sub gst_network_set_pap_passwd
+{
+ my ($file, $login, $passwd) = @_;
+ my ($line);
+
+ $login = '"' . $login . '"';
+ $passwd = '"'. $passwd . '"';
+ $line = "* $passwd";
+
+ return &gst_replace_split ($file, $login, "[ \t]+", $line);
+}
+
+# These functions do not honour the file nor call directives.
+sub gst_network_get_ppp_options_re
+{
+ my ($file, $re) = @_;
+ my ($fd, @res);
+
+ &gst_report_enter ();
+ &gst_report ("network_get_ppp_option", &gst_replace_regexp_to_separator ($re), $file);
+ $fd = &gst_file_open_read_from_names ("$file");
+ &gst_report_leave ();
+ return undef if !$fd;
+
+ while (($_ = &gst_parse_chomp_line_hash_comment ($fd)) != -1)
+ {
+ $_ = $$_;
+
+ if (/$re/)
+ {
+ return $1;
+ }
+ }
+
+ return undef;
+}
+
+sub gst_network_set_ppp_options_re
+{
+ my ($file, $re, $value) = @_;
+ my ($buff, $line, $replaced, $ret);
+ my ($pre_space, $post_comment);
+
+ &gst_report_enter ();
+ &gst_report ("network_set_ppp_option", &gst_replace_regexp_to_separator ($re), $file);
+
+ $buff = &gst_file_buffer_load ($file);
+
+ foreach $line (@$buff)
+ {
+ $pre_space = $post_comment = "";
+ chomp $line;
+ $pre_space = $1 if $line =~ s/^([ \t]+)//;
+ $post_comment = $1 if $line =~ s/([ \t]*\#.*)//;
+
+ if ($line =~ /$re/)
+ {
+ $line = "$value\n";
+ $replaced = 1;
+ last;
+ }
+
+ $line = $pre_space . $line . $post_comment . "\n";
+ }
+
+ push @$buff, "$value\n" if !$replaced;
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+sub gst_network_set_ppp_options_connect
+{
+ my ($file, $value) = @_;
+ my $ret;
+
+ &gst_report_enter ();
+ &gst_report ("network_set_ppp_connect", $file);
+ $ret = &gst_network_set_ppp_options_re ($file, "^connect", "connect \"/usr/sbin/chat -v -f $value\"");
+ &gst_report_leave ();
+ return $ret;
+}
+
+sub gst_network_get_ppp_options_unsup
+{
+ my ($file) = @_;
+ my ($fd, $line, $res, $re);
+ my @known_options = ("usepeerdns", "mtu", "mru", "user", "/dev/[^ \t]+", "[0-9]+",
+ "defaultroute", "debug", "persist", "escape", "crtscts", "connect",
+ "remotename", "hide-password", "noauth", "noipdefault", "ipparam", "name \".*\"");
+
+ $res = "";
+ &gst_report_enter ();
+ &gst_report ("network_get_ppp_unsup", $file);
+ $fd = &gst_file_open_read_from_names ("$file");
+ &gst_report_leave ();
+ return undef if !$fd;
+
+ GET_LINE: while (($line = &gst_parse_chomp_line_hash_comment ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if /^[ \t]*$/;
+
+ foreach $re (@known_options)
+ {
+ next GET_LINE if /^$re/;
+ }
+
+ $res .= "$_ ";
+ }
+
+ chop $res;
+
+ return $res;
+}
+
+sub gst_network_set_ppp_options_unsup
+{
+ my ($file, $value) = @_;
+ my ($buff, $line, $re, $ret);
+ my ($pre_space, $post_comment);
+ my @known_options = ("usepeerdns", "mtu", "mru", "user", "/dev/[^ \t]+", "[0-9]+",
+ "defaultroute", "debug", "persist", "escape", "crtscts", "connect",
+ "remotename", "hide-password", "noauth", "noipdefault", "ipparam", "name \".*\"");
+
+ # The options in the last row are those that are on by default in pppd and we don't handle,
+ # so we ignore them, as they are set implicitly if not specified.
+
+ &gst_report_enter ();
+ &gst_report ("network_set_ppp_unsup", $file);
+ $buff = &gst_file_buffer_load ($file);
+
+ GET_LINE: foreach $line (@$buff)
+ {
+ $pre_space = $post_comment = "";
+ $pre_space = $1 if $line =~ s/^([ \t]+)//;
+ $post_comment = $1 if $line =~ s/([ \t]*\#.*)//;
+
+ foreach $re (@known_options)
+ {
+ next GET_LINE if $line =~ /^$re/;
+ }
+ $line = $pre_space . $post_comment . "\n";
+ $line = "" if $line =~ /^[ \t]*$/;
+ }
+
+ $value =~ s/[ \t]+([^0-9])/\n$1/g;
+ push @$buff, $value . "\n";
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+sub gst_network_rh62_parse_bootproto
+{
+ my ($file, $key) = @_;
+ my %rh62_to_proto_name =
+ (
+ "bootp" => "bootp",
+ "dhcp" => "dhcp",
+ "none" => "none"
+ );
+ my $ret;
+
+ $ret = &gst_parse_sh ($file, $key);
+
+ if (!exists $rh62_to_proto_name{$ret})
+ {
+ &gst_report ("network_bootproto_unsup", $file, $ret);
+ $ret = "none";
+ }
+ return $rh62_to_proto_name{$ret};
+}
+
+sub gst_network_rh62_replace_bootproto
+{
+ my ($file, $key, $value) = @_;
+ my %proto_name_to_rh62 =
+ (
+ "bootp" => "bootp",
+ "dhcp" => "dhcp",
+ "none" => "none"
+ );
+
+ return &gst_replace_sh ($file, $key, $proto_name_to_rh62{$value});
+}
+
+sub gst_network_deb22_parse_bootproto
+{
+ my ($file, $iface) = @_;
+ my (@stanzas, $stanza, $method, $bootproto);
+ my %debian_to_proto_name =
+ (
+ "bootp" => "bootp",
+ "dhcp" => "dhcp",
+ "loopback" => "none",
+ "ppp" => "none",
+ "static" => "none"
+ );
+
+ &gst_report_enter ();
+ @stanzas = &gst_parse_interfaces_stanzas ($file, "iface");
+
+ foreach $stanza (@stanzas)
+ {
+ if (($$stanza[0] eq $iface) && ($$stanza[1] eq "inet"))
+ {
+ $method = $$stanza[2];
+ last;
+ }
+ }
+
+ if (exists $debian_to_proto_name {$method})
+ {
+ $bootproto = $debian_to_proto_name {$method};
+ }
+ else
+ {
+ $bootproto = "none";
+ &gst_report ("network_bootproto_unsup", $method, $iface);
+ }
+
+ &gst_report_leave ();
+ return $bootproto;
+}
+
+sub gst_network_deb22_replace_bootproto
+{
+ my ($file, $iface, $value) = @_;
+ my (@stanzas, $stanza, $method, $bootproto);
+ my %proto_name_to_debian =
+ (
+ "bootp" => "bootp",
+ "dhcp" => "dhcp",
+ "loopback" => "loopback",
+ "ppp" => "ppp",
+ "none" => "static"
+ );
+
+ my %dev_to_method =
+ (
+ "lo" => "loopback",
+ "ppp" => "ppp",
+ "ippp" => "ppp"
+ );
+
+ foreach $i (keys %dev_to_method)
+ {
+ $value = $dev_to_method{$i} if $iface =~ /^$i/;
+ }
+
+ return &gst_replace_interfaces_stanza_value ($file, $iface, 2, $proto_name_to_debian{$value});
+}
+
+sub gst_network_slackware91_parse_bootproto
+{
+ my ($file, $iface) = @_;
+
+ if (&gst_parse_rcinet1conf_bool ($file, $iface, USE_DHCP))
+ {
+ return "dhcp"
+ }
+ else
+ {
+ return "none";
+ }
+}
+
+sub gst_network_slackware91_replace_bootproto
+{
+ my ($file, $iface, $value) = @_;
+
+ if ($value eq "dhcp")
+ {
+ &gst_replace_rcinet1conf ($file, $iface, USE_DHCP, "yes");
+ }
+ else
+ {
+ &gst_replace_rcinet1conf ($file, $iface, USE_DHCP);
+ }
+}
+
+sub gst_network_suse70_parse_bootproto
+{
+ my ($file, $iface) = @_;
+ my ($ret);
+ my %suse70_to_proto_name =
+ (
+ "bootp" => "bootp",
+ "dhcpclient" => "dhcp"
+ );
+
+ $ret = &gst_network_suse70_parse_iface_sh ($file, $iface, "IFCONFIG");
+ if (!exists $suse70_to_proto_name {$ret})
+ {
+ &gst_report ("network_bootproto_unsup", $iface, $ret);
+ return "none";
+ }
+
+ return $suse70_to_proto_name {$ret};
+}
+
+sub gst_network_suse70_replace_bootproto
+{
+ my ($file, $iface, $value) = @_;
+ my ($ret, $val);
+ my %proto_name_to_suse70 =
+ (
+ "bootp" => "bootp",
+ "dhcp" => "dhcpclient",
+ "none" => ""
+ );
+
+ $val = $proto_name_to_suse70{$value};
+ return &gst_network_suse70_replace_iface_sh ($file, $iface, "IFCONFIG", $val);
+}
+
+sub gst_network_pld10_parse_bootproto
+{
+ my ($file, $key) = @_;
+ my %pld10_to_proto_name =
+ (
+ "bootp" => "bootp",
+ "dhcp" => "dhcp",
+ "pump" => "pump",
+ "none" => "none"
+ );
+ my $ret;
+
+ $ret = &gst_parse_sh ($file, $key);
+
+ if (!exists $pld10_to_proto_name{$ret})
+ {
+ &gst_report ("network_bootproto_unsup", $file, $ret);
+ $ret = "none";
+ }
+ return $pld10_to_proto_name{$ret};
+}
+
+sub gst_network_pld10_replace_bootproto
+{
+ my ($file, $key, $value) = @_;
+ my %proto_name_to_pld10 =
+ (
+ "bootp" => "bootp",
+ "dhcp" => "dhcp",
+ "pump" => "pump",
+ "none" => "none"
+ );
+
+ return &gst_replace_sh ($file, $key, $proto_name_to_pld10{$value});
+}
+
+sub gst_network_parse_bootproto
+{
+ my ($file, $key) = @_;
+
+ return "dhcp" if (&gst_parse_sh ($file, $key) =~ /dhcp/i);
+ return "bootp" if (&gst_parse_sh ($file, $key) =~ /bootp/i);
+ return "none";
+}
+
+sub gst_network_suse90_replace_bootproto
+{
+ my ($file, $key, $value) = @_;
+ my %proto_name_to_suse90 =
+ (
+ "dhcp" => "dhcp",
+ "bootp" => "bootp",
+ "static" => "none",
+ );
+
+ return &gst_replace_sh ($file, $key, $proto_name_to_suse90{$value});
+}
+
+sub gst_network_gentoo_parse_bootproto
+{
+ my ($file, $dev) = @_;
+
+ return "dhcp" if (&gst_parse_confd_net ($file, "config_$dev") =~ /dhcp/i);
+ return "none";
+}
+
+sub gst_network_gentoo_replace_bootproto
+{
+ my ($file, $dev, $value) = @_;
+
+ return if ($dev =~ /^ppp/);
+
+ return &gst_replace_confd_net ($file, "config_$dev", "dhcp") if ($value ne "none");
+
+ # replace with a fake IP address, I know it's a hack
+ return &gst_replace_confd_net ($file, "config_$dev", "0.0.0.0");
+}
+
+sub gst_network_freebsd5_replace_bootproto
+{
+ my ($file, $dev, $value) = @_;
+
+ return &gst_replace_sh ($file, "ifconfig_$dev", "dhcp") if ($value ne "none");
+ return &gst_replace_sh ($file, "ifconfig_$dev", "");
+}
+
+sub gst_network_pump_iface_supported
+{
+ my ($iface) = @_;
+ my ($dev);
+ my @devs = qw(eth wlan plip irlan);
+
+ foreach $dev (@devs)
+ {
+ return 1 if $iface =~ /^$dev/;
+ }
+
+ return 0;
+}
+
+sub gst_network_parse_pppconf
+{
+ my ($pppconf, $startif, $iface, $key) = @_;
+ my ($section);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ return undef if ($section eq undef);
+
+ return &gst_parse_pppconf ($pppconf, $section, $key);
+ }
+}
+
+sub gst_network_parse_pppconf_bool
+{
+ my ($pppconf, $startif, $iface, $key) = @_;
+ my ($section);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ return undef if ($section eq undef);
+
+ return &gst_parse_pppconf_bool ($pppconf, $section, $key);
+ }
+}
+
+sub gst_network_parse_pppconf_re
+{
+ my ($pppconf, $startif, $iface, $key, $re) = @_;
+ my ($section);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ return undef if ($section eq undef);
+
+ return &gst_parse_pppconf_re ($pppconf, $section, $key, $re);
+ }
+}
+
+sub gst_network_replace_pppconf
+{
+ my ($pppconf, $startif, $iface, $key, $val) = @_;
+ my ($section);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ &gst_replace_pppconf ($pppconf, $section, $key, $val);
+ }
+}
+
+sub gst_network_replace_pppconf_bool
+{
+ my ($pppconf, $startif, $iface, $key, $val) = @_;
+ my ($section);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ &gst_replace_pppconf_bool ($pppconf, $section, $key, $val);
+ }
+}
+
+sub gst_network_replace_pppconf_route
+{
+ my ($pppconf, $startif, $iface, $key, $val) = @_;
+ my ($section);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ &gst_replace_pppconf_common ($pppconf, $section, $key,
+ ($val == 1)? "add default HISADDR" : undef);
+ }
+}
+
+sub gst_network_replace_pppconf_dial_command
+{
+ my ($pppconf, $startif, $iface, $val) = @_;
+ my ($section, $dial);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ $dial = &gst_parse_pppconf ($pppconf, $section, "dial");
+ $dial =~ s/ATD[TP]/$val/;
+
+ &gst_replace_pppconf ($pppconf, $section, "dial", $dial);
+ }
+}
+
+sub gst_network_replace_pppconf_volume
+{
+ my ($pppconf, $startif, $iface, $val) = @_;
+ my ($section, $dial, $vol, $pre, $post);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ $dial = &gst_parse_pppconf ($pppconf, $section, "dial");
+
+ if ($dial =~ /(.*AT[^ \t]*)([ML][0-3])(.* OK .*)/i)
+ {
+ $pre = $1;
+ $post = $3;
+ }
+ elsif ($dial =~ /(.*AT[^ \t]*)( OK .*)/i)
+ {
+ $pre = $1;
+ $post = $2;
+ }
+
+ if ($val == 0)
+ {
+ $vol = "M0";
+ }
+ else
+ {
+ $vol = "L$val";
+ }
+
+ $dial = $pre . $vol . $post;
+ &gst_replace_pppconf ($pppconf, $section, "dial", $dial);
+ }
+}
+
+sub gst_network_get_freebsd5_ppp_persist
+{
+ my ($startif, $iface) = @_;
+ my ($val);
+
+ if ($iface =~ /^tun[0-9]+/)
+ {
+ $val = &gst_parse_startif ($startif, "ppp[ \t]+\-(auto|ddial)[ \t]+");
+
+ return 1 if ($val eq "ddial");
+ return 0;
+ }
+
+ return undef;
+}
+
+sub gst_network_pump_get_nodns
+{
+ my ($file, $iface, $bootproto) = @_;
+
+ return undef if (!&gst_network_pump_iface_supported ($iface));
+
+ return &gst_parse_pump_get_iface_kw_not ($file, $iface, "nodns");
+}
+
+sub gst_network_pump_set_nodns
+{
+ my ($file, $iface, $bootproto, $value) = @_;
+
+ return 0 if $bootproto ne "dhcp";
+ return 0 if (!&gst_network_pump_iface_supported ($iface));
+
+ return &gst_replace_pump_iface_kw_not ($file, $iface, "nodns", $value);
+}
+
+sub gst_network_debian_parse_remote_address
+{
+ my ($file, $iface) = @_;
+ my ($str, @tuples, $tuple, @res);
+
+ &gst_report_enter ();
+ &gst_report ("network_get_remote", $iface);
+
+ @tuples = &gst_parse_interfaces_option_tuple ($file, $iface, "up", 1);
+
+ &gst_report_leave ();
+
+ foreach $tuple (@tuples)
+ {
+ @res = $$tuple[1] =~ /[ \t]+pointopoint[ \t]+([^ \t]+)/;
+ return $res[0] if $res[0];
+ }
+
+ return undef;
+}
+
+sub gst_network_debian_replace_remote_address
+{
+ my ($file, $iface, $value) = @_;
+ my ($ifconfig, $ret);
+
+ &gst_report_enter ();
+ &gst_report ("network_set_remote", $iface);
+
+ $ifconfig = &gst_file_locate_tool ("ifconfig");
+
+ $ret = &gst_replace_interfaces_option_str ($file, $iface, "up", "$ifconfig $iface pointopoint $value");
+ &gst_report_leave ();
+ return $ret;
+}
+
+sub gst_network_debian_woody_get_auto_by_stanza
+{
+ my ($file, $iface) = @_;
+ my (@stanzas, $stanza, $i);
+
+ @stanzas = &gst_parse_interfaces_stanzas ($file, "auto");
+
+ foreach $stanza (@stanzas)
+ {
+ foreach $i (@$stanza)
+ {
+ return $stanza if $i eq $iface;
+ }
+ }
+
+ return undef;
+}
+
+sub gst_network_debian_woody_get_auto
+{
+ my ($file, $iface) = @_;
+
+ return (&gst_network_debian_woody_get_auto_by_stanza ($file, $iface) ne undef)? 1 : 0;
+}
+
+sub gst_network_debian_woody_set_auto
+{
+ my ($file, $iface, $value) = @_;
+ my ($buff, $line_no, $found);
+
+ $buff = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($buff);
+ $line_no = 0;
+
+ while (($found = &gst_replace_interfaces_get_next_stanza ($buff, \$line_no, "auto")) != -1)
+ {
+ if ($value)
+ {
+ if ($$buff[$line_no] =~ /[ \t]$iface([\# \t\n])/)
+ {
+ return &gst_file_buffer_save ($buff, $file);
+ }
+ }
+ else
+ {
+ # I'm including the hash here, although the man page says it's not supported.
+ last if $$buff[$line_no] =~ s/[ \t]$iface([\# \t\n])/$1/;
+ }
+
+ $line_no ++;
+ }
+
+ if ($found == -1)
+ {
+ if ($value)
+ {
+ &gst_replace_interfaces_auto_stanza_create ($buff, $iface);
+ }
+ }
+ else
+ {
+ if ($value)
+ {
+ chomp $$buff[$line_no];
+ $$buff[$line_no] .= " $iface\n";
+ }
+ $$buff[$line_no] =~ s/auto[ \t]*$//;
+ }
+
+ return &gst_file_buffer_save ($buff, $file);
+}
+
+# looks for eth_up $eth_iface_number
+sub gst_network_slackware91_get_auto
+{
+ my ($file, $rclocal, $iface) = @_;
+ my ($search) = 0;
+ my ($buff);
+
+ if ($iface =~ /^eth/)
+ {
+ $buff = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($buff);
+
+ $iface =~ s/eth//;
+
+ foreach $i (@$buff)
+ {
+ if ($i =~ /^[ \t]*'start'\)/)
+ {
+ $search = 1;
+ }
+ elsif (($i =~ /^[ \t]*;;/) && ($search == 1))
+ {
+ return 0;
+ }
+ elsif (($i =~ /^[ \t]*eth_up (\S+)/) && ($search == 1))
+ {
+ return 1 if ($1 == $iface);
+ }
+ }
+
+ return 0;
+ }
+ elsif ($iface =~ /^ppp/)
+ {
+ return &gst_parse_kw ($rclocal, "ppp-go");
+ }
+}
+
+# adds or deletes eth_up $eth_iface_number
+sub gst_network_slackware91_set_auto
+{
+ my ($file, $rclocal, $iface, $active) = @_;
+ my ($search) = 0;
+ my ($nline) = 0;
+ my ($buff, $sline);
+
+ if ($iface =~ /^eth/)
+ {
+ $buff = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($buff);
+
+ $iface =~ s/eth//;
+
+ foreach $i (@$buff)
+ {
+ if ($i =~ /^[ \t]*('start'\)|\*\))/)
+ {
+ # if the line is 'start') or *), begin the search
+ $search = 1;
+ }
+ elsif (($i =~ /^[ \t]*gateway_up/) && ($search == 1))
+ {
+ # save the line in which we're going to save the eth_up stuff
+ $sline = $nline;
+ }
+ elsif (($i =~ /^[ \t]*(;;|esac)/) && ($search == 1))
+ {
+ # we've arrived to the end of the case, if we wanted to
+ # add the iface, now it's the moment
+ $$buff[$sline] = "\teth_up $iface\n" . $$buff[$sline] if ($active == 1);
+ $search = 0;
+ }
+ elsif (($i =~ /^[ \t]*eth_up (\S+)/) && ($search == 1))
+ {
+ if ($1 == $iface)
+ {
+ delete $$buff[$nline] if ($active == 0);
+ $search = 0;
+ }
+ }
+
+ $nline++;
+ }
+
+ return &gst_file_buffer_save ($buff, $file);
+ }
+ elsif ($iface =~ /^ppp/)
+ {
+ return &gst_replace_kw ($rclocal, "ppp-go", $active);
+ }
+}
+
+# finds out if a interface is active at boot time
+sub gst_network_freebsd5_get_auto
+{
+ my ($file, $defaults_file, $iface) = @_;
+ my ($val);
+
+ $val = &gst_parse_sh ($file, "network_interfaces");
+ $val = &gst_parse_sh ($defaults_file, "network_interfaces") if ($val eq undef);
+
+ return 1 if ($val eq "auto");
+ return 1 if ($val =~ /$iface/);
+ return 0;
+}
+
+sub gst_network_freebsd5_set_auto
+{
+ my ($file, $iface, $active) = @_;
+ my ($val);
+
+ $val = &gst_parse_sh ($file, "network_interfaces");
+ $val = &gst_file_run_backtick ("ifconfig -l") if ($val =~ /auto/);
+ $val .= " ";
+
+ if ($active && ($val !~ /$iface /))
+ {
+ $val .= $iface;
+ }
+ elsif (!$active && ($val =~ /$iface /))
+ {
+ $val =~ s/$iface //;
+ }
+
+ # Trim the string
+ $val =~ s/^[ \t]*//;
+ $val =~ s/[ \t]*$//;
+
+ &gst_replace_sh ($file, "network_interfaces", $val);
+}
+
+sub gst_network_suse90_get_auto
+{
+ my ($file, $key) = @_;
+ my ($ret);
+
+ $ret = &gst_parse_sh ($file, $key);
+
+ return 1 if ($ret =~ /^onboot$/i);
+ return 0;
+}
+
+sub gst_network_suse90_set_auto
+{
+ my ($file, $key, $enabled) = @_;
+ my ($ret);
+
+ if($enabled)
+ {
+ return &gst_replace_sh($file, $key, "onboot");
+ }
+ else
+ {
+ return &gst_replace_sh($file, $key, "manual");
+ }
+}
+
+# Return IP address or netmask, depending on $what
+sub gst_network_pld10_get_ipaddr
+{
+ my ($file, $key, $what) = @_;
+ my ($ipaddr, $netmask, $ret, $i);
+ my @netmask_prefixes = (0, 128, 192, 224, 240, 248, 252, 254, 255);
+
+ $ipaddr = &gst_parse_sh($file, $key);
+ return undef if $ipaddr eq "";
+
+ if($ipaddr =~ /([^\/]*)\/([[:digit:]]*)/)
+ {
+ $netmask = $2;
+ return undef if $netmask eq "";
+
+ if($what eq "address")
+ {
+ return $1;
+ }
+
+ for($i = 0; $i < int($netmask/8); $i++)
+ {
+ $ret .= "255.";
+ }
+
+ $ret .= "$netmask_prefixes[$b%8]." if $netmask < 32;
+
+ for($i = int($netmask/8) + 1; $i < 4; $i++)
+ {
+ $ret .= "0.";
+ }
+
+ chop($ret);
+ return $ret;
+ }
+ return undef;
+}
+
+# Writes IP address or netmask, depending in $what, to $file
+sub gst_network_pld10_set_ipaddr
+{
+ my ($file, $key, $what, $value) = @_;
+ my %prefixes =
+ (
+ "0" => 0,
+ "128" => 1,
+ "192" => 2,
+ "224" => 3,
+ "240" => 4,
+ "248" => 5,
+ "252" => 6,
+ "254" => 7,
+ "255" => 8
+ );
+ my ($ipaddr, $netmask);
+
+ $ipaddr = &gst_parse_sh($file, $key);
+ return undef if $ipaddr eq "";
+
+ if($what eq "address")
+ {
+ $ipaddr =~ s/.*\//$value\//;
+ }
+ else
+ {
+ if($value =~ /([[:digit:]]*).([[:digit:]]*).([[:digit:]]*).([[:digit:]]*)/)
+ {
+ $netmask = $prefixes{$1} + $prefixes{$2} + $prefixes{$3} + $prefixes{$4};
+ $ipaddr =~ s/\/[[:digit:]]*/\/$netmask/;
+ }
+ }
+
+ return &gst_replace_sh($file, $key, $ipaddr);
+}
+
+# FIXME: this function isn't IPv6-aware
+# it checks if a IP address is in the same network than another
+sub gst_network_is_ip_in_same_network
+{
+ my ($address1, $address2, $netmask) = @_;
+ my (@add1, @add2, @mask);
+ my ($i);
+
+ return 0 if (($address1 eq undef) ||
+ ($address2 eq undef) ||
+ ($netmask eq undef));
+
+ @add1 = split (/\./, $address1);
+ @add2 = split (/\./, $address2);
+ @mask = split (/\./, $netmask);
+
+ for ($i = 0; $i < 4; $i++)
+ {
+ $add1[$i] += 0;
+ $add2[$i] += 0;
+ $mask[$i] += 0;
+
+ return 0 if (($add1[$i] & $mask[$i]) != ($add2[$i] & $mask[$i]));
+ }
+
+ return 1;
+}
+
+# function that gets a gateway device from the gateway address
+sub gst_network_get_gateway_dev_from_address
+{
+ my ($interface, $gateway) = @_;
+ my ($address, $netmask, $key);
+
+ foreach $key (keys %$interface)
+ {
+ $address = $$interface{$key}{"address"};
+ $netmask = $$interface{$key}{"netmask"};
+
+ return $$interface{$key}{"dev"} if (&gst_network_is_ip_in_same_network ($address, $gateway, $netmask));
+ }
+
+ return undef;
+}
+
+sub gst_network_get_plip_gateway
+{
+ my ($file, $key, $remote_address) = @_;
+ my ($gateway);
+
+ $gateway = &gst_parse_sh ($file, $key);
+
+ return $gateway if ($gateway eq $remote_address);
+}
+
+sub gst_network_get_gateway
+{
+ my ($file, $key, $address, $netmask) = @_;
+ my ($gateway);
+
+ return undef if ($address eq undef);
+
+ $gateway = &gst_parse_sh ($file, $key);
+
+ return $gateway if &gst_network_is_ip_in_same_network ($address, $gateway, $netmask);
+ return undef;
+}
+
+sub gst_network_suse90_get_gateway
+{
+ my ($file, $address, $netmask) = @_;
+ my ($gateway) = &gst_parse_split_first_array_pos ($file, "default", 0, "[ \t]+", "[ \t]+");
+
+ return $gateway if &gst_network_is_ip_in_same_network ($address, $gateway, $netmask);
+ return undef;
+}
+
+sub gst_network_suse90_get_plip_gateway
+{
+ my ($file, $remote_address) = @_;
+ my ($gateway) = &gst_parse_split_first_array_pos ($file, "default", 0, "[ \t]+", "[ \t]+");
+
+ return $gateway if ($gateway eq $remote_address);
+ return undef;
+}
+
+sub gst_network_suse90_replace_gateway
+{
+ my ($file, $dev, $address, $netmask, $value) = @_;
+
+
+ return &gst_replace_split ($file, "default", "[ \t]+", "$value \- $dev") if &gst_network_is_ip_in_same_network ($address, $value, $netmask);
+# return &gst_replace_split ($file, "default", "[ \t]+", "$value \- $dev") ;
+ return undef;
+
+}
+
+
+# runs a function if the interface is of type $type
+sub gst_network_check_type
+{
+ my ($iface) = shift @_;
+ my ($type) = shift @_;
+ my ($func) = shift @_;
+ my ($t);
+
+ $t = &gst_network_get_interface_type ($iface);
+
+ if ($t =~ "^$type")
+ {
+ &$func (@_);
+ }
+}
+
+# creates files neccesary for gentoo ifaces
+sub gst_network_gentoo_create_files
+{
+ my ($dev) = @_;
+ my ($init) = "/etc/init.d/net.$dev";
+ my ($conf) = "/etc/conf.d/net.$dev";
+ my ($backup) = "/etc/conf.d/net.ppp0.gstbackup";
+
+ if ($dev =~ /ppp/)
+ {
+ &gst_file_copy ("/etc/init.d/net.ppp0", $init) if (!&gst_file_exists ($init));
+
+ # backup the ppp config file
+ &gst_file_copy ("/etc/conf.d/net.ppp0", $backup) if (!&gst_file_exists ($backup));
+ &gst_file_copy ($backup, $conf) if (!&gst_file_exists ($conf));
+ }
+ else
+ {
+ &gst_file_copy ("/etc/init.d/net.eth0", $init) if (!&gst_file_exists ($init));
+ }
+
+ chmod 0755, "$gst_prefix/$init";
+}
+
+# we need this function because essid can be multiword, and thus it can't be in rc.conf
+sub gst_network_freebsd5_replace_essid
+{
+ my ($file, $startif, $iface, $essid) = @_;
+
+ if ($essid =~ /[ \t]/)
+ {
+ # It's multiword
+ &gst_file_buffer_save ("ifconfig $iface ssid \"$essid\"", $startif);
+ &gst_replace_sh_re ($file, "ifconfig_$iface", "ssid[ \t]+([^ \t]*)", "");
+ }
+ else
+ {
+ &gst_replace_sh_re ($file, "ifconfig_$iface", "ssid[ \t]+([^ \t]*)", " ssid $essid");
+ }
+}
+
+sub gst_network_freebsd_create_ppp_startif
+{
+ my ($startif, $iface, $dev, $persist) = @_;
+ my ($section);
+
+ if ($dev =~ /^tun[0-9]+/)
+ {
+ $section = &gst_parse_startif ($startif, "ppp[ \t]+\-[^ \t]+[ \t]+([^ \t]+)");
+ $section = $dev if ($section eq undef);
+
+ return &gst_file_buffer_save ("ppp -ddial $section", $startif) if ($persist eq 1);
+ return &gst_file_buffer_save ("ppp -auto $section", $startif);
+ }
+}
+
+# Functions for parsing provider file in suse 9.X
+sub gst_network_suse90_parse_provider_file_func
+{
+ my ($provider, $key, $func) = @_;
+ my ($path) = "/etc/sysconfig/network/providers/";
+
+ return &$func ("$path/$provider", $key);
+}
+
+sub gst_network_suse90_parse_provider_file
+{
+ my ($provider, $key) = @_;
+ return &gst_network_suse90_parse_provider_file_func ($provider, $key, \&gst_parse_sh);
+}
+
+sub gst_network_suse90_parse_provider_file_bool
+{
+ my ($provider, $key) = @_;
+ return &gst_network_suse90_parse_provider_file_func ($provider, $key, \&gst_parse_sh_bool);
+}
+
+# Functions for replacing in provider file in SuSE 9.X
+sub gst_network_suse90_replace_provider_file_func
+{
+ my ($provider, $key, $value, $func) = @_;
+ my ($path) = "/etc/sysconfig/network/providers/";
+
+ return &$func ("$path/$provider", $key, $value);
+}
+
+sub gst_network_suse90_replace_provider_file
+{
+ my ($provider, $key, $value) = @_;
+ #make sure the function is called only by modem
+ if ($provider =~ /ppp/)
+ {
+ return &gst_network_suse90_replace_provider_file_func ($provider, $key, $value, \&gst_replace_sh);
+ }
+}
+
+sub gst_network_suse90_replace_provider_file_bool
+{
+ my ($provider, $key, $value) = @_;
+ #make sure the function is called only by modem
+ if ($provider =~ /ppp/)
+ {
+ return &gst_network_suse90_replace_provider_file_func ($provider, $key, $value, \&gst_replace_sh_bool);
+ }
+}
+
+sub gst_network_suse9_get_dev_name
+{
+ my ($iface) = @_;
+ my ($ifaces, $dev, $hwaddr, $d);
+ my ($dev);
+
+ $dev = &gst_parse_sh ("/var/run/sysconfig/if-$iface", "interface");
+
+ if ($dev eq undef)
+ {
+ $fd = &gst_file_run_backtick ("getcfg-interface $iface");
+ }
+
+ if ($dev eq undef)
+ {
+ # Those are the last cases, we make rough guesses
+ if ($iface =~ /-pcmcia-/)
+ {
+ # it's something like wlan-pcmcia-0
+ $dev =~ s/-pcmcia-//;
+ }
+ elsif ($iface =~ /-id-([a-fA-F0-9\:]*)/)
+ {
+ # it's something like eth-id-xx:xx:xx:xx:xx:xx, which is the NIC MAC
+ $hwaddr = $1;
+ $ifaces = &gst_network_interfaces_get_info ();
+
+ foreach $d (keys %$ifaces)
+ {
+ if ($hwaddr eq $$ifaces{$d}{"hwaddr"})
+ {
+ $dev = $d;
+ last;
+ }
+ }
+ }
+ }
+
+ if ($dev eq undef)
+ {
+ # We give up, take $iface as $dev
+ $dev = $iface;
+ }
+
+ return $dev;
+}
+
+sub gst_network_detect_essids
+{
+ my ($iface) = @_;
+ my ($fd, @arr, $encrypted);
+
+ # some wireless cards need to be up before scanning
+ &gst_file_run ("ifconfig $iface up");
+ $fd = &gst_file_run_pipe_read ("iwlist $iface scanning");
+ return undef if (!$fd);
+
+ while (<$fd>)
+ {
+ if (/^[ \t]*Encryption key:([^ \t\n]+)/)
+ {
+ $encrypted = ($1 eq "off") ? 0 : 1;
+ }
+ elsif (/^[ \t]*ESSID\:"(.+)"/)
+ {
+ push @arr, {"essid" => $1,
+ "encrypted" => $encrypted };
+ }
+ }
+
+ return \@arr;
+}
+
+sub gst_network_get_wep_key_type
+{
+ my ($func) = shift @_;
+ my ($val);
+
+ $val = &$func (@_);
+
+ return undef if (!$val);
+ return "ascii" if ($val =~ /^s\:/);
+ return "hexadecimal";
+}
+
+sub gst_network_get_wep_key
+{
+ my ($func) = shift @_;
+ my ($val);
+
+ $val = &$func (@_);
+ $val =~ s/^s\://;
+
+ return $val;
+}
+
+sub gst_network_get_full_key
+{
+ my ($key, $key_type) = @_;
+
+ if ($key_type eq "ascii")
+ {
+ $key = "s:" . $key;
+ }
+
+ return $key;
+}
+
+sub gst_network_set_wep_key_type
+{
+ my ($key, $key_type, $func);
+
+ # seems kind of hackish, but we want to use distro
+ # specific saving functions, so we need to leave
+ # the args as variable as possible
+ $func = shift @_;
+ $key_type = pop @_;
+ $key = pop @_;
+
+ push @_, &gst_network_get_full_key ($key, $key_type);
+ &$func (@_);
+}
+
+# Set dist_map for your distro to "" if you don't want
+# loopback ensuring. See suse-7.0 entry for example.
+sub gst_network_ensure_loopback_interface
+{
+ my ($interface) = @_;
+ my $dev;
+ my %dist_map =
+ (
+ "redhat-5.2" => "lo",
+ "redhat-6.0" => "lo",
+ "redhat-6.1" => "lo",
+ "redhat-6.2" => "lo",
+ "redhat-7.0" => "lo",
+ "redhat-7.1" => "lo",
+ "redhat-7.2" => "lo",
+ "redhat-8.0" => "lo",
+ "redhat-9" => "",
+ "openna-1.0" => "lo",
+ "mandrake-7.1" => "lo",
+ "mandrake-7.2" => "lo",
+ "mandrake-9.0" => "lo",
+ "mandrake-9.1" => "lo",
+ "mandrake-9.2" => "lo",
+ "mandrake-10.0" => "lo",
+ "mandrake-10.1" => "lo",
+ "mandrake-10.2" => "lo",
+ "mandriva-2006.0" => "lo",
+ "mandriva-2006.1" => "lo",
+ "mandriva-2007.0" => "lo",
+ "mandriva-2007.1" => "lo",
+ "yoper-2.2" => "lo",
+ "blackpanther-4.0" => "lo",
+ "conectiva-9" => "lo",
+ "conectiva-10" => "lo",
+ "debian-2.2" => "lo",
+ "debian-3.0" => "lo",
+ "debian-3.1" => "lo",
+ "debian-4.0" => "lo",
+ "debian-5.0" => "lo",
+ "debian-testing" => "lo",
+ "ubuntu-5.04" => "lo",
+ "ubuntu-5.10" => "lo",
+ "ubuntu-6.06" => "lo",
+ "ubuntu-6.10" => "lo",
+ "ubuntu-7.04" => "lo",
+ "ubuntu-7.10" => "lo",
+ "ubuntu-8.04" => "lo",
+ "suse-7.0" => "",
+ "suse-9.0" => "",
+ "suse-9.1" => "",
+ "turbolinux-7.0" => "lo",
+ "pld-1.0" => "lo",
+ "pld-1.1" => "lo",
+ "pld-1.99" => "lo",
+ "fedora-1" => "",
+ "fedora-2" => "",
+ "fedora-3" => "",
+ "fedora-4" => "",
+ "fedora-5" => "",
+ "rpath" => "",
+ "vine-3.0" => "lo",
+ "vine-3.1" => "lo",
+ "ark" => "lo",
+ "slackware-9.1.0" => "",
+ "slackware-10.0.0" => "",
+ "slackware-10.1.0" => "",
+ "slackware-10.2.0" => "",
+ "gentoo" => "",
+ "vlos-1.2" => "",
+ "freebsd-5" => "",
+ "freebsd-6" => "",
+ );
+
+ $dev = $dist_map {$gst_dist};
+
+ return if $dev eq "";
+
+ if (!exists $$interface{$dev})
+ {
+ my %iface = (
+ "auto" => 1,
+ "user" => 0,
+ "dev" => "lo",
+ "address" => "127.0.0.1",
+ "netmask" => "255.0.0.0",
+ "broadcast" => "127.255.255.255",
+ "network" => "127.0.0.0",
+ "bootproto" => "none",
+ "enabled" => 1,
+ "update_dns" => 0
+ );
+
+ $$interface{$dev} = \%iface;
+ &gst_network_interface_set ($dev, \%iface);
+ }
+ elsif (! $ {$$interface{$dev}}{"enabled"})
+ {
+ $ {$$interface{$dev}}{"enabled"} = 1;
+ &gst_network_interface_set ($dev, $$interface{$dev});
+ }
+}
+
+sub gst_network_statichost_add_alias
+{
+ my ($localhost, $alias) = @_;
+ my $i;
+
+ foreach $i (@$localhost)
+ {
+ return if ($i eq $alias);
+ }
+
+ push @$localhost, $alias;
+}
+
+sub gst_network_statichost_remove_alias
+{
+ my ($localhost, $alias) = @_;
+ my $i;
+
+ for ($i = 0; $i < @$localhost; $i++) {
+ if ($$localhost[$i] eq $alias)
+ {
+ delete $$localhost[$i];
+ return;
+ }
+ }
+}
+
+sub gst_network_ensure_loopback_statichost
+{
+ my ($statichost, $hostname, $old_hostname, $lo_ip) = @_;
+ my $i;
+
+ if (exists $$statichost{$lo_ip})
+ {
+ my $localhost = $$statichost{$lo_ip};
+ &gst_network_statichost_remove_alias ($localhost, $old_hostname) if ($old_hostname);
+ &gst_network_statichost_add_alias ($localhost, $hostname);
+ }
+ else
+ {
+ $$statichost{$lo_ip} = [ ("localhost", "localhost.localdomain", $hostname) ];
+ }
+}
+
+sub get_network_get_lo_ip
+{
+ my ($statichost) = @_;
+
+ foreach $i (keys %$statichost)
+ {
+ return $i if ($i =~ /^127\./);
+ }
+
+ return "127.0.0.1";
+}
+
+sub gst_network_ensure_loopback
+{
+ my $values_hash = $_[0];
+ my $old_values_hash = $_[1];
+ my $interface = $$values_hash{"interface"};
+ my $hostname = $$values_hash{"hostname"};
+ my $statichost = $$values_hash{"statichost"};
+ my $lo_ip = &get_network_get_lo_ip ($statichost);
+
+ # needed for replacing hostname safely
+ my $old_hostname = $$old_values_hash{"hostname"};
+
+ &gst_report_enter ();
+ &gst_report ("network_ensure_lo");
+
+ &gst_network_ensure_loopback_statichost ($statichost, $hostname, $old_hostname, $lo_ip);
+ &gst_network_ensure_loopback_interface ($interface, $lo_ip);
+
+ &gst_report_leave ();
+}
+
+sub gst_network_get_parse_table
+{
+ my %dist_map =
+ (
+ "redhat-5.2" => "redhat-6.2",
+ "redhat-6.0" => "redhat-6.2",
+ "redhat-6.1" => "redhat-6.2",
+ "redhat-6.2" => "redhat-6.2",
+ "redhat-7.0" => "redhat-7.0",
+ "redhat-7.1" => "redhat-7.0",
+ "redhat-7.2" => "redhat-7.2",
+ "redhat-8.0" => "redhat-7.2",
+ "redhat-9" => "redhat-7.2",
+ "openna-1.0" => "redhat-6.2",
+ "mandrake-7.1" => "redhat-6.2",
+ "mandrake-7.2" => "redhat-6.2",
+ "mandrake-9.0" => "redhat-7.0",
+ "mandrake-9.1" => "redhat-7.0",
+ "mandrake-9.2" => "redhat-7.0",
+ "mandrake-10.0" => "redhat-7.0",
+ "mandrake-10.1" => "redhat-7.0",
+ "mandrake-10.2" => "redhat-7.0",
+ "mandriva-2006.0" => "redhat-7.0",
+ "mandriva-2006.1" => "redhat-7.0",
+ "mandriva-2007.0" => "redhat-7.0",
+ "mandriva-2007.1" => "redhat-7.0",
+ "yoper-2.2" => "redhat-7.0",
+ "blackpanther-4.0" => "redhat-7.0",
+ "conectiva-9" => "redhat-7.0",
+ "conectiva-10" => "redhat-7.0",
+ "debian-2.2" => "debian-2.2",
+ "debian-3.0" => "debian-2.2",
+ "debian-3.1" => "debian-2.2",
+ "debian-4.0" => "debian-2.2",
+ "debian-5.0" => "debian-2.2",
+ "debian-testing" => "debian-2.2",
+ "ubuntu-5.04" => "debian-2.2",
+ "ubuntu-5.10" => "debian-2.2",
+ "ubuntu-6.06" => "debian-2.2",
+ "ubuntu-6.10" => "debian-2.2",
+ "ubuntu-7.04" => "debian-2.2",
+ "ubuntu-7.10" => "debian-2.2",
+ "ubuntu-8.04" => "debian-2.2",
+ "suse-7.0" => "suse-7.0",
+ "suse-9.0" => "suse-9.0",
+ "suse-9.1" => "suse-9.0",
+ "turbolinux-7.0" => "redhat-7.0",
+ "pld-1.0" => "pld-1.0",
+ "pld-1.1" => "pld-1.0",
+ "pld-1.99" => "pld-1.0",
+ "fedora-1" => "redhat-7.2",
+ "fedora-2" => "redhat-7.2",
+ "fedora-3" => "redhat-7.2",
+ "fedora-4" => "redhat-7.2",
+ "fedora-5" => "redhat-7.2",
+ "rpath" => "redhat-7.2",
+ "vine-3.0" => "redhat-7.0",
+ "vine-3.1" => "redhat-7.0",
+ "ark" => "redhat-7.0",
+ "slackware-9.1.0" => "slackware-9.1.0",
+ "slackware-10.0.0" => "slackware-9.1.0",
+ "slackware-10.1.0" => "slackware-9.1.0",
+ "slackware-10.2.0" => "slackware-9.1.0",
+ "gentoo" => "gentoo",
+ "vlos-1.2" => "gentoo",
+ "freebsd-5" => "freebsd-5",
+ "freebsd-6" => "freebsd-5",
+ );
+
+ my %dist_tables =
+ (
+ "redhat-6.2" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => "/etc/sysconfig/network",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "gateway", \&gst_parse_sh, SYSCONFIG_NW, GATEWAY ],
+ [ "gatewaydev", \&gst_parse_sh, SYSCONFIG_NW, GATEWAYDEV ],
+ [ "userifacectl", \&gst_parse_trivial, 1 ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_get_status_any, "smbd", "nmbd" ],
+ [ "smbinstalled", \&gst_service_sysv_installed, "smb" ],
+ [ "smartdhcpcd", \&gst_file_tool_installed, "pump" ],
+ [ "dialinstalled", \&gst_file_tool_installed, "wvdial" ],
+ [ "interface", \&gst_network_interfaces_get ]
+ ]
+ },
+
+ "redhat-7.0" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => "/etc/sysconfig/network",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "gateway", \&gst_parse_sh, SYSCONFIG_NW, GATEWAY ],
+ [ "gatewaydev", \&gst_parse_sh, SYSCONFIG_NW, GATEWAYDEV ],
+ [ "userifacectl", \&gst_parse_trivial, 1 ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_get_status_any, "smbd", "nmbd" ],
+ [ "smbinstalled", \&gst_service_sysv_installed, "smb" ],
+ [ "smartdhcpcd", \&gst_file_tool_installed, "pump" ],
+ [ "dialinstalled", \&gst_file_tool_installed, "wvdial" ],
+ [ "interface", \&gst_network_interfaces_get ]
+ ]
+ },
+
+ "redhat-7.2" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => ["/etc/sysconfig/networking/profiles/default/network",
+ "/etc/sysconfig/networking/network",
+ "/etc/sysconfig/network"],
+ RESOLV_CONF => ["/etc/sysconfig/networking/profiles/default/resolv.conf",
+ "/etc/resolv.conf"],
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => ["/etc/sysconfig/networking/profiles/default/hosts",
+ "/etc/hosts"],
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf",
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "gateway", \&gst_parse_sh, SYSCONFIG_NW, GATEWAY ],
+ [ "gatewaydev", \&gst_parse_sh, SYSCONFIG_NW, GATEWAYDEV ],
+ [ "userifacectl", \&gst_parse_trivial, 1 ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_get_status_any, "smbd", "nmbd" ],
+ [ "smbinstalled", \&gst_service_sysv_installed, "smb" ],
+ [ "smartdhcpcd", \&gst_file_tool_installed, "pump" ],
+ [ "dialinstalled", \&gst_file_tool_installed, "wvdial" ],
+ [ "interface", \&gst_network_interfaces_get ]
+ ]
+ },
+
+ "debian-2.2" =>
+ {
+ fn =>
+ {
+ OPTIONS => "/etc/network/options",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ HOSTNAME => "/etc/hostname",
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_line_first, HOSTNAME ],
+ [ "gateway", \&gst_network_get_default_gateway ],
+ [ "gatewaydev", \&gst_network_get_default_gatewaydev ],
+# [ "gwdevunsup", \&gst_parse_trivial, 1 ],
+# [ "userifacectl", \&gst_parse_trivial, 0 ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_parse_split_all_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_parse_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_get_status_any, "smbd", "nmbd" ],
+ [ "smbinstalled", \&gst_service_sysv_installed, "samba" ],
+ [ "smartdhcpcd", \&gst_file_tool_installed, "pump" ],
+ [ "dialinstalled", \&gst_file_tool_installed, "wvdial" ],
+ [ "interface", \&gst_network_interfaces_get ]
+ ]
+ },
+
+ "suse-7.0" =>
+ {
+ fn =>
+ {
+ RC_CONFIG => "/etc/rc.config",
+ ROUTE_CONF => "/etc/route.conf",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_sh_get_hostname, RC_CONFIG, FQHOSTNAME ],
+ [ "gateway", \&gst_parse_split_first_str, ROUTE_CONF, "default", "[ \t]+" ],
+ [ "gateway", \&gst_parse_split_first_str, ROUTE_CONF, "0.0.0.0", "[ \t]+" ],
+ [ "gwdevunsup", \&gst_parse_trivial, 1 ],
+ [ "userifacectl", \&gst_parse_trivial, 0 ],
+ [ "domain", \&gst_parse_sh_get_domain, RC_CONFIG, FQHOSTNAME ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+# This was to take the values from SuSEConfig, but a better solution is to get
+# the configuration from /etc/resolv.conf and then replace in rc.config, so those
+# files stay in sync.
+# [ "nameserver", \&gst_parse_sh_split, RC_CONFIG, NAMESERVER, "[ \t]+" ],
+# [ "searchdomain", \&gst_parse_sh_split, RC_CONFIG, SEARCHLIST, "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_parse_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_get_status_any, "smbd", "nmbd" ],
+ [ "smbinstalled", \&gst_service_sysv_installed, "smb" ],
+ [ "dialinstalled", \&gst_file_tool_installed, "wvdial" ],
+ [ "interface_tmp", \&gst_network_interfaces_get ],
+ [ "interface", \&gst_network_suse70_get_ppp, "%dialing%", "%interface_tmp%" ],
+ ]
+ },
+
+ "suse-9.0" =>
+ {
+ fn =>
+ {
+ ROUTE_CONF => "/etc/sysconfig/network/routes",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ HOSTNAME => "/etc/HOSTNAME",
+ SMB_CONF => "/etc/samba/smb.conf",
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_fq_hostname, HOSTNAME ],
+ [ "domain", \&gst_parse_fq_domain, HOSTNAME ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_get_status, "smb" ],
+ [ "smbinstalled", \&gst_service_installed, "smb" ],
+ [ "dialinstalled", \&gst_parse_trivial, 1 ],
+ [ "interface", \&gst_network_interfaces_get ],
+ [ "gateway", \&gst_parse_split_first_array_pos, ROUTE_CONF, "default", 0, "[ \t]+", "[ \t]+" ],
+ [ "gatewaydev", \&gst_network_get_gateway_dev_from_address, "%interface%", "%gateway%" ],
+ ]
+ },
+
+ "pld-1.0" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => "/etc/sysconfig/network",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/smb/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "gateway", \&gst_parse_sh, SYSCONFIG_NW, GATEWAY ],
+ [ "gatewaydev", \&gst_parse_sh, SYSCONFIG_NW, GATEWAYDEV ],
+ [ "userifacectl", \&gst_parse_trivial, 1 ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_get_status_any, "smbd", "nmbd" ],
+ [ "smbinstalled", \&gst_service_sysv_installed, "smb" ],
+ [ "smartdhcpcd", \&gst_file_tool_installed, "pump" ],
+ [ "dialinstalled", \&gst_file_tool_installed, "wvdial" ],
+ [ "interface", \&gst_network_interfaces_get ]
+ ]
+ },
+
+ "slackware-9.1.0" =>
+ {
+ fn =>
+ {
+ RC_INET_CONF => "/etc/rc.d/rc.inet1.conf",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ HOSTNAME => "/etc/HOSTNAME",
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_fq_hostname, HOSTNAME ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "order", \&gst_parse_split_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_parse_split_first_bool, HOST_CONF, "multi", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_get_status_any, "smbd", "nmbd" ],
+ [ "smbinstalled", \&gst_service_installed, "/etc/rc.d/rc.samba" ],
+ [ "dialinstalled", \&gst_parse_trivial, 1 ],
+ [ "interface", \&gst_network_interfaces_get ],
+ [ "gateway", \&gst_parse_sh, RC_INET_CONF, GATEWAY ],
+ [ "gatewaydev", \&gst_network_get_gateway_dev_from_address, "%interface%", "%gateway%" ],
+ ]
+ },
+
+ "gentoo" =>
+ {
+ fn =>
+ {
+ HOSTNAME => "/etc/conf.d/hostname",
+ DOMAINNAME => "/etc/conf.d/domainname",
+ NET => "/etc/conf.d/net",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/samba/smb.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_sh, HOSTNAME, "HOSTNAME" ],
+ [ "domain", \&gst_parse_sh, DOMAINNAME, "DNSDOMAIN" ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_gentoo_get_status, "samba" ],
+ [ "smbinstalled", \&gst_service_installed, "samba" ],
+ [ "dialinstalled", \&gst_parse_trivial, 1 ],
+ [ "gateway", \&gst_network_get_default_gateway ],
+ [ "gatewaydev", \&gst_network_get_default_gatewaydev ],
+ [ "interface", \&gst_network_interfaces_get ],
+ ]
+ },
+
+ "freebsd-5" =>
+ {
+ fn =>
+ {
+ RC_CONF => "/etc/rc.conf",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/usr/local/etc/smb.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_parse_sh_re, RC_CONF, hostname, "^([^\.]*)\." ],
+ [ "domain", \&gst_parse_split_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_parse_split_all_unique_hash_comment, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_parse_split_first_array_unique, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "statichost", \&gst_parse_split_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_parse_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_network_rh_get_smb_desc, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_parse_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_parse_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "dialinstalled", \&gst_parse_trivial, 1 ],
+ [ "smbinstalled", \&gst_service_installed, "samba" ],
+ [ "smbuse", \&gst_service_rcng_get_status, "smbd" ],
+ [ "interface", \&gst_network_interfaces_get ],
+ [ "gateway", \&gst_parse_sh, RC_CONF, defaultrouter ],
+ [ "gatewaydev", \&gst_network_get_gateway_dev_from_address, "%interface%", "%gateway%" ],
+ ]
+ },
+ );
+
+ my $dist = $dist_map{$gst_dist};
+ return %{$dist_tables{$dist}} if $dist;
+
+ &gst_report ("platform_no_table", $gst_dist);
+ return undef;
+}
+
+sub gst_network_get_interface_parse_table
+{
+ my %dist_map =
+ (
+ "redhat-5.2" => "redhat-6.2",
+ "redhat-6.0" => "redhat-6.2",
+ "redhat-6.1" => "redhat-6.2",
+ "redhat-6.2" => "redhat-6.2",
+ "redhat-7.0" => "redhat-6.2",
+ "redhat-7.1" => "redhat-6.2",
+ "redhat-7.2" => "redhat-7.2",
+ "redhat-8.0" => "redhat-8.0",
+ "redhat-9" => "redhat-8.0",
+ "openna-1.0" => "redhat-6.2",
+ "mandrake-7.1" => "redhat-6.2",
+ "mandrake-7.2" => "redhat-6.2",
+ "mandrake-9.0" => "mandrake-9.0",
+ "mandrake-9.1" => "mandrake-9.0",
+ "mandrake-9.2" => "mandrake-9.0",
+ "mandrake-10.0" => "mandrake-9.0",
+ "mandrake-10.1" => "mandrake-9.0",
+ "mandrake-10.2" => "mandrake-9.0",
+ "mandriva-2006.0" => "mandrake-9.0",
+ "mandriva-2006.1" => "mandrake-9.0",
+ "mandriva-2007.0" => "mandrake-9.0",
+ "mandriva-2007.1" => "mandrake-9.0",
+ "yoper-2.2" => "redhat-6.2",
+ "blackpanther-4.0" => "mandrake-9.0",
+ "conectiva-9" => "conectiva-9",
+ "conectiva-10" => "conectiva-9",
+ "debian-2.2" => "debian-2.2",
+ "debian-3.0" => "debian-3.0",
+ "debian-3.1" => "debian-3.0",
+ "debian-4.0" => "debian-3.0",
+ "debian-5.0" => "debian-3.0",
+ "debian-testing" => "debian-3.0",
+ "ubuntu-5.04" => "debian-3.0",
+ "ubuntu-5.10" => "debian-3.0",
+ "ubuntu-6.06" => "debian-3.0",
+ "ubuntu-6.10" => "debian-3.0",
+ "ubuntu-7.04" => "debian-3.0",
+ "ubuntu-7.10" => "debian-3.0",
+ "ubuntu-8.04" => "debian-3.0",
+ "suse-7.0" => "suse-7.0",
+ "suse-9.0" => "suse-9.0",
+ "suse-9.1" => "suse-9.0",
+ "turbolinux-7.0" => "redhat-6.2",
+ "pld-1.0" => "pld-1.0",
+ "pld-1.1" => "pld-1.0",
+ "pld-1.99" => "pld-1.0",
+ "fedora-1" => "redhat-7.2",
+ "fedora-2" => "redhat-7.2",
+ "fedora-3" => "redhat-7.2",
+ "fedora-4" => "redhat-7.2",
+ "fedora-5" => "redhat-7.2",
+ "rpath" => "redhat-7.2",
+ "vine-3.0" => "vine-3.0",
+ "vine-3.1" => "vine-3.0",
+ "ark" => "vine-3.0",
+ "slackware-9.1.0" => "slackware-9.1.0",
+ "slackware-10.0.0" => "slackware-9.1.0",
+ "slackware-10.1.0" => "slackware-9.1.0",
+ "slackware-10.2.0" => "slackware-9.1.0",
+ "gentoo" => "gentoo",
+ "vlos-1.2" => "gentoo",
+ "freebsd-5" => "freebsd-5",
+ "freebsd-6" => "freebsd-5",
+ );
+
+ my %dist_tables =
+ (
+ "redhat-6.2" =>
+ {
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_parse_sh_bool, IFCFG, ONBOOT ],
+# [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+ [ "dev", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_parse_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_parse_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_parse_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_parse_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMIP ],
+# [ "update_dns", \&gst_network_pump_get_nodns, PUMP, "%dev%", "%bootproto%" ],
+# [ "dns1", \&gst_parse_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_parse_sh, IFCFG, DNS2 ],
+# [ "ppp_options", \&gst_parse_sh, IFCFG, PPPOPTIONS ],
+ [ "section", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, WVDIALSECT ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PEERDNS ]],
+ [ "mtu", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MTU ]],
+ [ "mru", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MRU ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, PAPNAME ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MODEMPORT ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, LINESPEED ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, DEFROUTE ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PERSIST ]],
+ [ "serial_escapechars", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, ESCAPECHARS ]],
+ [ "serial_hwctl", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, HARDFLOWCTL ]],
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ]],
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+# [ "enabled", \&gst_network_interface_active, IFACE,
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ ]
+ },
+
+ "redhat-7.2" =>
+ {
+ ifaces_get => \&gst_network_sysconfig_rh72_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => ["/etc/sysconfig/networking/profiles/default/ifcfg-#iface#",
+ "/etc/sysconfig/networking/devices/ifcfg-#iface#",
+ "/etc/sysconfig/network-scripts/ifcfg-#iface#"],
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_parse_sh_bool, IFCFG, ONBOOT ],
+# [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+# [ "name", \&gst_parse_sh, IFCFG, NAME ],
+# [ "name", \&gst_parse_trivial, IFACE ],
+ [ "dev", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_parse_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_parse_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_parse_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_parse_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_parse_sh, IFCFG, ESSID ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_sh, IFCFG, KEY ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_sh, IFCFG, KEY ]],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMIP ],
+# [ "update_dns", \&gst_network_pump_get_nodns, PUMP, "%dev%", "%bootproto%" ],
+# [ "dns1", \&gst_parse_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_parse_sh, IFCFG, DNS2 ],
+ [ "section", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, WVDIALSECT ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PEERDNS ]],
+ [ "mtu", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MTU ]],
+ [ "mru", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MRU ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, PAPNAME ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MODEMPORT ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, LINESPEED ]],
+# [ "ppp_options", \&gst_parse_sh, IFCFG, PPPOPTIONS ],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, DEFROUTE ]],
+# [ "debug", \&gst_parse_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PERSIST ]],
+ [ "serial_escapechars", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, ESCAPECHARS ]],
+ [ "serial_hwctl", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, HARDFLOWCTL ]],
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ]],
+# [ "enabled", \&gst_network_interface_active, "%dev%",
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_network_interface_active, IFACE,
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "redhat-8.0" =>
+ {
+ ifaces_get => \&gst_network_sysconfig_rh72_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => ["/etc/sysconfig/networking/profiles/default/ifcfg-#iface#",
+ "/etc/sysconfig/networking/devices/ifcfg-#iface#",
+ "/etc/sysconfig/network-scripts/ifcfg-#iface#"],
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_parse_sh_bool, IFCFG, ONBOOT ],
+# [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+# [ "name", \&gst_parse_sh, IFCFG, NAME ],
+# [ "name", \&gst_parse_trivial, IFACE ],
+ [ "dev", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_parse_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_parse_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_parse_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_parse_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_parse_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMIP ],
+# [ "update_dns", \&gst_network_pump_get_nodns, PUMP, "%dev%", "%bootproto%" ],
+# [ "dns1", \&gst_parse_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_parse_sh, IFCFG, DNS2 ],
+ [ "section", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, WVDIALSECT ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PEERDNS ]],
+ [ "mtu", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MTU ]],
+ [ "mru", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MRU ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, PAPNAME ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MODEMPORT ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, LINESPEED ]],
+# [ "ppp_options", \&gst_parse_sh, IFCFG, PPPOPTIONS ],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, DEFROUTE ]],
+# [ "debug", \&gst_parse_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PERSIST ]],
+ [ "serial_escapechars", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, ESCAPECHARS ]],
+ [ "serial_hwctl", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, HARDFLOWCTL ]],
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ]],
+# [ "enabled", \&gst_network_interface_active, "%dev%",
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_network_interface_active, IFACE,
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "vine-3.0" =>
+ {
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_parse_sh_bool, IFCFG, ONBOOT ],
+# [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+# [ "name", \&gst_parse_sh, IFCFG, NAME ],
+ [ "dev", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_parse_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_parse_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_parse_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_parse_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_parse_sh, IFCFG, ESSID ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_sh, IFCFG, KEY ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_sh, IFCFG, KEY ]],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMIP ],
+# [ "update_dns", \&gst_network_pump_get_nodns, PUMP, "%dev%", "%bootproto%" ],
+# [ "dns1", \&gst_parse_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_parse_sh, IFCFG, DNS2 ],
+ [ "section", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, WVDIALSECT ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PEERDNS ]],
+ [ "mtu", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MTU ]],
+ [ "mru", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MRU ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, PAPNAME ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MODEMPORT ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, LINESPEED ]],
+# [ "ppp_options", \&gst_parse_sh, IFCFG, PPPOPTIONS ],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, DEFROUTE ]],
+# [ "debug", \&gst_parse_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PERSIST ]],
+ [ "serial_escapechars", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, ESCAPECHARS ]],
+ [ "serial_hwctl", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, HARDFLOWCTL ]],
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ]],
+# [ "enabled", \&gst_network_interface_active, IFACE, \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "mandrake-9.0" =>
+ {
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_parse_sh_bool, IFCFG, ONBOOT ],
+# [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+# [ "name", \&gst_parse_sh, IFCFG, NAME ],
+ [ "dev", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_parse_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_parse_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_parse_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_parse_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_parse_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMIP ],
+# [ "update_dns", \&gst_network_pump_get_nodns, PUMP, "%dev%", "%bootproto%" ],
+# [ "dns1", \&gst_parse_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_parse_sh, IFCFG, DNS2 ],
+ [ "section", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, WVDIALSECT ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PEERDNS ]],
+ [ "mtu", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MTU ]],
+ [ "mru", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MRU ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, PAPNAME ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MODEMPORT ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, LINESPEED ]],
+# [ "ppp_options", \&gst_parse_sh, IFCFG, PPPOPTIONS ],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, DEFROUTE ]],
+# [ "debug", \&gst_parse_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PERSIST ]],
+ [ "serial_escapechars", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, ESCAPECHARS ]],
+ [ "serial_hwctl", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, HARDFLOWCTL ]],
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ]],
+# [ "enabled", \&gst_network_interface_active, IFACE,
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "conectiva-9" =>
+ {
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_parse_sh_bool, IFCFG, ONBOOT ],
+# [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+# [ "name", \&gst_parse_sh, IFCFG, NAME ],
+ [ "dev", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_parse_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_parse_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_parse_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_parse_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_parse_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMIP ],
+# [ "update_dns", \&gst_network_pump_get_nodns, PUMP, "%dev%", "%bootproto%" ],
+# [ "dns1", \&gst_parse_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_parse_sh, IFCFG, DNS2 ],
+ [ "section", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, WVDIALSECT ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PEERDNS ]],
+ [ "mtu", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MTU ]],
+ [ "mru", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MRU ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, PAPNAME ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, MODEMPORT ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, LINESPEED ]],
+ [ "ppp_options", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh, IFCFG, PPPOPTIONS ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, DEFROUTE ]],
+# [ "debug", \&gst_parse_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, PERSIST ]],
+ [ "serial_escapechars", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, ESCAPECHARS ]],
+ [ "serial_hwctl", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_sh_bool, IFCFG, HARDFLOWCTL ]],
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ]],
+# [ "enabled", \&gst_network_interface_active, IFACE,
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_parse_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "debian-2.2" =>
+ {
+ ifaces_get => \&gst_network_debian_ifaces_get_existing,
+ fn =>
+ {
+ INTERFACES => "/etc/network/interfaces",
+ IFACE => "#iface#",
+ CHAT => "/etc/chatscripts/%section%",
+ PPP_OPTIONS => "/etc/ppp/peers/%section%",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+# [ "user", \&gst_parse_trivial, 0 ], # not supported.
+ [ "dev", \&gst_parse_trivial, IFACE ],
+ [ "bootproto", \&gst_network_deb22_parse_bootproto, [INTERFACES, IFACE]],
+ [ "auto", \&gst_parse_interfaces_option_kw_not, [INTERFACES, IFACE], "noauto" ],
+# [ "name", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "name" ],
+ [ "address", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "address" ],
+ [ "netmask", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "netmask" ],
+ [ "broadcast", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "broadcast" ],
+ [ "network", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "network" ],
+ [ "gateway", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "gateway" ],
+ [ "essid", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "wireless[_-]essid" ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_interfaces_option_str, INTERFACES, IFACE, "wireless[_-]key1?" ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_interfaces_option_str, INTERFACES, IFACE, "wireless[_-]key1?" ]],
+ [ "remote_address", \&gst_network_debian_parse_remote_address, [INTERFACES, IFACE]],
+ [ "section", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "provider" ],
+ [ "update_dns", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "usepeerdns" ]],
+ [ "noauth", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "noauth" ]],
+ [ "mtu", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_split_first_str, PPP_OPTIONS, "mtu", "[ \t]+" ]],
+ [ "mru", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_split_first_str, PPP_OPTIONS, "mru", "[ \t]+" ]],
+ [ "serial_port", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^(/dev/[^ \t]+)" ]],
+ [ "serial_speed", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^([0-9]+)" ]],
+ [ "login", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^login \"?([^\"]*)\"?" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "ppp_options", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_unsup, PPP_OPTIONS ]],
+ [ "set_default_gw", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "defaultroute" ]],
+ [ "debug", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "debug" ]],
+ [ "persist", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "persist" ]],
+ [ "serial_escapechars", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_split_first_str, PPP_OPTIONS, "escape", "[ \t]+" ]],
+ [ "serial_hwctl", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "crtscts" ]],
+ [ "external_line", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "atd[^0-9]([0-9*#]*)[wW]" ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "atd.*[ptwW]([0-9, -]+)" ]],
+ [ "dial_command", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "(atd[tp])[0-9, -w]+" ]],
+ [ "volume", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_modem_volume, CHAT ]],
+# [ "enabled", \&gst_network_interface_active, IFACE,
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ ]
+ },
+
+ # Basicly the same as debian-2.2, but the "auto" option changes.
+ "debian-3.0" =>
+ {
+ ifaces_get => \&gst_network_debian_ifaces_get_existing,
+ fn =>
+ {
+ INTERFACES => "/etc/network/interfaces",
+ IFACE => "#iface#",
+ CHAT => "/etc/chatscripts/%section%",
+ PPP_OPTIONS => "/etc/ppp/peers/%section%",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ },
+ table =>
+ [
+# [ "user", \&gst_parse_trivial, 0 ], # not supported.
+ [ "dev", \&gst_parse_trivial, IFACE ],
+ [ "bootproto", \&gst_network_deb22_parse_bootproto, [INTERFACES, IFACE]],
+ [ "auto", \&gst_network_debian_woody_get_auto, [INTERFACES, IFACE]],
+# [ "name", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "name" ],
+ [ "address", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "address" ],
+ [ "netmask", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "netmask" ],
+ [ "broadcast", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "broadcast" ],
+ [ "network", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "network" ],
+ [ "gateway", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "gateway" ],
+ [ "essid", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "wireless[_-]essid" ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_interfaces_option_str, INTERFACES, IFACE, "wireless[_-]key1?" ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_interfaces_option_str, INTERFACES, IFACE, "wireless[_-]key1?" ]],
+ [ "remote_address", \&gst_network_debian_parse_remote_address, [INTERFACES, IFACE]],
+ [ "section", \&gst_parse_interfaces_option_str, [INTERFACES, IFACE], "provider" ],
+ [ "update_dns", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_parse_kw, PPP_OPTIONS, "usepeerdns" ]],
+ [ "noauth", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_parse_kw, PPP_OPTIONS, "noauth" ]],
+ [ "mtu", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_parse_split_first_str, PPP_OPTIONS, "mtu", "[ \t]+" ]],
+ [ "mru", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_parse_split_first_str, PPP_OPTIONS, "mru", "[ \t]+" ]],
+ [ "serial_port", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^(/dev/[^ \t]+)" ]],
+ [ "serial_speed", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^([0-9]+)" ]],
+ [ "login", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^user \"?([^\"]*)\"?" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "ppp_options", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_unsup, PPP_OPTIONS ]],
+ [ "set_default_gw", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_parse_kw, PPP_OPTIONS, "defaultroute" ]],
+ [ "debug", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_parse_kw, PPP_OPTIONS, "debug" ]],
+ [ "persist", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_parse_kw, PPP_OPTIONS, "persist" ]],
+ [ "serial_escapechars", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_split_first_str, PPP_OPTIONS, "escape", "[ \t]+" ]],
+ [ "serial_hwctl", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "crtscts" ]],
+ [ "external_line", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "atd[^0-9]([0-9*#]*)[wW]" ]],
+ [ "external_line", \&gst_network_check_type, [IFACE, "isdn", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^number[ \t]+(.+)[wW]" ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "isdn", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^number.*[wW \t](.*)" ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "atd.*[ptwW]([0-9, -]+)" ]],
+ [ "dial_command", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "(atd[tp])[0-9, -w]+" ]],
+ [ "volume", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_modem_volume, CHAT ]],
+# [ "enabled", \&gst_network_interface_active, IFACE,
+# \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ ]
+ },
+
+ "suse-7.0" =>
+ {
+ ifaces_get => \&gst_network_suse70_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/rc.config",
+ IFACE => "#iface#"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_suse70_parse_bootproto, [IFCFG, IFACE] ],
+ [ "auto", \&gst_network_suse70_parse_iface_auto, [IFCFG, IFACE], NETCONFIG ],
+ [ "user", \&gst_parse_trivial, 0 ], # not supported.
+ [ "name", \&gst_network_suse70_parse_iface_sh, [IFCFG, IFACE], GST_IFACE_NAME ],
+ [ "dev", \&gst_network_suse70_parse_iface_sh, [IFCFG, IFACE], NETDEV ],
+ [ "address", \&gst_network_suse70_parse_iface_sh, [IFCFG, IFACE], IPADDR ],
+ [ "netmask", \&gst_network_suse70_get_ifconfig_arg, [IFCFG, IFACE], netmask ],
+ [ "broadcast", \&gst_network_suse70_get_ifconfig_arg, [IFCFG, IFACE], broadcast ],
+# [ "network", \&gst_parse_trivial, 0 ], # not supported.
+# [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ], # not supported
+ [ "remote_address", \&gst_network_suse70_get_ifconfig_arg, [IFCFG, IFACE], pointopoint ],
+ [ "enabled", \&gst_network_interface_active, IFACE,
+ \&gst_network_suse70_active_interfaces_get ],
+ [ "enabled", \&gst_parse_trivial, 0 ]
+ ]
+ },
+
+ "suse-9.0" =>
+ {
+ ifaces_get => \&gst_network_suse90_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network/ifcfg-#iface#",
+ ROUTE_CONF => "/etc/sysconfig/network/routes",
+ IFACE => "#iface#"
+ },
+ table =>
+ [
+ [ "dev", \&gst_network_suse9_get_dev_name, IFACE ],
+# [ "enabled", \&gst_network_interface_active, "%dev%", \&gst_network_active_interfaces_get ],
+ [ "auto", \&gst_network_suse90_get_auto, IFCFG, STARTMODE ],
+ [ "bootproto", \&gst_network_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "address", \&gst_parse_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_parse_sh, IFCFG, NETMASK ],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMOTE_IPADDR ],
+ [ "essid", \&gst_parse_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_sh, IFCFG, WIRELESS_KEY ]],
+ [ "gateway", \&gst_network_suse90_get_gateway, ROUTE_CONF, "%address%", "%netmask%" ],
+ [ "gateway", \&gst_network_suse90_get_plip_gateway, ROUTE_CONF, "%remote_address%" ],
+ # Modem stuff goes here
+ [ "serial_port", \&gst_parse_sh, IFCFG, MODEM_DEVICE ],
+ [ "serial_speed", \&gst_parse_sh, IFCFG, SPEED ],
+ [ "mtu", \&gst_parse_sh, IFCFG, MTU ],
+ [ "mru", \&gst_parse_sh, IFCFG, MRU ],
+# [ "ppp_options", \&gst_parse_sh, IFCFG, PPPD_OPTIONS ],
+ [ "dial_command", \&gst_parse_sh, IFCFG, DIALCOMMAND ],
+ [ "external_line", \&gst_parse_sh, IFCFG, DIALPREFIX ],
+ [ "section", \&gst_parse_sh, IFCFG, PROVIDER ],
+ [ "volume", \&gst_parse_sh_re, IFCFG, INIT8, "AT.*[ml]([0-3])" ],
+ [ "login", \&gst_network_suse90_parse_provider_file, "%section%", USERNAME ],
+ [ "password", \&gst_network_suse90_parse_provider_file, "%section%", PASSWORD ],
+ [ "phone_number", \&gst_network_suse90_parse_provider_file, "%section%", PHONE ],
+ [ "dns1", \&gst_network_suse90_parse_provider_file, "%section%", DNS1 ],
+ [ "dns2", \&gst_network_suse90_parse_provider_file, "%section%", DNS2 ],
+ [ "update_dns", \&gst_network_suse90_parse_provider_file_bool, "%section%", MODIFYDNS ],
+ [ "persist", \&gst_network_suse90_parse_provider_file_bool, "%section%", PERSIST ],
+ [ "stupid", \&gst_network_suse90_parse_provider_file_bool, "%section%", STUPIDMODE ],
+ [ "set_default_gw", \&gst_network_suse90_parse_provider_file_bool, "%section%", DEFAULTROUTE ],
+ ]
+ },
+
+ "pld-1.0" =>
+ {
+ ifaces_get => \&gst_network_sysconfig_pld10_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/interfaces/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/interfaces/data/chat-#iface#",
+ IFACE => "#iface#",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_pld10_parse_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_parse_sh_bool, IFCFG, ONBOOT ],
+# [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+# [ "name", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "dev", \&gst_parse_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_network_pld10_get_ipaddr, IFCFG, IPADDR, "address" ],
+ [ "netmask", \&gst_network_pld10_get_ipaddr, IFCFG, IPADDR, "netmask" ],
+# [ "broadcast", \&gst_parse_sh, IFCFG, BROADCAST ],
+# [ "network", \&gst_parse_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ],
+ [ "remote_address", \&gst_parse_sh, IFCFG, REMIP ],
+# [ "update_dns", \&gst_network_pump_get_nodns, PUMP, "%dev%", "%bootproto%" ],
+# [ "dns1", \&gst_parse_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_parse_sh, IFCFG, DNS2 ],
+ [ "update_dns", \&gst_parse_sh_bool, IFCFG, PEERDNS ],
+ [ "mtu", \&gst_parse_sh, IFCFG, MTU ],
+ [ "mru", \&gst_parse_sh, IFCFG, MRU ],
+ [ "login", \&gst_parse_sh, IFCFG, PAPNAME ],
+ [ "password", \&gst_network_get_pap_passwd, PAP, "%login%" ],
+ [ "password", \&gst_network_get_pap_passwd, CHAP, "%login%" ],
+ [ "serial_port", \&gst_parse_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_parse_sh, IFCFG, LINESPEED ],
+# [ "ppp_options", \&gst_parse_sh, IFCFG, PPPOPTIONS ],
+# [ "section", \&gst_parse_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_parse_sh_bool, IFCFG, DEFROUTE ],
+# [ "debug", \&gst_parse_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_parse_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_parse_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_parse_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_parse_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+# [ "enabled", \&gst_network_interface_active, IFACE, \&gst_network_active_interfaces_get ],
+# [ "enabled", \&gst_parse_trivial, 0 ]
+ ]
+ },
+ "slackware-9.1.0" =>
+ {
+ ifaces_get => \&gst_network_slackware91_ifaces_get_existing,
+ fn =>
+ {
+ RC_INET_CONF => "/etc/rc.d/rc.inet1.conf",
+ RC_INET => "/etc/rc.d/rc.inet1",
+ RC_LOCAL => "/etc/rc.d/rc.local",
+ IFACE => "#iface#",
+ WIRELESS => "/etc/pcmcia/wireless.opts",
+ PPP_OPTIONS => "/etc/ppp/options",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ CHAT => "/etc/ppp/pppscript",
+ },
+ table =>
+ [
+ [ "user", \&gst_parse_trivial, 0 ], # not supported.
+ [ "dev", \&gst_parse_trivial, IFACE ],
+ [ "address", \&gst_parse_rcinet1conf, [RC_INET_CONF, IFACE], IPADDR ],
+ [ "netmask", \&gst_parse_rcinet1conf, [RC_INET_CONF, IFACE], NETMASK ],
+ [ "gateway", \&gst_network_get_gateway, RC_INET_CONF, GATEWAY, "%address%", "%netmask%" ],
+ [ "auto", \&gst_network_slackware91_get_auto, [RC_INET, RC_LOCAL, IFACE]],
+ [ "bootproto", \&gst_network_slackware91_parse_bootproto, [RC_INET_CONF, IFACE]],
+ [ "essid", \&gst_parse_wireless_opts, [ WIRELESS, IFACE ], \&gst_network_get_wireless_ifaces, ESSID ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_wireless_opts, WIRELESS, IFACE, \&gst_network_get_wireless_ifaces, KEY ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_wireless_opts, WIRELESS, IFACE, \&gst_network_get_wireless_ifaces, KEY ]],
+ [ "enabled", \&gst_network_interface_active, IFACE, \&gst_network_active_interfaces_get ],
+ # Modem stuff
+ [ "update_dns", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "usepeerdns" ]],
+ [ "noauth", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "noauth" ]],
+ [ "mtu", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_split_first_str, PPP_OPTIONS, "mtu", "[ \t]+" ]],
+ [ "mru", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_split_first_str, PPP_OPTIONS, "mru", "[ \t]+" ]],
+ [ "serial_port", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^(/dev/[^ \t]+)" ]],
+ [ "serial_speed", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^([0-9]+)" ]],
+ [ "login", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_re, PPP_OPTIONS, "^name \"?([^\"]*)\"?" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_pap_passwd, CHAP, "%login%" ]],
+ [ "ppp_options", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_ppp_options_unsup, PPP_OPTIONS ]],
+ [ "set_default_gw", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "defaultroute" ]],
+ [ "debug", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "debug" ]],
+ [ "persist", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "persist" ]],
+ [ "serial_escapechars", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_split_first_str, PPP_OPTIONS, "escape", "[ \t]+" ]],
+ [ "serial_hwctl", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_kw, PPP_OPTIONS, "crtscts" ]],
+ [ "external_line", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "atd[^0-9]*([0-9*#]*)[wW]" ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "atd.*[ptw]([0-9, -]+)" ]],
+ [ "dial_command", \&gst_network_check_type, [IFACE, "modem", \&gst_parse_chat, CHAT, "(atd[tp])[0-9, -w]+" ]],
+ [ "volume", \&gst_network_check_type, [IFACE, "modem", \&gst_network_get_modem_volume, CHAT ]],
+ ]
+ },
+
+ "gentoo" =>
+ {
+ ifaces_get => \&gst_network_gentoo_ifaces_get_existing,
+ fn =>
+ {
+ NET => "/etc/conf.d/net",
+ PPPNET => "/etc/conf.d/net.#iface#",
+ INIT => "net.#iface#",
+ IFACE => "#iface#",
+ WIRELESS => "/etc/conf.d/wireless",
+ },
+ table =>
+ [
+ [ "auto", \&gst_service_gentoo_get_service_status, INIT, "default" ],
+ [ "user", \&gst_parse_trivial, 0 ], # not supported.
+ [ "dev", \&gst_parse_trivial, IFACE ],
+ [ "address", \&gst_parse_confd_net_re, NET, "config_%dev%", "^[ \t]*([0-9\.]+)" ],
+ [ "netmask", \&gst_parse_confd_net_re, NET, "config_%dev%", "netmask[ \t]+([0-9\.]*)" ],
+ [ "remote_address", \&gst_parse_confd_net_re, NET, "config_%dev%", "dest_address[ \t]+([0-9\.]*)" ],
+# [ "gateway", \&gst_parse_sh_re, NET, "gateway", "%dev%/([0-9\.\:]*)" ],
+ [ "gateway", \&gst_network_gentoo_parse_gateway, [ NET, IFACE ]],
+ [ "enabled", \&gst_network_interface_active, IFACE, \&gst_network_active_interfaces_get ],
+ [ "bootproto", \&gst_network_gentoo_parse_bootproto, [ NET, IFACE ]],
+ [ "essid", \&gst_parse_sh, WIRELESS, "essid_%dev%" ],
+ [ "key_type", \&gst_network_get_wep_key_type, [ \&gst_parse_sh, WIRELESS, "key_%essid%" ]],
+ [ "key", \&gst_network_get_wep_key, [ \&gst_parse_sh, WIRELESS, "key_%essid%" ]],
+ # modem stuff
+ [ "update_dns", \&gst_parse_sh_bool, PPPNET, PEERDNS ],
+ [ "mtu", \&gst_parse_sh, PPPNET, MTU ],
+ [ "mru", \&gst_parse_sh, PPPNET, MRU ],
+ [ "serial_port", \&gst_parse_sh, PPPNET, MODEMPORT ],
+ [ "serial_speed", \&gst_parse_sh, PPPNET, LINESPEED ],
+ [ "login", \&gst_parse_sh, PPPNET, USERNAME ],
+ [ "password", \&gst_parse_sh, PPPNET, PASSWORD ],
+ [ "ppp_options", \&gst_parse_sh, PPPNET, PPPOPTIONS ],
+ [ "set_default_gw", \&gst_parse_sh_bool, PPPNET, DEFROUTE ],
+ [ "debug", \&gst_parse_sh_bool, PPPNET, DEBUG ],
+ [ "persist", \&gst_parse_sh_bool, PPPNET, PERSIST ],
+ [ "serial_escapechars", \&gst_parse_sh_bool, PPPNET, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_parse_sh_bool, PPPNET, HARDFLOWCTL ],
+ [ "external_line", \&gst_parse_sh_re, PPPNET, NUMBER, "^([0-9*#]*)wW" ],
+ [ "phone_number", \&gst_parse_sh_re, PPPNET, NUMBER, "w?([0-9]*)\$" ],
+ [ "volume", \&gst_parse_sh_re, PPPNET, INITSTRING, "^at.*[ml]([0-3])" ],
+ ]
+ },
+
+ "freebsd-5" =>
+ {
+ ifaces_get => \&gst_network_freebsd_ifaces_get_existing,
+ fn =>
+ {
+ RC_CONF => "/etc/rc.conf",
+ RC_CONF_DEFAULT => "/etc/defaults/rc.conf",
+ STARTIF => "/etc/start_if.#iface#",
+ PPPCONF => "/etc/ppp/ppp.conf",
+ IFACE => "#iface#",
+ },
+ table =>
+ [
+ [ "auto", \&gst_network_freebsd5_get_auto, [RC_CONF, RC_CONF_DEFAULT, IFACE ]],
+ [ "user", \&gst_parse_trivial, 0 ], # not supported.
+ [ "dev", \&gst_parse_trivial, IFACE ],
+ # we need to double check these values both in the start_if and in the rc.conf files, in this order
+ [ "address", \&gst_parse_startif, STARTIF, "inet[ \t]+([0-9\.]+)" ],
+ [ "address", \&gst_parse_sh_re, RC_CONF, "ifconfig_%dev%", "inet[ \t]+([0-9\.]+)" ],
+ [ "netmask", \&gst_parse_startif, STARTIF, "netmask[ \t]+([0-9\.]+)" ],
+ [ "netmask", \&gst_parse_sh_re, RC_CONF, "ifconfig_%dev%", "netmask[ \t]+([0-9\.]+)" ],
+ [ "remote_address", \&gst_parse_startif, STARTIF, "dest_address[ \t]+([0-9\.]+)" ],
+ [ "remote_address", \&gst_parse_sh_re, RC_CONF, "ifconfig_%dev%", "dest_address[ \t]+([0-9\.]+)" ],
+ [ "essid", \&gst_parse_startif, STARTIF, "ssid[ \t]+(\".*\"|[^\"][^ ]+)" ],
+ [ "essid", \&gst_parse_sh_re, RC_CONF, "ifconfig_%dev%", "ssid[ \t]+([^ ]*)" ],
+ # this is for plip interfaces
+ [ "gateway", \&gst_network_get_plip_gateway, RC_CONF, "defaultrouter", "%remote_address%" ],
+ [ "gateway", \&gst_network_get_gateway, RC_CONF, "defaultrouter", "%address%", "%netmask%" ],
+ [ "enabled", \&gst_network_interface_active, IFACE, \&gst_network_freebsd5_active_interfaces_get ],
+ [ "bootproto", \&gst_network_parse_bootproto, RC_CONF, "ifconfig_%dev%" ],
+ # Modem stuff
+ [ "serial_port", \&gst_network_parse_pppconf, [ PPPCONF, STARTIF, IFACE ], "device" ],
+ [ "serial_speed", \&gst_network_parse_pppconf, [ PPPCONF, STARTIF, IFACE ], "speed" ],
+ [ "mtu", \&gst_network_parse_pppconf, [ PPPCONF, STARTIF, IFACE ], "mtu" ],
+ [ "mru", \&gst_network_parse_pppconf, [ PPPCONF, STARTIF, IFACE ], "mru" ],
+ [ "login", \&gst_network_parse_pppconf, [ PPPCONF, STARTIF, IFACE ], "authname" ],
+ [ "password", \&gst_network_parse_pppconf, [ PPPCONF, STARTIF, IFACE ], "authkey" ],
+ [ "update_dns", \&gst_network_parse_pppconf_bool, [ PPPCONF, STARTIF, IFACE ], "dns" ],
+ [ "set_default_gw", \&gst_network_parse_pppconf_bool, [ PPPCONF, STARTIF, IFACE ], "default HISADDR" ],
+ [ "external_line", \&gst_network_parse_pppconf_re, [ PPPCONF, STARTIF, IFACE ], "phone", "[ \t]+([0-9]+)[wW]" ],
+ [ "phone_number", \&gst_network_parse_pppconf_re, [ PPPCONF, STARTIF, IFACE ], "phone", "[wW]?([0-9]+)[ \t]*\$" ],
+ [ "dial_command", \&gst_network_parse_pppconf_re, [ PPPCONF, STARTIF, IFACE ], "dial", "(ATD[TP])" ],
+ [ "volume", \&gst_network_parse_pppconf_re, [ PPPCONF, STARTIF, IFACE ], "dial", "AT.*[ml]([0-3]) OK " ],
+ [ "persist", \&gst_network_get_freebsd5_ppp_persist, [ STARTIF, IFACE ]],
+ ]
+ },
+ );
+
+ my $dist = $dist_map{$gst_dist};
+ return %{$dist_tables{$dist}} if $dist;
+
+ &gst_report ("platform_no_table", $gst_dist);
+ return undef;
+}
+
+sub gst_network_get_replace_table
+{
+ my %dist_map =
+ (
+ "redhat-5.2" => "redhat-5.2",
+ "redhat-6.0" => "redhat-6.2",
+ "redhat-6.1" => "redhat-6.2",
+ "redhat-6.2" => "redhat-6.2",
+ "redhat-7.0" => "redhat-7.0",
+ "redhat-7.1" => "redhat-7.0",
+ "redhat-7.2" => "redhat-7.2",
+ "redhat-8.0" => "redhat-7.2",
+ "redhat-9" => "redhat-7.2",
+ "mandrake-7.1" => "redhat-6.2",
+ "mandrake-7.2" => "redhat-6.2",
+ "mandrake-9.0" => "redhat-7.0",
+ "mandrake-9.1" => "redhat-7.0",
+ "mandrake-9.2" => "redhat-7.0",
+ "mandrake-10.0" => "redhat-7.0",
+ "mandrake-10.1" => "redhat-7.0",
+ "mandrake-10.2" => "redhat-7.0",
+ "mandriva-2006.0" => "redhat-7.0",
+ "mandriva-2006.1" => "redhat-7.0",
+ "mandriva-2007.0" => "redhat-7.0",
+ "mandriva-2007.1" => "redhat-7.0",
+ "yoper-2.2" => "redhat-7.0",
+ "blackpanther-4.0" => "redhat-7.0",
+ "conectiva-9" => "redhat-7.0",
+ "conectiva-10" => "redhat-7.0",
+ "debian-2.2" => "debian-2.2",
+ "debian-3.0" => "debian-2.2",
+ "debian-3.1" => "debian-2.2",
+ "debian-4.0" => "debian-2.2",
+ "debian-5.0" => "debian-2.2",
+ "debian-testing" => "debian-2.2",
+ "ubuntu-5.04" => "debian-2.2",
+ "ubuntu-5.10" => "debian-2.2",
+ "ubuntu-6.06" => "debian-2.2",
+ "ubuntu-6.10" => "debian-2.2",
+ "ubuntu-7.04" => "debian-2.2",
+ "ubuntu-7.10" => "debian-2.2",
+ "ubuntu-8.04" => "debian-2.2",
+ "suse-7.0" => "suse-7.0",
+ "suse-9.0" => "suse-9.0",
+ "suse-9.1" => "suse-9.0",
+ "turbolinux-7.0" => "redhat-7.0",
+ "pld-1.0" => "pld-1.0",
+ "pld-1.1" => "pld-1.0",
+ "pld-1.99" => "pld-1.0",
+ "fedora-1" => "redhat-7.2",
+ "fedora-2" => "redhat-7.2",
+ "fedora-3" => "redhat-7.2",
+ "fedora-4" => "redhat-7.2",
+ "fedora-5" => "redhat-7.2",
+ "rpath" => "redhat-7.2",
+ "vine-3.0" => "redhat-7.0",
+ "vine-3.1" => "redhat-7.0",
+ "ark" => "redhat-7.0",
+ "slackware-9.1.0" => "slackware-9.1.0",
+ "slackware-10.0.0" => "slackware-9.1.0",
+ "slackware-10.1.0" => "slackware-9.1.0",
+ "slackware-10.2.0" => "slackware-9.1.0",
+ "gentoo" => "gentoo",
+ "vlos-1.2" => "gentoo",
+ "freebsd-5" => "freebsd-5",
+ "freebsd-6" => "freebsd-5",
+ );
+
+ my %dist_tables =
+ (
+ "redhat-6.2" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => "/etc/sysconfig/network",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "auto", \&gst_replace_sh_bool, SYSCONFIG_NW, NETWORKING ],
+ [ "hostname", \&gst_replace_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "gateway", \&gst_replace_sh, SYSCONFIG_NW, GATEWAY],
+ [ "gatewaydev", \&gst_replace_sh, SYSCONFIG_NW, GATEWAYDEV],
+ [ "domain", \&gst_replace_sh, SYSCONFIG_NW, DOMAIN],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_set_status, 91, "smb", "%smbuse%" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ],
+ [ "gateway", \&gst_network_route_set_default_gw, "%gatewaydev%" ]
+ ]
+ },
+
+ "redhat-7.0" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => "/etc/sysconfig/network",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "auto", \&gst_replace_sh_bool, SYSCONFIG_NW, NETWORKING ],
+ [ "hostname", \&gst_replace_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "gateway", \&gst_replace_sh, SYSCONFIG_NW, GATEWAY],
+ [ "gatewaydev", \&gst_replace_sh, SYSCONFIG_NW, GATEWAYDEV],
+ [ "domain", \&gst_replace_sh, SYSCONFIG_NW, DOMAIN],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_set_status, 91, "smb", "%smbuse%" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ],
+ [ "gateway", \&gst_network_route_set_default_gw, "%gatewaydev%" ]
+ ]
+ },
+
+ "redhat-7.2" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => ["/etc/sysconfig/networking/profiles/default/network",
+ "/etc/sysconfig/networking/network",
+ "/etc/sysconfig/network"],
+ RESOLV_CONF => ["/etc/sysconfig/networking/profiles/default/resolv.conf",
+ "/etc/resolv.conf"],
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => ["/etc/sysconfig/networking/profiles/default/hosts",
+ "/etc/hosts"],
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "auto", \&gst_replace_sh_bool, SYSCONFIG_NW, NETWORKING ],
+ [ "hostname", \&gst_replace_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "gateway", \&gst_replace_sh, SYSCONFIG_NW, GATEWAY],
+ [ "gatewaydev", \&gst_replace_sh, SYSCONFIG_NW, GATEWAYDEV],
+ [ "domain", \&gst_replace_sh, SYSCONFIG_NW, DOMAIN],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_set_status, 91, "smb", "%smbuse%" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ],
+ [ "gateway", \&gst_network_route_set_default_gw, "%gatewaydev%" ]
+ ]
+ },
+
+ "debian-2.2" =>
+ {
+ fn =>
+ {
+ OPTIONS => "/etc/network/options",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ HOSTNAME => "/etc/hostname",
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_replace_line_first, HOSTNAME ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_set_status, 91, "samba" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ]
+ ]
+ },
+
+ "suse-7.0" =>
+ {
+ fn =>
+ {
+ RC_CONFIG => "/etc/rc.config",
+ ROUTE_CONF => "/etc/route.conf",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/smb.conf",
+ WVDIAL => "/etc/wvdial.conf",
+ SUSECONFIG => "SuSEconfig"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_replace_sh_set_hostname, RC_CONFIG, FQHOSTNAME ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "gateway", \&gst_replace_join_first_str, ROUTE_CONF, "default", "[ \t]+" ],
+ [ "gateway", \&gst_replace_join_first_str, ROUTE_CONF, "0.0.0.0", "[ \t]+" ],
+ [ "domain", \&gst_replace_sh_set_domain, RC_CONFIG, FQHOSTNAME ],
+ [ "nameserver", \&gst_replace_sh_join, RC_CONFIG, NAMESERVER, "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_sh_join, RC_CONFIG, SEARCHLIST, "[ \t]+" ],
+# Remove /etc/resolv.conf so SuSEconfig sets the new values.
+ [ "searchdomain", \&gst_file_remove, RESOLV_CONF ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_set_status, 20, "smb", "%smbuse%" ],
+ [ "interface", \&gst_network_suse70_set_ppp, [WVDIAL, "%dialing%"] ],
+# We're calling this sepparated cuz we are going to call wvdial to activate.
+ [ "interface", \&gst_network_suse70_activate_ppp ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ],
+ [ "_always_", \&gst_file_run, SUSECONFIG ],
+ ]
+ },
+
+ "suse-9.0" =>
+ {
+ fn =>
+ {
+ ROUTE_CONF => "/etc/sysconfig/network/routes",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ HOSTNAME => "/etc/HOSTNAME",
+ SMB_CONF => "/etc/samba/smb.conf",
+ },
+ table =>
+ [
+ [ "hostname", \&gst_replace_fq_hostname, HOSTNAME, "%hostname%", "%domain%" ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_suse_set_status, "smb" ],
+ [ "gateway", \&gst_replace_join_first_str, ROUTE_CONF, "default", "[ \t]+", "%gateway% - -" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ],
+ ]
+ },
+
+ "pld-1.0" =>
+ {
+ fn =>
+ {
+ SYSCONFIG_NW => "/etc/sysconfig/network",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/smb/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "auto", \&gst_replace_sh_bool, SYSCONFIG_NW, NETWORKING ],
+ [ "hostname", \&gst_replace_sh, SYSCONFIG_NW, HOSTNAME ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "gateway", \&gst_replace_sh, SYSCONFIG_NW, GATEWAY],
+ [ "gatewaydev", \&gst_replace_sh, SYSCONFIG_NW, GATEWAYDEV],
+# [ "domain", \&gst_replace_sh, SYSCONFIG_NW, DOMAIN],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_sysv_set_status, 91, "smb", "%smbuse%" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ],
+ [ "gateway", \&gst_network_route_set_default_gw, "%gatewaydev%" ]
+ ]
+ },
+ "slackware-9.1.0" =>
+ {
+ fn =>
+ {
+ RC_INET_CONF => "/etc/rc.d/rc.inet1.conf",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOST_CONF => "/etc/host.conf",
+ HOSTS => "/etc/hosts",
+ HOSTNAME => "/etc/HOSTNAME",
+ SMB_CONF => "/etc/samba/smb.conf",
+ WVDIAL => "/etc/wvdial.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_replace_fq_hostname, HOSTNAME, "%hostname%", "%domain%" ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "gateway", \&gst_replace_rcinet1conf_global, RC_INET_CONF, GATEWAY ],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "order", \&gst_replace_join_first_array, HOST_CONF, "order", "[ \t]+", ",[ \t]*" ],
+ [ "hostmatch", \&gst_replace_join_first_bool, HOST_CONF, "multi", "[ \t]+", "on", "off" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_bsd_set_status, "/etc/rc.d/rc.samba" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ],
+ [ "gateway", \&gst_network_route_set_default_gw, "%gatewaydev%" ]
+ ]
+ },
+
+ "gentoo" =>
+ {
+ fn =>
+ {
+ HOSTNAME => "/etc/conf.d/hostname",
+ DOMAINNAME => "/etc/conf.d/domainname",
+ NET => "/etc/conf.d/net",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/etc/samba/smb.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_replace_sh, HOSTNAME, "HOSTNAME" ],
+ [ "hostname", \&gst_network_run_hostname ],
+ [ "gateway", \&gst_network_route_set_default_gw, "%gatewaydev%" ],
+ [ "domain", \&gst_replace_sh, DOMAINNAME, "DNSDOMAIN" ],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_gentoo_set_status, "samba", 1 ],
+ # first set the gateway to something like "eth0", then add the IP address like "eth0/1.1.1.1"
+# [ "gatewaydev", \&gst_replace_sh, NET, gateway ],
+# [ "gateway", \&gst_replace_sh_re, NET, gateway, "\/[0-9\.]*\$", "/%gateway%" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ]
+ ]
+ },
+
+ "freebsd-5" =>
+ {
+ fn =>
+ {
+ RC_CONF => "/etc/rc.conf",
+ RESOLV_CONF => "/etc/resolv.conf",
+ HOSTS => "/etc/hosts",
+ SMB_CONF => "/usr/local/etc/smb.conf"
+ },
+ table =>
+ [
+ [ "hostname", \&gst_replace_sh, RC_CONF, "hostname", "%hostname%.%domain%" ],
+ [ "hostname", \&gst_network_run_hostname, "%hostname%.%domain%" ],
+ [ "domain", \&gst_replace_join_first_str, RESOLV_CONF, "domain", "[ \t]+" ],
+ [ "nameserver", \&gst_replace_join_all, RESOLV_CONF, "nameserver", "[ \t]+" ],
+ [ "searchdomain", \&gst_replace_join_first_array, RESOLV_CONF, "search", "[ \t]+", "[ \t]+" ],
+ [ "statichost", \&gst_replace_join_hash, HOSTS, "[ \t]+", "[ \t]+" ],
+ [ "workgroup", \&gst_replace_ini, SMB_CONF, "global", "workgroup" ],
+ [ "smbdesc", \&gst_replace_ini, SMB_CONF, "global", "server string", "%hostname%" ],
+ [ "winsserver", \&gst_replace_ini, SMB_CONF, "global", "wins server" ],
+ [ "winsuse", \&gst_replace_ini_bool, SMB_CONF, "global", "wins support" ],
+ [ "smbuse", \&gst_service_rcng_set_status, "samba" ],
+ [ "gateway", \&gst_replace_sh, RC_CONF, "defaultrouter" ],
+ [ "interface", \&gst_network_interfaces_set, OLD_HASH ]
+ ]
+ }
+ );
+
+ my $dist = $dist_map{$gst_dist};
+ return %{$dist_tables{$dist}} if $dist;
+
+ &gst_report ("platform_no_table", $gst_dist);
+ return undef;
+}
+
+sub gst_network_get_interface_replace_table
+{
+ my %dist_map =
+ (
+ "redhat-5.2" => "redhat-5.2",
+ "redhat-6.0" => "redhat-6.2",
+ "redhat-6.1" => "redhat-6.2",
+ "redhat-6.2" => "redhat-6.2",
+ "redhat-7.0" => "redhat-6.2",
+ "redhat-7.1" => "redhat-6.2",
+ "redhat-7.2" => "redhat-7.2",
+ "redhat-8.0" => "redhat-8.0",
+ "redhat-9" => "redhat-8.0",
+ "mandrake-7.1" => "redhat-6.2",
+ "mandrake-7.2" => "redhat-6.2",
+ "mandrake-9.0" => "mandrake-9.0",
+ "mandrake-9.1" => "mandrake-9.0",
+ "mandrake-9.2" => "mandrake-9.0",
+ "mandrake-10.0" => "mandrake-9.0",
+ "mandrake-10.1" => "mandrake-9.0",
+ "mandrake-10.2" => "mandrake-9.0",
+ "mandriva-2006.0" => "mandrake-9.0",
+ "mandriva-2006.1" => "mandrake-9.0",
+ "mandriva-2007.0" => "mandrake-9.0",
+ "mandriva-2007.1" => "mandrake-9.0",
+ "yoper-2.2" => "redhat-6.2",
+ "blackpanther-4.0" => "mandrake-9.0",
+ "conectiva-9" => "conectiva-9",
+ "conectiva-10" => "conectiva-9",
+ "debian-2.2" => "debian-2.2",
+ "debian-3.0" => "debian-3.0",
+ "debian-3.1" => "debian-3.0",
+ "debian-4.0" => "debian-3.0",
+ "debian-5.0" => "debian-3.0",
+ "debian-testing" => "debian-3.0",
+ "ubuntu-5.04" => "debian-3.0",
+ "ubuntu-5.10" => "debian-3.0",
+ "ubuntu-6.06" => "debian-3.0",
+ "ubuntu-6.10" => "debian-3.0",
+ "ubuntu-7.04" => "debian-3.0",
+ "ubuntu-7.10" => "debian-3.0",
+ "ubuntu-8.04" => "debian-3.0",
+ "suse-7.0" => "suse-7.0",
+ "suse-9.0" => "suse-9.0",
+ "suse-9.1" => "suse-9.0",
+ "turbolinux-7.0" => "redhat-6.2",
+ "pld-1.0" => "pld-1.0",
+ "pld-1.1" => "pld-1.0",
+ "pld-1.99" => "pld-1.0",
+ "fedora-1" => "redhat-7.2",
+ "fedora-2" => "redhat-7.2",
+ "fedora-3" => "redhat-7.2",
+ "fedora-4" => "redhat-7.2",
+ "fedora-5" => "redhat-7.2",
+ "rpath" => "redhat-7.2",
+ "vine-3.0" => "vine-3.0",
+ "vine-3.1" => "vine-3.0",
+ "ark" => "vine-3.0",
+ "slackware-9.1.0" => "slackware-9.1.0",
+ "slackware-10.0.0" => "slackware-9.1.0",
+ "slackware-10.1.0" => "slackware-9.1.0",
+ "slackware-10.2.0" => "slackware-9.1.0",
+ "gentoo" => "gentoo",
+ "vlos-1.2" => "gentoo",
+ "freebsd-5" => "freebsd-5",
+ "freebsd-6" => "freebsd-5",
+ );
+
+ my %dist_tables =
+ (
+ "redhat-6.2" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate,
+ iface_delete => \&gst_network_rh62_interface_delete,
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ WVDIAL => "/etc/wvdial.conf",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_replace_sh_bool, IFCFG, ONBOOT ],
+ [ "user", \&gst_replace_sh_bool, IFCFG, USERCTL ],
+ [ "dev", \&gst_replace_sh, IFCFG, NAME ],
+ [ "dev", \&gst_replace_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_replace_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_replace_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_replace_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_replace_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_replace_sh, IFCFG, GATEWAY ],
+ [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_sh_bool, IFCFG, PEERDNS ],
+ [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+ [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMIP ],
+ [ "login", \&gst_replace_sh, IFCFG, PAPNAME ],
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, LINESPEED ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPOPTIONS ],
+ [ "section", \&gst_replace_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_replace_sh_bool, IFCFG, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "redhat-7.2" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate,
+ iface_delete => \&gst_network_rh72_interface_delete,
+ ifaces_get => \&gst_network_sysconfig_rh72_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => ["/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ "/etc/sysconfig/networking/profiles/default/ifcfg-#iface#",
+ "/etc/sysconfig/networking/devices/ifcfg-#iface#"],
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ WVDIAL => "/etc/wvdial.conf",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_replace_sh_bool, IFCFG, ONBOOT ],
+ [ "user", \&gst_replace_sh_bool, IFCFG, USERCTL ],
+ [ "name", \&gst_replace_sh, IFCFG, NAME ],
+ [ "dev", \&gst_replace_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_replace_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_replace_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_replace_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_replace_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_replace_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_replace_sh, IFCFG, ESSID ],
+ [ "key", \&gst_replace_sh, IFCFG, KEY ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_sh, IFCFG, KEY, "%key%" ]],
+ [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_sh_bool, IFCFG, PEERDNS ],
+ [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+ [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMIP ],
+ [ "login", \&gst_replace_sh, IFCFG, PAPNAME ],
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, LINESPEED ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPOPTIONS ],
+ [ "section", \&gst_replace_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_replace_sh_bool, IFCFG, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "redhat-8.0" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate,
+ iface_delete => \&gst_network_rh72_interface_delete,
+ ifaces_get => \&gst_network_sysconfig_rh72_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => ["/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ "/etc/sysconfig/networking/profiles/default/ifcfg-#iface#",
+ "/etc/sysconfig/networking/devices/ifcfg-#iface#"],
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ WVDIAL => "/etc/wvdial.conf",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_replace_sh_bool, IFCFG, ONBOOT ],
+ [ "user", \&gst_replace_sh_bool, IFCFG, USERCTL ],
+ [ "name", \&gst_replace_sh, IFCFG, NAME ],
+ [ "dev", \&gst_replace_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_replace_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_replace_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_replace_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_replace_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_replace_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_replace_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key", \&gst_replace_sh, IFCFG, WIRELESS_KEY ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_sh, IFCFG, WIRELESS_KEY, "%key%" ]],
+ [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_sh_bool, IFCFG, PEERDNS ],
+ [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+ [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMIP ],
+ [ "login", \&gst_replace_sh, IFCFG, PAPNAME ],
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, LINESPEED ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPOPTIONS ],
+ [ "section", \&gst_replace_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_replace_sh_bool, IFCFG, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "vine-3.0" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate,
+ iface_delete => \&gst_network_rh62_interface_delete,
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ WVDIAL => "/etc/wvdial.conf",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_replace_sh_bool, IFCFG, ONBOOT ],
+ [ "user", \&gst_replace_sh_bool, IFCFG, USERCTL ],
+ [ "name", \&gst_replace_sh, IFCFG, NAME ],
+ [ "dev", \&gst_replace_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_replace_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_replace_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_replace_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_replace_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_replace_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_replace_sh, IFCFG, ESSID ],
+ [ "key", \&gst_replace_sh, IFCFG, KEY ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_sh, IFCFG, KEY, "%key%" ]],
+ [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_sh_bool, IFCFG, PEERDNS ],
+ [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+ [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMIP ],
+ [ "login", \&gst_replace_sh, IFCFG, PAPNAME ],
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, LINESPEED ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPOPTIONS ],
+ [ "section", \&gst_replace_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_replace_sh_bool, IFCFG, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "mandrake-9.0" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate,
+ iface_delete => \&gst_network_rh62_interface_delete,
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ WVDIAL => "/etc/wvdial.conf",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_replace_sh_bool, IFCFG, ONBOOT ],
+ [ "user", \&gst_replace_sh_bool, IFCFG, USERCTL ],
+ [ "name", \&gst_replace_sh, IFCFG, NAME ],
+ [ "dev", \&gst_replace_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_replace_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_replace_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_replace_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_replace_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_replace_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_replace_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key", \&gst_replace_sh, IFCFG, WIRELESS_KEY ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_sh, IFCFG, WIRELESS_KEY, "%key%" ]],
+ [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_sh_bool, IFCFG, PEERDNS ],
+ [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+ [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMIP ],
+ [ "login", \&gst_replace_sh, IFCFG, PAPNAME ],
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, LINESPEED ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPOPTIONS ],
+ [ "section", \&gst_replace_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_replace_sh_bool, IFCFG, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "conectiva-9" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate,
+ iface_delete => \&gst_network_rh62_interface_delete,
+ ifaces_get => \&gst_network_sysconfig_rh62_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network-scripts/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/network-scripts/chat-#iface#",
+ IFACE => "#iface#",
+ WVDIAL => "/etc/wvdial.conf",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_rh62_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_replace_sh_bool, IFCFG, ONBOOT ],
+ [ "user", \&gst_replace_sh_bool, IFCFG, USERCTL ],
+ [ "name", \&gst_replace_sh, IFCFG, NAME ],
+ [ "dev", \&gst_replace_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_replace_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_replace_sh, IFCFG, NETMASK ],
+ [ "broadcast", \&gst_replace_sh, IFCFG, BROADCAST ],
+ [ "network", \&gst_replace_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_replace_sh, IFCFG, GATEWAY ],
+ [ "essid", \&gst_replace_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key", \&gst_replace_sh, IFCFG, WIRELESS_KEY ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_sh, IFCFG, WIRELESS_KEY, "%key%" ]],
+ [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_sh_bool, IFCFG, PEERDNS ],
+ [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+ [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMIP ],
+ [ "login", \&gst_replace_sh, IFCFG, PAPNAME ],
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, LINESPEED ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPOPTIONS ],
+ [ "section", \&gst_replace_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_replace_sh_bool, IFCFG, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+ # wvdial settings
+ [ "phone_number", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Phone" ]],
+ [ "update_dns", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto DNS" ]],
+ [ "login", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Username" ]],
+ [ "password", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Password" ]],
+ [ "serial_port", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Modem" ]],
+ [ "serial_speed", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Baud" ]],
+ [ "set_default_gw", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Check Def Route" ]],
+ [ "persist", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Auto Reconnect" ]],
+ [ "dial_command", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Command" ]],
+ [ "external_line", \&gst_network_check_type, ["%dev%", "modem", \&gst_replace_ini, WVDIAL, "Dialer %section%", "Dial Prefix" ]],
+ ]
+ },
+
+ "debian-2.2" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate, # They use the same ifup/ifdown cmds.
+ iface_delete => \&gst_network_deb22_interface_delete,
+ ifaces_get => \&gst_network_debian_ifaces_get_existing,
+ fn =>
+ {
+ INTERFACES => "/etc/network/interfaces",
+ IFACE => "#iface#",
+ CHAT => "/etc/chatscripts/%section%",
+ PPP_OPTIONS => "/etc/ppp/peers/%section%",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+# not sup [ "user", \&gst_parse_sh_bool, IFCFG, USERCTL ],
+ [ "_always_", \&gst_network_deb22_replace_bootproto, [INTERFACES, IFACE]],
+ [ "bootproto", \&gst_network_deb22_replace_bootproto, [INTERFACES, IFACE]],
+ [ "auto", \&gst_replace_interfaces_option_kw_not, [INTERFACES, IFACE], "noauto" ],
+ [ "name", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "name" ],
+ [ "address", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "address" ],
+ [ "netmask", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "netmask" ],
+ [ "broadcast", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "broadcast" ],
+ [ "network", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "network" ],
+ [ "gateway", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "gateway" ],
+ [ "section", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "provider" ],
+ [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_kw, PPP_OPTIONS, "usepeerdns" ],
+# not sup [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+# not sup [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "noauth", \&gst_replace_kw, PPP_OPTIONS, "noauth" ],
+ [ "mtu", \&gst_replace_join_first_str, PPP_OPTIONS, "mtu", "[ \t]+" ],
+ [ "mru", \&gst_replace_join_first_str, PPP_OPTIONS, "mru", "[ \t]+" ],
+ [ "remote_address", \&gst_network_debian_replace_remote_address, [INTERFACES, IFACE]],
+ [ "login", \&gst_replace_join_first_str, PPP_OPTIONS, "user", "[ \t]+" ],
+ [ "serial_port", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^(/dev/[^ \t]+)" ],
+ [ "serial_speed", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^([0-9]+)" ],
+ [ "section", \&gst_network_set_ppp_options_connect, PPP_OPTIONS ],
+ [ "ppp_options", \&gst_network_set_ppp_options_unsup, PPP_OPTIONS ],
+ [ "set_default_gw", \&gst_replace_kw, PPP_OPTIONS, "defaultroute" ],
+ [ "debug", \&gst_replace_kw, PPP_OPTIONS, "debug" ],
+ [ "persist", \&gst_replace_kw, PPP_OPTIONS, "persist" ],
+ [ "serial_escapechars", \&gst_replace_join_first_str, PPP_OPTIONS, "escape", "[ \t]+" ],
+ [ "serial_hwctl", \&gst_replace_kw, PPP_OPTIONS, "crtscts" ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ],
+ ]
+ },
+
+ # Basicly the same as debian-2.2, but the "auto" option changes.
+ "debian-3.0" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate, # They use the same ifup/ifdown cmds.
+ iface_delete => \&gst_network_deb22_interface_delete,
+ ifaces_get => \&gst_network_debian_ifaces_get_existing,
+ fn =>
+ {
+ INTERFACES => "/etc/network/interfaces",
+ IFACE => "#iface#",
+ CHAT => "/etc/chatscripts/%section%",
+ PPP_OPTIONS => "/etc/ppp/peers/%section%",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ },
+ table =>
+ [
+ [ "_always_", \&gst_network_deb22_replace_bootproto, [INTERFACES, IFACE]],
+ [ "bootproto", \&gst_network_deb22_replace_bootproto, [INTERFACES, IFACE]],
+ [ "auto", \&gst_network_debian_woody_set_auto, [INTERFACES, IFACE]],
+ [ "address", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "address" ],
+ [ "netmask", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "netmask" ],
+ [ "gateway", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "gateway" ],
+ [ "essid", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "wireless-essid" ],
+ [ "key", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "wireless-key" ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_interfaces_option_str, INTERFACES, IFACE, "wireless-key", "%key%" ]],
+ # ugly hack for deleting undesired options (due to syntax duality)
+ [ "essid", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "wireless_essid", "" ],
+ [ "key", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "wireless_key", "" ],
+ [ "key", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "wireless_key1", "" ],
+ # End of hack
+ [ "section", \&gst_replace_interfaces_option_str, [INTERFACES, IFACE], "provider" ],
+ [ "remote_address", \&gst_network_debian_replace_remote_address, [INTERFACES, IFACE]],
+ # Modem stuff
+ [ "section", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_ppp_options_connect, PPP_OPTIONS ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_network_create_pppscript, CHAT ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "isdn", \&gst_network_create_isdn_options, PPP_OPTIONS ]],
+ [ "update_dns", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_replace_kw, PPP_OPTIONS, "usepeerdns" ]],
+ [ "noauth", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_replace_kw, PPP_OPTIONS, "noauth" ]],
+ [ "set_default_gw", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_replace_kw, PPP_OPTIONS, "defaultroute" ]],
+ [ "debug", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_replace_kw, PPP_OPTIONS, "debug" ]],
+ [ "persist", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_replace_kw, PPP_OPTIONS, "persist" ]],
+ [ "serial_hwctl", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_kw, PPP_OPTIONS, "crtscts" ]],
+ [ "mtu", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_replace_join_first_str, PPP_OPTIONS, "mtu", "[ \t]+" ]],
+ [ "mru", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_replace_join_first_str, PPP_OPTIONS, "mru", "[ \t]+" ]],
+ [ "serial_port", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^(/dev/[^ \t]+)" ]],
+ [ "serial_speed", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^([0-9]+)" ]],
+ [ "login", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^user (.*)", "user \"%login%\"" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_network_set_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "(modem|isdn)", \&gst_network_set_pap_passwd, CHAP, "%login%" ]],
+ [ "serial_escapechars", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_join_first_str, PPP_OPTIONS, "escape", "[ \t]+" ]],
+ [ "dial_command", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_chat, CHAT, "(atd[tp])[0-9w, -]+" ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_chat, CHAT, "atd[tp]([0-9w]+)" ]],
+ [ "external_line", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_chat, CHAT, "atd[tp]([0-9w, -]+)", "%external_line%W%phone_number%" ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "isdn", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^number (.*)", "number %phone_number%" ]],
+ [ "external_line", \&gst_network_check_type, [IFACE, "isdn", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^number (.*)", "number %external_line%W%phone_number%" ]],
+ [ "volume", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_modem_volume, CHAT ]],
+ ]
+ },
+
+ "suse-7.0" =>
+ {
+ iface_set => \&gst_network_suse70_interface_activate,
+ iface_delete => \&gst_network_suse70_interface_delete,
+ ifaces_get => \&gst_network_suse70_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/rc.config",
+ IFACE => "#iface#",
+ PPP_OPTIONS => "/etc/ppp/options"
+ },
+ table =>
+ [
+# bootproto has to go second for suse, as it uses the same value for bootproto and params.
+ [ "bootproto", \&gst_network_suse70_replace_bootproto, [IFCFG, IFACE] ],
+ [ "auto", \&gst_network_suse70_replace_iface_auto, [IFCFG, IFACE], NETCONFIG ],
+ [ "dev", \&gst_network_suse70_replace_iface_sh, [IFCFG, IFACE], NETDEV ],
+# not sup [ "user", \&gst_parse_trivial, 0 ], # not supported.
+ [ "name", \&gst_network_suse70_replace_iface_sh, [IFCFG, IFACE], GST_IFACE_NAME ],
+ [ "address", \&gst_network_suse70_replace_iface_sh, [IFCFG, IFACE], IPADDR ],
+ [ "address", \&gst_network_suse70_set_ifconfig_ip, [IFCFG, IFACE] ],
+ [ "netmask", \&gst_network_suse70_set_ifconfig_arg, [IFCFG, IFACE], netmask ],
+ [ "broadcast", \&gst_network_suse70_set_ifconfig_arg, [IFCFG, IFACE], broadcast ],
+# [ "network", \&gst_parse_trivial, 0 ], # not supported.
+# [ "gateway", \&gst_parse_sh, IFCFG, GATEWAY ], # not supported
+ [ "remote_address", \&gst_network_suse70_set_ifconfig_arg, [IFCFG, IFACE], pointopoint ],
+ [ "update_dns", \&gst_replace_kw, PPP_OPTIONS, "usepeerdns" ]
+ ]
+ },
+
+ "suse-9.0" =>
+ {
+ iface_set => \&gst_network_suse9_interface_activate,
+ iface_delete => \&gst_network_suse90_interface_delete,
+ ifaces_get => \&gst_network_suse90_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/network/ifcfg-#iface#",
+ ROUTE_CONF => "/etc/sysconfig/network/routes",
+ IFACE => "#iface#",
+ PPP_OPTIONS => "/etc/ppp/options"
+ },
+ table =>
+ [
+ [ "auto", \&gst_network_suse90_set_auto, IFCFG, STARTMODE ],
+ [ "bootproto", \&gst_network_suse90_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "address", \&gst_replace_sh, IFCFG, IPADDR ],
+ [ "netmask", \&gst_replace_sh, IFCFG, NETMASK ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMOTE_IPADDR ],
+ [ "essid", \&gst_replace_sh, IFCFG, WIRELESS_ESSID ],
+ [ "key", \&gst_replace_sh, IFCFG, WIRELESS_KEY ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_sh, IFCFG, WIRELESS_KEY, "%key%" ]],
+ # Modem stuff goes here
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEM_DEVICE ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, SPEED ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPD_OPTIONS ],
+ [ "dial_command", \&gst_replace_sh, IFCFG, DIALCOMMAND ],
+ [ "external_line", \&gst_replace_sh, IFCFG, DIALPREFIX ],
+ [ "provider", \&gst_replace_sh, IFCFG, PROVIDER ],
+ [ "volume", \&gst_network_check_type, [ IFACE, "modem", \&gst_network_set_modem_volume_string, IFCFG, INIT8 ]],
+ [ "login", \&gst_network_suse90_replace_provider_file, "%provider%", USERNAME ],
+ [ "password", \&gst_network_suse90_replace_provider_file, "%provider%", PASSWORD ],
+ [ "phone_number", \&gst_network_suse90_replace_provider_file, "%provider%", PHONE ],
+ [ "dns1", \&gst_network_suse90_replace_provider_file, "%provider%", DNS1 ],
+ [ "dns2", \&gst_network_suse90_replace_provider_file, "%provider%", DNS2 ],
+ [ "update_dns", \&gst_network_suse90_replace_provider_file_bool, "%provider%", MODIFYDNS ],
+ [ "stupid", \&gst_network_suse90_replace_provider_file_bool, "%provider%", STUPIDMODE ],
+ [ "persist", \&gst_network_suse90_replace_provider_file_bool, "%provider%", PERSIST ],
+ [ "set_default_gw", \&gst_network_suse90_replace_provider_file_bool, "%provider%", DEFAULTROUTE ],
+ ]
+ },
+
+ "pld-1.0" =>
+ {
+ iface_set => \&gst_network_rh62_interface_activate,
+ iface_delete => \&gst_network_pld10_interface_delete,
+ ifaces_get => \&gst_network_sysconfig_pld10_ifaces_get_existing,
+ fn =>
+ {
+ IFCFG => "/etc/sysconfig/interfaces/ifcfg-#iface#",
+ CHAT => "/etc/sysconfig/interfaces/data/chat-#iface#",
+ IFACE => "#iface#",
+ WVDIAL => "/etc/wvdial.conf",
+ PUMP => "/etc/pump.conf"
+ },
+ table =>
+ [
+ [ "bootproto", \&gst_network_pld10_replace_bootproto, IFCFG, BOOTPROTO ],
+ [ "auto", \&gst_replace_sh_bool, IFCFG, ONBOOT ],
+ [ "user", \&gst_replace_sh_bool, IFCFG, USERCTL ],
+# [ "name", \&gst_replace_sh, IFCFG, NAME ],
+ [ "dev", \&gst_replace_sh, IFCFG, DEVICE ],
+ [ "address", \&gst_network_pld10_set_ipaddr, IFCFG, IPADDR, "address" ],
+ [ "netmask", \&gst_network_pld10_set_ipaddr, IFCFG, IPADDR, "netmask" ],
+# [ "broadcast", \&gst_replace_sh, IFCFG, BROADCAST ],
+# [ "network", \&gst_replace_sh, IFCFG, NETWORK ],
+ [ "gateway", \&gst_replace_sh, IFCFG, GATEWAY ],
+# [ "update_dns", \&gst_network_pump_set_nodns, PUMP, "%dev%", "%bootproto%" ],
+ [ "update_dns", \&gst_replace_sh_bool, IFCFG, PEERDNS ],
+# [ "dns1", \&gst_replace_sh, IFCFG, DNS1 ],
+# [ "dns2", \&gst_replace_sh, IFCFG, DNS2 ],
+ [ "mtu", \&gst_replace_sh, IFCFG, MTU ],
+ [ "mru", \&gst_replace_sh, IFCFG, MRU ],
+ [ "remote_address", \&gst_replace_sh, IFCFG, REMIP ],
+ [ "login", \&gst_replace_sh, IFCFG, PAPNAME ],
+ [ "serial_port", \&gst_replace_sh, IFCFG, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, IFCFG, LINESPEED ],
+ [ "ppp_options", \&gst_replace_sh, IFCFG, PPPOPTIONS ],
+# [ "section", \&gst_replace_sh, IFCFG, WVDIALSECT ],
+ [ "set_default_gw", \&gst_replace_sh_bool, IFCFG, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, IFCFG, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, IFCFG, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, IFCFG, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, IFCFG, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_chat, CHAT, "^atd[^0-9]*([0-9, -]+)" ]
+ ]
+ },
+
+ "slackware-9.1.0" =>
+ {
+ iface_set => \&gst_network_slackware91_interface_activate,
+ iface_delete => \&gst_network_slackware91_interface_delete,
+ ifaces_get => \&gst_network_slackware91_ifaces_get_existing,
+ fn =>
+ {
+ RC_INET_CONF => "/etc/rc.d/rc.inet1.conf",
+ RC_INET => "/etc/rc.d/rc.inet1",
+ RC_LOCAL => "/etc/rc.d/rc.local",
+ IFACE => "#iface#",
+ WIRELESS => "/etc/pcmcia/wireless.opts",
+ PPP_OPTIONS => "/etc/ppp/options",
+ PAP => "/etc/ppp/pap-secrets",
+ CHAP => "/etc/ppp/chap-secrets",
+ CHAT => "/etc/ppp/pppscript",
+ },
+ table =>
+ [
+ [ "address", \&gst_replace_rcinet1conf, [ RC_INET_CONF, IFACE ], IPADDR ],
+ [ "netmask", \&gst_replace_rcinet1conf, [ RC_INET_CONF, IFACE ], NETMASK ],
+ [ "gateway", \&gst_replace_rcinet1conf_global, RC_INET_CONF, GATEWAY ],
+ [ "bootproto", \&gst_network_slackware91_replace_bootproto, [ RC_INET_CONF, IFACE ] ],
+ [ "auto", \&gst_network_slackware91_set_auto, [ RC_INET, RC_LOCAL, IFACE ] ],
+ [ "essid", \&gst_replace_wireless_opts, [ WIRELESS, IFACE ], \&gst_network_get_wireless_ifaces, ESSID ],
+ [ "key", \&gst_replace_wireless_opts, [ WIRELESS, IFACE ], \&gst_network_get_wireless_ifaces, KEY ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_wireless_opts, [ WIRELESS, IFACE ], \&gst_network_get_wireless_ifaces, KEY, "%key%" ]],
+ # Modem stuff
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_network_create_pppscript, CHAT ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_network_slackware91_create_pppgo ]],
+ [ "update_dns", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_kw, PPP_OPTIONS, "usepeerdns" ]],
+ [ "noauth", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_kw, PPP_OPTIONS, "noauth" ]],
+ [ "set_default_gw", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_kw, PPP_OPTIONS, "defaultroute" ]],
+ [ "debug", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_kw, PPP_OPTIONS, "debug" ]],
+ [ "persist", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_kw, PPP_OPTIONS, "persist" ]],
+ [ "serial_hwctl", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_kw, PPP_OPTIONS, "crtscts" ]],
+ [ "mtu", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_join_first_str, PPP_OPTIONS, "mtu", "[ \t]+" ]],
+ [ "mru", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_join_first_str, PPP_OPTIONS, "mru", "[ \t]+" ]],
+ [ "serial_port", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^(/dev/[^ \t]+)" ]],
+ [ "serial_speed", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^([0-9]+)" ]],
+ [ "login", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_ppp_options_re, PPP_OPTIONS, "^name \"(.*)\"", "name \"%login%\"" ]],
+ [ "ppp_options", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_ppp_options_unsup, PPP_OPTIONS ]],
+ [ "serial_escapechars", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_join_first_str, PPP_OPTIONS, "escape", "[ \t]+" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_pap_passwd, PAP, "%login%" ]],
+ [ "password", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_pap_passwd, CHAP, "%login%" ]],
+ [ "dial_command", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_chat, CHAT, "(atd[tp])[0-9w, -]+" ]],
+ [ "phone_number", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_chat, CHAT, "atd[tp]([0-9w]+)" ]],
+ [ "external_line", \&gst_network_check_type, [IFACE, "modem", \&gst_replace_chat, CHAT, "atd[tp]([0-9w, -]+)", "%external_line%W%phone_number%" ]],
+ [ "volume", \&gst_network_check_type, [IFACE, "modem", \&gst_network_set_modem_volume, CHAT ]],
+ ]
+ },
+
+ "gentoo" =>
+ {
+ iface_set => \&gst_network_gentoo_interface_activate,
+ iface_delete => \&gst_network_gentoo_interface_delete,
+ ifaces_get => \&gst_network_gentoo_ifaces_get_existing,
+ fn =>
+ {
+ NET => "/etc/conf.d/net",
+ PPPNET => "/etc/conf.d/net.#iface#",
+ INIT => "net.#iface#",
+ IFACE => "#iface#",
+ WIRELESS => "/etc/conf.d/wireless",
+ },
+ table =>
+ [
+ [ "dev", \&gst_network_gentoo_create_files ],
+ [ "auto", \&gst_service_gentoo_set_status, INIT , 0 ],
+ [ "bootproto", \&gst_network_gentoo_replace_bootproto, [ NET, IFACE ]],
+ [ "address", \&gst_replace_confd_net_re, NET, "config_%dev%", "^[ \t]*([0-9\.]+)" ],
+ [ "address", \&gst_replace_confd_net_re, NET, "config_%dev%", "^[ \t]*([0-9\.]+)" ],
+ [ "netmask", \&gst_replace_confd_net_re, NET, "config_%dev%", "[ \t]+netmask[ \t]+[0-9\.]*", " netmask %netmask%"],
+ [ "broadcast", \&gst_replace_confd_net_re, NET, "config_%dev%", "[ \t]+broadcast[ \t]+[0-9\.]*", " broadcast %broadcast%" ],
+ [ "remote_address", \&gst_replace_confd_net_re, NET, "config_%dev%", "[ \t]+dest_address[ \t]+[0-9\.]*", " dest_address %remote_address%" ],
+ [ "gateway", \&gst_replace_confd_net_re, NET, "routes_%dev%", "[ \t]*default[ \t]+(via|gw)[ \t]+[0-9\.\:]*", "default via %gateway%" ],
+ [ "essid", \&gst_replace_sh, WIRELESS, "essid_%dev%" ],
+ [ "key", \&gst_replace_sh, WIRELESS, "key_%essid%" ],
+ [ "key_type", \&gst_network_set_wep_key_type, [ \&gst_replace_sh, WIRELESS, "key_%essid%", "%key%" ]],
+ # modem stuff
+ [ "dev", \&gst_network_check_type, [ IFACE, "modem", \&gst_replace_sh, PPPNET, PEER ]],
+ [ "update_dns", \&gst_network_check_type, [ IFACE, "modem", \&gst_replace_sh_bool, PPPNET, PEERDNS ]],
+ [ "mtu", \&gst_replace_sh, PPPNET, MTU ],
+ [ "mru", \&gst_replace_sh, PPPNET, MRU ],
+ [ "serial_port", \&gst_replace_sh, PPPNET, MODEMPORT ],
+ [ "serial_speed", \&gst_replace_sh, PPPNET, LINESPEED ],
+ [ "login", \&gst_replace_sh, PPPNET, USERNAME ],
+ [ "password", \&gst_replace_sh, PPPNET, PASSWORD ],
+ [ "ppp_options", \&gst_replace_sh, PPPNET, PPPOPTIONS ],
+ [ "set_default_gw", \&gst_replace_sh_bool, PPPNET, DEFROUTE ],
+ [ "debug", \&gst_replace_sh_bool, PPPNET, DEBUG ],
+ [ "persist", \&gst_replace_sh_bool, PPPNET, PERSIST ],
+ [ "serial_escapechars", \&gst_replace_sh_bool, PPPNET, ESCAPECHARS ],
+ [ "serial_hwctl", \&gst_replace_sh_bool, PPPNET, HARDFLOWCTL ],
+ [ "phone_number", \&gst_replace_sh, PPPNET, NUMBER ],
+ [ "external_line", \&gst_replace_sh, PPPNET, NUMBER, "%external_line%W%phone_number%" ],
+ [ "volume", \&gst_network_set_modem_volume_string, PPPNET, INITSTRING ],
+ ]
+ },
+
+ "freebsd-5" =>
+ {
+ iface_set => \&gst_network_freebsd_interface_activate,
+ iface_delete => \&gst_network_freebsd_interface_delete,
+ ifaces_get => \&gst_network_freebsd_ifaces_get_existing,
+ fn =>
+ {
+ RC_CONF => "/etc/rc.conf",
+ STARTIF => "/etc/start_if.#iface#",
+ PPPCONF => "/etc/ppp/ppp.conf",
+ IFACE => "#iface#",
+ },
+ table =>
+ [
+ [ "auto", \&gst_network_freebsd5_set_auto, [ RC_CONF, IFACE ]],
+ [ "bootproto", \&gst_network_freebsd5_replace_bootproto, [ RC_CONF, IFACE ]],
+ [ "address", \&gst_replace_sh_re, RC_CONF, "ifconfig_%dev%", "inet[ \t]+([0-9\.]+)", "inet %address%" ],
+ [ "netmask", \&gst_replace_sh_re, RC_CONF, "ifconfig_%dev%", "netmask[ \t]+([0-9\.]+)", " netmask %netmask%" ],
+ [ "remote_address", \&gst_replace_sh_re, RC_CONF, "ifconfig_%dev%", "dest_address[ \t]+([0-9\.]+)", " dest_address %remote_address%" ],
+ [ "essid", \&gst_network_freebsd5_replace_essid, [ RC_CONF, STARTIF, IFACE ]],
+ # Modem stuff
+ # we need this for putting an empty ifconfig_tunX command in rc.conf
+ [ "phone_number", \&gst_replace_sh, RC_CONF, "ifconfig_%dev%", " " ],
+ [ "file", \&gst_network_freebsd_create_ppp_startif, [ STARTIF, IFACE ]],
+ [ "persist", \&gst_network_freebsd_create_ppp_startif, [ STARTIF, IFACE ], "%file%" ],
+ [ "serial_port", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "device" ],
+ [ "serial_speed", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "speed" ],
+ [ "mtu", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "mtu" ],
+ [ "mru", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "mru" ],
+ [ "login", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "authname" ],
+ [ "password", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "authkey" ],
+ [ "update_dns", \&gst_network_replace_pppconf_bool, [ PPPCONF, STARTIF, IFACE ], "dns" ],
+ [ "set_default_gw", \&gst_network_replace_pppconf_route, [ PPPCONF, STARTIF, IFACE ], "default HISADDR" ],
+ [ "phone_number", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "phone" ],
+ [ "external_line", \&gst_network_replace_pppconf, [ PPPCONF, STARTIF, IFACE ], "phone", "%external_line%W%phone_number%" ],
+ [ "dial_command", \&gst_network_replace_pppconf_dial_command, [ PPPCONF, STARTIF, IFACE ]],
+ [ "volume", \&gst_network_replace_pppconf_volume, [ PPPCONF, STARTIF, IFACE ]],
+ ]
+ }
+ );
+
+ my $dist = $dist_map{$gst_dist};
+ return %{$dist_tables{$dist}} if $dist;
+
+ &gst_report ("platform_no_table", $gst_dist);
+ return undef;
+}
+
+1;
diff --git a/knetworkconf/backends/parse.pl.in b/knetworkconf/backends/parse.pl.in
new file mode 100644
index 0000000..9bad7d8
--- /dev/null
+++ b/knetworkconf/backends/parse.pl.in
@@ -0,0 +1,1828 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# parse.pl: Common parsing stuff for the ximian-setup-tools backends.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Arturo Espinosa <arturo@ximian.com>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/){
+
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/util.pl$DOTIN";
+require "$SCRIPTSDIR/file.pl$DOTIN";
+require "$SCRIPTSDIR/debug.pl$DOTIN";
+
+
+# The concept of keyword (kw) here is a key, normaly in its own line, whose
+# boolean representation is its own existence.
+
+# Every final parsing function to be used by a table must handle one key
+# at a time, but maybe parse several values from there and return a
+# ref to array or hash.
+#
+# Always return a scalar. If you need to return an array or a hash,
+# return a ref to it.
+
+# First some helper functions for the whole process.
+# Expand substrings of the form #$substr# to the $value in
+# the string or recursively in the array $strarr.
+
+sub gst_parse_expand
+{
+ my ($strarr, $substr, $value) = @_;
+
+ if (ref $strarr eq "ARRAY")
+ {
+ my ($i);
+
+ $strarr = [ @$strarr ];
+ foreach $i (@$strarr)
+ {
+ $i = &gst_parse_expand ($i, $substr, $value);
+ }
+
+ return $strarr;
+ }
+
+ $strarr =~ s/\#$substr\#/$value/;
+ return $strarr;
+}
+
+sub gst_parse_replace_hash_values
+{
+ my ($cp, $hash) = @_;
+ my ($j, $replace_key, $value);
+
+ foreach $j (@$cp)
+ {
+ while ($j =~ /%([^%]*)%/)
+ {
+ $replace_key = $1;
+ if (exists $$hash{$replace_key})
+ {
+ $value = $$hash{$replace_key};
+ if (ref $value)
+ {
+ $j = $value;
+ }
+ else
+ {
+ $j =~ s/%$replace_key%/$value/g;
+ }
+ }
+ else
+ {
+ &gst_debug_print_line ("Warning: gst_parse_replace_hash_values: key $replace_key doesn't exist.");
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+sub gst_parse_replace_files
+{
+ my ($values, $fn_hash) = @_;
+ my @ret;
+
+ return () if $values eq undef;
+ $values = [$values] if !ref $values;
+
+ foreach $i (@$values)
+ {
+ if (exists $$fn_hash{$i})
+ {
+ push @ret, $$fn_hash{$i};
+ }
+ else
+ {
+ push @ret, $i;
+ }
+ }
+
+ return @ret;
+}
+
+# Additional abstraction: parse table entries can have
+# arrays inside. The parsing proc will be ran with every
+# combination that the arrays provide. Ex:
+# ["user", \&gst_parse_foo, [0, 1], [2, 3] ] will parse
+# using the combinatory of [0, 1]x[2, 3] until a result
+# ne undef is given. Check RedHat 7.2's network parse table
+# for further enlightenment.
+sub gst_parse_run_entry
+{
+ my ($hash, $key, $proc, $cp) = @_;
+ my ($ncp, $i, $j, $res);
+
+ $ncp = [@$cp];
+ for ($i = 0; $i < scalar (@$cp); $i ++)
+ {
+ if (ref $$cp[$i] eq "ARRAY")
+ {
+ foreach $j (@{$$cp[$i]})
+ {
+ $$ncp[$i] = $j;
+ $res = &gst_parse_run_entry ($hash, $key, $proc, $ncp);
+ return $res if $res ne undef;
+ }
+ return undef;
+ }
+ }
+
+ # OK, the given entry didn't have any array refs in it...
+
+ return undef if (!&gst_parse_replace_hash_values ($cp, $hash));
+
+ &gst_report_enter ();
+ &gst_report ("parse_table", "$key");
+ &gst_report_leave ();
+
+ $$hash{$key} = &$proc (@$cp);
+ return $$hash{$key};
+}
+
+# OK, this is the good stuff:
+
+# gst_parse_from_table takes a file mapping and a parse table.
+#
+# The functions in the replace tables, most of which are coded in
+# this file, receive the mapped files of the first argument, and then
+# a set of values.
+
+# The value the parse function returns is set into a hash,
+# using as key the first item of the parse table entry. This is done
+# only if the $hash{$key} is empty, which allows us to try with
+# several parse methods to try to get a value, where our parse functions
+# can return undef if they failed to get the requested value.
+#
+# A ref to the hash with all the fetched values is returned.
+sub gst_parse_from_table
+{
+ my ($fn, $table) = @_;
+ my %hash;
+ my ($key, $proc, @param);
+ my ($i, @cp, @files);
+
+ foreach $i (@$table)
+ {
+ @cp = @$i;
+ $key = shift (@cp);
+
+ if ($hash{$key} eq undef)
+ {
+ $proc = shift (@cp);
+ @files = &gst_parse_replace_files (shift (@cp), $fn);
+
+ # Don't unshift the resulting files if none were given.
+ unshift @cp, @files if (scalar @files) > 0;
+
+ &gst_parse_run_entry (\%hash, $key, $proc, \@cp);
+ }
+ }
+
+ foreach $i (keys (%hash))
+ {
+ delete $hash{$i} if ($hash{$i} eq undef);
+ }
+
+ return \%hash;
+}
+
+# Just return the passed values. If there's just
+# one value, the value. If more, a reference to an
+# array with the values.
+sub gst_parse_trivial
+{
+ my (@res) = @_;
+
+ &gst_report_enter ();
+ &gst_report ("parse_trivial", "@res");
+ &gst_report_leave ();
+
+ return $res[0] if (scalar @res) <= 1;
+ return \@res;
+}
+
+# Try to read a line from $fd and remove any leading or
+# trailing white spaces. Return ref to read $line or
+# -1 if eof.
+sub gst_parse_chomp_line_std
+{
+ my ($fd) = @_;
+ my $line;
+
+ $line = <$fd>;
+ return -1 if !$line;
+
+ chomp $line;
+ $line =~ s/^[ \t]+//;
+ $line =~ s/[ \t]+$//;
+
+ return \$line;
+}
+
+# Assuming $line is a line read from a shell file,
+# remove comments.
+sub gst_parse_process_sh_line
+{
+ my ($line) = @_;
+ my ($pline);
+
+ # This will put escaped hashes out of danger.
+ # But only inside valid quotes!
+ while ($line =~ /([^\"\']*[\"\'][^\#\"\']*)(\#?)([^\"\']*[\"\'])/g)
+ {
+ $pline .= $1;
+ $pline .= "__hash__" if ($2 ne undef);
+ $pline .= $3;
+ }
+
+ # The line may not match the regexp above,
+ $pline = $line if ($pline eq undef);
+
+ $pline =~ s/\\\#/\\__hash__/g;
+
+ # Nuke everything after a hash and bye bye trailing spaces.
+ $pline =~ s/[ \t]*\#.*//;
+
+ # Let escaped hashes come back home.
+ $pline =~ s/__hash__/\#/g;
+
+ return $pline;
+}
+
+# Same as gst_parse_chomp_line_std, but apply
+# the sh line processing before returning.
+# -1 if eof, ref to read $line if success.
+sub gst_parse_chomp_line_hash_comment
+{
+ my ($fd) = @_;
+ my $line;
+
+ $line = &gst_parse_chomp_line_std ($fd);
+ return -1 if $line == -1;
+
+ $line = &gst_parse_process_sh_line ($$line);
+ return \$line;
+}
+
+# Get an sh line, and remove the export keyword, if any.
+sub gst_parse_chomp_line_sh_export
+{
+ my ($fd) = @_;
+ my $line;
+
+ $line = &gst_parse_chomp_line_hash_comment ($fd);
+ return -1 if $line == -1;
+
+ $line = $$line;
+
+ $line =~ s/^export //;
+
+ return \$line;
+}
+
+# Parse a $file, wich is assumed to have a column-based format, with $re matching field separators
+# and one record per line. Search for $key, and return either a scalar with the first ocurrence,
+# or an array with all the found ocurrences.
+sub gst_parse_split_ref
+{
+ my ($file, $key, $re, $all, $line_read_proc) = @_;
+ my ($fd, @line, @res);
+
+ &gst_report_enter ();
+ &gst_report ("parse_split", $key, $file);
+
+ $proc = $line_read_proc? $line_read_proc : \&gst_parse_chomp_line_std;
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $all = 0 if !$fd;
+
+ while (($line = &$proc ($fd)) != -1)
+ {
+ $line = $$line;
+ next if $line eq "";
+
+ @line = split ($re, $line, 2);
+
+ if (shift (@line) =~ "^$key\$")
+ {
+ if ($all) {
+ push @res, $line[0];
+ }
+ else
+ {
+ &gst_report_leave ();
+ &gst_file_close ($fd);
+ return \$line[0];
+ }
+ }
+ }
+
+ &gst_report_leave ();
+ &gst_file_close ($fd);
+ return \@res if ($all);
+ return -1;
+}
+
+sub gst_parse_split
+{
+ my $res;
+
+ # Don't pass @_ like this anywhere. This is bad practice.
+ $res = &gst_parse_split_ref (@_);
+
+ return $$res if ref $res eq "SCALAR";
+ return @$res if ref $res eq "ARRAY";
+ return undef;
+}
+
+# This gives meaning to the $all flag of gst_parse_split, and returns a reference to the array, which
+# is what we want. (ie search a.com\nsearch b.com\nsearch c.com)
+sub gst_parse_split_all
+{
+ my ($file, $key, $re, $line_read_proc) = @_;
+ my @a;
+
+ @a = &gst_parse_split ($file, $key, $re, 1, $line_read_proc);
+
+ return \@a;
+}
+
+# Same, but use the hash_comment routine for line analysis.
+sub gst_parse_split_all_hash_comment
+{
+ my ($file, $key, $re) = @_;
+
+ return &gst_parse_split_all ($file, $key, $re, \&gst_parse_chomp_line_hash_comment);
+}
+
+# Make the elements of the resulting array unique.
+sub gst_parse_split_all_unique_hash_comment
+{
+ my ($file, $key, $re) = @_;
+ my ($arr, @res);
+ my (%hash, $i);
+
+ $arr = &gst_parse_split_all ($file, $key, $re, \&gst_parse_chomp_line_hash_comment);
+
+ foreach $i (@$arr)
+ {
+ next if exists $hash{$i};
+ $hash{$i} = 1;
+ push @res, $i;
+ }
+
+ return \@res;
+}
+
+sub gst_parse_split_all_array_with_pos
+{
+ my ($file, $key, $pos, $re, $sep, $line_read_proc) = @_;
+ my ($arr, @s, @ret, $i);
+
+ $arr = &gst_parse_split_all ($file, $key, $re, $line_read_proc);
+
+ foreach $i (@$arr)
+ {
+ @s = split ($sep, $i);
+ push @ret, @s[0];
+ }
+
+ return \@ret;
+}
+
+# Same, but for $all = 0. (ie nameserver 10.0.0.1)
+sub gst_parse_split_first_str
+{
+ my ($file, $key, $re, $line_read_proc) = @_;
+
+ return &gst_parse_split ($file, $key, $re, 0, $line_read_proc);
+}
+
+# Interpret the result as a boolean. (ie multi on)
+sub gst_parse_split_first_bool
+{
+ my ($file, $key, $re, $line_read_proc) = @_;
+ my $ret;
+
+ $ret = &gst_parse_split_first_str ($file, $key, $re, $line_read_proc);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+# After getting the first field, split the result with $sep matching separators. (ie order hosts,bind)
+sub gst_parse_split_first_array
+{
+ my ($file, $key, $re, $sep, $line_read_proc) = @_;
+ my @ret;
+
+ @ret = split ($sep, &gst_parse_split ($file, $key, $re, 0, $line_read_proc));
+
+ return \@ret;
+}
+
+sub gst_parse_split_first_array_pos
+{
+ my ($file, $key, $pos, $re, $sep, $line_read_proc) = @_;
+ my (@ret);
+
+ @ret = split ($sep, &gst_parse_split ($file, $key, $re, 0, $line_read_proc));
+ return $ret[$pos];
+}
+
+# Do an gst_parse_split_first_array and then make
+# the array elements unique. This is to fix broken
+# searchdomain entries in /etc/resolv.conf, for example.
+sub gst_parse_split_first_array_unique
+{
+ my ($file, $key, $re, $sep, $line_read_proc) = @_;
+ my (@arr, @res);
+ my (%hash, $i);
+
+ @arr = split ($sep, &gst_parse_split ($file, $key, $re, 0, $line_read_proc));
+
+ foreach $i (@arr)
+ {
+ next if exists $hash{$i};
+ $hash{$i} = 1;
+ push @res, $i;
+ }
+
+ return \@res;
+}
+
+# For all keys in $file, sepparated from its values
+# by $key_re, sepparate its values using $value_re
+# and assign to a newly created hash. Use ONLY when
+# you don't know what keys you are going to parse
+# (i.e. /etc/hosts). Any other application will not
+# be very portable and should be avoided.
+sub gst_parse_split_hash
+{
+ my ($file, $key_re, $value_re) = @_;
+ my ($fd, @line, %res, $key);
+
+ &gst_report_enter ();
+ &gst_report ("parse_split_hash", $file);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (<$fd>)
+ {
+ chomp;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+ s/\#.*$//;
+ next if (/^$/);
+ @line = split ($key_re, $_, 2);
+
+ $key = shift (@line);
+ push @{$res{$key}}, split ($value_re, $line[0]);
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+ return undef if (scalar keys (%res) == 0);
+ return \%res;
+}
+
+# Same as above, but join lines that end with '\'.
+sub gst_parse_split_hash_with_continuation
+{
+ my ($file, $key_re, $value_re) = @_;
+ my ($fd, $l, @line, %res, $key);
+
+ &gst_report_enter ();
+ &gst_report ("parse_split_hash_cont", $file);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($l = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$l;
+ chomp;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+ s/\#.*$//;
+ next if (/^$/);
+ @line = split ($key_re, $_, 2);
+
+ $key = shift (@line);
+ $res{$key} = [ split ($value_re, $line[0]) ];
+ }
+
+ &gst_file_close ($fd);
+ &gst_report_leave ();
+ return undef if (scalar keys (%res) == 0);
+ return \%res;
+}
+
+# Remove escape sequences in a shell value.
+sub gst_parse_shell_unescape
+{
+ my $ret = $_[0];
+
+ # Quote shell special chars.
+ $ret =~ s/\\\"/\\_/g;
+ $ret =~ s/\"//g;
+ $ret =~ s/\\_/\"/g;
+ $ret =~ s/\\\'/\\_/g;
+ $ret =~ s/\'//g;
+ $ret =~ s/\\_/\'/g;
+ $ret =~ s/\\(.)/$1/g;
+
+ return $ret;
+}
+
+# unescape (escape (x)) == x
+sub gst_parse_shell_escape
+{
+ my ($value) = @_;
+
+ $value =~ s/([\"\`\$\\])/\\$1/g;
+ $value = "\"$value\"" if ($value =~ /[ \t\'&|*?\[\]\{\}\{\}<>]/);
+
+ return $value;
+}
+
+# For files which are a list of /bin/sh shell variable declarations. (ie GATEWAY=10.10.10.1)
+sub gst_parse_sh
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ &gst_report_enter ();
+ &gst_report ("parse_sh", $key, $file);
+ $ret = &gst_parse_split_first_str ($file, $key, "[ \t]*=[ \t]*",
+ \&gst_parse_chomp_line_hash_comment);
+ &gst_report_leave ();
+
+ return &gst_parse_shell_unescape ($ret);
+}
+
+# Same, but interpret the returning value as a bool. (ie NETWORKING=yes)
+sub gst_parse_sh_bool
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ $ret = &gst_parse_sh ($file, $key);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+# Get an sh value and then split with $re, returning ref to resulting array.
+sub gst_parse_sh_split
+{
+ my ($file, $key, $re) = @_;
+ my (@ret, $val);
+
+ $val = &gst_parse_sh ($file, $key);
+ @ret = split ($re, $val);
+
+ return \@ret;
+}
+
+# Get a fully qualified hostname from a $key shell var in $file
+# and extract the hostname from there. e.g.: suse70's /etc/rc.config's FQHOSTNAME.
+sub gst_parse_sh_get_hostname
+{
+ my ($file, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_sh_split ($file, $key, "\\.");
+
+ return $$val[0];
+}
+
+# Get a fully qualified hostname from a $key shell var in $file
+# and extract the domain from there. e.g.: suse70's /etc/rc.config's FQHOSTNAME.
+sub gst_parse_sh_get_domain
+{
+ my ($file, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_sh_split ($file, $key, "\\.");
+
+ return join ".", @$val[1..$#$val];
+}
+
+# For files which are a list of /bin/sh shell variable exports. (eg export GATEWAY=10.10.10.1)
+sub gst_parse_sh_export
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ &gst_report_enter ();
+ &gst_report ("parse_sh", $key, $file);
+ $ret = &gst_parse_split_first_str ($file, $key, "[ \t]*=[ \t]*",
+ \&gst_parse_chomp_line_sh_export);
+ &gst_report_leave ();
+
+ return &gst_parse_shell_unescape ($ret);
+}
+
+# Same, but interpret the returing value as a bool. (ie export NETWORKING=yes)
+sub gst_parse_sh_export_bool
+{
+ my ($file, $key) = @_;
+ my $ret;
+
+ $ret = &gst_parse_sh_export ($file, $key);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+# Same, but accepting a regexp and returning the value between the paren operator
+sub gst_parse_sh_re
+{
+ my ($file, $key, $re) = @_;
+ my $ret;
+
+ $ret = &gst_parse_sh ($file, $key);
+
+ $ret =~ /$re/i;
+ return $1;
+}
+
+
+# Search for $keyword in $file, delimited by $re (default " ") or EOL.
+# If keyword exists, return 1, else 0.
+sub gst_parse_kw
+{
+ my ($file, $keyword, $re, $line_read_proc) = @_;
+ my $res;
+
+ &gst_report_enter ();
+ &gst_report ("parse_kw", $keyword, $file);
+
+ if (! -f "$gst_prefix/$file")
+ {
+ &gst_report_enter ();
+ &gst_report ("file_open_read_failed", $file);
+ &gst_report_leave ();
+ &gst_report_leave ();
+ return undef;
+ }
+
+ $re = " " if $re eq undef;
+ $res = &gst_parse_split_ref ($file, $keyword, $re, 0, $line_read_proc);
+
+ &gst_report_leave ();
+ return 0 if $res == -1;
+ return 1;
+}
+
+# A file containing the desired value in its first line. (ie /etc/hostname)
+sub gst_parse_line_first
+{
+ my ($file) = @_;
+ my ($fd, $res);
+
+ &gst_report_enter ();
+ &gst_report ("parse_line_first", $file);
+ $fd = &gst_file_open_read_from_names ($file);
+ &gst_report_leave ();
+
+ return undef if !$fd;
+
+ chomp ($res = <$fd>);
+ &gst_file_close ($fd);
+ return $res;
+}
+
+# parse a chat file, searching for an entry that matches $re.
+# $re must have one paren operator (ie "^atd[^0-9]*([0-9, -]+)").
+sub gst_parse_chat
+{
+ my ($file, $re) = @_;
+ my ($fd, $found);
+
+ &gst_report_enter ();
+ &gst_report ("parse_chat", $file);
+ $fd = &gst_file_open_read_from_names ("$file");
+ &gst_report_leave ();
+ return undef if !$fd;
+
+ while (<$fd>)
+ {
+ # We'll be emptying $_ as we "scan".
+ chomp;
+ while ($_ ne "")
+ {
+ # If it uses quotes. FIXME: Assuming they surround the whole string.
+ if (/^\'/)
+ {
+ s/\'([^\']*)\' ?//;
+ $found = $1;
+ }
+ else
+ {
+ s/([^ \t]*) ?//;
+ $found = $1;
+ }
+
+ # If it looks like what we're looking for, return what matched the parens.
+ if ($found =~ /$re/i)
+ {
+ &gst_file_close ($fd);
+ return $1;
+ }
+ }
+ }
+
+ &gst_file_close ($fd);
+ # Oops: not found.
+ return undef;
+}
+
+# Clean an ini line of comments and leading or
+# trailing spaces.
+sub gst_parse_ini_line_clean
+{
+ $_ = $_[0];
+
+ chomp;
+ s/\#.*//;
+ s/;.*//;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+
+ return $_;
+}
+
+# Read an ini line, which may have to be joined
+# with the next one if it ends with '\'.
+sub gst_parse_ini_line_read
+{
+ my $fd = $_[0];
+ my $l;
+
+ $l = <$fd>;
+ return -1 if ($l eq undef);
+
+ $l = &gst_parse_ini_line_clean ($l);
+ while ($l =~ /\\$/)
+ {
+ $l =~ s/\\$//;
+ $l .= &gst_parse_ini_line_clean (scalar <$fd>);
+ }
+
+ return \$l;
+}
+
+# Return an array of all found sections in $file.
+sub gst_parse_ini_sections
+{
+ my ($file) = @_;
+ my (@sections, $line);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ push @sections, $1 if (/\[([^\]]+)\]/i);
+ }
+
+ &gst_file_close ($fd);
+
+ return @sections;
+}
+
+# Get the value of a $var in a $section from $file.
+sub gst_parse_ini
+{
+ my ($file, $section, $var) = @_;
+ my ($fd, $res, $line);
+ my $found_section_flag = 0;
+
+ &gst_report_enter ();
+ &gst_report ("parse_ini", $var, $file, $section);
+ $fd = &gst_file_open_read_from_names ($file);
+ &gst_report_leave ();
+ $res = undef;
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+
+ if (/\[$section\]/i)
+ {
+ $found_section_flag = 1;
+ next;
+ }
+
+ if ($found_section_flag)
+ {
+ if (/^$var[ \t]*=/i)
+ {
+ s/^$var[ \t]*=[ \t]*//i;
+ $res = $_;
+ last;
+ }
+ elsif (/\[\S+\]/i)
+ {
+ last;
+ }
+ }
+ }
+
+ &gst_file_close ($fd);
+
+ return $res;
+}
+
+# Same, but treat value as bool and return 1/0.
+sub gst_parse_ini_bool
+{
+ my ($file, $section, $var) = @_;
+ my $ret;
+
+ $ret = &gst_parse_ini ($file, $section, $var);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+sub gst_parse_cap_line_clean
+{
+ $_ = $_[0];
+
+ chomp;
+ s/^[ \t]*\#.*//;
+ s/;.*//;
+ s/^[ \t]+//;
+ s/[ \t]+$//;
+
+ return $_;
+}
+
+sub gst_parse_cap_line_read
+{
+ my $fd = $_[0];
+ my $l;
+
+ $l = <$fd>;
+ return -1 if ($l eq undef);
+
+ $l = &gst_parse_cap_line_clean ($l);
+ while ($l =~ /\\$/)
+ {
+ $l =~ s/\\$//;
+ $l .= &gst_parse_cap_line_clean (scalar <$fd>);
+ }
+
+ return \$l;
+}
+
+sub gst_parse_cap_sections
+{
+ my ($file) = @_;
+ my (@sections, $line);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($line = &gst_parse_cap_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ push @sections, $1 if (/^([^:|]+)/i);
+ }
+
+ &gst_file_close ($fd);
+ return @sections;
+}
+
+sub gst_parse_cap
+{
+ my ($file, $section, $var) = @_;
+ my ($fd, $res, $line);
+ my $found_section_flag = 0;
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $res = undef;
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ if (/^$section[:|]/i)
+ {
+ $found_section_flag = 1;
+ }
+
+ if ($found_section_flag && /:$var\#/i)
+ {
+ $_ =~ /:$var\#([^:]*)/;
+ $res = $1;
+ last;
+ }
+# if ($found_section_flag && /:$var[#=]/i)
+# {
+# $_ =~ /:$var[#=]([^:]*)/;
+# $res = $1;
+# last;
+# }
+ }
+
+ &gst_file_close ($fd);
+ return $res;
+}
+
+sub gst_parse_cap_bool
+{
+ my ($file, $section, $var) = @_;
+ my ($fd, $res, $line);
+ my $found_section_flag = 0;
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $res = 0;
+
+ while (($line = &gst_parse_ini_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if (/^$/);
+ if (/^$section[:|]/i)
+ {
+ $found_section_flag = 1;
+ }
+
+ if ($found_section_flag && /:$var[:\#=]/i)
+ {
+ $res = 1;
+ last;
+ }
+ }
+
+ &gst_file_close ($fd);
+ return $res;
+}
+
+# Load a printcap file to buffer, join \ lines and split them back up into a
+# 'one option, printtool comment or section name per line' format.
+sub gst_parse_printcap_buffer_load
+{
+ my ($file) = @_;
+ my ($inbuf, @outbuf);
+
+ $inbuf = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($inbuf);
+
+ for $i (@$inbuf)
+ {
+ my ($comment) = ("");
+
+ chomp $i;
+ $comment = $1 if $i =~ s/^([ \t]*[\#].*)//;
+
+ if ($i ne "")
+ {
+ my @line = split /:/, $i;
+
+ if ($i =~ /^[a-z0-9]+/i)
+ {
+ push @outbuf, ($line [0] . ":\n");
+ shift @line;
+ }
+
+ for $elem (@line)
+ {
+ $elem =~ s/^[ \t]//;
+ $elem =~ s/[ \t]$//;
+ if ($elem ne "")
+ {
+ push @outbuf, ("\t:$elem:\n");
+ }
+ }
+ }
+ elsif ($comment ne "")
+ {
+ push @outbuf, ($comment . "\n");
+ }
+ else
+ {
+ push @outbuf, "\n";
+ }
+ }
+
+ return \@outbuf;
+}
+
+# Find next printer definition, returning (printtool-comment-lineno, stanza-name-lineno).
+sub gst_parse_printcap_get_next_stanza
+{
+ my ($buf, $line_no) = @_;
+ my ($last_printtool_line) = (-1);
+
+ while ($line_no <= $#$buf)
+ {
+ if ($$buf [$line_no] =~ /^\#\#PRINTTOOL3\#\#/)
+ {
+ $last_printtool_line = $line_no;
+ }
+ elsif ($$buf [$line_no] =~ /^[a-z0-9]+/i)
+ {
+ return ($last_printtool_line, $line_no);
+ }
+
+ $line_no++;
+ }
+
+ return (-1, -1);
+}
+
+# Find next printer option.
+sub gst_parse_printcap_get_next_option
+{
+ my ($buf, $line_no) = @_;
+
+ while ($line_no <= $#$buf)
+ {
+ if ($$buf [$line_no] =~ /^\#\#PRINTTOOL3\#\#/ ||
+ $$buf [$line_no] =~ /^[a-z0-9]+/i)
+ {
+ last;
+ }
+
+ if ($$buf [$line_no] =~ /^\t:/)
+ {
+ return $line_no;
+ }
+
+ $line_no++;
+ }
+
+ return -1;
+}
+
+sub gst_parse_printcap_parse_stanza
+{
+ my ($stanza) = @_;
+ my ($key);
+
+ $key = $1 if $stanza =~ /^([a-z0-9]+)/i;
+ return $key;
+}
+
+sub gst_parse_printcap_parse_option
+{
+ my ($option) = @_;
+ my ($key, $value);
+
+ $key = $1 if $option =~ /^\t:([a-z0-9]+)/i;
+ $value = $1 if $option =~ /^\t:[a-z0-9]+[\#=]([a-z0-9\/_-]*)/i;
+ return ($key, $value);
+}
+
+# Locate stanza line for $printer in $buf, starting at $line_no.
+sub gst_parse_printcap_find_stanza
+{
+ my ($buf, $line_no, $printer) = @_;
+ my ($printtool_line_no, $found_printer);
+
+ while ((($printtool_line_no, $line_no) = &gst_parse_printcap_get_next_stanza ($buf, $line_no)))
+ {
+ if ($line_no == -1) { last; }
+
+ $found_printer = &gst_parse_printcap_parse_stanza ($$buf [$line_no]);
+ return ($printtool_line_no, $line_no) if ($found_printer eq $printer);
+ $line_no++;
+ }
+
+ return (-1, -1);
+}
+
+# Search buffer for option with key $key, starting
+# at $line_no position. Return line number, or -1 if not found.
+sub gst_parse_printcap_find_option
+{
+ my ($buf, $line_no, $key) = @_;
+ my $found_key;
+
+ while (($line_no = &gst_parse_printcap_get_next_option ($buf, $line_no)) != -1)
+ {
+ ($found_key) = &gst_parse_printcap_parse_option ($$buf [$line_no]);
+ return $line_no if ($found_key eq $key);
+ $line_no++;
+ }
+
+ return -1;
+}
+
+# High-level API.
+sub gst_parse_printcap
+{
+ my ($file, $section, $var) = @_;
+ my ($printtool_line_no, $stanza_line_no, $option_line_no);
+ my ($buf);
+ my ($key, $value);
+
+ $buf = &gst_parse_printcap_buffer_load ($file);
+
+ ($printtool_line_no, $stanza_line_no) = &gst_parse_printcap_find_stanza ($buf, 0, $section);
+ return undef if ($stanza_line_no == -1);
+
+ $option_line_no = &gst_parse_printcap_find_option ($buf, $stanza_line_no + 1, $var);
+ return undef if ($option_line_no == -1);
+
+ ($key, $value) = &gst_parse_printcap_parse_option ($$buf [$option_line_no]);
+ return $value;
+}
+
+# High-level API.
+sub gst_parse_printcap_bool
+{
+ my ($file, $section, $var) = @_;
+ my ($printtool_line_no, $stanza_line_no, $option_line_no);
+ my ($buf);
+ my ($key, $value);
+
+ $buf = &gst_parse_printcap_buffer_load ($file);
+
+ ($printtool_line_no, $stanza_line_no) = &gst_parse_printcap_find_stanza ($buf, 0, $section);
+ return 0 if ($stanza_line_no == -1);
+
+ $option_line_no = &gst_parse_printcap_find_option ($buf, $stanza_line_no + 1, $var);
+ return 0 if ($option_line_no == -1);
+
+ return 1;
+}
+
+# Debian interfaces(5) states that files starting with # are comments.
+# Also, leading and trailing spaces are ignored.
+sub gst_parse_interfaces_line_clean
+{
+ $_ = $_[0];
+
+ chomp;
+ s/^[ \t]+//;
+ s/^\#.*//;
+ s/[ \t]+$//;
+
+ return $_;
+}
+
+# interfaces(5) also states that \ line continuation is possible.
+sub gst_parse_interfaces_line_read
+{
+ my $fd = $_[0];
+ my $l;
+
+ $l = <$fd>;
+ return -1 if ($l eq undef);
+
+ $l = &gst_parse_interfaces_line_clean ($l);
+ while ($l =~ /\\$/)
+ {
+ $l =~ s/\\$//;
+ $l .= &gst_parse_interfaces_line_clean (scalar <$fd>);
+ }
+
+ return \$l;
+}
+
+# Read lines until a stanza, a line starting with $stanza_type is found.
+# Return ref to an array with the stanza params split.
+sub gst_parse_interfaces_get_next_stanza
+{
+ my ($fd, $stanza_type) = @_;
+ my $line;
+
+ while (($line = &gst_parse_interfaces_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ if (/^$stanza_type[ \t]+[^ \t]/)
+ {
+ s/^$stanza_type[ \t]+//;
+ return [ split ("[ \t]+", $_) ];
+ }
+ }
+
+ return -1;
+}
+
+# Read lines until a line not recognized as a stanza is
+# found, and split in a "tuple" of key/value.
+sub gst_parse_interfaces_get_next_option
+{
+ my $fd = $_[0];
+ my $line;
+
+ while (($line = &gst_parse_interfaces_line_read ($fd)) != -1)
+ {
+ $_ = $$line;
+ next if /^$/;
+
+ return [ split ("[ \t]+", $_, 2) ] if (!/^iface[ \t]/);
+ return -1;
+ }
+
+ return -1;
+}
+
+# Get all stanzas from file. Return array.
+sub gst_parse_interfaces_stanzas
+{
+ my ($file, $stanza_type) = @_;
+ my ($fd, @res);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $res = undef;
+
+ while (($_ = &gst_parse_interfaces_get_next_stanza ($fd, $stanza_type)) != -1)
+ {
+ push @res, $_;
+ }
+
+ &gst_file_close ($fd);
+
+ return @res;
+}
+
+# Find stanza for $iface in $file, and return
+# tuple for option with $key. Return -1 if unexisting.
+sub gst_parse_interfaces_option_tuple
+{
+ my ($file, $iface, $key, $all) = @_;
+ my ($fd, @res);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ while (($stanza = &gst_parse_interfaces_get_next_stanza ($fd, "iface")) != -1)
+ {
+ if ($$stanza[0] eq $iface)
+ {
+ while (($tuple = &gst_parse_interfaces_get_next_option ($fd)) != -1)
+ {
+ if ($$tuple[0] =~ /$key/)
+ {
+ return $tuple if !$all;
+ push @res, $tuple;
+ }
+ }
+
+ return -1 if !$all;
+ }
+ }
+
+ return @res if $all;
+ return -1;
+}
+
+# Go get option $kw for $iface stanza. If found,
+# return 1 (true), else, false.
+sub gst_parse_interfaces_option_kw
+{
+ my ($file, $iface, $kw) = @_;
+ my $tuple;
+
+ &gst_report_enter ();
+ &gst_report ("parse_ifaces_kw", $kw, $file);
+ $tuple = &gst_parse_interfaces_option_tuple ($file, $iface, $kw);
+ &gst_report_leave ();
+
+ if ($tuple != -1)
+ {
+ &gst_report ("parse_ifaces_kw_strange", $iface, $file) if ($$tuple[1] ne "");
+
+ return 1;
+ }
+
+ return 0;
+}
+
+# For such keywords as noauto, whose existence means
+# a false value.
+sub gst_parse_interfaces_option_kw_not
+{
+ my ($file, $iface, $kw) = @_;
+
+ return &gst_parse_interfaces_option_kw ($file, $iface, $kw)? 0 : 1;
+}
+
+# Go get option $key for $iface in $file and return value.
+sub gst_parse_interfaces_option_str
+{
+ my ($file, $iface, $key) = @_;
+ my $tuple;
+
+ &gst_report_enter ();
+ &gst_report ("parse_ifaces_str", $kw, $file);
+ $tuple = &gst_parse_interfaces_option_tuple ($file, $iface, $key);
+ &gst_report_leave ();
+
+ if ($tuple != -1)
+ {
+ return $$tuple[1];
+ }
+
+ return undef;
+}
+
+
+# Implementing pump(8) pump.conf file format parser.
+# May be useful for dhcpd too.
+sub gst_parse_pump_get_next_option
+{
+ my ($fd) = @_;
+ my $line;
+
+ while (($line = &gst_parse_interfaces_line_read ($fd)) != -1)
+ {
+ $line = $$line;
+ if ($line ne "")
+ {
+ return [ split ("[ \t]+", $line, 2) ];
+ }
+ }
+
+ return -1;
+}
+
+sub gst_parse_pump_get_device
+{
+ my ($fd, $iface) = @_;
+ my ($opt);
+
+ while (($opt = &gst_parse_pump_get_next_option ($fd)) != -1)
+ {
+ if ($$opt[0] eq "device")
+ {
+ $$opt[1] =~ s/[ \t]*\{//;
+ return 1 if $$opt[1] eq $iface;
+ }
+ }
+
+ return 0;
+}
+
+sub gst_parse_pump_get_iface_option_ref
+{
+ my ($file, $iface, $key) = @_;
+ my ($fd, $opt, $ret);
+
+ $fd = &gst_file_open_read_from_names ($file);
+
+ if (&gst_parse_pump_get_device ($fd, $iface))
+ {
+ while (($opt = &gst_parse_pump_get_next_option ($fd)) != -1)
+ {
+ if ($$opt[0] eq $key)
+ {
+ $ret = &gst_parse_shell_unescape ($$opt[1]);
+ return \$ret;
+ }
+
+ return -1 if ($$opt[0] eq "}");
+ }
+ }
+
+ return -1;
+}
+
+sub gst_parse_pump_get_iface_kw
+{
+ my ($file, $iface, $key) = @_;
+ my ($ret);
+
+ return 1 if &gst_parse_pump_get_iface_option_ref ($file, $iface, $key) != -1;
+ return 0;
+}
+
+sub gst_parse_pump_get_iface_kw_not
+{
+ my ($file, $iface, $key) = @_;
+
+ return 0 if &gst_parse_pump_get_iface_option_ref ($file, $iface, $key) != -1;
+ return 1;
+}
+
+# Read a variable out of an XML document. The varpath is the '/'-separated path to the
+# XML tag. If the name of a property is passed, that property of the leaf tag is read,
+# otherwise the tag's PCDATA.
+sub gst_parse_xml
+{
+ my ($file, $varpath, $property) = @_;
+ my ($model, $branch);
+
+ ($model) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_find ($model, $varpath);
+
+ if ($branch)
+ {
+ return &gst_xml_model_get_attribute ($branch, $property) if $property ne "";
+ return &gst_xml_model_get_pcdata ($branch);
+ }
+
+ return undef;
+}
+
+sub gst_parse_xml_child_names
+{
+ my ($file, $varpath) = @_;
+ my ($model, $branch, @children);
+
+ ($model) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_find ($model, $varpath);
+
+ if (!$branch) { return @children; }
+
+ my @list = @$branch;
+ shift @list; # Attributes
+
+ while (@list)
+ {
+ if ($list [0] ne "__unparsed__" && $list [0] ne "0")
+ {
+ push @children, shift @list;
+ }
+ else
+ {
+ shift @list;
+ }
+
+ shift @list;
+ }
+
+ return @children;
+}
+
+sub gst_parse_alchemist
+{
+ my ($file, $varpath) = @_;
+
+ $varpath = "/adm_context/datatree/" . $varpath;
+ return &gst_parse_xml ($file, $varpath, "VALUE");
+}
+
+sub gst_parse_alchemist_print
+{
+ my ($file, $printer, $varpath) = @_;
+
+ $varpath = "printconf/print_queues/" . $printer . "/" . $varpath;
+ return &gst_parse_alchemist ($file, $varpath);
+}
+
+sub gst_parse_alchemist_print_option
+{
+ my ($file, $printer, $name) = @_;
+ my ($varpath, $model, $branch, $fd, $options, $option);
+
+ ($model) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_find ($model, "/adm_context/datatree/printconf/print_queues/" . $printer .
+ "/filter_data/foomatic_defaults");
+
+ return undef if (!$branch);
+
+ $options = &gst_xml_model_get_children ($branch);
+
+ foreach $o (@$options)
+ {
+ my $opt_node = &gst_xml_model_find ($o, "name");
+ next if (!$opt_node);
+
+ if (&gst_xml_model_get_attribute ($opt_node, "VALUE") eq $name)
+ {
+ $option = $o;
+ last;
+ }
+ }
+
+ return undef if (!$option);
+
+ my $node = &gst_xml_model_find ($option, "default");
+ return undef if (!$node);
+
+ return &gst_xml_model_get_attribute ($node, "VALUE");
+}
+
+# extracts hostname from a fully qualified hostname
+# contained in a file
+sub gst_parse_fq_hostname
+{
+ my ($file) = @_;
+ my ($ret);
+
+ $ret = &gst_parse_line_first ($file);
+ $ret =~ s/\..*//; #remove domain
+
+ return $ret;
+}
+
+# extracts domain from a fully qualified hostname
+# contained in a file
+sub gst_parse_fq_domain
+{
+ my ($file) = @_;
+ my ($ret);
+
+ $ret = &gst_parse_line_first ($file);
+ $ret =~ s/^[^\.]*\.//;
+
+ return $ret;
+}
+
+sub gst_parse_rcinet1conf
+{
+ my ($file, $iface, $kw) = @_;
+ my ($line);
+
+ $iface =~ s/eth//;
+
+ #we must double escape those []
+ $line = "$kw\\[$iface\\]";
+
+ return &gst_parse_sh ($file, $line);
+}
+
+sub gst_parse_rcinet1conf_bool
+{
+ my ($file, $iface, $kw) = @_;
+ my ($ret);
+
+ $ret = &gst_parse_rcinet1conf ($file, $iface, $kw);
+
+ return undef if ($ret eq undef);
+ return (&gst_util_read_boolean ($ret)? 1: 0);
+}
+
+sub gst_parse_wireless_opts
+{
+ my ($file, $iface, $proc, $kw) = @_;
+ my $ifaces = &$proc ();
+ my $found = 0;
+ my $search = 1;
+ my $val = "";
+ my $fd;
+
+ foreach $i (@$ifaces)
+ {
+ $found = 1 if ($iface eq $i);
+ }
+
+ return undef if (!$found);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ while (<$fd>)
+ {
+ $line = $_;
+
+ if ($line =~ /^case/)
+ {
+ # we don't want to search inside the case
+ $search = 0;
+ }
+ elsif ($line =~ /^esac/)
+ {
+ # continue searching
+ $search = 1;
+ }
+ elsif (($line =~ /^[ \t]*$kw/ ) && ($search))
+ {
+ $line =~ s/.*=//;
+
+ if ($line =~ /"(.*)"/)
+ {
+ $line = $1;
+ }
+
+ $val = $line;
+ }
+ }
+
+ &gst_file_close ($fd);
+ return $val;
+}
+
+# function for parsing /etc/start_if.$iface files in FreeBSD
+sub gst_parse_startif
+{
+ my ($file, $regex) = @_;
+ my ($fd, $line, $val);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ $val = undef;
+
+ return undef if ($fd eq undef);
+
+ while (<$fd>)
+ {
+ chomp;
+
+ # ignore comments
+ next if (/^\#/);
+
+ if (/$regex/)
+ {
+ $val = $1;
+ }
+ }
+
+ # remove double quote
+ if ($val =~ /\"(.*)\"/)
+ {
+ $val = $1;
+ }
+
+ return $val;
+}
+
+# functions for parsing /etc/ppp/ppp.conf sections in FreeBSD
+sub gst_parse_pppconf_find_next_stanza
+{
+ my ($buff, $line_no) = @_;
+
+ $line_no = 0 if ($line_no eq undef);
+
+ while ($$buff[$line_no] ne undef)
+ {
+ if ($$buff[$line_no] !~ /^[\#\n]/)
+ {
+ return $line_no if ($$buff[$line_no] =~ /^[^ \t]+/);
+ }
+
+ $line_no++;
+ }
+
+ return -1;
+}
+
+sub gst_parse_pppconf_find_stanza
+{
+ my ($buff, $section) = @_;
+ my ($line_no) = 0;
+
+ while (($line_no = &gst_parse_pppconf_find_next_stanza ($buff, $line_no)) != -1)
+ {
+ return $line_no if ($$buff[$line_no] =~ /^$section\:/);
+ $line_no++;
+ }
+
+ return -1;
+}
+
+sub gst_parse_pppconf_common
+{
+ my ($file, $section, $key) = @_;
+ my ($fd, $val);
+
+ $fd = &gst_file_open_read_from_names ($file);
+ return undef if ($fd eq undef);
+
+ $val = undef;
+
+ # First of all, we must find the line where the section begins
+ while (<$fd>)
+ {
+ chomp;
+ last if (/^$section\:[ \t]*/);
+ }
+
+ while (<$fd>)
+ {
+ chomp;
+
+ # read until the next section arrives
+ last if (/^[^ \t]/);
+
+ next if (/^\#/);
+
+ if (/^[ \t]+(add|set|enable|disable)[ \t]+$key/)
+ {
+ $val = $_;
+ last;
+ }
+ }
+
+ # this is done because commands can be multiline
+ while (<$fd>)
+ {
+ last if (/^[^ \t]/);
+ last if ($val !~ /\\$/);
+
+ s/^[ \t]*/ /;
+ $val =~ s/\\$//;
+ $val .= $_;
+ }
+
+ &gst_file_close ($fd);
+
+ if ($val eq undef)
+ {
+ return undef if ($section eq "default");
+ return &gst_parse_pppconf_common ($file, "default", $key);
+ }
+ else
+ {
+ $val =~ s/\#[^\#]*$//;
+ $val =~ s/[ \t]*$//;
+ $val =~ s/^[ \t]*//;
+ return $val;
+ }
+}
+
+sub gst_parse_pppconf
+{
+ my ($file, $section, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_pppconf_common ($file, $section, $key);
+
+ if ($val =~ /$key[ \t]+(.+)/)
+ {
+ return $1;
+ }
+}
+
+sub gst_parse_pppconf_bool
+{
+ my ($file, $section, $key) = @_;
+ my ($val);
+
+ $val = &gst_parse_pppconf_common ($file, $section, $key);
+
+ return 1 if ($val ne undef);
+ return 0;
+}
+
+sub gst_parse_pppconf_re
+{
+ my ($file, $section, $key, $re) = @_;
+ my ($val);
+
+ $val = &gst_parse_pppconf_common ($file, $section, $key);
+
+ if ($val =~ /$re/i)
+ {
+ return $1;
+ }
+}
+
+sub gst_parse_confd_net
+{
+ my ($file, $key) = @_;
+ my ($str, $contents, $i);
+
+ $contents = &gst_file_buffer_load ($file);
+
+ for ($i = 0; $i <= scalar (@$contents); $i++)
+ {
+ # search for key
+ if ($$contents[$i] =~ /^$key[ \t]*=[ \t]*\(/)
+ {
+ # contents can be multiline,
+ # just get the first value
+ do {
+ $$contents[$i] =~ /\"([^\"]*)\"/;
+ $str = $1;
+ $i++;
+ } while (!$str);
+ }
+ }
+
+ return $str;
+}
+
+sub gst_parse_confd_net_re
+{
+ my ($file, $key, $re) = @_;
+ my ($str);
+
+ $str = &gst_parse_confd_net ($file, $key);
+
+ if ($str =~ /$re/i)
+ {
+ return $1;
+ }
+}
diff --git a/knetworkconf/backends/platform.pl.in b/knetworkconf/backends/platform.pl.in
new file mode 100644
index 0000000..c81a9e1
--- /dev/null
+++ b/knetworkconf/backends/platform.pl.in
@@ -0,0 +1,685 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Determine the platform we're running on.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Arturo Espinosa <arturo@ximian.com>
+# Hans Petter Jansson <hpj@ximian.com>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+# --- System guessing --- #
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/parse.pl$DOTIN";
+require "$SCRIPTSDIR/xml.pl$DOTIN";
+
+
+$PLATFORM_INFO = {
+ "debian-2.2" => "Debian GNU/Linux 2.2 Potato",
+ "debian-3.0" => "Debian GNU/Linux 3.0 Woody",
+ "debian-3.1" => "Debian GNU/Linux 3.1 Sarge",
+ "debian-4.0" => "Debian GNU/Linux 4.0 Etch",
+ "debian-5.0" => "Debian GNU/Linux 5.0 Lenny",
+ "debian-testing" => "Debian GNU/Linux Testing/Unstable",
+ "ubuntu-5.04" => "Kubuntu 5.04, Hoary Hedgehog",
+ "ubuntu-5.10" => "Kubuntu 5.10, Breezy Badger",
+ "ubuntu-6.06" => "Kubuntu 6.06, Dapper Drake",
+ "ubuntu-6.10" => "Kubuntu 6.10, Edgy Eft",
+ "ubuntu-7.04" => "Kubuntu 7.04, Feisty Fawn",
+ "ubuntu-7.10" => "Kubuntu 7.10, Gutsy Gibbon",
+ "ubuntu-8.04" => "Kubuntu 8.04, Hardy Heron",
+ "redhat-5.2" => "Red Hat Linux 5.2 Apollo",
+ "redhat-6.0" => "Red Hat Linux 6.0 Hedwig",
+ "redhat-6.1" => "Red Hat Linux 6.1 Cartman",
+ "redhat-6.2" => "Red Hat Linux 6.2 Zoot",
+ "redhat-7.0" => "Red Hat Linux 7.0 Guinness",
+ "redhat-7.1" => "Red Hat Linux 7.1 Seawolf",
+ "redhat-7.2" => "Red Hat Linux 7.2 Enigma",
+ "redhat-7.3" => "Red Hat Linux 7.3 Valhalla",
+ "redhat-8.0" => "Red Hat Linux 8.0 Psyche",
+ "redhat-9" => "Red Hat Linux 9.0 Shrike",
+ "openna-1.0" => "OpenNA Linux 1.0 VSLC",
+ "mandrake-7.1" => "Linux Mandrake 7.1",
+ "mandrake-7.2" => "Linux Mandrake 7.2 Odyssey",
+ "mandrake-8.0" => "Linux Mandrake 8.0 Traktopel",
+ "mandrake-9.0" => "Linux Mandrake 9.0 Dolphin",
+ "mandrake-9.1" => "Linux Mandrake 9.1 Bamboo",
+ "mandrake-9.2" => "Linux Mandrake 9.2 FiveStar",
+ "mandrake-10.0" => "Linux Mandrake 10.0",
+ "mandrake-10.1" => "Linux Mandrake 10.1",
+ "mandrake-10.2" => "Linux Mandrake 2005 LE",
+ "mandriva-2006.0" => "Mandriva Linux 2006.0",
+ "mandriva-2006.1" => "Mandriva Linux 2006.1",
+ "mandriva-2007.0" => "Mandriva Linux 2007.0",
+ "mandriva-2007.1" => "Mandriva Linux 2007.1",
+ "yoper-2.2" => "Yoper Linux 2.2",
+ "blackpanther-4.0" => "Black Panther OS 4.0",
+ "conectiva-9" => "Conectiva Linux 9",
+ "conectiva-10" => "Conectiva Linux 10",
+ "suse-7.0" => "SuSE Linux 7.0",
+ "suse-9.0" => "SuSE Linux 9.0",
+ "suse-9.1" => "SuSE Linux 9.1",
+ "turbolinux-7.0" => "Turbolinux 7.0",
+ "slackware-8.0.0" => "Slackware 8.0.0",
+ "slackware-8.1" => "Slackware 8.1",
+ "slackware-9.0.0" => "Slackware 9.0.0",
+ "slackware-9.1.0" => "Slackware 9.1.0",
+ "slackware-10.0.0" => "Slackware 10.0.0",
+ "slackware-10.1.0" => "Slackware 10.1.0",
+ "slackware-10.2.0" => "Slackware 10.2.0",
+ "freebsd-4" => "FreeBSD 4",
+ "freebsd-5" => "FreeBSD 5",
+ "freebsd-6" => "FreeBSD 6",
+ "gentoo" => "Gentoo Linux",
+ "vlos-1.2" => "Vida Linux OS 1.2",
+ "archlinux" => "Arch Linux",
+ "pld-1.0" => "PLD 1.0 Ra",
+ "pld-1.1" => "PLD 1.1 Ra",
+ "pld-1.99" => "PLD 1.99 Ac-pre",
+ "vine-3.0" => "Vine Linux 3.0",
+ "vine-3.1" => "Vine Linux 3.1",
+ "fedora-1" => "Fedora Core 1 (Yarrow)",
+ "fedora-2" => "Fedora Core 2 (Tettnang)",
+ "fedora-3" => "Fedora Core 3 (Heidelberg)",
+ "fedora-4" => "Fedora Core 4 (Stentz)",
+ "fedora-5" => "Fedora Core 5 (Bordeaux)",
+ "rpath" => "rPath Linux",
+ "ark" => "Ark Linux",
+};
+
+sub check_lsb
+{
+ my ($ver, $dist);
+# my %vermap =
+# ("3.0" => "woody");
+
+ my %distmap =
+ ("Debian" => "debian"),
+ ("Mandrake" => "mandrake"),
+ ("Conectiva" => "conectiva"),
+ ("Blackpanther" => "blackpanther");
+
+ # gst_prefix not required here: parse already does that for us.
+ $dist = lc (&gst_parse_sh ("/etc/lsb-release", "DISTRIB_ID"));
+ $ver = lc (&gst_parse_sh ("/etc/lsb-release", "DISTRIB_RELEASE"));
+
+# $ver = $vermap{$ver} if exists $vermap{$ver};
+ $dist = $distmap{$dist} if exists $dirmap{$dir};
+
+ return -1 if ($dist eq "") || ($ver eq "");
+ return "$dist-$ver";
+}
+
+sub check_debian
+{
+ my ($ver, $i);
+ my %vermap =
+ ("testing/unstable" => "testing",
+ "lenny/sid" => "testing",
+ "3.1" => "sarge",
+ "4.0" => "etch",
+ "5.0" => "lenny");
+
+ open DEBIAN, "$gst_prefix/etc/debian_version" or return -1;
+ chomp ($ver = <DEBIAN>);
+ close DEBIAN;
+
+ #if $ver is not found, we will assume it is testing
+ if($ver and exists $vermap{$ver}) {
+ $ver = $vermap{$ver};
+ } else {
+ $ver = "testing";
+ }
+
+ return "debian-$ver";
+}
+
+
+sub check_redhat
+{
+ open RELEASE, "$gst_prefix/etc/redhat-release" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if (/^Red Hat Linux.*\s+([0-9.]+)\s+.*/)
+ {
+ close RELEASE;
+ return "redhat-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_openna
+{
+ open OPENNA, "$gst_prefix/etc/openna-release" or return -1;
+ while (<OPENNA>)
+ {
+ chomp;
+ if (/^OpenNA*/)
+ {
+ close OPENNA;
+ return "openna-$1";
+ }
+ }
+ close OPENNA;
+ return -1;
+}
+
+sub check_caldera
+{
+ open INSTALLED, "$gst_prefix/etc/.installed" or return -1;
+ while (<INSTALLED>)
+ {
+ chomp;
+ if (/^OpenLinux-(.*)-.*/)
+ {
+ close INSTALLED;
+ return "caldera-$1";
+ }
+ }
+ close INSTALLED;
+ return -1;
+}
+
+
+sub check_suse
+{
+ open RELEASE, "$gst_prefix/etc/SuSE-release" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if (/^VERSION\s*=\s*(\S+)/)
+ {
+ close RELEASE;
+ return "suse-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_mandrake
+{
+ open MANDRAKE, "$gst_prefix/etc/mandrake-release" or return -1;
+ while (<MANDRAKE>)
+ {
+ $ver = $_;
+ chomp ($ver);
+ if ($ver =~ /^Linux Mandrake release (\S+)/)
+ {
+ close MANDRAKE;
+ return "mandrake-$1";
+ }
+ elsif ($ver =~ /^Mandrake( L|l)inux release ([\d\.]+)/i)
+ {
+ close MANDRAKE;
+ return "mandrake-$2";
+ }
+ }
+ close MANDRAKE;
+ return -1;
+}
+
+sub check_mandriva
+{
+ open MANDRIVA, "$gst_prefix/etc/mandriva-release" or return -1;
+ while (<MANDRIVA>)
+ {
+ $ver = $_;
+ chomp ($ver);
+ if ($ver =~ /^Linux Mandriva release (\S+)/)
+ {
+ close MANDRIVA;
+ return "mandriva-$1";
+ }
+ elsif ($ver =~ /^Mandriva( L|l)inux release ([\d\.]+)/i)
+ {
+ close MANDRIVA;
+ return "mandriva-$2";
+ }
+ }
+ close MANDRIVA;
+ return -1;
+}
+
+sub check_yoper
+{
+ open YOPER, "$gst_prefix/etc/yoper-release" or return -1;
+ while (<YOPER>)
+ {
+ $ver = $_;
+ chomp ($ver);
+ if ($ver =~ m/Yoper (\S+)/)
+ {
+ close YOPER;
+ # find the first digit of our release
+ $mystring= ~m/(\d)/;
+ #store it in $fdigit
+ $fdigit= $1;
+ # the end of the release is marked with -2 so find the -
+ $end = index($ver,"-");
+ $start = index($ver,$fdigit);
+ # extract the substring into $newver
+ $newver= substr($ver,$start,$end-$start);
+ print $newver;
+ return "yoper-$newver";
+ }
+ }
+ close YOPER;
+ return -1;
+}
+
+sub check_blackpanther
+{
+ open BLACKPANTHER, "$gst_prefix/etc/blackPanther-release" or return -1;
+
+ while (<BLACKPANTHER>)
+ {
+ $ver = $_;
+ chomp ($ver);
+ if ($ver =~ /^Linux Black Panther release (\S+)/)
+ {
+ close BLACKPANTHER;
+ return "blackPanther-$1";
+ }
+ elsif ($ver =~ /^Black Panther ( L|l)inux release ([\d\.]+)/i)
+ {
+ close BLACKPANTHER;
+ return "blackPanther-$2";
+ }
+ }
+
+ close BLACKPANTHER;
+ return -1;
+}
+
+sub check_fedora
+{
+ open FEDORA, "$gst_prefix/etc/fedora-release" or return -1;
+ while (<FEDORA>)
+ {
+ $ver = $_;
+ chomp ($ver);
+
+ if ($ver =~ /^Fedora Core release (\S+)/)
+ {
+ close FEDORA;
+ return "fedora-$1";
+ }
+ }
+
+ close FEDORA;
+ return -1;
+}
+
+sub check_rpath
+{
+ open RPATH, "$gst_prefix/etc/distro-release" or return -1;
+
+ while (<RPATH>)
+ {
+ $ver = $_;
+ chomp ($ver);
+
+ if ($ver =~ /^rPath Linux/)
+ {
+ close RPATH;
+ return "rpath";
+ }
+ if ($ver =~ /Foresight/)
+ {
+ close RPATH;
+ return "rpath";
+ }
+ }
+
+ close RPATH;
+ return -1;
+}
+
+sub check_conectiva
+{
+ open RELEASE, "$gst_prefix/etc/conectiva-release" or return -1;
+
+ while (<RELEASE>)
+ {
+ chomp;
+
+ if (/^Conectiva Linux (\S+)/)
+ {
+ close RELEASE;
+ return "conectiva-$1";
+ }
+ }
+
+ close RELEASE;
+ return -1;
+}
+
+sub check_turbolinux
+{
+ open RELEASE, "$gst_prefix/etc/turbolinux-release" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if (/^Turbolinux\s.*\s([0-9.]+)\s.*/)
+ {
+ close RELEASE;
+ return "turbolinux-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_slackware
+{
+ open RELEASE, "$gst_prefix/etc/slackware-version" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if (/^Slackware ([0-9.]+)/)
+ {
+ close RELEASE;
+ return "slackware-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_gentoo
+{
+ return "gentoo" if stat ("$gst_prefix/usr/portage");
+ return -1;
+}
+
+sub check_vlos
+{
+ open RELEASE, "$gst_prefix/etc/vlos-release" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if (/^VLOS.*\s+([0-9.]+)/)
+ {
+ close RELEASE;
+ return "vlos-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_archlinux
+{
+ # Since Arch stores gnome in /opt/gnome, use full dir
+ return "archlinux" if stat ("/etc/arch-release");
+ return -1;
+}
+
+sub check_linuxppc
+{
+ open RELEASE, "$gst_prefix/etc/redhat-release" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if (/^LinuxPPC\s+(\S+)/)
+ {
+ close RELEASE;
+ return "linuxppc-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_pld
+{
+ open RELEASE, "$gst_prefix/etc/pld-release" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if(/^([0-9.]+) PLD Linux/)
+ {
+ close RELEASE;
+ return "pld-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_vine
+{
+ open RELEASE, "$gst_prefix/etc/vine-release" or return -1;
+ while (<RELEASE>)
+ {
+ chomp;
+ if(/^Vine Linux ([0-9.]+)\s+.*/)
+ {
+ close RELEASE;
+ return "vine-$1";
+ }
+ }
+ close RELEASE;
+ return -1;
+}
+
+sub check_ark
+{
+ open ARK, "$gst_prefix/etc/ark-release" or return -1;
+ while (<ARK>)
+ {
+ $ver = $_;
+ chomp ($ver);
+
+ if ($ver =~ /^Ark Linux/)
+ {
+ close ARK;
+ return "ark";
+ }
+ }
+
+ close ARK;
+ return -1;
+}
+
+sub check_freebsd
+{
+ my ($sysctl_cmd, @output);
+
+ $sysctl_cmd = &gst_file_locate_tool ("sysctl");
+ @output = (readpipe("$sysctl_cmd -n kern.version"));
+ foreach (@output)
+ {
+ chomp;
+ if (/^FreeBSD\s([0-9]+)\.\S+.*/)
+ {
+ return "freebsd-$1";
+ }
+ }
+ return -1;
+}
+
+sub check_solaris
+{
+ my ($fd, $dist);
+
+ #
+ # The file /etc/release is present for solaris-2.6
+ # solaris 2.5 does not have the file. Solaris-7.0 and 8.0 have not
+ # been checked
+ #
+ # uname output
+ # Solaris 2.5: 5.5(.1)
+ # Solaris 2.6: 5.6
+ # Solaris 7: unknown, assume 7.0
+ # Solaris 8: unknown, assume 8.0
+ #
+ $fd = &gst_file_run_pipe_read ("uname -r");
+ return -1 if $fd eq undef;
+ chomp ($dist = <$fd>);
+ &gst_file_close ($fd);
+
+ if ($dist =~ /^5\.(\d)/) { return "solaris-2.$1" }
+ else { if ($dist =~ /^([78])\.\d/) { return "solaris-$1.0" } }
+ return -1;
+}
+
+sub gst_platform_get_system
+{
+ my ($tool) = @_;
+
+ # get the output of 'uname -s', it returns the system we are running
+ $$tool{"system"} = &gst_file_run_backtick ("uname -s");
+ chomp ($$tool{"system"});
+}
+
+sub gst_platform_guess
+{
+ my ($tool) = @_;
+
+ my %check = (
+ # Red Hat check must run after Vine, Mandrake and Fedora, and Mandrake after BlackPanther
+ "Linux" => [ \&check_lsb, \&check_debian, \&check_caldera, \&check_suse, \&check_blackpanther, \&check_vine,
+ \&check_fedora, \&check_mandrake, \&check_mandriva, \&check_conectiva, \&check_linuxppc, \&check_redhat, \&check_openna,
+ \&check_turbolinux, \&check_slackware, \&check_vlos, \&check_gentoo, \&check_pld, \&check_rpath, \&check_archlinux, \&check_ark ],
+ "FreeBSD" => [ \&check_freebsd ],
+ "SunOS" => [ \&check_solaris ]
+ );
+ my $plat;
+
+ # Fool-the-backend hack.
+ if (exists $ENV{"GST_DIST"})
+ {
+ $$tool{"platform"} = $gst_dist = $ENV{"GST_DIST"};
+ return;
+ }
+
+ foreach $plat (keys %check)
+ {
+ if ($$tool{"system"} =~ /$plat/)
+ {
+ my ($check, $dist);
+
+ foreach $check (@{$check{$plat}})
+ {
+ $dist = &$check ();
+ if ($dist != -1)
+ {
+ $$tool{"platform"} = $gst_dist = $dist;
+ return;
+ }
+ }
+ }
+ }
+
+ $$tool{"platform"} = $gst_dist = "unknown";
+}
+
+
+# gst_platform_ensure_supported
+#
+# Takes a list of supported platforms and sees if the one detected is found in
+# this list. If not, will report a list of supported platforms and fail.
+
+sub gst_platform_ensure_supported
+{
+ my ($tool, @supported) = @_;
+
+ $$tool{"platforms"} = [ @supported ];
+
+ foreach $platform (@supported)
+ {
+ if ($platform eq $$tool{"platform"})
+ {
+ &gst_report ("platform_success", $platform, $$PLATFORM_INFO{$platform});
+ return;
+ }
+ }
+
+ # Not supported.
+ if (exists $$tool{"platform"})
+ {
+ &gst_report ("platform_unsup", $$tool{"platform"});
+ }
+ else
+ {
+ &gst_report ("platform_undet");
+ }
+}
+
+
+# A directive handler that sets the currently selected platform.
+sub gst_platform_set
+{
+ my ($tool, $platform) = @_;
+ my ($p);
+
+ foreach $p (@{ $$tool{"platforms"}})
+ {
+ if ($p eq $platform)
+ {
+ $$tool{"platform"} = $gst_dist = $platform;
+ &gst_report ("platform_success", $platform, $$PLATFORM_INFO{$platform});
+ &gst_report_end ();
+ return;
+ }
+ }
+
+ &gst_report ("platform_unsup", $platform);
+ &gst_report_end ();
+}
+
+sub gst_platform_print_list
+{
+ my ($platforms) = @_;
+ my ($platform, $name);
+
+ &gst_xml_print_begin ("platforms");
+ foreach $platform (sort @$platforms)
+ {
+ $name = $$PLATFORM_INFO{$platform};
+
+ &gst_xml_container_enter ("platform");
+ &gst_xml_print_line ("<key>$platform</key>");
+ &gst_xml_print_line ("<name>$name</name>");
+ &gst_xml_container_leave ();
+ }
+ &gst_xml_print_end ("platforms");
+}
+
+sub gst_platform_list
+{
+ my ($tool) = @_;
+
+ &gst_report_end ();
+ &gst_platform_print_list ($$tool{"platforms"});
+}
+
+1;
diff --git a/knetworkconf/backends/process.pl.in b/knetworkconf/backends/process.pl.in
new file mode 100644
index 0000000..c1047d6
--- /dev/null
+++ b/knetworkconf/backends/process.pl.in
@@ -0,0 +1,54 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Common process stuff for the setup tools backends.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Carlos Garnacho Parro <carlosg@gnome.org>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/general.pl$DOTIN";
+require "$SCRIPTSDIR/file.pl$DOTIN";
+
+sub gst_process_kill_by_pidfile
+{
+ my ($pidfile) = @_;
+ my ($buf, $pid);
+
+ if ($pidfile !~ /^\//)
+ {
+ # add default pidfiles path if it isn't full path
+ $pidfile = "/var/run/" . $pidfile;
+ }
+
+ if (&gst_file_exists ($pidfile))
+ {
+ $buf = &gst_file_buffer_load ($pidfile);
+ $pid = $$buf[0];
+
+ &gst_file_run ("kill -9 $pid");
+ }
+}
+
+1;
diff --git a/knetworkconf/backends/replace.pl.in b/knetworkconf/backends/replace.pl.in
new file mode 100644
index 0000000..79e5cf2
--- /dev/null
+++ b/knetworkconf/backends/replace.pl.in
@@ -0,0 +1,1770 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# replace.pl: Common in-line replacing stuff for the ximian-setup-tools backends.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Arturo Espinosa <arturo@ximian.com>
+# Michael Vogt <mvo@debian.org> - Debian 2.[2|3] support.
+# David Lee Ludwig <davidl@wpi.edu> - Debian 2.[2|3] support.
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/util.pl$DOTIN";
+require "$SCRIPTSDIR/file.pl$DOTIN";
+require "$SCRIPTSDIR/parse.pl$DOTIN";
+
+
+# General rules: all replacing is in-line. Respect unsupported values, comments
+# and as many spacing as possible.
+
+# The concept of keyword (kw) here is a key, normaly in its own line, whose
+# boolean representation is its own existence.
+
+# A $re is a regular expression. In most functions here, regular expressions
+# are converted to simple separators, by using gst_replace_regexp_to_separator.
+# This makes it easier to convert a parse table into a replace table.
+
+# Every final replacing function to be used by a table must handle one key
+# at a time, but may replace several values from there.
+#
+# Return 0 for success, and -1 for failure.
+#
+# Most of these functions have a parsing counterpart. The convention is
+# that parse becomes replace and split becomes join:
+# gst_parse_split_first_str -> gst_replace_join_first_str
+
+# Additional abstraction: replace table entries can have
+# arrays inside. The replace proc will be ran with every
+# combination that the arrays provide. Ex:
+# ["user", \&gst_replace_foo, [0, 1], [2, 3] ] will replace
+# using all possibilities in the combinatory of [0, 1]x[2, 3].
+# Check RedHat 7.2's network replace table for further
+# enlightenment.
+sub gst_replace_run_entry
+{
+ my ($values_hash, $key, $proc, $cp, $value) = @_;
+ my ($ncp, $i, $j, $res);
+
+ $ncp = [@$cp];
+ for ($i = 0; $i < scalar (@$cp); $i ++)
+ {
+ if (ref $$cp[$i] eq "ARRAY")
+ {
+ foreach $j (@{$$cp[$i]})
+ {
+ $$ncp[$i] = $j;
+ $res = -1 if &gst_replace_run_entry ($values_hash, $key, $proc, $ncp, $value);
+ }
+ return $res;
+ }
+ }
+
+ # OK, the given entry didn't have any array refs in it...
+
+ &gst_debug_print_line ("gst_replace_from_table: $key");
+ return -1 if (!&gst_parse_replace_hash_values ($ncp, $values_hash));
+ push (@$ncp, $$values_hash{$key}) unless $key eq "_always_";
+ $res = -1 if &$proc (@$ncp);
+ return $res;
+}
+
+# gst_replace_from_table takes a file mapping, a replace table, a hash
+# of values, probably made from XML parsing, and whose keys are
+# the same keys the table handles.
+#
+# Table entries whose keys are not present in the values_hash
+# will not be processed. More than one entry may process the same key.
+#
+# The functions in the replace tables, most of which are coded in
+# this file, receive the mapped files of the first argument, and then
+# a set of values. The last argument is the value of the $values_hash
+# for the corresponding key of the entry.
+sub gst_replace_from_table
+{
+ my ($fn, $table, $values_hash, $old_hash) = @_;
+ my ($key, $proc, @param);
+ my ($i, @cp, @files, $res);
+
+ $$fn{"OLD_HASH"} = $old_hash;
+
+ foreach $i (@$table)
+ {
+ @cp = @$i;
+ $key = shift (@cp);
+
+ $proc = shift (@cp);
+ @files = &gst_parse_replace_files (shift (@cp), $fn);
+ unshift @cp, @files if (scalar @files) > 0;
+
+ if ((exists $$values_hash{$key}) or ($key eq "_always_"))
+ {
+ $res = &gst_replace_run_entry ($values_hash, $key, $proc, \@cp, $$values_hash{$key});
+ }
+ elsif ((!exists $$values_hash{$key}) && (exists $$old_hash{$key}))
+ {
+ # we need to remove all the instances of the known variables that doesn't exist in the XML
+ $res = &gst_replace_run_entry ($values_hash, $key, $proc, \@cp, undef);
+ }
+ }
+
+ return $res;
+}
+
+# Wacky function that tries to create a field separator from a regular expression.
+# Doesn't work with all possible regular expressions: just with the ones we are working with.
+sub gst_replace_regexp_to_separator
+{
+ $_ = $_[0];
+
+ s/\[([^^])([^\]])[^\]]*\]/$1/g;
+ s/\+//g;
+ s/\$//g;
+ s/[^\*]\*//g;
+
+ return $_;
+}
+
+sub is_array_ref
+{
+ my $val;
+
+ return 1 if (ref ($val) eq "ARRAY");
+ return 0 if (ref ($val) eq undef);
+
+ &gst_debug_print_line ("is_array_ref: We shouldn't be here!");
+
+ return 0;
+}
+
+sub set_value
+{
+ my ($key, $val, $re) = @_;
+
+ return $key . &gst_replace_regexp_to_separator ($re) . $val;
+}
+
+# Edit a $file, wich is assumed to have a column-based format, with $re matching field separators
+# and one record per line. Search for lines with the corresponding $key.
+# The last arguments can be any number of standard strings.
+sub gst_replace_split
+{
+ my ($file, $key, $re, @value) = @_;
+ my ($fd, @line, @res);
+ my ($buff, $i);
+ my ($pre_space, $post_comment);
+ my ($line_key, $val, $ret);
+
+ &gst_report_enter ();
+ &gst_report ("replace_split", $key, $file);
+
+ $buff = &gst_file_buffer_load ($file);
+
+ foreach $i (@$buff)
+ {
+ $pre_space = $post_comment = "";
+
+ chomp $i;
+ $pre_space = $1 if $i =~ s/^([ \t]+)//;
+ $post_comment = $1 if $i =~ s/([ \t]*\#.*)//;
+
+ if ($i ne "")
+ {
+ @line = split ($re, $i, 2);
+ $line_key = shift (@line);
+
+ # found the key?
+ if ($line_key eq $key)
+ {
+ shift (@value) while ($value[0] eq "" && (scalar @value) > 0);
+
+ if ((scalar @value) == 0)
+ {
+ $i = "";
+ next;
+ }
+
+ $val = shift (@value);
+
+ chomp $val;
+ $i = &set_value ($key, $val, $re);
+ }
+ }
+
+ $i = $pre_space . $i . $post_comment . "\n";
+ }
+
+ foreach $i (@value)
+ {
+ push (@$buff, &set_value ($key, $i, $re) . "\n") if ($i ne "");
+ }
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+# Replace all key/values in file with those in @$value,
+# deleting exceeding ones and appending those required.
+sub gst_replace_join_all
+{
+ my ($file, $key, $re, $value) = @_;
+
+ return &gst_replace_split ($file, $key, $re, @$value);
+}
+
+# Find first $key value and replace with $value. Append if not found.
+sub gst_replace_join_first_str
+{
+ my ($file, $key, $re, $value) = @_;
+
+ return &gst_replace_split ($file, $key, $re, $value);
+}
+
+# Treat value as a bool value, using val_off and val_on as corresponding
+# boolean representations.
+sub gst_replace_join_first_bool
+{
+ my ($file, $key, $re, $val_on, $val_off, $value) = @_;
+
+ # Fixme: on and off should be a parameter.
+ $value = ($value == 1)? $val_on: $val_off;
+
+ return &gst_replace_split ($file, $key, $re, $value);
+}
+
+# Find first key in file, and set array join as value.
+sub gst_replace_join_first_array
+{
+ my ($file, $key, $re1, $re2, $value) = @_;
+
+ return &gst_replace_split ($file, $key, $re1, join (&gst_replace_regexp_to_separator ($re2), @$value));
+}
+
+# Escape $value in /bin/sh way, find/append key and set escaped value.
+sub gst_replace_sh
+{
+ my ($file, $key, $value) = @_;
+ my $ret;
+
+ $value = &gst_parse_shell_escape ($value);
+
+ &gst_report_enter ();
+ &gst_report ("replace_sh", $key, $file);
+
+ # This will expunge the whole var if the value is empty.
+ if ($value eq "")
+ {
+ $ret = &gst_replace_split ($file, $key, "[ \t]*=[ \t]*");
+ }
+ else
+ {
+ $ret = &gst_replace_split ($file, $key, "[ \t]*=[ \t]*", $value);
+ }
+
+ &gst_report_leave ();
+ return $ret;
+}
+
+# Escape $value in /bin/sh way, find/append key and set escaped value, make sure line har
+sub gst_replace_sh_export
+{
+ my ($file, $key, $value) = @_;
+ my $ret;
+
+ $value = &gst_parse_shell_escape ($value);
+
+ # This will expunge the whole var if the value is empty.
+
+ # FIXME: Just adding "export " works for the case I need, though it doesn't
+ # handle arbitraty whitespace. Something should be written to replace gst_replace_split()
+ # here.
+
+ if ($value eq "")
+ {
+ $ret = &gst_replace_split ($file, "export " . $key, "[ \t]*=[ \t]*");
+ }
+ else
+ {
+ $ret = &gst_replace_split ($file, "export " . $key, "[ \t]*=[ \t]*", $value);
+ }
+
+ return $ret;
+}
+
+# Treat value as a yes/no bool, replace in shell style.
+# val_true and val_false have default yes/no values.
+# use &gst_replace_sh_bool (file, key, value) if defaults are desired.
+sub gst_replace_sh_bool
+{
+ my ($file, $key, $val_true, $val_false, $value) = @_;
+
+ # default value magic.
+ if ($val_false eq undef)
+ {
+ $value = $val_true;
+ $val_true = undef;
+ }
+
+ $val_true = "yes" unless $val_true;
+ $val_false = "no" unless $val_false;
+
+ $value = ($value == 1)? $val_true: $val_false;
+
+ return &gst_replace_sh ($file, $key, $value);
+}
+
+# Treat value as a yes/no bool, replace in export... shell style.
+sub gst_replace_sh_export_bool
+{
+ my ($file, $key, $val_true, $val_false, $value) = @_;
+
+ # default value magic.
+ if ($val_false eq undef)
+ {
+ $value = $val_true;
+ $val_true = undef;
+ }
+
+ $val_true = "yes" unless $val_true;
+ $val_false = "no" unless $val_false;
+
+ $value = ($value == 1)? $val_true: $val_false;
+
+ return &gst_replace_sh_export ($file, $key, $value);
+}
+
+# Get a fully qualified hostname from a $key shell var in $file
+# and set the hostname part. e.g.: suse70's /etc/rc.config's FQHOSTNAME.
+sub gst_replace_sh_set_hostname
+{
+ my ($file, $key, $value) = @_;
+ my ($domain);
+
+ $domain = &gst_parse_sh_get_domain ($file, $key);
+ return &gst_replace_sh ($file, $key, "$value.$domain");
+}
+
+# Get a fully qualified hostname from a $key shell var in $file
+# and set the domain part. e.g.: suse70's /etc/rc.config's FQHOSTNAME.
+sub gst_replace_sh_set_domain
+{
+ my ($file, $key, $value) = @_;
+ my ($hostname);
+
+ $hostname = &gst_parse_sh_get_hostname ($file, $key);
+ return &gst_replace_sh ($file, $key, "$hostname.$value");
+}
+
+# Join the array pointed by $value with the corresponding $re separator
+# and assign that to the $key shell variable in $file.
+sub gst_replace_sh_join
+{
+ my ($file, $key, $re, $value) = @_;
+
+ return &gst_replace_sh ($file, $key,
+ join (&gst_replace_regexp_to_separator ($re), @$value));
+}
+
+# replace a regexp with $value
+sub gst_replace_sh_re
+{
+ my ($file, $key, $re, $value) = @_;
+ my ($val);
+
+ $val = &gst_parse_sh ($file, $key);
+
+ if ($val =~ /$re/)
+ {
+ $val =~ s/$re/$value/;
+ }
+ else
+ {
+ $val .= $value;
+ }
+
+ $val = '"' . $val . '"' if ($val !~ /^\".*\"$/);
+
+ return &gst_replace_split ($file, $key, "[ \t]*=[ \t]*", $val)
+}
+
+# Quick trick to set a keyword $key in $file. (think /etc/lilo.conf keywords).
+sub gst_replace_kw
+{
+ my ($file, $key, $value) = @_;
+ my $ret;
+
+ &gst_report_enter ();
+ &gst_report ("replace_kw", $key, $file);
+ $ret = &gst_replace_split ($file, $key, "\$", ($value)? "\n" : "");
+ &gst_report_leave ();
+ return $ret;
+}
+
+# The kind of $file whose $value is its first line contents.
+# (/etc/hostname)
+sub gst_replace_line_first
+{
+ my ($file, $value) = @_;
+ my $fd;
+
+ &gst_report_enter ();
+ &gst_report ("replace_line_first", $file);
+ $fd = &gst_file_open_write_from_names ($file);
+ &gst_report_leave ();
+ return -1 if !$fd;
+
+ print $fd "$value\n";
+ &gst_file_close ($fd);
+
+ return 0;
+}
+
+# For every key in %$value, replace/append the corresponding key/value pair.
+# The separator for $re1
+sub gst_replace_join_hash
+{
+ my ($file, $re1, $re2, $value) = @_;
+ my ($i, $res, $tmp, $val);
+ my ($oldhash, %merge);
+
+ $oldhash = &gst_parse_split_hash ($file, $re1, $re2);
+ foreach $i (keys (%$value), keys (%$oldhash))
+ {
+ $merge{$i} = 1;
+ }
+
+ $res = 0;
+
+ foreach $i (keys (%merge))
+ {
+ if (exists $$value{$i})
+ {
+ $val = join (&gst_replace_regexp_to_separator ($re2), @{$$value{$i}});
+ $tmp = &gst_replace_split ($file, $i, $re1, $val);
+ }
+ else
+ {
+ # This deletes the entry.
+ $tmp = &gst_replace_split ($file, $i, $re1);
+ }
+ $res = $tmp if !$res;
+ }
+
+ return $res;
+}
+
+# Find $re matching send string and replace parenthesyzed
+# part of $re with $value. FIXME: apply meeks' more general impl.
+sub gst_replace_chat
+{
+ my ($file, $re, $value) = @_;
+ my ($buff, $i, $bak, $found, $substr, $ret);
+
+ &gst_report_enter ();
+ &gst_report ("replace_chat", $file);
+ $buff = &gst_file_buffer_load ($file);
+
+ SCAN: foreach $i (@$buff)
+ {
+ $bak = "";
+ $found = "";
+ my ($quoted);
+ chomp $i;
+
+ while ($i ne "")
+ {
+ # If it uses quotes. FIXME: Assuming they surround the whole string.
+ if ($i =~ /^\'/)
+ {
+ $i =~ s/\'([^\']*)\' ?//;
+ $found = $1;
+ $quoted = 1;
+ }
+ else
+ {
+ $i =~ s/([^ \t]*) ?//;
+ $found = $1;
+ $quoted = 0;
+ }
+
+ # If it looks like what we're looking for,
+ # substitute what is in parens with value.
+ if ($found =~ /$re/i)
+ {
+ $substr = $1;
+ $found =~ s/$substr/$value/i;
+
+ if ($quoted == 1)
+ {
+ $i = $bak . "\'$found\' " . $i . "\n";
+ }
+ else
+ {
+ $i = $bak . "$found " . $i . "\n";
+ }
+
+ last SCAN;
+ }
+
+ if ($quoted == 1)
+ {
+ $bak .= "\'$found\'";
+ }
+ else
+ {
+ $bak .= "$found";
+ }
+
+ $bak .= " " if $bak ne "";
+ }
+
+ $i = $bak . "\n";
+ }
+
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+# Find/append $section in ini $file and replace/append
+# $var = $value pair. FIXME: should reimplement with
+# interfaces style. This is too large.
+sub gst_replace_ini
+{
+ my ($file, $section, $var, $value) = @_;
+ my ($buff, $i, $found_flag, $ret);
+ my ($pre_space, $post_comment, $sec_save);
+
+ &gst_report_enter ();
+ &gst_report ("replace_ini", $var, $section, $file);
+
+ $buff = &gst_file_buffer_load ($file);
+
+ &gst_file_buffer_join_lines ($buff);
+ $found_flag = 0;
+
+ foreach $i (@$buff)
+ {
+ $pre_space = $post_comment = "";
+
+ chomp $i;
+ $pre_space = $1 if $i =~ s/^([ \t]+)//;
+ $post_comment = $1 if $i =~ s/([ \t]*[\#;].*)//;
+
+ if ($i ne "")
+ {
+ if ($i =~ /\[$section\]/i)
+ {
+ $i =~ s/(\[$section\][ \t]*)//i;
+ $sec_save = $1;
+ $found_flag = 1;
+ }
+
+ if ($found_flag)
+ {
+ if ($i =~ /\[[^\]]+\]/)
+ {
+ $i = "$var = $value\n$i" if ($value ne "");
+ $found_flag = 2;
+ }
+
+ if ($i =~ /^$var[ \t]*=/i)
+ {
+ if ($value ne "")
+ {
+ $i =~ s/^($var[ \t]*=[ \t]*).*/$1$value/i;
+ }
+ else
+ {
+ $i = "";
+ }
+ $found_flag = 2;
+ }
+ }
+ }
+
+ if ($found_flag && $sec_save ne "")
+ {
+ $i = $sec_save . $i;
+ $sec_save = "";
+ }
+
+ $i = $pre_space . $i . $post_comment . "\n";
+ last if $found_flag == 2;
+ }
+
+ push @$buff, "\n[$section]\n" if (!$found_flag);
+ push @$buff, "$var = $value\n" if ($found_flag < 2 && $value ne "");
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+# Well, removes a $section from an ini type $file.
+sub gst_replace_remove_ini_section
+{
+ my ($file, $section) = @_;
+ my ($buff, $i, $found_flag, $ret);
+ my ($pre_space, $post_comment, $sec_save);
+
+ &gst_report_enter ();
+ &gst_report ("replace_del_ini_sect", $section, $file);
+
+ $buff = &gst_file_buffer_load ($file);
+
+ &gst_file_buffer_join_lines ($buff);
+ $found_flag = 0;
+
+ foreach $i (@$buff)
+ {
+ $pre_space = $post_comment = "";
+
+ chomp $i;
+ $pre_space = $1 if $i =~ s/^([ \t]+)//;
+ $post_comment = $1 if $i =~ s/([ \t]*[\#;].*)//;
+
+ if ($i ne "")
+ {
+ if ($i =~ /\[$section\]/i)
+ {
+ $i =~ s/(\[$section\][ \t]*)//i;
+ $found_flag = 1;
+ }
+ elsif ($found_flag && $i =~ /\[.+\]/i)
+ {
+ $i = $pre_space . $i . $post_comment . "\n";
+ last;
+ }
+ }
+
+ if ($found_flag)
+ {
+ if ($post_comment =~ /^[ \t]*$/)
+ {
+ $i = "";
+ }
+ else
+ {
+ $i = $post_comment . "\n";
+ }
+ }
+ else
+ {
+ $i = $pre_space . $i . $post_comment . "\n";
+ }
+ }
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+# Removes a $var in $section of a ini type $file.
+sub gst_replace_remove_ini_var
+{
+ my ($file, $section, $var) = @_;
+ &gst_replace_ini ($file, $section, $var, "");
+}
+
+# Replace using boolean $value with a yes/no representation,
+# ini style.
+sub gst_replace_ini_bool
+{
+ my ($file, $section, $var, $value) = @_;
+
+ $value = ($value == 1)? "yes": "no";
+
+ return &gst_replace_ini ($file, $section, $var, $value);
+}
+
+# *cap replacement methods.
+#sub gst_replace_cap
+#{
+# my ($file, $section, $var, $value) = @_;
+# my ($buff, $i, $found_flag, $ret);
+# my ($pre_space, $post_comment, $sec_save);
+#
+# $buff = &gst_file_buffer_load ($file);
+## &gst_file_buffer_join_lines ($buff);
+# $found_flag = 0;
+#
+# foreach $i (@$buff)
+# {
+# $pre_space = $post_comment = "";
+#
+# chomp $i;
+# $pre_space = $1 if $i =~ s/^([ \t]+)//;
+# $post_comment = $1 if $i =~ s/^([ \t]*[\#].*)//;
+#
+# if ($i ne "")
+# {
+# if ($i =~ /^$section[|:]/i)
+# {
+# $i =~ s/^($section)//i;
+# $sec_save = $1;
+# $found_flag = 1;
+# }
+#
+# if ($found_flag)
+# {
+# if ($i =~ /^[a-z0-9]+[|:]/)
+# {
+# $i = "\t:$var=$value:\n$i";
+# $found_flag = 2;
+# }
+#
+# if ($found_flag && $i =~ /^:$var[=:]/i)
+# {
+# if ($value ne "")
+# {
+# $i =~ s/^(:$var)[^:]*/$1=$value/i;
+# }
+# else
+# {
+# $i = "";
+# }
+# $found_flag = 2;
+# }
+# }
+# }
+#
+# if ($found_flag && $sec_save ne "")
+# {
+# $i = $sec_save . $i;
+# $sec_save = "";
+# }
+#
+# $i = $pre_space . $i . $post_comment . "\n";
+# last if $found_flag == 2;
+# }
+#
+# push @$buff, "\n$section:\\\n" if (!$found_flag);
+# push @$buff, "\t:$var=$value:\n" if ($found_flag < 2 && $value ne "");
+#
+# &gst_file_buffer_clean ($buff);
+# $ret = &gst_file_buffer_save ($buff, $file);
+# return $ret;
+#}
+
+sub gst_replace_remove_cap_section
+{
+ my ($file, $section) = @_;
+ my ($buff, $i, $found_flag, $ret);
+ my ($pre_space, $post_comment, $sec_save);
+
+ $buff = &gst_file_buffer_load ($file);
+ $found_flag = 0;
+
+ foreach $i (@$buff)
+ {
+ $pre_space = $post_comment = "";
+
+ chomp $i;
+ $pre_space = $1 if $i =~ s/^([ \t]+)//;
+ $post_comment = $1 if $i =~ s/^([ \t]*[\#].*)//;
+
+ if ($i ne "")
+ {
+ if ($i =~ /^$section[|:]/i)
+ {
+ $i = "";
+ $found_flag = 1;
+ }
+ elsif ($found_flag && $i =~ /^[a-z0-9]+[|:]/i)
+ {
+ $i = $pre_space . $i . $post_comment . "\n";
+ last;
+ }
+ }
+
+ if ($found_flag)
+ {
+ if ($post_comment =~ /^[ \t]*$/)
+ {
+ $i = "";
+ }
+ else
+ {
+ $i = $post_comment . "\n";
+ }
+ }
+ else
+ {
+ $i = $pre_space . $i . $post_comment . "\n";
+ }
+ }
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ return $ret;
+}
+
+# Save a printcap buffer to file. This doesn't do any extra processing for now,
+# but it may do so in the future.
+sub gst_replace_printcap_buffer_save
+{
+ my ($file, $buf) = @_;
+ my $ret;
+
+ &gst_file_buffer_clean ($buf);
+ $ret = &gst_file_buffer_save ($buf, $file);
+ return $ret;
+}
+
+sub gst_replace_printcap_print_stanza
+{
+ my ($stanza) = @_;
+ return $stanza . ":\n";
+}
+
+sub gst_replace_printcap_print_option
+{
+ my ($option, $type, $value) = @_;
+ return "\t:" . $option . $type . $value . ":\n";
+}
+
+sub gst_replace_printcap_add_stanza
+{
+ my ($buf, $stanza) = @_;
+
+ push @$buf, "\n";
+ push @$buf, "##PRINTTOOL3## LOCAL unknown NAxNA {} Unknown Default {}\n";
+ push @$buf, &gst_replace_printcap_print_stanza ($stanza);
+
+ return ($#$buf - 1, $#$buf);
+}
+
+sub gst_replace_printcap_add_option_slot
+{
+ my ($buf, $stanza_line_no) = @_;
+ my (@buf_tail);
+
+ @buf_tail = splice (@$buf, $stanza_line_no + 1);
+ push @$buf, "\t:NEW_OPTION:\n";
+ push @$buf, @buf_tail;
+
+ return $stanza_line_no + 1;
+}
+
+sub gst_replace_printcap_remove_stanza_from_buf
+{
+ my ($buf, $printtool_line_no, $stanza_line_no) = @_;
+ my ($next_printtool_line_no, $next_stanza_line_no);
+ my ($splice_start, $splice_end);
+
+ ($next_printtool_line_no, $next_stanza_line_no) =
+ &gst_parse_printcap_get_next_stanza ($buf, $stanza_line_no + 1);
+
+ if ($printtool_line_no != -1)
+ {
+ $splice_start = $printtool_line_no;
+ }
+ else
+ {
+ $splice_start = $stanza_line_no;
+ }
+
+ if ($next_printtool_line_no != -1)
+ {
+ $splice_end = $next_printtool_line_no;
+ }
+ else
+ {
+ $splice_end = $next_stanza_line_no;
+ }
+
+ if ($splice_end != -1)
+ {
+ splice (@$buf, $splice_start, $splice_end - $splice_start);
+ }
+ else
+ {
+ splice (@$buf, $splice_start);
+ }
+}
+
+sub gst_replace_printcap_remove_option_slot
+{
+ my ($buf, $option_line_no) = @_;
+ splice (@$buf, $option_line_no, 1);
+}
+
+# High-level API.
+sub gst_replace_printcap_remove_printer
+{
+ my ($file, $printer) = @_;
+ my ($buf, $printtool_line_no, $stanza_line_no);
+
+ $buf = &gst_parse_printcap_buffer_load ($file);
+
+ ($printtool_line_no, $stanza_line_no) = &gst_parse_printcap_find_stanza ($buf, 0, $printer);
+ &gst_replace_printcap_remove_stanza_from_buf ($buf, $printtool_line_no, $stanza_line_no);
+
+ $ret = &gst_replace_printcap_buffer_save ($file, $buf);
+ return $ret;
+}
+
+# High-level API.
+sub gst_replace_printcap
+{
+ my ($file, $section, $var, $type, $value) = @_;
+ my ($printtool_line_no, $stanza_line_no, $option_line_no);
+ my ($buf, $ret);
+
+ $buf = &gst_parse_printcap_buffer_load ($file);
+
+ ($printtool_line_no, $stanza_line_no) = &gst_parse_printcap_find_stanza ($buf, 0, $section);
+ if ($stanza_line_no == -1)
+ {
+ ($printtool_line_no, $stanza_line_no) = &gst_replace_printcap_add_stanza ($buf, $section);
+ }
+
+ $option_line_no = &gst_parse_printcap_find_option ($buf, $stanza_line_no + 1, $var);
+ if ($option_line_no == -1)
+ {
+ $option_line_no = &gst_replace_printcap_add_option_slot ($buf, $stanza_line_no);
+ }
+
+ if ($type ne "")
+ {
+ $$buf [$option_line_no] = "\t:" . $var . $type . $value . ":\n";
+ }
+ elsif ($value == 1)
+ {
+ $$buf [$option_line_no] = "\t:" . $var . ":\n";
+ }
+ else
+ {
+ &gst_replace_printcap_remove_option_slot ($buf, $option_line_no);
+ }
+
+ $ret = &gst_replace_printcap_buffer_save ($file, $buf);
+ return $ret;
+}
+
+# Debian /etc/network/interfaces in-line replacing methods.
+
+# From loaded buffer, starting at $line_no, find next debian
+# interfaces format stanza. Return array ref with all stanza args.
+# -1 if not found.
+# NOTE: $line_no is a scalar ref. and gives the position of next stanza.
+sub gst_replace_interfaces_get_next_stanza
+{
+ my ($buff, $line_no, $stanza_type) = @_;
+ my ($i, $line);
+
+ while ($$line_no < (scalar @$buff))
+ {
+ $_ = $$buff[$$line_no];
+ $_ = &gst_parse_interfaces_line_clean ($_);
+
+ if (/^$stanza_type[ \t]+[^ \t]/)
+ {
+ s/^$stanza_type[ \t]+//;
+ return [ split ("[ \t]+", $_) ];
+ }
+ $$line_no ++;
+ }
+
+ return -1;
+}
+
+sub gst_replace_interfaces_line_is_stanza
+{
+ my ($line) = @_;
+
+ return 1 if $line =~ /^(iface|auto|mapping)[ \t]+[^ \t]/;
+ return 0;
+}
+
+# Scan for next option. An option is something that is
+# not a stanza. Return key/value tuple ref, -1 if not found.
+# $$line_no will contain position.
+sub gst_replace_interfaces_get_next_option
+{
+ my ($buff, $line_no) = @_;
+ my ($i, $line, $empty_lines);
+
+ $empty_lines = 0;
+
+ while ($$line_no < (scalar @$buff))
+ {
+ $_ = $$buff[$$line_no];
+ $_ = &gst_parse_interfaces_line_clean ($_);
+
+ if (!/^$/)
+ {
+ return [ split ("[ \t]+", $_, 2) ] if (! &gst_replace_interfaces_line_is_stanza ($_));
+ $$line_no -= $empty_lines;
+ return -1;
+ }
+ else
+ {
+ $empty_lines ++;
+ }
+
+ $$line_no ++;
+ }
+
+ $$line_no -= $empty_lines;
+ return -1;
+}
+
+# Search buffer for option with key $key, starting
+# at $$line_no position. Return 1/0 found result.
+# $$line_no will show position.
+sub gst_replace_interfaces_option_locate
+{
+ my ($buff, $line_no, $key) = @_;
+ my $option;
+
+ while (($option = &gst_replace_interfaces_get_next_option ($buff, $line_no)) != -1)
+ {
+ return 1 if ($$option[0] eq $key);
+ $$line_no ++;
+ }
+
+ return 0;
+}
+
+# Locate stanza line for $iface in $buff, starting at $$line_no.
+sub gst_replace_interfaces_next_stanza_locate
+{
+ my ($buff, $line_no) = @_;
+
+ return &gst_replace_interfaces_get_next_stanza ($buff, \$$line_no, "(iface|auto|mapping)");
+}
+
+sub gst_replace_interfaces_iface_stanza_locate
+{
+ my ($buff, $line_no, $iface) = @_;
+
+ return &gst_replace_interfaces_generic_stanza_locate ($buff, \$$line_no, $iface, "iface");
+}
+
+sub gst_replace_interfaces_auto_stanza_locate
+{
+ my ($buff, $line_no, $iface) = @_;
+
+ return &gst_replace_interfaces_generic_stanza_locate ($buff, \$$line_no, $iface, "auto");
+}
+
+sub gst_replace_interfaces_generic_stanza_locate
+{
+ my ($buff, $line_no, $iface, $stanza_name) = @_;
+ my $stanza;
+
+ while (($stanza = &gst_replace_interfaces_get_next_stanza ($buff, \$$line_no, $stanza_name)) != -1)
+ {
+ return 1 if ($$stanza[0] eq $iface);
+ $$line_no++;
+ }
+
+ return 0;
+}
+
+# Create a Debian Woody stanza, type auto, with the requested
+# @ifaces as values.
+sub gst_replace_interfaces_auto_stanza_create
+{
+ my ($buff, @ifaces) = @_;
+ my ($count);
+
+ push @$buff, "\n" if ($$buff[$count] ne "");
+ push @$buff, "auto " . join (" ", @ifaces) . "\n";
+}
+
+# Append a stanza for $iface to buffer.
+sub gst_replace_interfaces_iface_stanza_create
+{
+ my ($buff, $iface) = @_;
+ my ($count);
+
+ $count = $#$buff;
+ push @$buff, "\n" if ($$buff[$count] ne "");
+ push @$buff, "iface $iface inet static\n";
+}
+
+# Delete $iface stanza and all its option lines.
+sub gst_replace_interfaces_iface_stanza_delete
+{
+ my ($file, $iface) = @_;
+ my ($buff, $line_no, $line_end, $stanza);
+
+ $buff = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($buff);
+ $line_no = 0;
+
+ return -1 if (!&gst_replace_interfaces_iface_stanza_locate ($buff, \$line_no, $iface));
+ $line_end = $line_no + 1;
+ &gst_replace_interfaces_next_stanza_locate ($buff, \$line_end);
+
+ while ($line_no < $line_end)
+ {
+ delete $$buff[$line_no];
+ $line_no++;
+ }
+
+ $line_no = 0;
+ if (&gst_replace_interfaces_auto_stanza_locate ($buff, \$line_no, $iface))
+ {
+ $line_end = $line_no + 1;
+ &gst_replace_interfaces_next_stanza_locate ($buff, \$line_end);
+
+ while ($line_no < $line_end)
+ {
+ delete $$buff[$line_no];
+ $line_no++;
+ }
+ }
+
+ &gst_file_buffer_clean ($buff);
+ return &gst_file_buffer_save ($buff, $file);
+}
+
+# Find $iface stanza line and replace $pos value (ie the method).
+sub gst_replace_interfaces_stanza_value
+{
+ my ($file, $iface, $pos, $value) = @_;
+ my ($buff, $line_no, $stanza);
+ my ($pre_space, $line, $line_arr);
+
+ $buff = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($buff);
+ $line_no = 0;
+
+ if (!&gst_replace_interfaces_iface_stanza_locate ($buff, \$line_no, $iface))
+ {
+ $line_no = 0;
+ &gst_replace_interfaces_iface_stanza_create ($buff, $iface);
+ &gst_replace_interfaces_iface_stanza_locate ($buff, \$line_no, $iface);
+ }
+
+ $line = $$buff[$line_no];
+ chomp $line;
+ $pre_space = $1 if $line =~ s/^([ \t]+)//;
+ $line =~ s/^iface[ \t]+//;
+ @line_arr = split ("[ \t]+", $line);
+ $line_arr[$pos] = $value;
+ $$buff[$line_no] = $pre_space . "iface " . join (' ', @line_arr) . "\n";
+
+ &gst_file_buffer_clean ($buff);
+ return &gst_file_buffer_save ($buff, $file);
+}
+
+# Find/append $key option in $iface stanza and set $value.
+sub gst_replace_interfaces_option_str
+{
+ my ($file, $iface, $key, $value) = @_;
+ my ($buff, $line_no, $stanza, $ret);
+ my ($pre_space, $line, $line_arr);
+
+ &gst_report_enter ();
+ &gst_report ("replace_ifaces_str", $key, $iface);
+
+ $buff = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($buff);
+ $line_no = 0;
+
+ if (!&gst_replace_interfaces_iface_stanza_locate ($buff, \$line_no, $iface))
+ {
+ $line_no = 0;
+ &gst_replace_interfaces_iface_stanza_create ($buff, $iface);
+ &gst_replace_interfaces_iface_stanza_locate ($buff, \$line_no, $iface);
+ }
+
+ $line_no++;
+
+ if (&gst_replace_interfaces_option_locate ($buff, \$line_no, $key))
+ {
+ if ($value eq "") # Delete option if value is empty.
+ {
+ $$buff[$line_no] = "";
+ }
+ else
+ {
+ chomp $$buff[$line_no];
+ $$buff[$line_no] =~ s/^([ \t]*$key[ \t]).*/$1/;
+ }
+ }
+ elsif ($value ne "")
+ {
+ $line_no --;
+ chomp $$buff[$line_no];
+ $$buff[$line_no] =~ s/^([ \t]*)(.*)/$1$2\n$1$key /;
+ }
+
+ $$buff[$line_no] .= $value . "\n" if $value ne "";
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+# $key option is keyword. $value says if it should exist or not.
+sub gst_replace_interfaces_option_kw
+{
+ my ($file, $iface, $key, $value) = @_;
+
+ return &gst_replace_interfaces_option_str ($file, $iface, $key, $value? " ": "");
+}
+
+# !$value says if keyword should exist or not (ie noauto).
+sub gst_replace_interfaces_option_kw_not
+{
+ my ($file, $iface, $key, $value) = @_;
+
+ return &gst_replace_interfaces_option_kw ($file, $iface, $key, !$value);
+}
+
+
+# Implementing pump(8) pump.conf file format replacer.
+# May be useful for dhcpd too.
+
+# Try to find the next option, returning an array ref
+# with the found key and the rest of the options in
+# two items, or -1 if not found.
+sub gst_replace_pump_get_next_option
+{
+ my ($buff, $line_no) = @_;
+
+ while ($$line_no < (scalar @$buff))
+ {
+ $_ = $$buff[$$line_no];
+ $_ = &gst_parse_interfaces_line_clean ($_);
+ if ($_ ne "")
+ {
+ return [ split ("[ \t]+", $_, 2) ];
+ }
+
+ $$line_no ++;
+ }
+
+ return -1;
+}
+
+# Iterate with get_next_option, starting at $line_no
+# until the option with $key is found, or eof.
+# Return 0/1 as found.
+sub gst_replace_pump_option_locate
+{
+ my ($buff, $line_no, $key) = @_;
+ my ($opt);
+
+ while (($opt = &gst_replace_pump_get_next_option ($buff, $line_no)) != -1)
+ {
+ return 1 if $$opt[0] eq $key;
+ return 0 if $$opt[0] eq "}";
+
+ $$line_no ++;
+ }
+
+ return 0;
+}
+
+# Try to find a "device" option whose interface is $iface,
+# starting at $$line_no. Return 0/1 as found.
+sub gst_replace_pump_get_device
+{
+ my ($buff, $line_no, $iface) = @_;
+ my ($opt);
+
+ while (($opt = &gst_replace_pump_get_next_option ($buff, $line_no)) != -1)
+ {
+ if ($$opt[0] eq "device")
+ {
+ $$opt[1] =~ s/[ \t]*\{//;
+ return 1 if $$opt[1] eq $iface;
+ }
+
+ $$line_no ++;
+ }
+
+ return 0;
+}
+
+# Add a device entry for $iface at the end of $buff.
+sub gst_replace_pump_add_device
+{
+ my ($buff, $iface) = @_;
+
+ push @$buff, "\n";
+ push @$buff, "device $iface {\n";
+ push @$buff, "\t\n";
+ push @$buff, "}\n";
+}
+
+# Find a "device" section for $iface and
+# replace/add/delete the $key option inside the section.
+sub gst_replace_pump_iface_option_str
+{
+ my ($file, $iface, $key, $value) = @_;
+ my ($line_no, $ret);
+
+ $buff = &gst_file_buffer_load ($file);
+ $line_no = 0;
+
+ if (!&gst_replace_pump_get_device ($buff, \$line_no, $iface))
+ {
+ $line_no = 0;
+ &gst_replace_pump_add_device ($buff, $iface);
+ &gst_replace_pump_get_device ($buff, \$line_no, $iface);
+ }
+
+ $line_no ++;
+
+ if (&gst_replace_pump_option_locate ($buff, \$line_no, $key))
+ {
+ if ($value eq "")
+ {
+ $$buff[$line_no] = "";
+ }
+ else
+ {
+ chomp $$buff[$line_no];
+ $$buff[$line_no] =~ s/^([ \t]*$key[ \t]).*/$1/;
+ }
+ }
+ elsif ($value ne "")
+ {
+ $line_no --;
+ chomp $$buff[$line_no];
+ $$buff[$line_no] =~ s/^([ \t]*)(.*)/$1$2\n$1$key /;
+ }
+
+ if ($value ne "")
+ {
+ $value =~ s/^[ \t]+//;
+ $value =~ s/[ \t]+$//;
+ $$buff[$line_no] .= &gst_parse_shell_escape ($value) . "\n";
+ }
+
+ &gst_file_buffer_clean ($buff);
+ $ret = &gst_file_buffer_save ($buff, $file);
+ &gst_report_leave ();
+ return $ret;
+}
+
+# Same as function above, except $key is a keyword.
+sub gst_replace_pump_iface_kw
+{
+ my ($file, $iface, $key, $value) = @_;
+
+ return &gst_replace_pump_iface_option_str ($file, $iface, $key, $value? " ": "");
+}
+
+# Same, but use the negative of $value (i.e. nodns)
+sub gst_replace_pump_iface_kw_not
+{
+ my ($file, $iface, $key, $value) = @_;
+
+ return &gst_replace_pump_iface_kw ($file, $iface, $key, !$value);
+}
+
+sub gst_replace_xml_pcdata
+{
+ my ($file, $varpath, $data) = @_;
+ my ($model, $branch, $fd, $compressed);
+
+ ($model, $compressed) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_ensure ($model, $varpath);
+
+ &gst_xml_model_set_pcdata ($branch, $data);
+
+ return &gst_xml_model_save ($model, $file, $compressed);
+}
+
+sub gst_replace_xml_attribute
+{
+ my ($file, $varpath, $attr, $value) = @_;
+ my ($model, $branch, $fd, $compressed);
+
+ ($model, $compressed) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_ensure ($model, $varpath);
+
+ &gst_xml_model_set_attribute ($branch, $attr, $value);
+
+ return &gst_xml_model_save ($model, $file, $compressed);
+}
+
+sub gst_replace_xml_pcdata_with_type
+{
+ my ($file, $varpath, $type, $data) = @_;
+ my ($model, $branch, $fd, $compressed);
+
+ ($model, $compressed) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_ensure ($model, $varpath);
+
+ &gst_xml_model_set_pcdata ($branch, $data);
+ &gst_xml_model_set_attribute ($branch, "TYPE", $type);
+
+ return &gst_xml_model_save ($model, $file, $compressed);
+}
+
+sub gst_replace_xml_attribute_with_type
+{
+ my ($file, $varpath, $attr, $type, $value) = @_;
+ my ($model, $branch, $fd, $compressed);
+
+ ($model, $compressed) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_ensure ($model, $varpath);
+
+ &gst_xml_model_set_attribute ($branch, $attr, $value);
+ &gst_xml_model_set_attribute ($branch, "TYPE", $type);
+
+ return &gst_xml_model_save ($model, $file, $compressed);
+}
+
+sub gst_replace_alchemist_ensure_list_types
+{
+ my ($model, $varpath, $setpath) = @_;
+ my ($branch, @path);
+
+ $branch = &gst_xml_model_find ($model, $varpath);
+ @path = split /\//, $setpath;
+
+ # NOTE: The following could be done with a depth-iterator callback from a func
+ # similar to gst_xml_model_find ().
+
+ for $elem (@path)
+ {
+ next if ($elem eq "");
+ my @children = @$branch;
+ shift @children; # Attributes
+ $branch = undef;
+
+ while (@children)
+ {
+ if ($children [0] eq $elem)
+ {
+ shift @children;
+ $branch = shift @children;
+ &gst_xml_model_set_attribute ($branch, "TYPE", "LIST");
+ last;
+ }
+
+ shift @children;
+ shift @children;
+ }
+
+ last if ($branch == undef);
+ }
+}
+
+sub gst_replace_alchemist
+{
+ my ($file, $varpath, $type, $value) = @_;
+ my ($fullpath, $model, $branch, $fd, $compressed);
+
+ $fullpath = "/adm_context/datatree/" . $varpath;
+ ($model, $compressed) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_ensure ($model, $fullpath);
+ &gst_replace_alchemist_ensure_list_types ($model, "/adm_context/datatree/", $varpath);
+
+ &gst_xml_model_set_attribute ($branch, "VALUE", $value);
+ &gst_xml_model_set_attribute ($branch, "TYPE", $type);
+
+ return &gst_xml_model_save ($model, $file, $compressed);
+}
+
+sub gst_replace_alchemist_print
+{
+ my ($file, $printer, $varpath, $type, $value) = @_;
+ my ($fullpath, $model, $branch, $fd, $compressed);
+
+ $fullpath = "/adm_context/datatree/printconf/print_queues/" . $printer . "/" . $varpath;
+ ($model, $compressed) = &gst_xml_model_scan ($file);
+
+ $branch = &gst_xml_model_ensure ($model, $fullpath);
+
+ &gst_replace_alchemist_ensure_list_types ($model, "/adm_context/datatree/",
+ "printconf/print_queues/" . $printer . "/" . $varpath);
+
+ &gst_xml_model_set_attribute ($branch, "VALUE", $value);
+ &gst_xml_model_set_attribute ($branch, "TYPE", $type);
+
+ $branch = &gst_xml_model_find ($model, "/adm_context/datatree/printconf/print_queues/" . $printer);
+ &gst_xml_model_set_attribute ($branch, "ATOMIC", "TRUE");
+
+ return &gst_xml_model_save ($model, $file, $compressed);
+}
+
+# This could be split up.
+sub gst_replace_alchemist_print_option
+{
+ my ($file, $printer, $name, $type, $value) = @_;
+ my ($varpath, $model, $branch, $fd, $compressed, $options, $option);
+
+ ($model, $compressed) = &gst_xml_model_scan ($file);
+ $branch = &gst_xml_model_ensure ($model, "/adm_context/datatree/printconf/print_queues/" . $printer .
+ "/filter_data/foomatic_defaults");
+ &gst_replace_alchemist_ensure_list_types ($model, "/adm_context/datatree/", "printconf/print_queues/" .
+ $printer . "/filter_data/foomatic_defaults");
+ &gst_xml_model_set_attribute ($branch, "ANONYMOUS", "TRUE");
+
+ # See if option is already defined.
+
+ $options = &gst_xml_model_get_children ($branch);
+
+ foreach $o (@$options)
+ {
+ my $opt_node = &gst_xml_model_find ($o, "name");
+ next if (!$opt_node);
+
+ if (&gst_xml_model_get_attribute ($opt_node, "VALUE") eq $name)
+ {
+ $option = $o;
+ last;
+ }
+ }
+
+ # If not, create node for it.
+
+ if (!$option)
+ {
+ $option = &gst_xml_model_add ($branch, "", $option_default);
+ &gst_xml_model_set_attribute ($option, "TYPE", "LIST");
+ }
+
+ # Set the option attributes.
+
+ my $node = &gst_xml_model_ensure ($option, "name");
+ &gst_xml_model_set_attribute ($node, "TYPE", "STRING");
+ &gst_xml_model_set_attribute ($node, "VALUE", $name);
+
+ $node = &gst_xml_model_ensure ($option, "type");
+ &gst_xml_model_set_attribute ($node, "TYPE", "STRING");
+ &gst_xml_model_set_attribute ($node, "VALUE", $type);
+
+ $node = &gst_xml_model_ensure ($option, "default");
+ &gst_xml_model_set_attribute ($node, "TYPE", "STRING");
+ &gst_xml_model_set_attribute ($node, "VALUE", $value);
+
+ return &gst_xml_model_save ($model, $file, $compressed);
+}
+
+sub gst_replace_fq_hostname
+{
+ my ($file, $hostname, $domain) = @_;
+
+ if ($domain eq undef)
+ {
+ return &gst_replace_line_first ($file, "$hostname");
+ }
+ else
+ {
+ return &gst_replace_line_first ($file, "$hostname.$domain");
+ }
+}
+
+sub gst_replace_rcinet1conf
+{
+ my ($file, $iface, $kw, $val) = @_;
+ my ($line);
+
+ $iface =~ s/eth//;
+ $line = "$kw\[$iface\]";
+
+ $val = "\"$val\"" if ($val ne undef);
+
+ return &gst_replace_split ($file, $line, "[ \t]*=[ \t]*", $val);
+}
+
+sub gst_replace_rcinet1conf_global
+{
+ my ($file, $kw, $val) = @_;
+
+ $val = "\"$val\"";
+
+ return &gst_replace_split ($file, $kw, "[ \t]*=[ \t]*", $val)
+}
+
+sub gst_replace_wireless_opts
+{
+ my ($file, $iface, $proc, $kw, $value) = @_;
+ my $ifaces = &$proc ();
+ my $found = 0;
+ my $search = 1;
+ my $buff;
+
+ foreach $i (@$ifaces)
+ {
+ $found = 1 if ($iface eq $i);
+ }
+
+ $buff = &gst_file_buffer_load ($file);
+
+ foreach $i (@$buff)
+ {
+ if (/^case/)
+ {
+ # we don't want to search inside the case
+ $search = 0;
+ }
+ elsif (/^esac/)
+ {
+ # we want to continue searching
+ $search = 1;
+ }
+ if ((/^[ \t]*$kw/) && ($search))
+ {
+ $_ = "$kw=\"$value\"";
+ $found = 1;
+ }
+ }
+
+ if (!$found)
+ {
+ push @$buff, "$kw=\"$value\"";
+ }
+
+ &gst_file_buffer_clean ($buff);
+ return &gst_file_buffer_save ($buff, $file);
+}
+
+# Functions for replacing in FreeBSD's /etc/ppp/ppp.conf
+sub gst_replace_pppconf_common
+{
+ my ($pppconf, $section, $key, $string) = @_;
+ my ($buff, $line_no, $end_line_no, $i, $found);
+
+ $buff = &gst_file_buffer_load ($pppconf);
+
+ $line_no = &gst_parse_pppconf_find_stanza ($buff, $section);
+
+ if ($line_no ne -1)
+ {
+ # The stanza exists
+ $line_no++;
+
+ $end_line_no = &gst_parse_pppconf_find_next_stanza ($buff, $line_no);
+ $end_line_no = scalar @$buff + 1 if ($end_line_no == -1);
+ $end_line_no--;
+
+ for ($i = $line_no; $i <= $end_line_no; $i++)
+ {
+ if ($$buff[$i] =~ /[ \t]+$key/)
+ {
+ if ($string ne undef)
+ {
+ $$buff[$i] = " $string\n";
+ $found = 1;
+ }
+ else
+ {
+ delete $$buff[$i];
+ }
+ }
+ }
+
+ if ($found != 1)
+ {
+ $$buff[$end_line_no] .= " $string\n" if ($string ne undef);
+ }
+ }
+ else
+ {
+ if ($string ne undef)
+ {
+ push @$buff, "$section:\n";
+ push @$buff, " $string\n";
+ }
+ }
+
+ &gst_file_buffer_clean ($buff);
+ return &gst_file_buffer_save ($buff, $pppconf);
+}
+
+sub gst_replace_pppconf
+{
+ my ($pppconf, $section, $key, $value) = @_;
+ &gst_replace_pppconf_common ($pppconf, $section, $key, "set $key $value");
+}
+
+sub gst_replace_pppconf_bool
+{
+ my ($pppconf, $section, $key, $value) = @_;
+ &gst_replace_pppconf_common ($pppconf, $section, $key,
+ ($value == 1)? "enable $key" : "disable $key");
+}
+
+sub gst_replace_confd_net_re
+{
+ my ($file, $key, $re, $value) = @_;
+ my ($str, $contents, $i, $found, $done);
+
+ $found = $done = 0;
+ $contents = &gst_file_buffer_load ($file);
+
+ for ($i = 0; $i <= scalar (@$contents); $i++)
+ {
+ # search for key
+ if ($$contents[$i] =~ /^$key[ \t]*=[ \t]*\(/)
+ {
+ $found = 1;
+
+ do {
+ if ($$contents[$i] =~ /\"([^\"]*)\"/)
+ {
+ $str = $1;
+
+ if ($str =~ /$re/)
+ {
+ $str =~ s/$re/$value/;
+ }
+ else
+ {
+ $str .= $value;
+ }
+
+ $$contents[$i] =~ s/\"([^\"]*)\"/\"$str\"/;
+ $done = 1;
+ }
+
+ $i++;
+ } while (!$done);
+ }
+ }
+
+ if (!$found)
+ {
+ push @$contents, "$key=(\"$value\")\n";
+ }
+
+ return &gst_file_buffer_save ($contents, $file);
+}
+
+sub gst_replace_confd_net
+{
+ my ($file, $key, $value) = @_;
+
+ return &gst_replace_confd_net_re ($file, $key, ".*", $value);
+}
diff --git a/knetworkconf/backends/report.pl.in b/knetworkconf/backends/report.pl.in
new file mode 100644
index 0000000..a1c23d3
--- /dev/null
+++ b/knetworkconf/backends/report.pl.in
@@ -0,0 +1,366 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# /* Functions for on-the-fly commentary on a tool's work. */
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/general.pl$DOTIN";
+
+# --- Progress printing --- #
+
+
+$gst_progress_current = 0; # Compat with old $progress_max use.
+$gst_progress_last_percentage = 0;
+
+
+sub gst_progress
+{
+ my $prc = $_[0];
+
+ # /* Don't go backwards. */
+ $prc = $gst_progress_last_percentage if ($prc < $gst_progress_last_percentage);
+
+ # /* Don't go above 99%. */
+ $prc = 99 if ($prc >= 100);
+
+ if ($gst_progress && (int $prc > int $gst_progress_last_percentage))
+ {
+ &gst_report ("progress", $prc);
+ $gst_progress_last_percentage = $prc;
+ }
+}
+
+
+sub gst_progress_begin
+{
+ &gst_progress (0);
+}
+
+
+sub gst_progress_end
+{
+ &gst_progress (99);
+}
+
+
+sub gst_print_progress # Compat with old $progress_max use.
+{
+ my $prc;
+
+ $gst_progress_current++;
+ &gst_progress (($gst_progress_current * 100) / $progress_max);
+}
+
+
+# --- Report printing --- #
+
+
+sub gst_report_begin
+{
+ my ($tool) = @_;
+
+ &gst_report ("begin");
+ &gst_report_enter ();
+ &gst_progress_begin ();
+}
+
+
+sub gst_report_end
+{
+ &gst_progress_end ();
+ &gst_report_leave ();
+ &gst_report ("end");
+}
+
+
+sub gst_report_set_threshold
+{
+ $gst_report_threshold = $_[0];
+}
+
+
+sub gst_report_enter
+{
+ # This has been trivialized because it is not working
+ # correctly at the moment and is causing some trouble.
+ # /* We'll probably replace this with something smarter */
+ # (like a detail-level value in the report hash)
+ # when the report strings are used at the gui-level again.
+# $gst_report_level ++;
+ $gst_report_level = 0;
+}
+
+
+sub gst_report_leave
+{
+# $gst_report_level --;
+ $gst_report_level = 0;
+}
+
+
+# Escapes a report using the report line format.
+sub gst_report_escape
+{
+ my ($args) = @_;
+ my ($arg);
+
+ foreach $arg (@$args)
+ {
+ $arg =~ s/\\/\\\\/g;
+ $arg =~ s/::/\\::/g;
+ }
+}
+
+
+$gst_report_level = 0;
+$gst_report_started = 0;
+
+# Just to trap these errors with the debugger easily.
+sub gst_report_stderr
+{
+ my ($major, $key, $res) = @_;
+
+ print STDERR "$gst_name - $major::${key}::$res";
+}
+
+sub gst_report
+{
+ my (@args) = @_;
+ my ($key, $major, $minor, $str, $format, $res);
+ my $report_message = &gst_report_table ();
+
+ &gst_report_escape (\@args);
+
+ $key = shift @args;
+
+ if (! (exists $$report_message{$key}))
+ {
+ &gst_report ("report_minor_unk", $key);
+ return;
+ }
+
+ ($major, $str) = @{$$report_message{$key}};
+
+ if (! (exists $gst_report_valid_majors{$major}))
+ {
+ &gst_report ("report_major_unk", $major, join ("::", $key, @args));
+ return;
+ }
+
+ $gst_report_started = 1 if !$gst_report_started && $key eq "begin" && $major eq "sys";
+
+ # Verbose (--verbose) output is human-readable only.
+ $format = "$str\n";
+ $res = sprintf ($format, @args);
+
+ if ($gst_do_verbose ||
+ $major eq "error" ||
+ $major eq "debug")
+ {
+ &gst_report_stderr ($major, $key, $res);
+ }
+
+ if ($key ne "progress")
+ {
+ return if ($gst_report_level >= $gst_report_threshold || !$gst_report_started);
+ }
+
+ # Report (--report) output is machine-readable.
+ if ($gst_do_report)
+ {
+ print STDOUT join ("::", $major, $key, $str, @args) . "\n";
+ }
+
+ &gst_debug_print_indented_string ($gst_report_level, "report $major:$key: $res");
+}
+
+# Internal
+{
+ my $report_table = \%gst_report_message;
+ sub gst_report_table
+ {
+ my $table = shift @_;
+
+ if ($table) # Add
+ {
+ foreach my $key (keys %$table)
+ {
+ $$report_table{$key} = $$table{$key} unless exists $$report_table{$key};
+ }
+ }
+
+ else # Get
+ {
+ return $report_table;
+ }
+ }
+}
+
+# This disables reporting.
+&gst_report_set_threshold (0);
+
+%gst_report_valid_majors = (
+ "sys" => 1,
+ "error" => 1,
+ "warn" => 1,
+ "info" => 1,
+ "debug" => 1
+ );
+
+%gst_report_message =
+ (
+ "begin" => ["sys", "Start of work report."],
+ "end" => ["sys", "End of work report."],
+ "progress" => ["sys", "%d"],
+ "compat" => ["info", "%s."],
+
+ "report_major_unk" => ["error", "Unknown major [%s] in report [%s]."],
+ "report_minor_unk" => ["error", "Unknown minor [%s]."],
+
+ "directive_run" => ["info", "Running directive [%s] with args [%s]."],
+ "directive_unsup" => ["error", "Directive [%s] not supported."],
+ "directive_invalid" => ["error", "Directive [%s] structure has wrong format."],
+ "directive_badargs" => ["error", "Directive [%s] requires exactly [%s] args in [%s]."],
+ "directive_lowargs" => ["error", "Directive [%s] requires at least [%s] args in [%s]."],
+
+ "platform_unsup" => ["error", "Your platform [%s] is not supported."],
+ "platform_undet" => ["error", "Unable to determine host platform."],
+ "platform_success" => ["sys", "Configuring for platform [%s] (%s)."],
+ "platform_no_table" => ["error", "No parse/replace table for platform [%s]."],
+
+ "xml_unexp_tag" => ["error", "Unexpected tag [%s]."],
+ "xml_unexp_arg" => ["error", "Unexpected argument [%s] to tag [%s]."],
+
+ "file_copy_failed" => ["debug", "Could not copy file [%s] to [%s]."],
+ "file_open_read_failed" => ["warn", "Could not open [%s] for reading."],
+ "file_open_read_success" => ["info", "Reading options from [%s]."],
+ "file_open_write_failed" => ["error", "Failed to write to [%s]."],
+ "file_open_write_create" => ["warn", "Could not find [%s] for writing. Creating [%s]."],
+ "file_open_write_success" => ["info", "Writing to [%s]."],
+ "file_run_pipe_failed" => ["warn", "Failed to pipe command [%s] for reading."],
+ "file_run_pipe_success" => ["info", "Piping command [%s] for reading."],
+ "file_run" => ["info", "Running command [%s]."],
+ "file_create_path" => ["info", "Directory [%s] created."],
+ "file_backup_rotate" => ["info", "Backup directory [%s] was rotated."],
+ "file_backup_success" => ["info", "Saved backup for [%s]."],
+ "file_open_filter_failed" => ["warn", "No file to patch: [%s]."],
+ "file_open_filter_create" => ["warn", "Could not find [%s] for patching. Creating [%s]."],
+ "file_open_filter_success" => ["info", "Found [%s]. Patching [%s]."],
+ "file_buffer_load" => ["info", "Loading file [%s] to buffer."],
+ "file_buffer_save" => ["info", "Saving buffer to file [%s]."],
+ "file_remove" => ["info", "Removing file [%s]."],
+ "file_locate_tool_success" => ["info", "Found tool [%s]."],
+ "file_locate_tool_failed" => ["warn", "Couldn't find tool [%s]."],
+
+ "parse_table" => ["info", "Parsing option [%s]."],
+ "parse_trivial" => ["info", "Trivialy passing [%s]."],
+ "parse_split" => ["info", "Getting option [%s] from [%s]."],
+ "parse_split_hash" => ["info", "Getting configuration from [%s]."],
+ "parse_split_hash_cont" => ["info", "Getting configuration from [%s]."],
+ "parse_sh" => ["info", "Getting shell option [%s] from [%s]."],
+ "parse_kw" => ["info", "Getting keyword [%s] from [%s]."],
+ "parse_line_first" => ["info", "Getting information from [%s]."],
+ "parse_chat" => ["info", "Getting chat information from [%s]."],
+ "parse_ini" => ["info", "Getting option [%s] from [%s], section [%s]."],
+ "parse_ifaces_str" => ["info", "Getting option [%s] from interface [%s]."],
+ "parse_ifaces_kw" => ["info", "Getting keyword [%s] from interface [%s]."],
+ "parse_ifaces_kw_strange" => ["warn", "Keyword for interface [%s] in [%s] had unexpected value."],
+
+ "replace_split" => ["info", "Replacing key [%s] in [%s]."],
+ "replace_sh" => ["info", "Replacing shell var [%s] in [%s]."],
+ "replace_kw" => ["info", "Replacing keyword [%s] in [%s]."],
+ "replace_line_first" => ["info", "Replacing contents of file [%s]."],
+ "replace_chat" => ["info", "Replacing values in [%s]."],
+ "replace_ini" => ["info", "Replacing variable [%s] in section [%s] of [%s]."],
+ "replace_del_ini_sect" => ["info", "Removing section [%s] from [%s]."],
+ "replace_ifaces_str" => ["info", "Replacing option [%s] from interface [%s]."],
+ "replace_ifaces_kw" => ["info", "Replacing keyword [%s] from interface [%s]."],
+
+ "service_status_running" => ["info", "Service [%s] is running."],
+ "service_status_stopped" => ["info", "Service [%s] is stopped."],
+ "service_sysv_unsupported" => ["info", "No SystemV support for platform [%s]."],
+ "service_sysv_not_found" => ["warn", "Could not find SystemV scripts for service [%s]."],
+ "service_sysv_no_runlevel" => ["warn", "Could not find SystemV runlevel [%s] directory [%s]."],
+ "service_sysv_remove_link" => ["info", "Removed SystemV link [%s]."],
+ "service_sysv_add_link" => ["info", "Created SystemV link [%s]."],
+ "service_sysv_op_unk" => ["error", "Unknown initd operation [%s]."],
+ "service_sysv_op_success" => ["info", "Service [%s] %s."],
+ "service_sysv_op_failed" => ["warn", "Service [%s] could not be %s."],
+
+ "network_dialing_get" => ["info", "Loading ISP configurations."],
+ "network_iface_active_get" => ["info", "Finding active interfaces."],
+ "network_iface_is_active" => ["info", "Checking if interface [%s] is active."],
+ "network_hostname_set" => ["info", "Setting hostname to [%s]."],
+ "network_dialing_set" => ["info", "Saving ISP configurations."],
+ "network_remove_pap" => ["info", "Removing entry [%s] from [%s]."],
+ "network_iface_set" => ["info", "Configuring interface [%s]."],
+ "network_iface_activate" => ["info", "Activating interface [%s]."],
+ "network_iface_deactivate" => ["info", "Deactivating interface [%s]."],
+ "network_ifaces_set" => ["info", "Setting up interfaces."],
+ "network_get_pap_passwd" => ["info", "Getting PAP/CHAP password for [%s] from [%s]."],
+ "network_get_ppp_option" => ["info", "Getting option [%s] from [%s]."],
+ "network_set_ppp_option" => ["info", "Setting option [%s] in [%s]."],
+ "network_set_ppp_connect" => ["info", "Setting connect option in [%s]."],
+ "network_get_ppp_unsup" => ["info", "Getting additional options from [%s]."],
+ "network_set_ppp_unsup" => ["info", "Setting additional options in [%s]."],
+ "network_bootproto_unsup" => ["warn", "Boot method [%s] for interface [%s] not supported."],
+ "network_get_remote" => ["info", "Getting remote address for interface [%s]."],
+ "network_set_remote" => ["info", "Setting remote address for interface [%s]."],
+ "network_ensure_lo" => ["info", "Ensuring loopback interface configuration."],
+
+ "filesys_mount" => ["info", "Mounting [%s] on [%s]."],
+ "filesys_mount_failed" => ["warn", "Failed to mount [%s] on [%s]."],
+ "filesys_unmount" => ["info", "Unmounting [%s] from [%s]."],
+ "filesys_unmount_failed" => ["warn", "Failed to unmount [%s] from [%s]."],
+
+ "boot_lilo_failed" => ["warn", "Failed to run lilo."],
+ "boot_lilo_success" => ["info", "Succesfully executed lilo."],
+ "boot_conf_read_failed" => ["error", "Failed to open boot configuration file [%s]."],
+ "boot_grub_convert_failed" => ["error", "Conversion of [%s] failed."],
+
+ "sfdisk_failed" => ["error", "Could not run sfdisk."],
+
+ "disks_fstab_add" => ["info", "Adding [%s] to fstab."],
+ "disks_partition_probe" => ["info", "Looking for partitions on [%s]."],
+ "disks_size_query" => ["info", "Querying size of [%s]."],
+ "disks_mount" => ["info", "Mounting [%s]."],
+ "disks_umount" => ["info", "Unmounting [%s]."],
+ "disks_mount_error" => ["error", "Could not find mount tools. No mounting done."],
+
+ "memory_swap_found" => ["info", "Found swap entry [%s]."],
+ "memory_swap_probe" => ["info", "Looking for swap entries."],
+
+ "print_no_printtool" => ["warn", "No printtool setup in directory [%s]."],
+
+ "time_timezone_scan" => ["info", "Scanning timezones."],
+ "time_timezone_cmp" => ["info", "Scanning timezones: [%s]."],
+ "time_timezone_set" => ["info", "Setting timezone as [%s]."],
+ "time_localtime_set" => ["info", "Setting local time as [%s]."]
+ );
+
+1;
diff --git a/knetworkconf/backends/service-list.pl.in b/knetworkconf/backends/service-list.pl.in
new file mode 100644
index 0000000..460c4ea
--- /dev/null
+++ b/knetworkconf/backends/service-list.pl.in
@@ -0,0 +1,337 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Functions for getting service descriptions.
+#
+# Copyright (C) 2002 Ximian, Inc.
+#
+# Authors: Carlos Garnacho Parro <garnacho@tuxerver.net>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+# This function determines if a service is "forbidden" or not (if runlevel-admin must show it or not)
+sub gst_service_list_service_is_forbidden
+{
+ my ($service) = @_;
+ my ($ret);
+
+ my ($service_forbidden_list) =
+ [
+ # These are the forbidden services I found in Red Hat
+ "halt",
+ "functions",
+ "killall",
+ # These are the forbidden services I found in Debian Woody
+ "single",
+ "sendsigs",
+ "reboot",
+ "rcS",
+ "modutils",
+ "hostname\.sh",
+ "devpts\.sh",
+ "console-screen\.sh",
+ "checkroot\.sh",
+ "checkfs\.sh",
+ "bootmisc\.sh",
+ "bootclean\.sh",
+ "checkfs\.sh",
+ "keymap\.sh",
+ "hwclockfirst\.sh",
+ "etc-setserial",
+ "procps\.sh",
+ "mountall\.sh",
+ "dns-clean",
+ "ifupdown",
+ "networking",
+ "mountnfs\.sh",
+ "mountkernfs",
+ "mountvirtfs",
+ "setserial",
+ "hwclock\.sh",
+ "urandom",
+ "nviboot",
+ "pppd-dns",
+ "skeleton",
+ "xfree86-common",
+ "rc",
+ ".*\.dpkg-old",
+ ".*~",
+ # this shouldn't be shown in slackware
+ "inet2",
+ # those were found in gentoo
+ "bootmisc",
+ "checkfs",
+ "checkroot",
+ "clock",
+ "consolefont",
+ "crypto-loop",
+ "domainname",
+ "hostname",
+ "keymaps",
+ "localmount",
+ "net\..*",
+ "numlock",
+ "depscan\.sh",
+ "functions\.sh",
+ "halt\.sh",
+ "reboot\.sh",
+ "rmnologin",
+ "runscript\.sh",
+ "serial",
+ "shutdown\.sh",
+ "switch",
+ # those were found in FreeBSD
+ "DAEMON",
+ "LOGIN",
+ "NETWORKING",
+ "SERVERS",
+ "addswap",
+ "adjkerntz",
+ "archdep",
+ "atm2\.sh",
+ "atm3\.sh",
+ "ccd",
+ "cleanvar",
+ "devdb",
+ "devfs",
+ "dhclient",
+ "diskless",
+ "dumpon",
+ "fsck",
+ "hostname",
+ "initdiskless",
+ "initrandom",
+ "ldconfig",
+ "local",
+ "localdaemons",
+ "mountcritlocal",
+ "mountcritremote",
+ "msgs",
+ "netif",
+ "network1",
+ "network2",
+ "network3",
+ "nisdomain",
+ "othermta",
+ "pccard",
+ "pcvt",
+ "pwcheck",
+ "random",
+ "rcconf\.sh",
+ "root",
+ "savecore",
+ "securelevel",
+ "serial",
+ "sppp",
+ "swap1",
+ "syscons",
+ "sysctl",
+ "ttys",
+ "virecover",
+ # These are the services found in SuSE
+ "rc[sS0-9]\.d",
+ "boot",
+ "boot\..*",
+ ];
+
+ foreach $i (@$service_forbidden_list)
+ {
+ return 1 if ($service =~ "^$i\$");
+ }
+
+ return undef;
+}
+
+
+# Ok, maybe we should define this roles stuff a bit:
+#
+# SYSTEM: all system related services that only powerusers care of
+# SOUND: any service related to sound
+# WEB_SERVER: any web server
+# COMMAND_SCHEDULER: any service which runs scheduled commands
+# NETWORK: network related services that only powerusers care of
+# PRINTER_SERVICE: printing daemons in general
+# DYNAMIC_DNS: Dinamic DNS services
+# DICT:
+# MTA: Mail transport agents
+# MAIL_FETCHER: services that fetch the mail from other accounts
+# DISPLAY_MANAGER: Display managers
+# SYSTEM_LOGGER: system log services
+# DATABASE_SERVER: database servers
+# FILE_SERVER: file servers
+# NTP_SERVER: Network time protocol servers
+# SECURE_SHELL_SERVER: Secure shell servers
+# AUTOMOUNTER: automounter daemons and so
+# ANTIVIRUS:
+# FILE_SHARING: for emule-like services
+# FTP_SERVER:
+#
+#
+# If you feel that there are more important/necessary roles,
+# mail me at carlosg@gnome.org
+
+sub gst_service_get_role
+{
+ my ($script) = @_;
+
+ my %service_roles = (
+ "acpid" => "SYSTEM",
+ "alsa" => "SOUND",
+ "am-utils" => "AUTOMOUNTER",
+ "amavis" => "ANTIVIRUS",
+ "amavis-ng" => "ANTIVIRUS",
+ "apache" => "WEB_SERVER",
+ "apache-perl" => "WEB_SERVER",
+ "apache-ssl" => "WEB_SERVER",
+ "apache2" => "WEB_SERVER",
+ "anacron" => "COMMAND_SCHEDULER",
+ "apmd" => "SYSTEM",
+ "atd" => "COMMAND_SCHEDULER", #FIXME
+ "atftpd" => "FTP_SERVER",
+ "aumix" => "SOUND",
+ "autofs" => "AUTOMOUNTER",
+ "bind" => "NETWORK",
+ "binfmt-support" => "SYSTEM",
+ "bootlogd" => "SYSTEM",
+ "chargen" => "NETWORK",
+ "chargen-udp" => "NETWORK",
+ "cherokee" => "WEB_SERVER",
+ "clamav-daemon" => "ANTIVIRUS",
+ "courier" => "MTA",
+ "courier-mta" => "MTA",
+ "cpufreqd" => "SYSTEM",
+ "cron" => "COMMAND_SCHEDULER",
+ "crond" => "COMMAND_SCHEDULER",
+ "cupsd" => "PRINTER_SERVICE",
+ "cups" => "PRINTER_SERVICE",
+ "cupsys" => "PRINTER_SERVICE",
+ "daytime" => "NETWORK",
+ "daytime-udp" => "NETWORK",
+ "dbus-1" => "SYSTEM",
+ "ddclient" => "DYNAMIC_DNS",
+ "dhis-client" => "DYNAMIC_DNS",
+ "dictd" => "DICT",
+ "echo" => "NETWORK",
+ "echo-udp" => "NETWORK",
+ "esound" => "SOUND",
+ "exim" => "MTA",
+ "fam" => "SYSTEM",
+ "fcron" => "COMMAND_SCHEDULER",
+ "firstboot" => "SYSTEM",
+ "festival" => "SOUND", #FIXME
+ "fetchmail" => "MAIL_FETCHER",
+ "freenet6" => "NETWORK",
+ "ftpd" => "FTP_SERVER",
+ "gdm" => "DISPLAY_MANAGER",
+ "gpm" => "SYSTEM", #FIXME
+ "hdparm" => "SYSTEM",
+ "hotplug" => "SYSTEM",
+ "httpd" => "WEB_SERVER",
+ "inetd" => "NETWORK",
+ "iptables" => "NETWORK",
+ "irda" => "SYSTEM",
+ "isakmpd" => "NETWORK",
+ "isdn" => "NETWORK",
+ "joystick" => "SYSTEM",
+ "kdm" => "DISPLAY_MANAGER",
+ "keytable" => "SYSTEM",
+ "klogd" => "SYSTEM_LOGGER",
+ "kudzu" => "SYSTEM",
+ "lircd" => "SYSTEM",
+ "lircmd" => "SYSTEM",
+ "local" => "SYSTEM",
+ "lpd" => "PRINTER_SERVICE",
+ "lpdng" => "PRINTER_SERVICE",
+ "mailscanner" => "ANTIVIRUS",
+ "makedev" => "SYSTEM",
+ "metalog" => "SYSTEM_LOGGER",
+ "mldonkey-server" => "FILE_SHARING",
+ "modules" => "SYSTEM",
+ "module-init-tools" => "SYSTEM",
+ "mysql" => "DATABASE_SERVER",
+ "muddleftpd" => "FTP_SERVER",
+ "named" => "NETWORK",
+ "netfs" => "SYSTEM",
+ "network" => "SYSTEM",
+ "nfs" => "FILE_SERVER",
+ "nfs-user-server" => "FILE_SERVER",
+ "nfs-kernel-server" => "FILE_SERVER",
+ "nfslock" => "SYSTEM",
+ "nscd" => "NETWORK",
+ "ntpd" => "NTP_SERVER",
+ "ntpdate" => "NTP_SERVER",
+ "ntp-client" => "NTP_CLIENT",
+ "ntp-simple" => "NTP_SERVER",
+ "oftpd" => "FTP_SERVER",
+ "oops" => "NETWORK",
+ "pcmcia" => "SYSTEM",
+ "pdnsd" => "NETWORK",
+ "pipsecd" => "NETWORK",
+ "portmap" => "NETWORK",
+ "postfix" => "MTA",
+ "postgresql" => "DATABASE_SERVER",
+ "postgresql-7.4" => "DATABASE_SERVER",
+ "postgresql-8.0" => "DATABASE_SERVER",
+ "ppp" => "NETWORK",
+ "proftpd" => "FTP_SERVER",
+ "privoxy" => "NETWORK",
+ "pure-ftpd" => "FTP_SERVER",
+ "qmail" => "MTA",
+ "random" => "SYSTEM",
+ "rawdevices" => "SYSTEM",
+ "rhnsd" => "SYSTEM",
+ "rsync" => "NETWORK",
+ "rsyncd" => "NETWORK",
+ "samba" => "FILE_SERVER",
+ "saslauthd" => "SYSTEM", # FIXME: maybe a SECURITY role makes sense?
+ "sendmail" => "MTA",
+ "servers" => "NETWORK",
+ "services" => "NETWORK",
+ "setserial" => "SYSTEM",
+ "sgi_fam" => "SYSTEM",
+ "smartmontools" => "SYSTEM",
+ "spamassassin" => "SYSTEM",
+ "snmpd" => "NETWORK",
+ "ssh" => "SECURE_SHELL_SERVER",
+ "sshd" => "SECURE_SHELL_SERVER",
+ "sysklogd" => "SYSTEM_LOGGER",
+ "syslog" => "SYSTEM_LOGGER",
+ "tftpd-hpa" => "FTP_SERVER",
+ "time" => "NETWORK",
+ "time-udp" => "NETWORK",
+ "urandom" => "SYSTEM",
+ "vcron" => "COMMAND_SCHEDULER",
+ "vmware" => "SYSTEM", # FIXME
+ "vsftpd" => "FTP_SERVER",
+ "wdm" => "DISPLAY_MANAGER",
+ "webmin" => "SYSTEM", # FIXME as well
+ "winbind" => "NETWORK",
+ "wine" => "SYSTEM", # FIXME like vmware
+ "wu-ftpd" => "FTP_SERVER",
+ "wzdftpd" => "FTP_SERVER",
+ "xdm" => "DISPLAY_MANAGER",
+ "xfs" => "SYSTEM",
+ "xinetd" => "NETWORK",
+ "zmailer" => "MTA",
+ );
+
+ my ($role) = $service_roles{$script};
+
+ return $role if ($role);
+ return "UNKNOWN";
+}
+
+1;
diff --git a/knetworkconf/backends/service.pl.in b/knetworkconf/backends/service.pl.in
new file mode 100644
index 0000000..d4ce8b3
--- /dev/null
+++ b/knetworkconf/backends/service.pl.in
@@ -0,0 +1,2119 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Functions for manipulating system services, like daemons and network.
+#
+# Copyright (C) 2002 Ximian, Inc.
+#
+# Authors: Carlos Garnacho Parro <garparr@teleline.es>,
+# Hans Petter Jansson <hpj@ximian.com>,
+# Arturo Espinosa <arturo@ximian.com>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+$rcd_path;
+$initd_path;
+$relative_path;
+
+$SCRIPTSDIR = "@scriptsdir@";
+$FILESDIR = "@filesdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $FILESDIR = "files";
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+use File::Copy;
+
+require "$SCRIPTSDIR/file.pl$DOTIN";
+require "$SCRIPTSDIR/report.pl$DOTIN";
+require "$SCRIPTSDIR/service-list.pl$DOTIN";
+
+# Where is the SysV subsystem installed?
+sub gst_service_sysv_get_paths
+{
+ my %dist_map =
+ (
+ # gst_dist => [rc.X dirs location, init.d scripts location, relative path location]
+ "redhat-5.2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-6.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-6.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-6.2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-7.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-7.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-7.2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-7.3" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-8.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "redhat-9" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "openna-1.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+
+ "mandrake-7.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandrake-7.2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandrake-9.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandrake-9.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandrake-9.2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandrake-10.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandrake-10.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandrake-10.2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandriva-2006.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandriva-2006.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandriva-2007.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "mandriva-2007.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "yoper-2.2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+
+ "blackpanther-4.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+
+ "conectiva-9" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "conectiva-10" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+
+ "debian-2.2" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "debian-3.0" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "debian-3.1" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "debian-4.0" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "debian-5.0" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "debian-testing" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "ubuntu-5.04" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "ubuntu-5.10" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "ubuntu-6.06" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "ubuntu-6.10" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "ubuntu-7.04" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "ubuntu-7.10" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+ "ubuntu-8.04" => ["$gst_prefix/etc", "$gst_prefix/etc/init.d", "../init.d"],
+
+ "suse-7.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d", "../"],
+ "suse-9.0" => ["$gst_prefix/etc/init.d", "$gst_prefix/etc/init.d", "../"],
+ "suse-9.1" => ["$gst_prefix/etc/init.d", "$gst_prefix/etc/init.d", "../"],
+
+ "turbolinux-7.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+
+ "pld-1.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "pld-1.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "pld-1.99" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+
+ "fedora-1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "fedora-2" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "fedora-3" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "fedora-4" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "fedora-5" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "rpath" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+
+ "vine-3.0" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "vine-3.1" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ "ark" => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
+ );
+ my $res;
+
+ $res = $dist_map{$gst_dist};
+ &gst_report ("service_sysv_unsupported", $gst_dist) if ($res eq undef);
+ return @$res;
+}
+
+# Those runlevels that are usually used. Maybe we should add
+# the current running runlevel, using the "runlevel" command.
+sub gst_service_sysv_get_runlevels
+{
+ my %dist_map =
+ (
+ "redhat-5.2" => [3, 5],
+ "redhat-6.0" => [3, 5],
+ "redhat-6.1" => [3, 5],
+ "redhat-6.2" => [3, 5],
+ "redhat-7.0" => [3, 5],
+ "redhat-7.1" => [3, 5],
+ "redhat-7.2" => [3, 5],
+ "redhat-7.3" => [3, 5],
+ "redhat-8.0" => [3, 5],
+ "redhat-9" => [3, 5],
+ "openna-1.0" => [3, 5],
+
+ "mandrake-7.1" => [3, 5],
+ "mandrake-7.2" => [3, 5],
+ "mandrake-9.0" => [3, 5],
+ "mandrake-9.1" => [3, 5],
+ "mandrake-9.2" => [3, 5],
+ "mandrake-10.0" => [3, 5],
+ "mandrake-10.1" => [3, 5],
+ "mandrake-10.2" => [3, 5],
+ "mandriva-2006.0" => [3, 5],
+ "mandriva-2006.1" => [3, 5],
+ "mandriva-2007.0" => [3, 5],
+ "mandriva-2007.1" => [3, 5],
+
+ "yoper-2.2" => [3, 5],
+
+ "blackpanther-4.0" => [3, 5],
+
+ "conectiva-9" => [3, 5],
+ "conectiva-10" => [3, 5],
+
+ "debian-2.2" => [2, 3],
+ "debian-3.0" => [2, 3],
+ "debian-3.1" => [2, 3],
+ "debian-4.0" => [2, 3],
+ "debian-5.0" => [2, 3],
+ "debian-testing" => [2, 3],
+ "ubuntu-5.04" => [2, 3],
+ "ubuntu-5.10" => [2, 3],
+ "ubuntu-6.06" => [2, 3],
+ "ubuntu-6.10" => [2, 3],
+ "ubuntu-7.04" => [2, 3],
+ "ubuntu-7.10" => [2, 3],
+ "ubuntu-8.04" => [2, 3],
+
+ "suse-7.0" => [3, 5],
+ "suse-9.0" => [3, 5],
+ "suse-9.1" => [3, 5],
+
+ "turbolinux-7.0" => [3, 5],
+
+ "pld-1.0" => [3, 5],
+ "pld-1.1" => [3, 5],
+ "pld-1.99" => [3, 5],
+
+ "fedora-1" => [3, 5],
+ "fedora-2" => [3, 5],
+ "fedora-3" => [3, 5],
+ "fedora-4" => [3, 5],
+ "fedora-5" => [3, 5],
+ "rpath" => [3, 5],
+
+ "vine-3.0" => [3, 5],
+ "vine-3.1" => [3, 5],
+ "ark" => [3, 5],
+ );
+ my $res;
+
+ $res = $dist_map{$gst_dist};
+ &gst_report ("service_sysv_unsupported", $gst_dist) if ($res eq undef);
+ return @$res;
+}
+
+sub gst_service_get_runlevel_roles
+{
+ my (%dist_map, %runlevels, $desc, $distro);
+ %dist_map =
+ (
+ "redhat-5.2" => "redhat-5.2",
+ "redhat-6.0" => "redhat-5.2",
+ "redhat-6.1" => "redhat-5.2",
+ "redhat-6.2" => "redhat-5.2",
+ "redhat-7.0" => "redhat-5.2",
+ "redhat-7.1" => "redhat-5.2",
+ "redhat-7.2" => "redhat-5.2",
+ "redhat-7.3" => "redhat-5.2",
+ "redhat-8.0" => "redhat-5.2",
+ "redhat-9" => "redhat-5.2",
+ "openna-1.0" => "redhat-5.2",
+
+ "mandrake-7.1" => "redhat-5.2",
+ "mandrake-7.2" => "redhat-5.2",
+ "mandrake-9.0" => "redhat-5.2",
+ "mandrake-9.1" => "redhat-5.2",
+ "mandrake-9.2" => "redhat-5.2",
+ "mandrake-10.0" => "redhat-5.2",
+ "mandrake-10.1" => "redhat-5.2",
+ "mandrake-10.2" => "redhat-5.2",
+ "mandriva-2006.0" => "redhat-5.2",
+ "mandriva-2006.1" => "redhat-5.2",
+ "mandriva-2007.0" => "redhat-5.2",
+ "mandriva-2007.1" => "redhat-5.2",
+
+ "yoper-2.2" => "redhat-5.2",
+
+ "blackpanther-4.0" => "redhat-5.2",
+
+ "conectiva-9" => "redhat-5.2",
+ "conectiva-10" => "redhat-5.2",
+
+ "debian-2.2" => "debian-2.2",
+ "debian-3.0" => "debian-2.2",
+ "debian-3.1" => "debian-2.2",
+ "debian-4.0" => "debian-2.2",
+ "debian-5.0" => "debian-2.2",
+ "debian-testing" => "debian-2.2",
+ "ubuntu-5.04" => "debian-2.2",
+ "ubuntu-5.10" => "debian-2.2",
+ "ubuntu-6.06" => "debian-2.2",
+ "ubuntu-6.10" => "debian-2.2",
+ "ubuntu-7.04" => "debian-2.2",
+ "ubuntu-7.10" => "debian-2.2",
+ "ubuntu-8.04" => "debian-2.2",
+
+ "suse-7.0" => "redhat-5.2",
+ "suse-9.0" => "redhat-5.2",
+ "suse-9.1" => "redhat-5.2",
+
+ "turbolinux-7.0" => "redhat-5.2",
+ "pld-1.0" => "redhat-5.2",
+ "pld-1.1" => "redhat-5.2",
+ "pld-1.99" => "redhat-5.2",
+ "fedora-1" => "redhat-5.2",
+ "fedora-2" => "redhat-5.2",
+ "fedora-3" => "redhat-5.2",
+ "fedora-4" => "redhat-5.2",
+ "fedora-5" => "redhat-5.2",
+ "rpath" => "redhat-5.2",
+
+ "vine-3.0" => "redhat-5.2",
+ "vine-3.1" => "redhat-5.2",
+ "ark" => "redhat-5.2",
+
+ "slackware-9.1.0" => "slackware-9.1.0",
+ "slackware-10.0.0" => "slackware-9.1.0",
+ "slackware-10.1.0" => "slackware-9.1.0",
+ "slackware-10.2.0" => "slackware-9.1.0",
+
+ "gentoo" => "gentoo",
+ "vlos-1.2" => "gentoo",
+
+ "archlinux" => "freebsd-5",
+ "freebsd-5" => "freebsd-5",
+ "freebsd-6" => "freebsd-5",
+ );
+
+ %runlevels=
+ (
+ "redhat-5.2" => {"0" => "HALT",
+ "1" => "RECOVER",
+ "2" => "NONE",
+ "3" => "TEXT",
+ "4" => "NONE",
+ "5" => "GRAPHICAL",
+ "6" => "REBOOT"
+ },
+ "debian-2.2" => {"0" => "HALT",
+ "1" => "RECOVER",
+ "2" => "NONE",
+ "3" => "NONE",
+ "4" => "NONE",
+ "5" => "NONE",
+ "6" => "REBOOT"
+ },
+ "gentoo" => {"boot" => "BOOT",
+ "default" => "GRAPHICAL",
+ "nonetwork" => "RECOVER"
+ },
+ "freebsd-5" => {"rc" => "GRAPHICAL" },
+ "slackware-9.1.0" => {"4" => "GRAPHICAL" }
+ );
+
+ $distro = $dist_map{$gst_dist};
+ $desc = $runlevels{$distro};
+
+ return $runlevels{$distro};
+}
+
+# --- Plain process utilities --- #
+
+# Get owners list (login) of named process.
+sub gst_service_proc_get_owners
+{
+ my ($service) = @_;
+ my ($user, $pid, $command);
+ my ($fd);
+ my (@arr);
+
+ &gst_report_enter ();
+
+ $fd = gst_file_run_pipe_read ("ps acx -o user,pid,command");
+
+ while (<$fd>)
+ {
+ /(.*)[ \t]+(.*)[ \t]+(.*)/;
+ $user = $1;
+ $pid = $2;
+ $command = $3;
+
+ push @arr, $user if ($command eq $service);
+ }
+
+ &gst_report_leave ();
+ return \@arr;
+}
+
+# Stops all instances of a process
+sub gst_service_proc_stop_all
+{
+ my ($service) = @_;
+
+ return &gst_file_run ("killall $service");
+}
+
+# Starts instances of a process for a given list of users
+sub gst_service_proc_start_all
+{
+ my ($cmd, $users) = @_;
+ my ($fqcmd, $fqsu);
+
+ $fqcmd = &gst_file_get_cmd_path ($cmd);
+ $fqsu = &gst_file_locate_tool ("su");
+
+ foreach $user (@$users)
+ {
+ # Can't use gst_file_run_bg here, since it clobbers the quotes.
+ system ("$fqsu $user -c \"$fqcmd &\" >/dev/null 2>/dev/null");
+ }
+}
+
+sub gst_service_sysv_list_dir
+{
+ my ($path) = @_;
+ my ($service, @services);
+
+ foreach $service (<$path/*>)
+ {
+ if (-x $service)
+ {
+ $service =~ s/.*\///;
+ push @services, $service;
+ }
+ }
+
+ return \@services;
+}
+
+sub gst_service_sysv_list_available
+{
+ my ($rcd_path, $initd_path);
+
+ ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+
+ return &gst_service_sysv_list_dir ($initd_path);
+}
+
+# Return 1 or 0: is the service running?
+# Depends on the rc script to support the "status" arg.
+# Maybe we should do something more portable.
+sub gst_service_sysv_get_status
+{
+ my ($service) = @_;
+ my ($rc_path, $initd_path, $res);
+ my ($pid);
+
+ &gst_report_enter ();
+
+ # Stolen from RedHat's /etc/rc.d/init.d/functions:status
+ # FIXME: portable to other UNIXES?
+ $pid = &gst_file_run_backtick ("pidof -o %PPID -x $service");
+ chomp $pid;
+
+ if ($pid)
+ {
+ $res = 1;
+ &gst_report ("service_status_running", $service);
+ }
+ else
+ {
+ $res = 0;
+ &gst_report ("service_status_stopped", $service);
+ }
+
+# ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+# $res = 0;
+#
+# if (-f "$initd_path/$service")
+# {
+# $res = &gst_file_run ("$initd_path/$service status")? 0 : 1;
+# &gst_report ("service_status_running", $service) if $res;
+# &gst_report ("service_status_stopped", $service) if !$res;
+# }
+
+ &gst_report_leave ();
+ return $res;
+}
+
+# If any of the passed services is running, return true.
+sub gst_service_sysv_get_status_any
+{
+ my (@services) = @_;
+ my $i;
+
+ foreach $i (@services)
+ {
+ return 1 if &gst_service_sysv_get_status ($i);
+ }
+
+ return 0;
+}
+
+# Set start links and remove stop links at the usual runlevels.
+# Old start link is removed, in case the priority is different from $pri.
+sub gst_service_sysv_set_links_active
+{
+ my ($pri, $service) = @_;
+
+ foreach $runlevel (&gst_service_sysv_get_runlevels ())
+ {
+ &gst_service_sysv_remove_link ($runlevel, $service);
+ &gst_service_sysv_add_link ($runlevel, "S", $pri, $service);
+ }
+}
+
+# Set stop links and remove start links at the usual runlevels.
+sub gst_service_sysv_set_links_inactive
+{
+ my ($pri, $service) = @_;
+
+ foreach $runlevel (&gst_service_sysv_get_runlevels ())
+ {
+ &gst_service_sysv_remove_link ($runlevel, "$service");
+ &gst_service_sysv_add_link ($runlevel, "K", $pri, $service);
+ }
+}
+
+# Set links for active/inactive service at the given priority.
+sub gst_service_sysv_set_links
+{
+ my ($pri, $service, $active) = @_;
+
+ if ($active)
+ {
+ &gst_service_sysv_set_links_active ($pri, $service);
+ }
+ else
+ {
+ &gst_service_sysv_set_links_inactive (100 - $pri, $service);
+ }
+}
+
+
+
+# Start or stop the service, depending on $active. Set
+# links accordingly. $force makes this function use
+# start/stop only, without considerations for restart.
+# Not to be called from parse/replace tables, due to last $force
+# param: use the following two functions instead.
+sub gst_service_sysv_set_status_do
+{
+ my ($priority, $service, $active, $force) = @_;
+ my ($arg, $status);
+
+ &gst_service_sysv_set_links ($priority, $service, $active);
+
+ $status = &gst_service_sysv_get_status ($service);
+ if ($status && !$force)
+ {
+ # if it's already active and you want it active, restart.
+ $arg = $active? "restart" : "stop";
+ }
+ else
+ {
+ # normal operation.
+ $arg = $active? "start" : "stop";
+ }
+
+ return &gst_service_sysv_run_initd_script ($service, $arg);
+}
+
+sub gst_service_sysv_set_status
+{
+ my ($priority, $service, $active) = @_;
+
+ return &gst_service_sysv_set_status_do ($priority, $service, $active, 0);
+}
+
+sub gst_service_sysv_force_status
+{
+ my ($priority, $service, $active) = @_;
+
+ return &gst_service_sysv_set_status_do ($priority, $service, $active, 1);
+}
+
+sub gst_service_sysv_install_script
+{
+ my ($service, $file) = @_;
+ my ($res, $rcd_path, $initd_path);
+
+ ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+
+ if (!copy ("$FILESDIR/$file", "$initd_path/$service"))
+ {
+ &gst_report ("file_copy_failed", "$FILESDIR/$file", "$initd_path/$service");
+ return -1;
+ }
+
+ chmod (0755, "$initd_path/$service");
+
+ return 0;
+}
+
+# THESE ARE THE FUNCTIONS WHICH EXTRACT THE CONFIGURATION FROM THE COMPUTER
+
+# we are going to extract the name of the script
+sub gst_service_sysv_get_service_name
+{
+ my ($service) = @_;
+
+ $service =~ s/$initd_path\///;
+
+ return $service;
+}
+
+# This function gets the state of the service along the runlevels,
+# it also returns the average priority
+sub gst_service_sysv_get_runlevels_status
+{
+ my ($service) = @_;
+ my ($link);
+ my ($runlevel, $action, $priority);
+ my (@arr, @ret);
+
+ foreach $link (<$rcd_path/rc[0-6].d/[SK][0-9][0-9]$service>)
+ {
+ $link =~ s/$rcd_path\///;
+ $link =~ /rc([0-6])\.d\/([SK])([0-9][0-9]).*/;
+ ($runlevel,$action,$priority)=($1,$2,$3);
+ if ($action eq "S")
+ {
+ push @arr, { "name" => $runlevel,
+ "priority" => $priority,
+ "action" => "start" };
+ }
+ elsif ($action eq "K")
+ {
+ push @arr, { "name" => $runlevel,
+ "priority" => (100 - $priority),
+ "action" => "stop" };
+ }
+ }
+
+ return undef if (scalar(@arr) eq 0);
+
+ push @ret, { "runlevel" => \@arr };
+ return \@ret;
+}
+
+# We are going to extract the information of the service
+sub gst_service_sysv_get_service_info
+{
+ my ($service) = @_;
+ my ($script, @actions, @runlevels);
+ my %hash, $role;
+
+ # Return if it's a directory
+ return undef if (-d $service);
+
+ # We have to check if the service is executable
+ return undef unless (-x $service);
+
+ $script = &gst_service_sysv_get_service_name ($service);
+
+ # We have to check out if the service is in the "forbidden" list
+ return undef if (&gst_service_list_service_is_forbidden ($script));
+
+ $runlevels = &gst_service_sysv_get_runlevels_status($script);
+
+ $hash{"script"} = $script;
+ $hash{"runlevels"} = $runlevels unless ($runlevels eq undef);
+ $hash{"role"} = &gst_service_get_role ($script);
+
+ return \%hash;
+}
+
+# This function gets an ordered array of the available services from a SysV system
+sub gst_service_sysv_get_services
+{
+ my ($service);
+ my (@arr,%ret);
+
+ ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+
+ foreach $service (<$initd_path/*>)
+ {
+ my (%hash);
+ $hash = &gst_service_sysv_get_service_info ($service);
+ if ($hash ne undef)
+ {
+ $ret{$service} = $hash;
+ }
+ }
+
+ return \%ret;
+}
+
+# This functions get an ordered array of the available services from a file-rc system
+sub gst_service_filerc_get_runlevels_status
+{
+ my ($start_service, $stop_service, $priority) = @_;
+ my (@arr, @ret);
+
+ # we start with the runlevels in which the service starts
+ if ($start_service !~ /-/) {
+ my (@runlevels);
+
+ @runlevels = split /,/, $start_service;
+
+ foreach $runlevel (@runlevels)
+ {
+ push @arr, { "name" => $runlevel,
+ "action" => "start",
+ "priority" => $priority};
+ }
+ }
+
+ # now let's go with the runlevels in which the service stops
+ if ($stop_service !~ /-/) {
+ my (@runlevels);
+
+ @runlevels = split /,/, $stop_service;
+
+ foreach $runlevel (@runlevels)
+ {
+ push @arr, { "name" => $runlevel,
+ "action" => "stop",
+ "priority" => $priority};
+ }
+ }
+
+ push @ret, {"runlevel" => \@arr};
+ return \@ret;
+}
+
+sub gst_service_filerc_get_service_info
+{
+ my ($line, %ret) = @_;
+ my %hash;
+ my @runlevels;
+
+ if ($line =~ /^([0-9][0-9])[\t ]+([0-9\-S,]+)[\t ]+([0-9\-S,]+)[\t ]+\/etc\/init\.d\/(.*)/)
+ {
+ $priority = $1;
+ $stop_service = $2;
+ $start_service = $3;
+ $script = $4;
+
+ return undef if (&gst_service_list_service_is_forbidden ($script));
+
+ $hash{"script"} = $script;
+
+ $hash{"runlevels"} = &gst_service_filerc_get_runlevels_status ($start_service, $stop_service, $priority);
+ $hash{"role"} = &gst_service_get_role ($script);
+
+ return (\%hash);
+ }
+
+ return undef;
+}
+
+sub gst_service_filerc_get_services
+{
+ my ($script);
+ my (%ret);
+
+ open FILE, "$gst_prefix/etc/runlevel.conf" or return undef;
+ while ($line = <FILE>)
+ {
+ if ($line !~ /^#.*/)
+ {
+ my (%hash);
+ my ($start_service, $stop_service);
+ $hash = &gst_service_filerc_get_service_info ($line);
+
+ if ($hash ne undef)
+ {
+ $script = $$hash{"script"};
+
+ if ($ret{$script} eq undef)
+ {
+ $ret{$script} = $hash;
+ }
+ else
+ {
+ my (@runlevels);
+
+ # We need to mix the runlevels
+ @runlevels = $$hash{"runlevels"}[0]{"runlevel"};
+ foreach $runlevel (@runlevels)
+ {
+ push @{$ret{$script}{"runlevels"}[0]{"runlevel"}}, $runlevel;
+ }
+ }
+ }
+ }
+ }
+
+ return \%ret;
+}
+
+# this functions get a list of the services that run on a bsd init
+sub gst_service_bsd_get_service_info
+{
+ my ($service) = @_;
+ my ($script);
+ my (%hash);
+ my (@arr, @rl);
+
+ $script = $service;
+ $script =~ s/^.*\///;
+ $script =~ s/^rc\.//;
+
+ return undef if (! gst_file_exists ($service));
+
+ return undef if (&gst_service_list_service_is_forbidden ($script));
+
+ $hash {"script"} = $service;
+
+ # we hardcode the fourth runlevel, it's the graphical one
+ if ( -x $service)
+ {
+ push @arr, { "name" => 4,
+ "action" => "start" };
+ }
+ else
+ {
+ push @arr, { "name" => 4,
+ "action" => "stop" };
+ }
+
+ push @rl, { "runlevel" => \@arr };
+
+ $hash{"runlevels"} = \@rl;
+ $hash{"role"} = &gst_service_get_role ($script);
+
+ return \%hash;
+}
+
+sub gst_service_bsd_get_services
+{
+ my (%ret);
+ my ($files) = [ "rc.M", "rc.inet2", "rc.4" ];
+ my ($file);
+
+ foreach $i (@$files)
+ {
+ $file = "/etc/rc.d/" . $i;
+ $fd = &gst_file_open_read_from_names ($file);
+
+ if (!$fd) {
+ &gst_report ("rc_file_read_failed", $file);
+ return undef;
+ }
+
+ while (<$fd>)
+ {
+ $line = $_;
+
+ if ($line =~ /^if[ \t]+\[[ \t]+\-x[ \t]([0-9a-zA-Z\/\.\-_]+) .*\]/)
+ {
+ my (%hash);
+ $service = $1;
+
+ $hash = &gst_service_bsd_get_service_info ($service);
+
+ if ($hash ne undef)
+ {
+ $ret{$service} = $hash;
+ }
+ }
+ }
+
+ gst_file_close ($fd);
+ }
+
+ return \%ret;
+}
+
+# these functions get a list of the services that run on a gentoo init
+sub gst_service_gentoo_get_service_status
+{
+ my ($script, $runlevel) = @_;
+ my ($services) = &gst_service_gentoo_get_services_by_runlevel ($runlevel);
+
+ foreach $i (@$services)
+ {
+ return 1 if ($i eq $script);
+ }
+
+ return 0;
+}
+
+sub gst_service_gentoo_get_runlevels
+{
+ my($raw_output) = gst_file_run_backtick("rc-status -l");
+ my(@runlevels) = split(/\n/,$raw_output);
+
+ return @runlevels;
+}
+
+sub gst_service_gentoo_get_services_by_runlevel
+{
+ my($runlevel) = @_;
+ my($raw_output) = gst_file_run_backtick("rc-status $runlevel");
+ my(@raw_lines) = split(/\n/,$raw_output);
+ my(@services);
+ my($line);
+
+ foreach $line (@raw_lines)
+ {
+ if ($line !~ /^Runlevel/)
+ {
+ $line=(split(" ",$line))[0];
+ push(@services,$line);
+ }
+ }
+
+ return \@services
+}
+
+sub gst_service_gentoo_get_services_list
+{
+ return &gst_service_sysv_list_dir ("/etc/init.d/");
+}
+
+sub gst_service_gentoo_service_exist
+{
+ my($service) = @_;
+ my($services) = &gst_service_gentoo_get_services_list();
+
+ foreach $i (@$services)
+ {
+ return 1 if ($i =~ /$service/);
+ }
+
+ return 0;
+}
+
+sub gst_service_gentoo_get_runlevels_by_service
+{
+ my ($service) = @_;
+ my(@runlevels,@services_in_runlevel,@contain_runlevels, $runlevel);
+ my ($elem);
+
+ # let's do some caching to improve performance
+ if ($gentoo_services_hash eq undef)
+ {
+ @runlevels = &gst_service_gentoo_get_runlevels ();
+
+ foreach $runlevel (@runlevels)
+ {
+ $$gentoo_services_hash{$runlevel} = &gst_service_gentoo_get_services_by_runlevel ($runlevel);
+ }
+ }
+
+ if (&gst_service_gentoo_service_exist($service))
+ {
+ foreach $runlevel (keys %$gentoo_services_hash)
+ {
+ $services_in_runlevel = $$gentoo_services_hash {$runlevel};
+
+ foreach $elem (@$services_in_runlevel)
+ {
+ push (@contain_runlevels, $runlevel) if ($elem eq $service);
+ }
+ }
+ }
+
+ return @contain_runlevels;
+}
+
+sub gst_service_gentoo_runlevel_status_by_service
+{
+ my ($service) = @_;
+ my (@arr, @ret);
+ my (@runlevels) = &gst_service_gentoo_get_runlevels();
+ my (@started) = &gst_service_gentoo_get_runlevels_by_service($service);
+ my (%start_runlevels) = map { $started[$_], 1 } 0 .. $#started;
+
+ foreach $runlevel (@runlevels)
+ {
+ if (defined $start_runlevels{$runlevel})
+ {
+ push @arr, { "name" => $runlevel,
+ "action" => "start" };
+ }
+ else
+ {
+ push @arr, { "name" => $runlevel,
+ "action" => "stop" };
+ }
+ }
+
+ push @ret, { "runlevel" => \@arr };
+ return @ret;
+}
+
+sub gst_service_gentoo_get_service_info
+{
+ my ($service) = @_;
+ my ($script, @actions, @runlevels);
+ my %hash;
+
+ # We have to check out if the service is in the "forbidden" list
+ return undef if (&gst_service_list_service_is_forbidden ($service));
+
+ my($runlevels) = &gst_service_gentoo_runlevel_status_by_service ($service);
+
+ $hash{"script"} = $service;
+ $hash{"runlevels"} = $runlevels unless ($runlevels eq undef);
+ $hash{"role"} = &gst_service_get_role ($service);
+
+ return \%hash;
+}
+
+sub gst_service_gentoo_get_services
+{
+ my ($service);
+ my (%ret);
+ my ($service_list) = &gst_service_gentoo_get_services_list ();
+
+ foreach $service (@$service_list)
+ {
+ my (%hash);
+ $hash = &gst_service_gentoo_get_service_info ($service);
+
+ $ret{$service} = $hash if ($hash ne undef);
+ }
+
+ return \%ret;
+}
+
+# rcNG functions, mostly for FreeBSD
+
+
+sub gst_service_archlinux_status_by_service
+{
+ my ($service) = @_;
+ return 1 if( -f "/var/run/daemons/$service");
+ return 0;
+}
+
+sub gst_service_rcng_status_by_service
+{
+ my ($service) = @_;
+ my ($fd, $line, $active);
+
+ $fd = &gst_file_run_pipe_read ("/etc/rc.d/$service rcvar");
+
+ while (<$fd>)
+ {
+ $line = $_;
+
+ if ($line =~ /^\$.*=YES$/)
+ {
+ $active = 1;
+ last;
+ }
+ }
+
+ gst_file_close ($fd);
+ return $active;
+}
+
+sub gst_service_rcng_get_service_info
+{
+ my ($service) = @_;
+ my ($script, @actions, @runlevels);
+ my (%hash, @arr, @rl);
+
+ # We have to check if the service is in the "forbidden" list
+ return undef if (&gst_service_list_service_is_forbidden ($service));
+
+ $hash{"script"} = $service;
+
+ if (gst_service_rcng_status_by_service ($service))
+ {
+ push @arr, { "name" => "rc",
+ "action" => "start" };
+ }
+ else
+ {
+ push @arr, { "name" => "rc",
+ "action" => "stop" };
+ }
+
+ push @rl, { "runlevel", \@arr };
+
+ $hash {"runlevels"} = \@rl;
+ $hash{"role"} = &gst_service_get_role ($service);
+
+ return \%hash;
+}
+
+sub gst_service_archlinux_get_service_info
+{
+ my ($service) = @_;
+ my ($script, @actions, @runlevels);
+ my (%hash, @arr, @rl);
+
+ # We have to check if the service is in the "forbidden" list
+ return undef if (&gst_service_list_service_is_forbidden ($service));
+
+ $hash{"script"} = $service;
+
+ if (&gst_service_archlinux_status_by_service ($service))
+ {
+ push @arr, { "name" => "rc",
+ "action" => "start" };
+ }
+ else
+ {
+ push @arr, { "name" => "rc",
+ "action" => "stop" };
+ }
+
+ push @rl, { "runlevel", \@arr };
+
+ $hash {"runlevels"} = \@rl;
+ $hash{"role"} = &gst_service_get_role ($service);
+
+ return \%hash;
+}
+
+sub gst_service_archlinux_get_services
+{
+ my ($service);
+ my (%ret);
+
+ foreach $service (<$gst_prefix/etc/rc.d/*>)
+ {
+ my (%hash);
+
+ $service =~ s/.*\///;
+ $hash = &gst_service_archlinux_get_service_info ($service);
+
+ $ret{$service} = $hash if ($hash ne undef);
+ }
+
+ return \%ret;
+}
+
+sub gst_service_rcng_get_services
+{
+ my ($service);
+ my (%ret);
+
+ foreach $service (<$gst_prefix/etc/rc.d/*>)
+ {
+ my (%hash);
+
+ $service =~ s/.*\///;
+ $hash = &gst_service_rcng_get_service_info ($service);
+
+ $ret{$service} = $hash if ($hash ne undef);
+ }
+
+ return \%ret;
+}
+# SuSE functions, quite similar to SysV, but not equal...
+sub gst_service_suse_get_service_info ($service)
+{
+ my ($service) = @_;
+ my (%hash, @arr, @ret);
+
+ # We have to check if the service is in the "forbidden" list
+ return undef if (&gst_service_list_service_is_forbidden ($service));
+
+ $hash{"script"} = $service;
+
+ foreach $link (<$rcd_path/rc[0-9S].d/S[0-9][0-9]$service>)
+ {
+ $link =~ s/$rcd_path\///;
+ $link =~ /rc([0-6])\.d\/S[0-9][0-9].*/;
+ $runlevel = $1;
+
+ push @arr, { "name" => $runlevel,
+ "action" => "start" };
+ }
+
+ foreach $link (<$rcd_path/boot.d/S[0-9][0-9]$service>)
+ {
+ push @arr, {"name" => "B",
+ "action" => "start" };
+ }
+
+ if (scalar @arr > 0)
+ {
+ push @ret, { "runlevel" => \@arr };
+ $hash{"runlevels"} = \@ret;
+ $hash{"role"} = &gst_service_get_role ($service);
+ }
+
+ return \%hash;
+}
+
+sub gst_service_suse_get_services
+{
+ my ($service, %ret);
+
+ ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+
+ foreach $service (<$gst_prefix/etc/init.d/*>)
+ {
+ my (%hash);
+
+ next if (-d $service || ! -x $service);
+
+ $service =~ s/.*\///;
+ $hash = &gst_service_suse_get_service_info ($service);
+
+ $ret{$service} = $hash if ($hash ne undef);
+ }
+
+ return \%ret;
+}
+
+# generic functions to get the available services
+sub gst_get_init_type
+{
+ if (($gst_dist =~ /debian/) && (stat ("$gst_prefix/etc/runlevel.conf")))
+ {
+ return "file-rc";
+ }
+ elsif ($gst_dist =~ /slackware/)
+ {
+ return "bsd";
+ }
+ elsif ($gst_dist =~ /freebsd/)
+ {
+ return "rcng";
+ }
+ elsif ($gst_dist =~ /archlinux/)
+ {
+ return "archlinux";
+ }
+ elsif (($gst_dist =~ /gentoo/) || ($gst_dist =~ /^vlos/))
+ {
+ return "gentoo";
+ }
+ elsif ($gst_dist =~ /suse/)
+ {
+ return "suse";
+ }
+ else
+ {
+ return "sysv";
+ }
+}
+
+sub gst_service_get_services
+{
+ $type = &gst_get_init_type ();
+
+ return &gst_service_sysv_get_services () if ($type eq "sysv");
+ return &gst_service_filerc_get_services () if ($type eq "file-rc");
+ return &gst_service_bsd_get_services () if ($type eq "bsd");
+ return &gst_service_gentoo_get_services () if ($type eq "gentoo");
+ return &gst_service_rcng_get_services () if ($type eq "rcng");
+ return &gst_service_suse_get_services () if ($type eq "suse");
+ return &gst_service_archlinux_get_services() if ($type eq "archlinux");
+ return undef;
+}
+
+
+# This function gets the runlevel that is in use
+sub gst_service_sysv_get_default_runlevel
+{
+ my (@arr);
+
+ @arr = split / /, `/sbin/runlevel` ;
+ $arr[1] =~ s/\n//;
+
+ return $arr[1];
+}
+
+sub gst_service_get_default_runlevel
+{
+ my ($type) = &gst_get_init_type ();
+
+ return "default" if ($type eq "gentoo");
+ return "rc" if ($type eq "rcng");
+ return "rc" if ($type eq "archlinux");
+ return &gst_service_sysv_get_default_runlevel ();
+}
+
+
+# THESE ARE THE FUNCTIONS WHICH APPLY THE CHANGES MADE TO THE CONFIGURATION OF THE COMPUTER
+
+sub gst_service_sysv_add_link
+{
+ my ($runlevel, $action, $priority, $service) = @_;
+ my ($prio) = sprintf ("%0.2d",$priority);
+
+ symlink ("$relative_path/$service", "$rcd_path/rc$runlevel.d/$action$prio$service");
+
+ &gst_report_enter ();
+ &gst_report ("service_sysv_add_link", "$rcd_path/rc$runlevel.d/$action$prio$service");
+ &gst_report_leave ();
+}
+
+sub gst_service_sysv_remove_link
+{
+ my ($runlevel, $script) = @_;
+
+ foreach $link (<$rcd_path/rc$runlevel.d/[SK][0-9][0-9]$script>)
+ {
+ &gst_report ("service_sysv_remove_link", "$link");
+ unlink ("$link");
+ &gst_report_leave ();
+ }
+}
+
+
+# These are the functions for storing the service settings from XML in SysV
+sub gst_service_sysv_set_service
+{
+ my ($service) = @_;
+ my ($script, $priority, $runlevels);
+ my ($action);
+
+ ($rcd_path, $initd_path, $relative_path) = &gst_service_sysv_get_paths ();
+
+ $script = $$service{"script"};
+ $runlevels = $$service{"runlevels"}[0]{"runlevel"};
+
+ # pass though all the runlevels checking if the service must be started, stopped or removed
+ for ($i = 0; $i <= 6; $i++)
+ {
+ &gst_service_sysv_remove_link ($i, $script);
+
+ $action = undef;
+ foreach $j (@$runlevels)
+ {
+ if ($i == $$j{"name"})
+ {
+ $found = 1;
+ $action = $$j{"action"};
+ $priority = $$j{"priority"};
+ $priority = 50 if (!$priority); #very rough guess
+ }
+ }
+
+ if ($action ne undef)
+ {
+ if ($action eq "start")
+ {
+ &gst_service_sysv_add_link ($i, "S", $priority, $script);
+ }
+ else
+ {
+ &gst_service_sysv_add_link ($i, "K", 100 - $priority, $script);
+ }
+ }
+ }
+}
+
+sub gst_service_sysv_set_services
+{
+ my ($services, $runlevel) = @_;
+
+ foreach $i (@$services)
+ {
+ &gst_service_sysv_set_service($i);
+ }
+}
+
+sub gst_service_filerc_concat_runlevels
+{
+ my (@runlevels) = @_;
+
+ $str = join (",", sort (@runlevels));
+ return ($str) ? $str : "-";
+}
+
+sub gst_service_filerc_set_service
+{
+ my ($buff, $service) = @_;
+ my (%hash, $priority, $line, $str);
+
+ $arr = $$service{"runlevels"}[0]{"runlevel"};
+
+ foreach $i (@$arr)
+ {
+ $priority = 0 + $$i{"priority"};
+ $priority = 50 if ($priority == 0); #very rough guess
+
+ if ($$i{"action"} eq "start")
+ {
+ $hash{$priority}{"start"} = [] if (!$hash{$priority}{"start"});
+ push @{$hash{$priority}{"start"}}, $$i{"name"};
+ }
+ else
+ {
+ $hash{$priority}{"stop"} = [] if (!$hash{$priority}{"stop"});
+ push @{$hash{$priority}{"stop"}}, $$i{"name"};
+ }
+ }
+
+ foreach $priority (keys %hash)
+ {
+ $line = sprintf ("%0.2d", $priority) . "\t";
+ $line .= &gst_service_filerc_concat_runlevels (@{$hash{$priority}{"stop"}}) . "\t";
+ $line .= &gst_service_filerc_concat_runlevels (@{$hash{$priority}{"start"}}) . "\t";
+ $line .= "/etc/init.d/" . $$service{"script"} . "\n";
+
+ push @$buff, $line;
+ }
+}
+
+# This is the function for storing the service settings from XML in file-rc
+sub gst_service_filerc_set_services
+{
+ my ($services, $runlevel) = @_;
+ my ($buff, $lineno, $line, $file);
+ my ($rcd_path, $initd_path, $relative_path) = &gst_service_sysv_get_paths ();
+
+ $file = "$gst_prefix/etc/runlevel.conf";
+
+ $buff = &gst_file_buffer_load ($file);
+ &gst_file_buffer_join_lines ($buff);
+
+ $lineno = 0;
+
+ # We prepare the file for storing the configuration, save the initial comments
+ # and delete the rest
+ while ($$buff[$lineno] =~ /^#.*/)
+ {
+ $lineno++;
+ }
+
+ for ($i = $lineno; $i < scalar (@$buff); $i++)
+ {
+ $$buff[$i] =~ /.*\/etc\/init\.d\/(.*)/;
+
+ # we need to keep the forbidden services and the services that only start in rcS.d
+ if (!gst_service_list_service_is_forbidden ($1))
+ {
+ delete $$buff[$i];
+ }
+ }
+
+ # Now we append the services
+ foreach $service (@$services)
+ {
+ &gst_service_filerc_set_service ($buff, $service);
+ }
+
+ @$buff = sort @$buff;
+
+ push @$buff, "\n";
+ &gst_file_buffer_clean ($buff);
+ &gst_file_buffer_save ($buff, $file);
+}
+
+sub gst_service_bsd_set_services
+{
+ my ($services, $runlevel) = @_;
+ my ($script, $runlevels);
+
+ foreach $service (@$services)
+ {
+ $script = $$service{"script"};
+ $runlevels = $$service{"runlevels"}[0]{"runlevel"}[0];
+
+ $action = $$runlevels {"action"};
+
+ if ($action eq "start")
+ {
+ &gst_file_run ("chmod ugo+x $script");
+ }
+ else
+ {
+ &gst_file_run ("chmod ugo-x $script");
+ }
+ }
+}
+
+sub gst_service_gentoo_set_services
+{
+ my ($services, $runlevel) = @_;
+ my ($action);
+
+ foreach $service (@$services)
+ {
+ $script = $$service{"script"};
+ $arr = $$service{"runlevels"}[0]{"runlevel"};
+
+ foreach $i (@$arr)
+ {
+ $action = $$i{"action"};
+ $rl = $$i{"name"};
+
+ if ( $action eq "start")
+ {
+ &gst_file_run ("rc-update add $script $rl");
+ }
+ elsif ($action eq "stop")
+ {
+ &gst_file_run ("rc-update del $script $rl");
+ }
+ }
+ }
+}
+
+sub gst_service_rcng_set_status
+{
+ my ($service, $action) = @_;
+ my ($fd, $key, $res);
+ my ($default_rcconf) = "/etc/defaults/rc.conf";
+ my ($rcconf) = "/etc/rc.conf";
+
+ if (&gst_file_exists ("/etc/rc.d/$service"))
+ {
+ $fd = &gst_file_run_pipe_read ("/etc/rc.d/$service rcvar");
+
+ while (<$fd>)
+ {
+ if (/^\$(.*)=.*$/)
+ {
+ # to avoid cluttering rc.conf with duplicated data,
+ # we first look in the defaults/rc.conf for the key
+ $key = $1;
+ $res = &gst_parse_sh_bool ($default_rcconf, $key);
+
+ if ($res == $action)
+ {
+ &gst_replace_sh ($rcconf, $key);
+ }
+ else
+ {
+ &gst_replace_sh_bool ($rcconf, $key, "YES", "NO", $action);
+ }
+ }
+ }
+
+ &gst_file_close ($fd);
+ }
+ elsif (&gst_file_exists ("/usr/local/etc/rc.d/$service.sh"))
+ {
+ if ($action)
+ {
+ gst_file_copy ("/usr/local/etc/rc.d/$service.sh.sample",
+ "/usr/local/etc/rc.d/$service.sh");
+ }
+ else
+ {
+ gst_file_remove ("/usr/local/etc/rc.d/$service.sh");
+ }
+ }
+}
+
+sub gst_service_rcng_set_services
+{
+ my ($services, $runlevel) = @_;
+ my ($action, $runlevels, $script);
+
+ foreach $service (@$services)
+ {
+ $script = $$service {"script"};
+ $runlevels = $$service{"runlevels"}[0]{"runlevel"}[0];
+ $action = ($$runlevels {"action"} eq "start")? 1 : 0;
+
+ &gst_service_rcng_set_status ($script, $action);
+ }
+}
+
+sub gst_service_suse_set_services
+{
+ my ($services, $runlevel) = @_;
+ my ($action, $runlevels, $script, $rllist);
+
+ foreach $service (@$services)
+ {
+ $script = $$service{"script"};
+ $runlevels = $$service{"runlevels"}[0]{"runlevel"};
+ $rllist = "";
+
+ &gst_file_run ("insserv -r $script");
+
+ foreach $rl (@$runlevels)
+ {
+ if ($$rl{"action"} eq "start")
+ {
+ $rllist .= $$rl{"name"} . ",";
+ }
+ }
+
+ if ($rllist ne "")
+ {
+ $rllist =~ s/,$//;
+
+ &gst_file_run ("insserv $script,start=$rllist");
+ }
+ }
+}
+
+
+sub gst_service_archlinux_set_status
+{
+ my ($script, $active) = @_;
+ my $rcconf = '/etc/rc.conf';
+ open DATA, "$rcconf";
+ my @rcconflines = <DATA>;
+ close (DATA);
+ open DATAOUT, ">", "$rcconf";
+ if(($active) && (! -f "/var/run/daemons/$script"))
+ {
+ &gst_service_archlinux_run_script($script,"start");
+ }
+ if((!$active) && ( -f "/var/run/daemons/$script"))
+ {
+ &gst_service_archlinux_run_script($script,"start");
+ }
+
+
+ foreach my $line (@rcconflines)
+ {
+ if($line =~ /\DAEMONS=/)
+ {
+ if($line =~ m/$script/)
+ {
+ if(!$active)
+ {
+ $line =~ s/$script //;
+ }
+ }
+ else
+ {
+ if($active)
+ {
+ $line =~ s/network/network $script/g;
+ }
+ }
+ }
+ print DATAOUT "$line";
+ }
+
+ close (DATAOUT);
+}
+
+sub gst_service_archlinux_set_services
+{
+ my ($services, $runlevel) = @_;
+ my ($action, $runlevels, $script);
+ foreach $service (@$services)
+ {
+ $script = $$service {"script"};
+ $runlevels = $$service{"runlevels"}[0]{"runlevel"}[0];
+ $action = ($$runlevels {"action"} eq "start")? 1 : 0;
+ &gst_service_archlinux_set_status ($script, $action);
+ }
+}
+
+sub gst_service_set_services
+{
+ my ($services, $runlevel) = @_;
+
+ $type = &gst_get_init_type ();
+ &gst_service_sysv_set_services ($services, $runlevel) if ($type eq "sysv");
+ &gst_service_filerc_set_services ($services, $runlevel) if ($type eq "file-rc");
+ &gst_service_bsd_set_services ($services, $runlevel) if ($type eq "bsd");
+ &gst_service_gentoo_set_services ($services, $runlevel) if ($type eq "gentoo");
+ &gst_service_rcng_set_services ($services, $runlevel) if ($type eq "rcng");
+ &gst_service_suse_set_services ($services, $runlevel) if ($type eq "suse");
+ &gst_service_archlinux_set_services ($services, $runlevel) if ($type eq "archlinux");
+}
+
+sub gst_service_set_conf
+{
+ my ($hash) = @_;
+ my ($services, $runlevel);
+
+ return unless $hash;
+ $services = $$hash{"services"}[0]{"service"};
+ return unless $services;
+ $runlevel = $$hash{"runlevel"};
+ return unless $runlevel;
+
+ &gst_service_set_services($services, $runlevel);
+}
+
+# stuff for checking whether service is running
+sub gst_service_debian_get_status
+{
+ my ($service) = @_;
+ my ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+ my ($output, $pidfile);
+
+ $output = `grep "\/var\/run\/.*\.pid" $initd_path\/$service`;
+
+ if ($output =~ /.*(\/var\/run\/.*\.pid).*/ )
+ {
+ $pidfile = $1;
+ $pidval = `cat $pidfile`;
+
+ return 0 if $pidval eq "";
+
+ $pid = `ps h $pidval`;
+
+ if ($pid eq "")
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ return undef;
+}
+
+sub gst_service_redhat_get_status
+{
+ my ($service) = @_;
+ my ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+
+ if (-f "/var/lock/subsys/$service")
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+sub gst_service_gentoo_get_status
+{
+ my ($service) = @_;
+
+ $line = `/etc/init.d/$service status`;
+
+ return 1 if ($line =~ /started/);
+ return 0;
+}
+
+sub gst_service_rcng_get_status
+{
+ my ($service) = @_;
+
+ $line = gst_file_run_backtick ("/etc/rc.d/$service forcestatus");
+ return 1 if ($line =~ /pid [0-9]*/);
+
+ # hacky as hell, we need to check services in /usr/local/etc/rc.d
+ # and there's no standard way to check they're running
+ return 1 if (-f "/var/run/$service.pid");
+
+ # we give up, the service isn't running
+ return 0;
+}
+sub gst_service_archlinux_get_status
+{
+ my ($service) = @_;
+ return 1 if( -f "/var/run/daemons/$service");
+ return 0;
+}
+
+sub gst_service_suse_get_status
+{
+ my ($service) = @_;
+
+ $line = gst_file_run_backtick ("/etc/init.d/$service status");
+ return 1 if ($line =~ /running/);
+ return 0;
+}
+
+# returns true if the service is already running
+sub gst_service_get_status
+{
+ my ($service) = @_;
+ my %dist_map =
+ (
+ "debian-2.2" => \&gst_service_debian_get_status,
+ "debian-3.0" => \&gst_service_debian_get_status,
+ "debian-3.1" => \&gst_service_debian_get_status,
+ "debian-4.0" => \&gst_service_debian_get_status,
+ "debian-5.0" => \&gst_service_debian_get_status,
+ "debian-testing" => \&gst_service_debian_get_status,
+ "ubuntu-5.04" => \&gst_service_debian_get_status,
+ "ubuntu-5.10" => \&gst_service_debian_get_status,
+ "ubuntu-6.06" => \&gst_service_debian_get_status,
+ "ubuntu-6.10" => \&gst_service_debian_get_status,
+ "ubuntu-7.04" => \&gst_service_debian_get_status,
+ "ubuntu-7.10" => \&gst_service_debian_get_status,
+ "ubuntu-8.04" => \&gst_service_debian_get_status,
+
+ "redhat-5.2" => \&gst_service_redhat_get_status,
+ "redhat-6.0" => \&gst_service_redhat_get_status,
+ "redhat-6.1" => \&gst_service_redhat_get_status,
+ "redhat-6.2" => \&gst_service_redhat_get_status,
+ "redhat-7.0" => \&gst_service_redhat_get_status,
+ "redhat-7.1" => \&gst_service_redhat_get_status,
+ "redhat-7.2" => \&gst_service_redhat_get_status,
+ "redhat-7.3" => \&gst_service_redhat_get_status,
+ "redhat-8.0" => \&gst_service_redhat_get_status,
+ "redhat-9" => \&gst_service_redhat_get_status,
+ "mandrake-7.2" => \&gst_service_redhat_get_status,
+ "fedora-1" => \&gst_service_redhat_get_status,
+ "fedora-2" => \&gst_service_redhat_get_status,
+ "fedora-3" => \&gst_service_redhat_get_status,
+ "fedora-4" => \&gst_service_redhat_get_status,
+ "fedora-5" => \&gst_service_redhat_get_status,
+
+ "rpath" => \&gst_service_redhat_get_status,
+
+ "suse-9.0" => \&gst_service_suse_get_status,
+ "suse-9.1" => \&gst_service_suse_get_status,
+ "archlinux" => \&gst_service_archlinux_get_status,
+ "gentoo" => \&gst_service_gentoo_get_status,
+ "vlos-1.2" => \&gst_service_gentoo_get_status,
+
+ "freebsd-5" => \&gst_service_rcng_get_status,
+ "freebsd-6" => \&gst_service_rcng_get_status,
+ );
+ my $proc;
+
+ $proc = $dist_map {$gst_dist};
+
+ return undef if ($proc eq undef);
+
+ return &$proc ($service);
+}
+
+# Functions to run a service
+sub gst_service_sysv_run_initd_script
+{
+ my ($service, $arg) = @_;
+ my ($rc_path, $initd_path);
+ my $str;
+ my %map =
+ ("restart" => "restarted",
+ "stop" => "stopped",
+ "start" => "started");
+
+ &gst_report_enter ();
+
+ if (!exists $map{$arg})
+ {
+ &gst_report ("service_sysv_op_unk", $arg);
+ &gst_report_leave ();
+ return -1;
+ }
+
+ $str = $map{$arg};
+
+ ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+
+ if (-f "$initd_path/$service")
+ {
+ if (!&gst_file_run ("$initd_path/$service $arg"))
+ {
+ &gst_report ("service_sysv_op_success", $service, $str);
+ &gst_report_leave ();
+ return 0;
+ }
+ }
+
+ &gst_report ("service_sysv_op_failed", $service, $str);
+ &gst_report_leave ();
+ return -1;
+}
+
+sub gst_service_bsd_run_script
+{
+ my ($service, $arg) = @_;
+ my ($chmod) = 0;
+
+ return if (!&gst_file_exists ($service));
+
+ # if it's not executable then chmod it
+ if (!((stat ($service))[2] & (S_IXUSR || S_IXGRP || S_IXOTH)))
+ {
+ $chmod = 1;
+ &gst_file_run ("chmod ugo+x $service");
+ }
+
+ &gst_file_run ("$service $arg");
+
+ # return it to it's normal state
+ if ($chmod)
+ {
+ &gst_file_run ("chmod ugo-x $service");
+ }
+}
+
+sub gst_service_gentoo_run_script
+{
+ my ($service, $arg) = @_;
+ my ($option);
+
+ my %map =
+ ("stop" => "stopped",
+ "start" => "started"
+ );
+
+ &gst_report_enter ();
+
+ if (!exists $map{$arg})
+ {
+ &gst_report ("service_sysv_op_unk", $arg);
+ &gst_report_leave ();
+ return -1;
+ }
+
+ if (&gst_service_gentoo_service_exist ($service))
+ {
+ if (!&gst_file_run ("/etc/init.d/$service $arg"))
+ {
+ &gst_report ("service_sysv_op_success", $service, $str);
+ &gst_report_leave ();
+ return 0;
+ }
+ }
+
+ &gst_report ("service_sysv_op_failed", $service, $str);
+ &gst_report_leave ();
+ return -1;
+}
+
+
+sub gst_service_rcng_run_script
+{
+ my ($service, $arg) = @_;
+ my ($farg);
+
+ my %map =
+ ("stop" => "forcestop",
+ "start" => "forcestart"
+ );
+
+ &gst_report_enter ();
+
+ if (!exists $map{$arg})
+ {
+ &gst_report ("service_sysv_op_unk", $arg);
+ &gst_report_leave ();
+ return -1;
+ }
+
+ $farg = $map {$arg};
+
+ if (!&gst_file_run ("/etc/rc.d/$service $farg"))
+ {
+ &gst_report ("service_sysv_op_success", $service, $str);
+ &gst_report_leave ();
+ return 0;
+ }
+
+ &gst_report ("service_sysv_op_failed", $service, $str);
+ &gst_report_leave ();
+ return -1;
+}
+
+sub gst_service_archlinux_run_script
+{
+ my ($service, $arg) = @_;
+ my ($farg);
+
+ my %map =
+ ("stop" => "stop",
+ "start" => "start"
+ );
+
+ &gst_report_enter ();
+
+ if (!exists $map{$arg})
+ {
+ &gst_report ("service_sysv_op_unk", $arg);
+ &gst_report_leave ();
+ return -1;
+ }
+
+ $farg = $map {$arg};
+
+ if (!&gst_file_run ("/etc/rc.d/$service $farg"))
+ {
+ &gst_report ("service_sysv_op_success", $service, $str);
+ &gst_report_leave ();
+ return 0;
+ }
+
+ &gst_report ("service_sysv_op_failed", $service, $str);
+ &gst_report_leave ();
+ return -1;
+}
+sub gst_service_run_script
+{
+ my ($service, $arg) = @_;
+ my ($proc, $type);
+ my %map =
+ (
+ "file-rc" => \&gst_service_sysv_run_initd_script,
+ "sysv" => \&gst_service_sysv_run_initd_script,
+ "bsd" => \&gst_service_bsd_run_script,
+ "gentoo" => \&gst_service_gentoo_run_script,
+ "rcng" => \&gst_service_rcng_run_script,
+ "suse" => \&gst_service_sysv_run_initd_script,
+ "archlinux" => \&gst_service_archlinux_run_script,
+ );
+
+ $type = &gst_get_init_type ();
+
+ $proc = $map {$type};
+
+ &$proc ($service, $arg);
+}
+
+# functions to know if a service will be installed
+sub gst_service_sysv_installed
+{
+ my ($service) = @_;
+ my ($res, $rcd_path, $initd_path);
+
+ &gst_report_enter ();
+
+ ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+
+ $res = 1;
+ if (! -f "$initd_path/$service")
+ {
+ $res = 0;
+ &gst_report ("service_sysv_not_found", $service);
+ }
+
+ &gst_report_leave ();
+ return $res;
+}
+
+sub gst_service_bsd_installed
+{
+ my ($service) = @_;
+
+ return 1 if ( -f "$service");
+ return 0;
+}
+
+sub gst_service_gentoo_installed
+{
+ my ($service) = @_;
+
+ return 1 if ( -f "/etc/init.d/$service");
+ return 0;
+}
+
+sub gst_service_rcng_installed
+{
+ my ($service) = @_;
+
+ return 1 if ( -f "/etc/rc.d/$service");
+ return 1 if ( -f "/usr/local/etc/rc.d/$service.sh.sample");
+ return 0;
+}
+
+sub gst_service_installed
+{
+ my ($service) = @_;
+ my ($type);
+ $type = &gst_get_init_type ();
+
+ return &gst_service_sysv_installed ($service) if (($type eq "sysv") || ($type eq "file-rc") || ($type eq "suse"));
+ return &gst_service_bsd_installed ($service) if ($type eq "bsd");
+ return &gst_service_gentoo_installed ($service) if ($type eq "gentoo");
+ return &gst_service_rcng_installed ($service) if ($type eq "rcng");
+ return &gst_service_rcng_installed ($service) if ($type eq "archlinux");
+ return 0;
+}
+
+sub gst_service_list_any_installed
+{
+ my @service = @_;
+ my $res;
+
+ $res = 0;
+
+ foreach $serv (@service)
+ {
+ if (gst_service_installed ($serv))
+ {
+ $res = 1;
+ }
+ }
+
+ return $res;
+}
+
+sub gst_service_bsd_set_status
+{
+ my ($script, $active) = @_;
+ my (@arr);
+
+ if ($active)
+ {
+ &gst_file_run ("chmod ugo+x $script");
+ &gst_service_run_script ($script, "start");
+ }
+ else
+ {
+ &gst_service_run_script ($script, "stop");
+ &gst_file_run ("chmod ugo-x $script");
+ }
+}
+
+sub gst_service_gentoo_set_status
+{
+ my ($script, $force_now, $active) = @_;
+ my (@arr);
+
+ if ($active)
+ {
+ &gst_file_run ("rc-update add $script default");
+ &gst_file_run ("/etc/init.d/$script start") if ($force_now == 1);
+ }
+ else
+ {
+ &gst_file_run ("rc-update del $script default");
+ &gst_file_run ("/etc/init.d/$script stop") if ($force_now == 1);
+ }
+}
+
+sub gst_service_suse_set_status
+{
+ my ($script, $active) = @_;
+ my (@runlevels, $rllist);
+ my ($rcd_path, $initd_path);
+ my ($rl);
+
+ ($rcd_path, $initd_path) = &gst_service_sysv_get_paths ();
+ @runlevels = &gst_service_sysv_get_runlevels ();
+
+ if ($active)
+ {
+ $rllist = join ",", @runlevels;
+ &gst_file_run ("insserv $script,start=$rllist");
+ &gst_service_run_script ($script, "start");
+ }
+ else
+ {
+ # to remove a service from a few runlevels we need to run
+ # insserv -r and then insserv blah,start=x,y,z
+ foreach $link (<$rcd_path/rc[0-9S].d/S[0-9][0-9]$script>)
+ {
+ $link =~ s/$rcd_path\///;
+ $link =~ /rc([0-9S])\.d\/S[0-9][0-9].*/;
+ $rllist .= "$1,";
+ }
+
+ foreach $link (<$rcd_path/boot.d/S[0-9][0-9]$service>)
+ {
+ $rllist .= "B,";
+ }
+
+ # remove the default runlevels from the list
+ foreach $runlevel (@runlevels)
+ {
+ $rllist =~ s/$runlevel,//;
+ }
+
+ $rllist =~ s/,$//;
+
+ &gst_file_run ("insserv -r $script");
+
+ if ($rllist ne "")
+ {
+ &gst_file_run ("insserv $script,start=$rllist");
+ }
+
+ &gst_service_run_script ($script, "stop");
+ }
+}
diff --git a/knetworkconf/backends/system-tools-backends.pc.in b/knetworkconf/backends/system-tools-backends.pc.in
new file mode 100644
index 0000000..185778f
--- /dev/null
+++ b/knetworkconf/backends/system-tools-backends.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=
+libdir=
+includedir=
+
+filessdir=@filesdir@
+backenddir=@scriptsdir@
+
+Name: gst-backends
+Description: GNOME System Tools backends
+Version: @VERSION@
+Requires:
+Libs:
+Cflags:
diff --git a/knetworkconf/backends/type1inst b/knetworkconf/backends/type1inst
new file mode 100755
index 0000000..86d6425
--- /dev/null
+++ b/knetworkconf/backends/type1inst
@@ -0,0 +1,1387 @@
+#!/usr/bin/perl
+#
+# You may need to change the above path.
+#
+#-----------------------------------------------------------------------------
+#
+# Copyright (C) 1996-1998 James Macnicol
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+#-----------------------------------------------------------------------------
+#
+# type1inst : Generate a "fonts.scale" file for Type 1 fonts in PFB format
+# for use with your favourite X server. Also generate a "Fontmap" for use
+# with ghostscript.
+#
+# cd to the directory you want to install fonts in and invoke this script.
+# Options:
+#
+# -samples Create sample PS files for each font
+# -nox Do not create fonts.scale and fonts.dir for X11
+# -nogs Do not create Fontmap for GhostScript
+# -quiet Don't print anything on the stdout, just to the log
+# (see also next section).
+# -silent Same as -quiet (for backwards compatiblity)
+# -q Same as -quiet
+# -nolog Don't create a log file
+# -version Print version info and quit
+# -v Same as -version
+#
+#
+#
+# THIS IS BETA SOFTWARE! PLEASE READ THE "README" FILE!!!
+#
+# Direct all correspondence regarding this software to
+#
+# J.Macnicol@student.anu.edu.au
+#
+#
+# Good luck!
+#
+#
+# James Macnicol
+#
+#-----------------------------------------------------------------------------
+
+# Version number and date information
+
+# NOTE THAT MY E-MAIL ADDRESS HAS CHANGED (AS OF VERSION 0.6.1) !!!!
+
+$version = "0.6.1";
+$versiondate = "11th February 1998";
+$emailaddress = "james.macnicol\@mailexcite.com";
+$copyright = "Copyright (C) 1996-1998 James Macnicol ($emailaddress)";
+
+#
+# Map identifying strings in /Notice into foundry names. Separate identifier
+# from name with a :. Someone let me know if this is a problem (i.e. foundry
+# has a : in its name which really ought to be there (although I may not
+# believe it) ; we'll change it to ! or something.
+#
+# You probably want to put foundries which license type from others near the
+# top of this list (e.g. Adobe). If the name of the original source of the
+# face is listed lower down then it will be used that instead. It's just that
+# Adobe does have its own faces too, but more often than not they are
+# licensed. Doing it this way will make it work out correctly in either case.
+#
+
+
+@foundries = (
+ "Adobe:adobe",
+ "Allied Corporation:allied",
+ "Publishers' Paradise:paradise",
+ "PUBLISHERS' PARADISE:paradise",
+ "Bigelow & Holmes:b&h",
+ "Bitstream:bitstream",
+ "Corel Corporation:corel",
+ "International Typeface Corporation:itc",
+ "IBM:ibm",
+ "LETRASET:letraset",
+ "Monotype Corporation:monotype",
+ "SoftMaker:softmaker",
+ "URW:urw",
+ "Jonathan Brecher:brecher",
+ "Brendel Informatik:brendel",
+ "A. Carr:carr",
+ "FontBank:fontbank",
+ "Hershey:hershey",
+ "A.S.Meit:meit",
+ "Andrew s. Meit:meit",
+ "S.G. Moye:moye",
+ "S. G. Moye:moye",
+ "D. Rakowski:rakowski",
+ "David Rakowski:rakowski",
+ "Reasonable Solutions:reasonable",
+ "Southern Software:southern",
+ "Title Wave:titlewave",
+ "ZSoft:zsoft",
+ "Digiteyes Multimedia:digiteyes",
+ "MWSoft:mwsoft",
+ "MacroMind:macromind",
+ "Three Islands Press:3ip",
+ "Hank Gillette:gillette",
+ "Doug Miles:miles",
+ "Richard Mitchell:mitchell");
+
+# Note: Hershey is the public Hershey fonts which come with Ghostscript.
+# These cause no end of problems since they look inside like funny PS
+# programs rather than standard fonts. The current version of type1inst will
+# refuse to process such fonts. Older versions (< 0.6) tended to fall over
+# when these were present.
+
+# Note 2 : Some of these are obviously names of people only, not companies.
+# They are generally public domain fonts.
+
+# Note 3 : Publisher's Paradise did not produce a majority of the fonts that
+# contain their name in the /Notice field, rather they distributed them on
+# their BBS. Unfortunately there is no other identifying info in these fonts.
+
+#
+# These are font weights. Some are synonyms, e.g. regular for medium. It
+# has been suggested we map "thin" to "light", however there are some font
+# families which have both "thin" and "light" variants. An example is
+# Linotype's Helvetica Neue. Please let me know if you find a font where
+# assuming "semi", and "demi" to be the same fails.
+#
+
+@weights = (
+ "book:book",
+ "demibold:demibold",
+ "semibold:demibold",
+ "demi:demibold",
+ "semi:demibold",
+ "extrabold:extrabold",
+ "boldface:bold",
+ "bold:bold",
+ "heavyface:heavyface",
+ "heavy:heavy",
+ "ultrablack:ultrablack",
+ "extrablack:extrablack",
+ "ultra:ultra", # it's gonna break some widths...
+ "black:black",
+ "extralight:extralight",
+ "light:light",
+ "thin:thin",
+ "super:super",
+ "thin:thin",
+ "light:light",
+ "semi:demi",
+ "bold:bold",
+ "heavy:heavy",
+ "black:black",
+ "normal:medium",
+ "regular:regular",
+ "roman:regular" # this too might break something...
+ );
+
+#
+# Likewise for slants
+#
+
+@slants = (
+ "italic:i",
+ "roman:r",
+ "regular:r",
+ # "it:i",
+ "cursive:i",
+ "kursiv:i",
+ "oblique:o",
+ "obl:o",
+ "slanted:o",
+ # Cyrillic fonts
+ "upright:r",
+ "inclined:i");
+
+#
+# Style. Wondering if we should put "serif" in here somehow....?
+#
+# I haven't put "ultracondensed" here since I think they're two different
+# things, i.e. Garamond Ultra Condensed is very bold but condensed.
+
+@styles = (
+ "extracondensed:extracondensed",
+ "condensed:condensed",
+ "cond:condensed",
+ "sans:sans",
+ "wide:wide",
+ "cn:condensed",
+ "narrow:narrow",
+ "extracompressed:extracompressed",
+ "compressed:compressed",
+ "extraextended:extraextended",
+ "extended:extended",
+ "expanded:expanded",
+ "normal:normal");
+
+#
+# Additional styles. Refer to the line that puts together $xline.
+#
+
+@addstyles = ("alt:alternate",
+ "beginning:beginning",
+ "display:display",
+ "dfr:dfr",
+ "ending:ending",
+ # "exp" and "ep" seems to be sometimes part of a fonts name,
+ # sometimes part of additional classification. I'm crying... :-(
+ "ep:expert",
+ "exp:expert",
+ "ornaments:ornaments",
+ "osf:oldstylefigures",
+ "outline:outline",
+ "sc:smallcaps",
+ "shaded:shaded",
+ "shadowed:shadowed",
+ "stencil:stencil",
+ "swash:swash",
+ "sw:swash",
+ "one:one",
+ "two:two",
+ "three:three",
+ "four:four",
+ # Some fonts use just "a" to mean a font with alternate
+ # character set.
+ "a:alternate");
+
+#
+# Write a message to the stdout and/or the log file depending on what the
+# user chose.
+#
+
+sub log_msg {
+ ($msg) = @_;
+
+ if (! $silent) {
+ print STDOUT "$msg";
+ }
+ if ($dologfile) {
+ print LOG "$msg";
+ }
+}
+
+sub log_only_msg {
+ ($msg) = @_;
+
+ if ($dologfile) {
+ print LOG "$msg";
+ }
+}
+
+#
+# Die with a bug message
+#
+
+sub die_bug {
+ ($msg) = @_;
+
+ die("BUG: $msg\nIf you have not modified the script in a way which might have\ncaused this error you are encouraged to report it as a bug to\n\n$emailaddress\n\n");
+}
+
+#
+# Print out a string with a given minimum width. This is used to make the
+# Fontmap entries look nice.
+#
+
+sub print_min_width {
+ ($stream, $minwidth, $string) = @_;
+ $_ = $string;
+ $strlength = length($string);
+ # Print the string
+ print $stream $string;
+ # Now pad out the rest of the space if the string is short.
+ if ($strlength < $minwidth) {
+ for ($i = 0; $i < ($minwidth - $strlength); $i = $i + 1) {
+ print $stream " ";
+ }
+ }
+}
+
+#
+# Indicate progress through the directory on the command line
+#
+
+sub print_progress {
+ $totalfonts = $numpffonts + $numgsfonts + $badfonts;
+ if (! $silent) {
+ if (($totalfonts % 10) == 0) {
+ print "[$totalfonts]\n";
+ }
+ }
+}
+
+#
+# Put the processing stuff into a procedure since we want to do the same for
+# .pfb, .pfa and .gsf files (once .pfb's are decompressed).
+#
+# Argument : filename.
+# Returns : X font description, name of font for Fontmap
+#
+
+sub process_font {
+ ($fname) = @_;
+ local($xline);
+
+ # Check to see if this is a ghostscript font
+ if ($fname =~ /\.gsf\s*$/) {
+ $gsfont = 1;
+ } else {
+ $gsfont = 0;
+ }
+
+ # Default is not MultipleMaster
+ $mm = 0;
+
+ open(IN, $fname) || die "cannot open $file for reading";
+ # An unlikely name to check to see we get a fontname out of the file.
+ $fontname = "abcXYZ:!@#";
+ $foundry = "unknown";
+ $notice = "No notice given.";
+ while(<IN>) {
+ if (/\/isFixedPitch\s+(.+)\s+def\s*/) {
+ if ($1 =~ /true/) {
+ $fixedpitch = "m";
+ } else {
+ $fixedpitch = "p";
+ }
+ }
+
+ # I think that we should accept the manufacturers classification.
+ # Try to extract this from FontName only if it's missing.
+ # (It shouldn't. There are other reasons why this won't work, though.)
+ if (/\/FamilyName\s*\((.+)\)\s+readonly\s+def\s*/) {
+ $familyname = $1;
+
+ # Convert to lower case (because case is insignificant).
+ # Spaces are acceptable according to XLFD.
+ $familyname =~ tr/A-Z/a-z/;
+ }
+ # Previous applies to this also... This might make xfontsels list a
+ # a little cluttered, though. Perhaps it would be better to map it
+ # to standard strings like you do. It's named $weight_add because
+ # you already used $weight...
+ if (/\/Weight\s*\((.+)\)\s+readonly\s+def\s*/) {
+ $weight_add = $1;
+
+ # Convert to lower case. Spaces are acceptable according to XLFD?
+ # Remove for consistency (as there would be any left after my
+ # slaughtering).
+ $weight_add =~ tr/A-Z/a-z/;
+ $weight_add =~ s/\s*//g;
+
+ # Remember if it's a MultipleMaster font
+ $mm = 1 if ($weight_add =~ /^all$/);
+ # Strange. This field seems to contain also width sometimes... remove it.
+ $numstyles = @styles;
+ for ($x = 0; $x < $numstyles; $x = $x + 1) {
+ $ident = $styles[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The style identification \"$ident\" is bad\n");
+ }
+ # Remove matched word from the font's name
+ $weight_add =~ s/$fields[0]//;
+ }
+ }
+ # FullName might contain useful information in determining
+ # the properties of a font.
+ if (/\/FullName\s*\((.+)\)\s+readonly\s+def\s*/) {
+ $fullname = $1;
+
+ # Convert to lower case
+ $fullname =~ tr/A-Z/a-z/;
+
+ # Some names got extra numerical information at the start.
+ $fullname =~ s/^\d*\s*(.+)/$1/;
+ }
+ # Note : some fonts have a suspect /FontName declaration where there
+ # is no space between /FontName and the name of the font itself....
+ if (/\/FontName\s*[\/\(]([^\)]+)\)?\s+def\s*/) {
+ $fontname = $1;
+
+ # Remove any embedded spaces
+ # (Probably unnecessary. If I remember it right, it can't contain any spaces,
+ # because it's a PostScript identifier/keyword or what's the right term...)
+ $fontname =~ s/\s//g;
+
+ # Save a copy of original full name for later
+ $fontnamecopy = $fontname;
+
+ # Convert to lower case
+ $fontname =~ tr/A-Z/a-z/;
+
+ # There are fonts like Mendoza Roman, Baskerville Book etc, where what
+ # looks like weight is part of the font's name, not it's weight.
+ # Split the name into fontname and fontstyle instead and handle them separate.
+ ($fontname, $fontstyle) = split(/-/, $fontname);
+
+ # Remove -s
+ $fontname =~ s/-//g;
+ $fontstyle =~ s/-//g;
+
+
+ # Check for weight modifiers (medium, bold, demi, light etc.)
+ $weight = "medium";
+ $numweights = @weights;
+ for ($x = 0; $x < $numweights; $x = $x + 1) {
+ $ident = $weights[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The weight identification \"$ident\" is bad\n");
+ }
+ if ($fontstyle =~ /$fields[0]/) {
+ $weight = $fields[1];
+ } elsif ($weight_add) {
+ # Try any possible way
+ $weight = $weight_add;
+ }
+ # Remove matched word from the font's name
+ $fontstyle =~ s/$fields[0]//;
+ }
+
+ # Check for slant (italic, roman, oblique)
+ $slant = "r";
+
+ $numslants = @slants;
+ for ($x = 0; $x < $numslants; $x = $x + 1) {
+ $ident = $slants[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The slant identification \"$ident\" is bad\n");
+ }
+ if ($fontstyle =~ /$fields[0]/) {
+ $slant = $fields[1];
+ }
+ # Remove matched word from the font's name
+ $fontstyle =~ s/$fields[0]//;
+ }
+
+ # Check for style (condensed, normal, sans, or wide)
+ $style = "normal";
+
+ $numstyles = @styles;
+ for ($x = 0; $x < $numstyles; $x = $x + 1) {
+ $ident = $styles[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The style identification \"$ident\" is bad\n");
+ }
+ if ($fontstyle =~ /$fields[0]/) {
+ $style = $fields[1];
+ }
+ # Remove matched word from the font's name
+ $fontstyle =~ s/$fields[0]//;
+ }
+
+ # Check for additional styles (alternate, smallcaps, oldstylefigures etc.)
+ $addstyle = "";
+
+ $numaddstyles = @addstyles;
+ for ($x = 0; $x < $numaddstyles; $x = $x + 1) {
+ $ident = $addstyles[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The additional style identification \"$ident\" is bad.\n");
+ }
+ if ($fontstyle =~ /$fields[0]/) {
+ $addstyle = $fields[1];
+ }
+ # Remove matched word from the font's name
+ $fontstyle =~ s/$fields[0]//;
+ }
+ }
+ if (/^\/Encoding\s+(\S+)\s*/) {
+ if ($1 =~ /StandardEncoding/) {
+ $encoding = "iso8859-1";
+ } else {
+ # This needs work
+ $encoding = "adobe-fontspecific";
+ }
+ }
+
+ if (/^\s*\/Notice\s*(.*)$/) {
+ $notice = $1;
+
+ $notice =~ s/readonly def//g;
+
+ $numfoundries = @foundries;
+ for ($x = 0; $x < $numfoundries; $x = $x + 1) {
+ $ident = $foundries[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The foundry identification \"$ident\" is bad.\n");
+ }
+ if ($notice =~ /$fields[0]/) {
+ $foundry = $fields[1];
+ }
+ }
+ }
+
+ # MultipleMaster fonts have this field.
+ if (/\/BlendAxisTypes\s+\[([^\]]+)\]\s*def/) {
+ $axis = $1;
+ # Remove axises we don't need
+ $axis =~ s/\/Weight\s+//;
+ $axis =~ s/\/Width\s+//;
+ # Are there still some axises left?
+ if ($axis =~ /\//) {
+ # Remove trailing spaces
+ $axis =~ s/^(.*?)\s*$/$1/;
+ $axis =~ s/\/\S+/0/g;
+ $axis= "[$axis]";
+ }
+ }
+
+ # Break out of loop if we've passed the interesting stuff.
+ # And time to try another way to find out the fontname.
+ if ((! $gsfont) && (/currentfile\s+eexec/)) {
+ &try_another_way();
+ # This is for .pfa and .pfb fonts
+ last;
+ } elsif (($gsfont) && (/currentdict\s+end/)) {
+ &try_another_way();
+ # This is for ghostscript .gsf fonts. Why don't all these have a
+ # currentfile eexec ?
+ last;
+ }
+ }
+ close(IN);
+
+ # I use quite different mechanism to get fontname etc. However it's done,
+ # the results are hard to get right. Should it be a command-line option?
+ # Now I try both ways.
+
+ # familyname, use fontname
+ $familyname = ($anotherway ? $familyname : $fontname);
+
+ # Oh, we are dealing with a MultipleMaster font...
+ if ($mm) {
+ $weight = "0";
+ $style = "0";
+ $addstyle .= $axis;
+ }
+
+ if ($familyname =~ /abcXYZ\:\!\@\#/) {
+ log_only_msg("\n");
+ log_only_msg("$filename : could not determine font name\n");
+ log_only_msg("\n");
+ $badfonts = $badfonts + 1;
+ &print_progress();
+ return;
+ }
+
+ if (($dox) && (! $gsfont) && ($foundry =~ /unknown/)) {
+ $nofoundry = $nofoundry + 1;
+ log_only_msg("\n");
+ log_only_msg("$filename ($fontnamecopy) : foundry not matched\n");
+ log_only_msg(" /Notice said : \"$notice\"\n");
+ log_only_msg("\n");
+ } elsif ($dox) {
+# log_only_msg("$filename ($fontnamecopy) : okay\n");
+ }
+
+ if (($dox) && (! $gsfont)) {
+ # Addstyle is any extra information needed to uniquely identify a variation of a font
+ # in it's family, like "alternate" (ACaslon-AltRegular) or "one" (EuropeanPi-One).
+ # Changed fontname to familyname because it describes that field better, but that's
+ # just my opinion...
+ $xline = "-$foundry-$familyname-$weight-$slant-$style-$addstyle-0-0-0-0-$fixedpitch-0-$encoding";
+ }
+
+ # Update count of each type
+ if ($gsfont) {
+ $numgsfonts = $numgsfonts + 1;
+ } else {
+ $numpffonts = $numpffonts + 1;
+ }
+
+ &print_progress();
+
+ ($xline, $fontnamecopy);
+}
+
+
+#
+# An alternative way to get fontname
+#
+
+sub try_another_way {
+ # Strip familyname from fullname. This seems to work most of time.
+ # Some fontnames have extra numerical information after familyname.
+ # Strip it if it's longer than two numbers.
+ # Otherwise, it's probably part of additional style classification.
+ # In a few cases it IS part of the name, and this algorithm should break.
+ # Sometimes there's a strange string of *'s somewhere. Get rid of it.
+ $fullname =~ s/\*//g;
+ print STDERR "1: ${fullname}:\n" if $debug;
+ if ($fullname =~ s/^$familyname\s*(\d\d+)?\s*(.*)/$2/) {
+ # Wow. It worked. Let's continue and remove excess whitespace.
+ $anotherway = 1;
+ $fullname =~ s/\s+//g;
+
+ # familyname can now stripped of -s
+ $familyname =~ s/-//g; # Or space?
+ print STDERR "2: ${fullname}:\n" if $debug;
+
+ # Check for weight modifiers (medium, bold, demi, light etc.)
+ $weight = "medium";
+ $numweights = @weights;
+ for ($x = 0; $x < $numweights; $x = $x + 1) {
+ $ident = $weights[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The weight identification \"$ident\" is bad\n");
+ }
+ if ($fullname =~ /$fields[0]/) {
+ $weight = $fields[1];
+ $weight =~ s/-//g;
+ }
+ # Remove matched word from the font's name
+ $fullname =~ s/$fields[0]//;
+ }
+
+ print STDERR "3: ${fullname}:\n" if $debug;
+
+ # Check for slant (italic, oblique)
+ $slant = "r";
+
+ $numslants = @slants;
+ for ($x = 0; $x < $numslants; $x = $x + 1) {
+ $ident = $slants[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The slant identification \"$ident\" is bad\n");
+ }
+ if ($fullname =~ /$fields[0]/) {
+ $slant = $fields[1];
+ $slant =~ s/-//g;
+ }
+ # Remove matched word from the font's name
+ $fullname =~ s/$fields[0]//;
+ }
+ print STDERR "4: ${fullname}:\n" if $debug;
+ # Check for style (normal or sans)
+ $style = "normal";
+
+ $numstyles = @styles;
+ for ($x = 0; $x < $numstyles; $x = $x + 1) {
+ $ident = $styles[$x];
+ @fields = split(/:/, $ident);
+ $numfields = @fields;
+ if ($numfields != 2) {
+ die_bug("The style identification \"$ident\" is bad\n");
+ }
+ if ($fullname =~ /$fields[0]/) {
+ $style = $fields[1];
+ $style =~ s/-//g;
+ }
+ # Remove matched word from the font's name
+ $fullname =~ s/$fields[0]//;
+ }
+
+ # What's left of fullname is probably additional style information.
+ # Some fontnames have some strange numerical information here too.
+ # If it's just one number, it usually refers to some variant of the
+ # fontfamily, otherwise, just get rid of it.
+ $fullname = "" if ($fullname =~ /^\d\d+$/);
+ print STDERR "5: ${fullname}:\n" if $debug;
+ $addstyle = $fullname;
+ $addstyle =~ s/-//g;
+ } else {
+ $anotherway = 0;
+ }
+}
+
+#
+# Makes associative array out of current entries in fonts.scale
+#
+
+sub read_fonts_scale {
+ local($finish, %rv, $line, $filename, $fontname);
+
+ $finish = open(SCALE, "fonts.scale") ? 0 : 1;
+ if ($finish == 1) {
+ %rv;
+ }
+
+ log_only_msg("Reading fonts.scale ....");
+
+ # First line should be an integer saying how many fonts there are.
+ # Discard.
+ $line = <SCALE>;
+ if (! $line =~ /\s*[0-9]+\s*/) {
+ log_only_msg("Warning : first line of fonts.scale is bad\n");
+ }
+
+ while (<SCALE>) {
+ # Very rough pattern
+ if (/\s*(\S+)\s+(.+)\s*/) {
+ chop;
+ $filename = $1;
+ $fontname = $2;
+ if (! -e $filename) {
+ $numxremoved++;
+ log_only_msg("Removed fonts.scale entry \"$_\" since the file did not exist\n");
+ next;
+ }
+ if ($rv{$filename}) {
+ $numxduplicates++;
+ log_only_msg("Warning : fonts.scale already contains a line for file \"$filename\"\n");
+ log_only_msg(" the line \"$_\" has been ignored\n");
+ } else {
+ $rv{$filename} = $fontname;
+ }
+ } else {
+ log_only_msg(" Couldn't understand line : \n");
+ log_only_msg(" \"$_\"\n");
+ }
+ }
+ close(SCALE);
+
+ log_only_msg("Done.\n");
+
+ %rv;
+}
+
+#
+# Write out an associative array into fonts.scale, making a backup copy
+# first.
+#
+
+sub write_fonts_scale {
+ (%fontdata) = @_;
+ local($numentries, $key);
+
+ # First, make backup copy
+ if (-e "fonts.scale") {
+ system ("cp -f fonts.scale fonts.scale.bak");
+ }
+
+ log_only_msg("Writing fonts.scale....\n");
+
+ $numentries = keys(%fontdata);
+ open(SCALE, ">fonts.scale") || die("Can't open fonts.scale!\n");
+ print SCALE "$numentries\n";
+ foreach $key (sort(keys %fontdata)) {
+ print_min_width(SCALE, 12, $key);
+ print SCALE " ";
+ print SCALE "$fontdata{$key}\n";
+ }
+ close(SCALE);
+ system ("chmod 0755 fonts.scale") && log_msg("Coudln't chmod \"fonts.scale\" ... continuing on anyway\n");
+
+ log_only_msg(" Done.\n");
+}
+
+#
+# Read the current Fontmap and return associative array with data.
+#
+
+sub read_fontmap {
+ local(%rv, $finish, $fontname, $filename);
+
+ $finish = open(FONTMAP, "Fontmap") ? 0 : 1;
+ if ($finish) {
+ %rv;
+ }
+
+ log_only_msg("Reading Fontmap ....\n");
+
+ while (<FONTMAP>) {
+ if (/\/+(\S+)\s+\((.*)\)\s+;\s+/) {
+ chop;
+ $fontname = $1;
+ $filename = $2;
+ if (! -e $filename) {
+ $numgsremoved++;
+ log_only_msg("Removed Fontmap entry \"$_\" since the file did not exist\n");
+ next;
+ }
+ if ($rv{$filename}) {
+ # Entry already exists
+ $numgsduplicates++;
+ log_only_msg("Warning : the Fontmap already contains a line for file \"$filename\"\n");
+ log_only_msg(" the line \"$_\" has been ignored\n");
+ } else {
+ $rv{$filename} = $fontname;
+ }
+ } else {
+ $numgsbarf++;
+ log_only_msg("Couldn't understand line :\n");
+ log_only_msg(" $_\n");
+ }
+ }
+
+ close(FONTMAP);
+
+ log_only_msg("Done.\n");
+
+ %rv;
+}
+
+#
+# Write associative array containing font data to Fontmap
+#
+
+sub write_fontmap {
+ (%fontdata) = @_;
+ local($numentries, $key);
+
+ # First, make backup copy
+ if (-e "Fontmap") {
+ system ("cp -f Fontmap Fontmap.bak");
+ }
+
+ log_only_msg("Writing Fontmap....");
+
+ $numentries = keys(%fontdata);
+ open(FONTMAP, ">Fontmap") || die("Couldn't open Fontmap!\n");
+ foreach $key (sort(keys %fontdata)) {
+ print_min_width(FONTMAP, 40, "/$fontdata{$key}");
+ print FONTMAP " ";
+ print FONTMAP "($key)\t;\n";
+ }
+ close(FONTMAP);
+ system ("chmod 0755 Fontmap") && log_msg("Couldn't chmod \"Fontmap\" ... continuing on anyway\n");
+
+ log_only_msg(" Done.\n");
+}
+
+#
+# Add a font (either X or gs) to hash table
+#
+
+sub add_font_to_aarray {
+ ($fname, $text, %aa) = @_;
+
+ if (($text =~ /^\s*$/) || ($fname =~ /^\s*$/)) {
+ # This will occur if the font is a dud (e.g. a Hershey font). We
+ # assume that $badfonts has been incremented and we just return.
+ %aa;
+ }
+
+ if (! $aa{$fname}) {
+ $aa{$fname} = $text;
+ }
+
+ %aa;
+}
+
+#
+# Create sample text using each font
+#
+
+sub font_sample {
+ ($filename, $fontname, $height) = @_;
+ local($text, $alltext, $samplefile);
+
+ if (($filename =~ /^\s*$/) || ($fontname =~ /^s*$/)) {
+ print "font_sample: $filename, $fontname\n";
+ die_bug("Bad argument(s) to font_sample()!\n");
+ }
+
+# Here we create a full page sample for the current font. It contains
+# a large point-size version, a normal sized version, and a small version.
+
+ $text = <<"TEXT";
+%!
+%%EndComments
+/$samplefont findfont
+18 scalefont
+setfont
+newpath
+200 715 moveto
+(File : $filename) show
+200 695 moveto
+(Font Name : $fontname) show
+% t1embed : $filename $fontname
+closepath
+
+/$fontname findfont
+60 scalefont
+setfont
+newpath
+40 640 moveto
+(ABCDE) show
+40 575 moveto
+(FGHIJK) show
+40 510 moveto
+(LMNOP) show
+40 445 moveto
+(QRSTU) show
+40 380 moveto
+(VWXYZ) show
+40 305 moveto
+(abcdefghijklm) show
+40 240 moveto
+(nopqrstuvwxyz) show
+40 175 moveto
+(1234567890) show
+closepath
+
+/$fontname findfont
+12 scalefont
+setfont
+newpath
+50 148 moveto
+(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) show
+50 132 moveto
+(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) show
+50 116 moveto
+(1 2 3 4 5 6 7 8 9 0 \! \$ \% \& \\\( \\\) \; \: \< \> ) show
+closepath
+
+/$fontname findfont
+4 scalefont
+setfont
+newpath
+50 99 moveto
+(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) show
+50 93 moveto
+(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) show
+50 87 moveto
+(1 2 3 4 5 6 7 8 9 0 \! \$ \% \& \\\( \\\) \; \: \< \> ) show
+closepath
+showpage
+TEXT
+
+ $samplefile = $fontname . ".ps";
+ open(SAMPLE, ">samples/$samplefile") ||
+ die("Couldn't open samples/$samplefile\n");
+ print SAMPLE "$text\n";
+ close(SAMPLE);
+ system("chmod 0755 samples/$samplefile") && log_msg("Couldn't chmod individual sample file \"samples/$samplefile\" ... continuing on anyway\n");
+
+# For the "allfont.ps" files we use a standard font for the font name so
+# that in the case of non-alpha fonts we still can still read the name of
+# the font (eg symbol or dingbats).
+
+ if ($height == 700) {
+ $allsample = "samples/allfont-$allcount.ps";
+ $allcount = $allcount + 1;
+
+ log_only_msg("Creating new sample file \"$allsample\"....");
+ open(ALLSAMPLE, ">$allsample") ||
+ die("Couldn't open $allsample\n");
+ log_only_msg("done\n");
+ print ALLSAMPLE "%!\n";
+ print ALLSAMPLE "%%EndComments\n";
+ }
+
+ $alltext = <<"ALLTEXT";
+
+% t1embed : $filename $fontname
+/$samplefont findfont
+12 scalefont
+setfont
+newpath
+30 $height moveto
+($fontname : ) show
+/$fontname findfont
+20 scalefont
+setfont
+(AbCdEfGhIjKlMnOpQrStUvWxYz 0123456789) show
+closepath
+ALLTEXT
+
+ print ALLSAMPLE "$alltext\n";
+ $height = $height - 32;
+ if ($height < 100) {
+ print ALLSAMPLE "showpage\n";
+ close(ALLSAMPLE);
+ system("chmod 0755 $allsample") && log_msg("Couldn't chmod all sample sheet \"$allsample\" ... continuing on anyway\n");
+ $height = 700;
+ }
+
+ ($height);
+}
+
+#
+# Some users have had problems with perl's file globbing not working. This
+# gets a shell to do it for us. It matches all files with the extension
+# specified in the parameter, i.e. if pat = "foo" then it matches all of
+# *.foo .
+#
+
+sub do_glob {
+ ($pat) = @_;
+ local($raw, @fnames);
+ open(SHELL, "echo *.$pat|") || die("Couldn't open shell in do_glob\n");
+ $raw = <SHELL>;
+ $raw =~ s/\*\.$pat//;
+ @fnames = split(/\s/,$raw);
+ close(SHELL);
+ (@fnames);
+}
+
+# ------------------------------------------------------------------------
+# Start of program proper
+# ------------------------------------------------------------------------
+
+# Process command line arguments
+$workdir = 0;
+$dox = 1;
+$dogs = 1;
+$silent = 0;
+$samples = 0;
+$dologfile = 1;
+@argvcopy = (@ARGV);
+$numargs = @ARGV;
+for ($x = 0; $x < $numargs; $x = $x + 1) {
+ $arg = $ARGV[$x];
+ if ($arg =~ /-nox/) {
+ $dox = 0;
+ } elsif ($arg =~ /-nogs/) {
+ $dogs = 0;
+ } elsif ($arg =~ /-silent/) {
+ $silent = 1;
+ } elsif ($arg =~ /-quiet/) {
+ $silent = 1;
+ } elsif ($arg =~ /-q/) {
+ $silent = 1;
+ } elsif ($arg =~ /-samples/) {
+ $samples = 1;
+ } elsif ($arg =~ /-nolog/) {
+ $dologfile = 0;
+ } elsif ($arg =~ /-d/) {
+ $x++;
+ $workdir = $ARGV[$x];
+ } elsif ($arg =~ /-version/) {
+ die("type1inst version $version ($versiondate)\n$copyright\n");
+ } elsif ($arg =~ /-v/) {
+ die("type1inst version $version ($versiondate)\n$copyright\n");
+ } else {
+ die("Usage: $0 [-silent] [-quiet] [-q] [-nox] [-nogs] [-samples] [-version] [-v]\n");
+ }
+}
+if ((! $dox) && (! $dogs) && (! $samples)) {
+ die("$0: Nothing to do!\n");
+}
+
+if ($workdir) {
+ chdir $workdir || die "Cannot change to \"$workdir\"";
+}
+
+# Open logfile
+if ($dologfile) {
+ open(LOG, ">type1inst.log") || die "Cannot open log file \"type1inst.log\"";
+}
+
+log_only_msg("type1inst Version $version ($versiondate)\n");
+log_only_msg("$copyright\n\n");
+open (DATE, "date|") || die("Couldn't run \"date\"\n");
+$currenttime = <DATE>;
+log_only_msg("Run started at $currenttime\n");
+close(DATE);
+
+# Setup directory for font samples
+if ($samples) {
+ if (! -e "samples") {
+ # Create directory for sample text PS files
+ log_only_msg("Creating directory for samples ...\n");
+ system("mkdir samples");
+ system("chmod 0755 samples") && log_msg("Coudln't chmod \"samples\" directory\n");
+
+ } elsif (-f "samples") {
+ die("$0: remove file \"samples\" or do not use -samples option\n");
+ } else {
+ log_msg("Clearing samples directory\n");
+ system("rm -f samples/*.ps");
+ }
+ $height = 700;
+ $samplefont = "Helvetica";
+ $allcount = 0;
+ $allsample = "samples/allfont-$allcount.ps";
+ log_only_msg("Creating new sample file \"$allsample\"....");
+ open(ALLSAMPLE, ">$allsample") || die("Couldn't open all sample file \"$allsample\"\n");
+ log_only_msg("done\n");
+ print ALLSAMPLE "%!\n";
+ print ALLSAMPLE "%%EndComments\n";
+}
+
+
+# Counts how many fonts we come across
+$numpffonts = 0;
+$numgsfonts = 0;
+$nofoundry = 0;
+$badfonts = 0;
+$numskipped = 0;
+$numxremoved = 0;
+$numgsremoved = 0;
+$numxduplicates = 0;
+$numgsduplicates = 0;
+$numxbarf = 0;
+$numgsbarf = 0;
+
+if (! $silent) {
+ print "type1inst Version $version ($versiondate)\n";
+ print "$copyright\n\n";
+}
+
+$totalfonts = 0;
+foreach $filename (do_glob("pfa")) {
+ $totalfonts++;
+}
+foreach $filename (do_glob("pfb")) {
+ $totalfonts++;
+}
+foreach $filename (do_glob("pfa.gz")) {
+ $totalfonts++;
+}
+foreach $filename (do_glob("pfb.gz")) {
+ $totalfonts++;
+}
+foreach $filename (do_glob("gsf")) {
+ $totalfonts++;
+}
+if (! $silent) {
+ if ($totalfonts == 0) {
+ die("There are no PostScript fonts in this directory\n");
+ } elsif ($totalfonts == 1) {
+ print "There is 1 PostScript font in this directory\n";
+ } else {
+ print "There are a total of $totalfonts PostScript fonts in this directory\n";
+ }
+}
+
+if ($dox) {
+ %fs = &read_fonts_scale();
+}
+if (($dogs) || ($samples)) {
+ %fm = &read_fontmap();
+}
+
+# Process ASCII PS fonts
+foreach $filename (do_glob("pfa")) {
+ if (($dox && (! $fs{$filename})) ||
+ (($dogs || $samples) && (! $fm{$filename}))) {
+ ($x, $gs) = &process_font($filename);
+ if ($dox) {
+ %fs = &add_font_to_aarray($filename, $x, %fs);
+ }
+ if (($dogs) || ($samples)) {
+ %fm = &add_font_to_aarray($filename, $gs, %fm);
+ }
+ } else {
+ $numpffonts = $numpffonts + 1;
+ $numskipped = $numskipped + 1;
+ &print_progress();
+ }
+ if ($samples) {
+ ($height) = &font_sample($filename, $fm{$filename}, $height);
+ }
+}
+
+# Process binary PS fonts
+foreach $filename (do_glob("pfb")) {
+ if (($dox && (! $fs{$filename})) ||
+ (($dogs || $samples) && (! $fm{$filename}))) {
+ system("pfbtops $filename > foo");
+ ($x, $gs) = &process_font("foo");
+ system("rm foo");
+ if ($dox) {
+ %fs = &add_font_to_aarray($filename, $x, %fs);
+ }
+ if ($dogs || $samples) {
+ %fm = &add_font_to_aarray($filename, $gs, %fm);
+ }
+ } else {
+ $numpffonts = $numpffonts + 1;
+ $numskipped = $numskipped + 1;
+ &print_progress();
+ }
+ if ($samples) {
+ ($height) = &font_sample($filename, $fm{$filename}, $height);
+ }
+}
+
+# Process binary PS fonts
+foreach $filename (do_glob("pfa.gz")) {
+ if (($dox && (! $fs{$filename})) ||
+ (($dogs || $samples) && (! $fm{$filename}))) {
+ system("gunzip -c $filename > foo");
+ ($x, $gs) = &process_font("foo");
+ system("rm foo");
+ if ($dox) {
+ %fs = &add_font_to_aarray($filename, $x, %fs);
+ }
+ if ($dogs || $samples) {
+ %fm = &add_font_to_aarray($filename, $gs, %fm);
+ }
+ } else {
+ $numpffonts = $numpffonts + 1;
+ $numskipped = $numskipped + 1;
+ &print_progress();
+ }
+ if ($samples) {
+ ($height) = &font_sample($filename, $fm{$filename}, $height);
+ }
+}
+
+# Process binary PS fonts
+foreach $filename (do_glob("pfb.gz")) {
+ if (($dox && (! $fs{$filename})) ||
+ (($dogs || $samples) && (! $fm{$filename}))) {
+ system("gunzip -c $filename | pfbtops > foo");
+ ($x, $gs) = &process_font("foo");
+ system("rm foo");
+ if ($dox) {
+ %fs = &add_font_to_aarray($filename, $x, %fs);
+ }
+ if ($dogs || $samples) {
+ %fm = &add_font_to_aarray($filename, $gs, %fm);
+ }
+ } else {
+ $numpffonts = $numpffonts + 1;
+ $numskipped = $numskipped + 1;
+ &print_progress();
+ }
+ if ($samples) {
+ ($height) = &font_sample($filename, $fm{$filename}, $height);
+ }
+}
+
+# Process Ghostscript fonts
+if ($dogs || $samples) {
+ foreach $filename (do_glob("gsf")) {
+ if (! $fm{$filename}) {
+ ($x, $gs) = &process_font($filename);
+ %fm = &add_font_to_aarray($filename, $gs, %fm);
+ } else {
+ $numgsfonts = $numgsfonts + 1;
+ $numskipped = $numskipped + 1;
+ &print_progress();
+ }
+ if ($samples) {
+ ($height) = &font_sample($filename, $fm{$filename}, $height);
+ }
+ }
+}
+
+if ($dox) {
+ &write_fonts_scale(%fs);
+ system("mkfontdir"); # Generate fonts.dir
+ system("chmod 0755 fonts.dir") && log_msg("Couldn't chmod \"fonts.dir\" ... continuing on anyway\n");
+}
+if ($dogs) {
+ &write_fontmap(%fm);
+}
+
+# Finish up the all font sample file
+if ($samples) {
+ log_only_msg("Finished font sample files\n");
+ if ($height < 700) {
+ print ALLSAMPLE "showpage\n";
+ close(ALLSAMPLE);
+ system("chmod 0755 $allsample") && log_msg("Couldn't chmod \"$allsample\" ... continuing on anyway\n");
+ }
+}
+
+# Report
+if (! $silent) {
+ $totalfonts = $numpffonts + $numgsfonts + $badfonts;
+
+ # List statistics
+ print "-------------------------------------------------------\n";
+ if ($totalfonts == 0) {
+ print "No fonts were found in this directory\n";
+ } elsif ($totalfonts == 1) {
+ print "1 font was found in this directory\n";
+ } else {
+ print "$totalfonts fonts found\n";
+ }
+ if ($numpffonts == 1) {
+ print "1 was a PostScript font\n";
+ } elsif ($numpffonts > 1) {
+ print "$numpffonts were standard PostScript fonts\n";
+ }
+ if ($numgsfonts == 1) {
+ print "1 was a Ghostscript font\n";
+ } elsif ($numgsfonts > 1) {
+ print "$numgsfonts were Ghostscript fonts\n";
+ }
+ if ($numskipped == 1) {
+ print "\n";
+ print "I skipped one of these fonts because it already had\n";
+ print "an overriding entry in both fonts.scale and/or Fontmap\n";
+ print "(X Windows font or Ghostscript font respectively).\n";
+ } elsif ($numskipped > 1) {
+ print "\n";
+ print "I skipped $numskipped of these fonts because they already\n";
+ print "had overriding entries in both fonts.scale and/or Fontmap\n";
+ print "(X Windows fonts or Ghostscript fonts respectively).\n";
+ }
+
+ # Print error messages
+ $wereerrors = 0;
+ if ($badfonts > 0) {
+ $wereerrors = 1;
+ print "-------------------------------------------------------\n";
+ if ($badfonts == 1) {
+ print "I couldn't extract a font name for 1 font in\n";
+ } else {
+ print "I couldn't extract font names for $ badfonts fonts in\n";
+ }
+ print "this directory. This means the font file had a non-standard\n";
+ print "format which this program doesn't know about or cannot do\n";
+ print "anything with. Check the README file to find out more.\n";
+ }
+ if ($dox) {
+ if ($nofoundry > 0) {
+ $wereerrors = 1;
+ print "-------------------------------------------------------\n";
+ print "For $nofoundry of these I couldn't figure out which foundry\n";
+ print "the font is from. Thus, these fonts will appear under the\n";
+ print "foundry unknown, i.e. X font name -unknown-*.\n";
+ print "Please consult the README file to see what this means.\n";
+ }
+
+ if ($numxremoved > 0) {
+ $wereerrors = 1;
+ print "-------------------------------------------------------\n";
+ if ($numxremoved == 1) {
+ print "While reading the existing fonts.scale file I saw 1 entry\n";
+ } else {
+ print "While reading the existing fonts.scale file I saw $numxremoved entries\n";
+ }
+ print "which mentioned a filename which now does not exist. Most likely\n";
+ print "you removed or renamed the file. I ignored these entries.\n";
+ }
+ if ($numxbarf > 0) {
+ $wereerrors = 1;
+ print "-------------------------------------------------------\n";
+ if ($numxbarf == 1) {
+ print "There was a line in fonts.scale I couldn't understand.\n";
+ } else {
+ print "There were $numxbarf lines in fonts.scale which I couldn't understand\n";
+ }
+ print "These were ignored.\n";
+ }
+ }
+ if ($dogs) {
+ if ($numgsremoved > 0) {
+ $wereerrors = 1;
+ print "-------------------------------------------------------\n";
+ if ($numgsremoved == 1) {
+ print "While reading the existing Fontmap file I saw 1 entry\n";
+ } else {
+ print "While reading the existing Fontmap file I saw $numgsremoved entries\n";
+ }
+ print "which mentioned a filename which now does not exist. Most likely\n";
+ print "you removed or renamed the file. I ignored these entries.\n";
+ }
+ if ($numgsbarf > 0) {
+ $wereerrors = 1;
+ print "-------------------------------------------------------\n";
+ if ($numgsbarf == 1) {
+ print "There was a line in Fontmap I couldn't understand.\n";
+ } else {
+ print "There were $numgsbarf lines in Fontmap which I couldn't understand\n";
+ }
+ print "These were ignored.\n";
+ }
+ }
+
+ if ($wereerrors) {
+ print "-------------------------------------------------------\n";
+ print "\n";
+ print "A log of errors is located in the file \"type1inst.log\"\n";
+ print "\n";
+ }
+}
diff --git a/knetworkconf/backends/util.pl.in b/knetworkconf/backends/util.pl.in
new file mode 100644
index 0000000..dea7036
--- /dev/null
+++ b/knetworkconf/backends/util.pl.in
@@ -0,0 +1,463 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# Utility functions.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Arturo Espinosa <arturo@ximian.com>
+# Michael Vogt <mvo@debian.org> - Debian 2.[2|3] support.
+# David Lee Ludwig <davidl@wpi.edu> - Debian 2.[2|3] support.
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+# --- Utilities for strings, arrays and other data structures --- #
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+sub gst_max
+{
+ return ($_[0] > $_[1])? $_[0]: $_[1];
+}
+
+# Boolean <-> strings conversion.
+
+sub gst_util_read_boolean
+{
+ my ($v) = @_;
+
+ return 1 if ($v =~ "true" ||
+ $v =~ "yes" ||
+ $v =~ "YES" ||
+ $v =~ "on" ||
+ $v eq "1");
+ return 0;
+}
+
+
+sub gst_print_boolean_yesno
+{
+ if ($_[0] == 1) { return "yes"; }
+ return "no";
+}
+
+
+sub gst_print_boolean_truefalse
+{
+ if ($_[0] == 1) { return "true"; }
+ return "false";
+}
+
+
+sub gst_print_boolean_onoff
+{
+ if ($_[0] == 1) { return "on"; }
+ return "off";
+}
+
+
+# Pushes a list to an array, only if it's not already in there.
+# I'm sure there's a smarter way to do this. Should only be used for small
+# lists, as it's O(N^2). Larger lists with unique members should use a hash.
+
+sub gst_push_unique
+{
+ my $arr = $_[0];
+ my $found;
+ my $i;
+
+ # Go through all elements in pushed list.
+
+ for ($i = 1; $_[$i]; $i++)
+ {
+ # Compare against all elements in destination array.
+
+ $found = "";
+ for $elem (@$arr)
+ {
+ if ($elem eq $_[$i]) { $found = $elem; last; }
+ }
+
+ if ($found eq "") { push (@$arr, $_[$i]); }
+ }
+}
+
+
+# Merges scr array into dest array.
+sub gst_arr_merge
+{
+ my ($dest, $src) = @_;
+ my (%h, $i);
+
+ foreach $i (@$a, @$b)
+ {
+ $h{$i} = 1;
+ }
+
+ @$a = keys %h;
+ return $a;
+}
+
+# Given an array and a pattern, it returns the index of the
+# array that contains it
+sub gst_array_find_index
+{
+ my($arrayRef, $pattern) = @_;
+ my(@array) = @{$arrayRef};
+ my($numElements) = scalar(@array);
+ my(@indexes) = (0..$numElements);
+ my(@elements);
+
+ @elements = grep @{$arrayRef}[$_] =~ /$pattern/, @indexes;
+ return(wantarray ? @elements : $elements[0]);
+}
+
+
+
+sub gst_ignore_line
+{
+ if (($_[0] =~ /^[ \t]*\#/) || ($_[0] =~ /^[ \t\n\r]*$/)) { return 1; }
+ return 0;
+}
+
+
+# &gst_item_is_in_list
+#
+# Given:
+# * A scalar value.
+# * An array.
+# this function will return 1 if the scalar value is in the array, 0 otherwise.
+
+sub gst_item_is_in_list
+{
+ my ($value, @arr) = @_;
+ my ($item);
+
+ foreach $item (@arr)
+ {
+ return 1 if $value eq $item;
+ }
+
+ return 0;
+}
+
+
+# Recursively compare a structure made of nested arrays and hashes, diving
+# into references, if necessary. Circular references will cause a loop.
+# Watch it: arrays must have elements in the same order to be equal.
+sub gst_util_struct_eq
+{
+ my ($a1, $a2) = @_;
+ my ($type1, $type2);
+ my (@keys1, @keys2);
+ my ($elem1, $elem2);
+ my $i;
+
+ $type1 = ref $a1;
+ $type2 = ref $a2;
+
+ return 0 if $type1 != $type2;
+ return 1 if $a1 eq $a2;
+ return 0 if (!$type1); # Scalars
+
+ if ($type1 eq "SCALAR") {
+ return 0 if $$a1 ne $$a2;
+ }
+ elsif ($type1 eq "ARRAY")
+ {
+ return 0 if $#$a1 != $#$a2;
+
+ for ($i = 0; $i <= $#$a1; $i++)
+ {
+ return 0 if !&gst_util_struct_eq ($$a1[$i], $$a2[$i]);
+ }
+ }
+ elsif ($type1 eq "HASH") {
+ @keys1 = sort keys (%$a1);
+ @keys2 = sort keys (%$a2);
+
+ return 0 if !&gst_util_struct_eq (\@keys1, \@keys2);
+ foreach $i (@keys1)
+ {
+ return 0 if !&gst_util_struct_eq ($$a1{$i}, $$a2{$i});
+ }
+ }
+ else
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+# &gst_get_key_for_subkeys
+#
+# Given:
+# * A hash-table with its values containing references to other hash-tables,
+# which are called "sub-hash-tables".
+# * A list of possible keys (stored as strings), called the "match_list".
+# this method will look through the "sub-keys" (the keys of each
+# sub-hash-table) seeing if one of them matches up with an item in the
+# match_list. If so, the key will be returned.
+
+sub gst_get_key_for_subkeys
+{
+ my %hash = %{$_[0]};
+ my @match_list = @{$_[1]};
+
+ foreach $key (keys (%hash))
+ {
+ my %subhash = %{$hash{$key}};
+ foreach $item (@match_list)
+ {
+ if ($subhash{$item} ne "") { return $key; }
+ }
+ }
+
+ return "";
+}
+
+
+# &gst_get_key_for_subkey_and_subvalues
+#
+# Given:
+# * A hash-table with its values containing references to other hash-tables,
+# which are called "sub-hash-tables". These sub-hash-tables contain
+# "sub-keys" with associated "sub-values".
+# * A sub-key, called the "match_key".
+# * A list of possible sub-values, called the "match_list".
+# this function will look through each sub-hash-table looking for an entry
+# whose:
+# * sub-key equals match_key.
+# * sub-key associated sub-value is contained in the match_list.
+
+sub gst_get_key_for_subkey_and_subvalues
+{
+ my %hash = %{$_[0]};
+ my $key;
+ my $match_key = $_[1];
+ my @match_list = @{$_[2]};
+
+ foreach $key (keys (%hash))
+ {
+ my %subhash = %{$hash{$key}};
+ my $subvalue = $subhash{$match_key};
+
+ if ($subvalue eq "") { next; }
+
+ foreach $item (@match_list)
+ {
+ if ($item eq $subvalue) { return $key; }
+ }
+ }
+
+ return "";
+}
+
+
+# --- IP calculation --- #
+
+
+# &gst_ip_calc_network (<IP>, <netmask>)
+#
+# Calculates the network address and returns it as a string.
+
+sub gst_ip_calc_network
+{
+ my @ip_reg1;
+ my @ip_reg2;
+
+ @ip_reg1 = ($_[0] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
+ @ip_reg2 = ($_[1] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
+
+ $ip_reg1[0] = ($ip_reg1[0] * 1) & ($ip_reg2[0] * 1);
+ $ip_reg1[1] = ($ip_reg1[1] * 1) & ($ip_reg2[1] * 1);
+ $ip_reg1[2] = ($ip_reg1[2] * 1) & ($ip_reg2[2] * 1);
+ $ip_reg1[3] = ($ip_reg1[3] * 1) & ($ip_reg2[3] * 1);
+
+ return join ('.', @ip_reg1);
+}
+
+
+# &gst_ip_calc_network (<IP>, <netmask>)
+#
+# Calculates the broadcast address and returns it as a string.
+
+sub gst_ip_calc_broadcast
+{
+ my @ip_reg1;
+ my @ip_reg2;
+
+ @ip_reg1 = ($_[0] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
+ @ip_reg2 = ($_[1] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
+
+ @ip_reg1 = ($cf_hostip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
+
+ $ip_reg1[0] = ($ip_reg1[0] * 1) | (~($ip_reg2[0] * 1) & 255);
+ $ip_reg1[1] = ($ip_reg1[1] * 1) | (~($ip_reg2[1] * 1) & 255);
+ $ip_reg1[2] = ($ip_reg1[2] * 1) | (~($ip_reg2[2] * 1) & 255);
+ $ip_reg1[3] = ($ip_reg1[3] * 1) | (~($ip_reg2[3] * 1) & 255);
+
+ return join ('.', @ip_reg1);
+}
+
+# Forks a process, running $proc with @args in the child, and
+# printing the returned value of $proc in the pipe. Parent
+# returns a structure with useful data about the process.
+sub gst_process_fork
+{
+ my ($proc, @args) = @_;
+ my $pid;
+ local *PARENT_RDR;
+ local *CHILD_WTR;
+
+ pipe (PARENT_RDR, CHILD_WTR);
+
+ $pid = fork ();
+ if ($pid)
+ {
+ # Parent
+ close CHILD_WTR;
+ return {"pid" => $pid, "fd" => *PARENT_RDR, "fileno" => fileno (*PARENT_RDR)};
+ }
+ else
+ {
+ my $ret;
+ close PARENT_RDR;
+ # Child
+ $ret = &$proc (@args);
+ my $type = ref ($ret);
+
+ if (!$type)
+ {
+ print CHILD_WTR $ret;
+ }
+ elsif ($type eq 'ARRAY')
+ {
+ print CHILD_WTR "$_\n" foreach (@$ret);
+ }
+
+ close CHILD_WTR;
+ exit (0);
+ }
+}
+
+
+# Close pipe, kill process, wait for it to finish.
+sub gst_process_kill
+{
+ my ($proc) = @_;
+
+ &gst_file_close ($$proc{"fd"});
+ kill 2, $$proc{"pid"};
+ waitpid ($$proc{"pid"}, undef);
+}
+
+
+# Populate a bitmap of the used file descriptors.
+sub gst_process_list_build_fd_bitmap
+{
+ my ($procs) = @_;
+ my ($bits, $proc);
+
+ foreach $proc (@$procs)
+ {
+ vec ($bits, $$proc{"fileno"}, 1) = 1;
+ }
+
+ return $bits;
+}
+
+
+# Receives a seconds timeout (may be float) and a ref to
+# a list of processes (each returned by gst_fork_process), and
+# set the "ready" key to true in all the procs that are ready
+# to return values, false otherwise. Returns time left before
+# timeout.
+sub gst_process_list_check_ready
+{
+ my ($timeout, $procs) = @_;
+ my ($bits, $bitsleft, $bitsready, $timestamp, $timeleft);
+
+ $procs = [ $procs ] if ref ($procs) ne 'ARRAY';
+ $bits = &gst_process_list_build_fd_bitmap ($procs);
+
+ # Check with timeout which descriptors are ready with info.
+ $timeout = undef if $timeout == 0;
+ $timeleft = $timeout;
+ $bitsleft = $bits;
+ while (($timeout eq undef) || ($timeleft > 0))
+ {
+ $timestamp = time;
+ select ($bitsleft, undef, undef, $timeleft);
+ $timeleft -= time - $timestamp if $timeout ne undef;
+
+ $bitsready |= $bitsleft;
+ $bitsleft = $bits & (~$bitsready);
+ last if $bitsready eq $bits;
+ }
+ $bits = $bitsready;
+
+ # For every process, set "ready" key to 1/0 depending on
+ # its file descriptor bit.
+ foreach $proc (@$procs)
+ {
+ $$proc{"ready"} = (ord ($bits) & (1 << $$proc{"fileno"}))? 1 : 0;
+ }
+
+ return $timeleft;
+}
+
+
+sub gst_process_result_collect
+{
+ my ($proc, $func, @args) = @_;
+ my ($value, $tmp, $lines);
+
+ if ($$proc{"ready"})
+ {
+ my @list;
+
+ $lines .= $tmp while (sysread ($$proc{"fd"}, $tmp, 4096));
+ goto PROC_KILL unless $lines;
+ if ($lines =~ /\n/)
+ {
+ @list = split ("\n", $lines);
+ }
+ else
+ {
+ push @list, $line;
+ }
+
+ $value = &$func (\@list, @args);
+ }
+
+ PROC_KILL:
+ &gst_process_kill ($proc);
+
+ return $value;
+}
+
+
+1;
diff --git a/knetworkconf/backends/xml.pl.in b/knetworkconf/backends/xml.pl.in
new file mode 100644
index 0000000..9ebbde5
--- /dev/null
+++ b/knetworkconf/backends/xml.pl.in
@@ -0,0 +1,1012 @@
+#!/usr/bin/env perl
+#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+# XML printing, scanning and parsing.
+#
+# Copyright (C) 2000-2001 Ximian, Inc.
+#
+# Authors: Hans Petter Jansson <hpj@ximian.com>
+# Arturo Espinosa <arturo@ximian.com>
+# Kenneth Christiansen <kenneth@gnu.org>
+#
+# This program 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 program is distributed in the hope that 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+
+$SCRIPTSDIR = "@scriptsdir@";
+if ($SCRIPTSDIR =~ /^@scriptsdir[@]/)
+{
+ $SCRIPTSDIR = ".";
+ $DOTIN = ".in";
+}
+
+require "$SCRIPTSDIR/util.pl$DOTIN";
+require "$SCRIPTSDIR/general.pl$DOTIN";
+require "$SCRIPTSDIR/debug.pl$DOTIN";
+
+use Text::ParseWords;
+
+$has_encode = 0;
+if (eval "require Encode") {
+ Encode->import ();
+ $has_encode = 1;
+}
+
+# --- XML print formatting --- #
+
+
+# &gst_xml_enter: Call after entering a block. Increases indent level.
+# &gst_xml_leave: Call before leaving a block. Decreases indent level.
+# &gst_xml_print_indent: Call before printing a line. Indents to current level.
+# &gst_xml_print_vspace: Ensures there is a vertical space of one and only one line.
+# &gst_xml_print: Indent, then print all arguments. Just for sugar.
+
+
+my $gst_indent_level = 0;
+my $gst_have_vspace = 0;
+
+my @gst_xml_stack;
+
+sub gst_xml_print_comment # (comment text)
+{
+ my ($comment) = @_;
+
+ &gst_xml_print_line ("<!-- $comment -->") if $comment;
+}
+
+
+sub gst_xml_print_begin
+{
+ my ($name) = @_;
+
+ $name = $gst_name if !$name;
+
+ &gst_xml_print_string ("<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n");
+ &gst_xml_print_string ("<!DOCTYPE $name []>\n\n");
+ &gst_xml_print_string ("<$name>\n");
+
+ &gst_xml_enter ();
+
+ &gst_xml_print_vspace ();
+}
+
+
+# The frontend expects exactly this string. Don not alter.
+sub gst_xml_print_request_end
+{
+ print "\n<!-- GST: end of request -->\n";
+}
+
+
+sub gst_xml_print_end
+{
+ my ($name) = @_;
+
+ $name = $gst_name if !$name;
+
+ &gst_xml_leave ();
+
+ &gst_xml_print_vspace ();
+ &gst_xml_print_string ("</$name>\n");
+}
+
+
+sub gst_xml_enter
+{
+ $gst_indent_level += 2;
+}
+
+
+sub gst_xml_leave
+{
+ $gst_indent_level -= 2;
+}
+
+
+sub gst_xml_print_string
+{
+ if ($has_encode)
+ {
+ if (&decode_utf8 ($_[0]) eq undef)
+ {
+ # we first decode the string, if it's not
+ # utf-8 (returns undef), then encode it
+ print "" . &encode_utf8 ($_[0]);
+ return;
+ }
+ }
+
+ # It could not encode the string, write it as is
+ print $_[0];
+}
+
+sub gst_xml_format_indent
+{
+ $gst_have_vspace = 0;
+ return " " x $gst_indent_level;
+}
+
+sub gst_xml_print_indent
+{
+ &gst_xml_print_string(&gst_xml_format_indent ());
+}
+
+sub gst_xml_print_vspace
+{
+ if (not $gst_have_vspace)
+ {
+ &gst_xml_print_string ("\n");
+ $gst_have_vspace = 1;
+ }
+}
+
+
+sub gst_xml_print_line
+{
+ my $line;
+ $line = join ("", @_);
+ $line =~ tr/\n//d;
+
+ &gst_xml_print_indent ();
+ &gst_xml_print_string ($line . "\n");
+}
+
+sub gst_xml_format_pcdata # (name, pcdata)
+{
+ my ($name, $pcdata) = @_;
+ return "<$name>$pcdata</$name>" if defined ($name) || defined ($pcdata);
+}
+
+sub gst_xml_print_pcdata # (name, pcdata)
+{
+ my ($name, $pcdata) = @_;
+ my $line = &gst_xml_format_pcdata ($name, $pcdata);
+
+ &gst_xml_print_line ($line) if $line;
+}
+
+sub gst_xml_format_state_tag
+{
+ my ($name, $state) = @_;
+ my $boolean = &gst_print_boolean_truefalse ($state);
+
+ return "<$name state='$boolean'/>";
+}
+
+sub gst_xml_print_state_tag
+{
+ my ($name, $state) = @_;
+ my $state_tag = &gst_xml_format_state_tag ($name, $state);
+
+ &gst_xml_print_line ($state_tag);
+}
+
+# Pass a hash and the keys whose items are scalars. Print <key>val</key>.
+sub gst_xml_print_scalars
+{
+ my ($h, @scalar_keys) = @_;
+ my ($i, $val);
+
+ @scalar_keys = sort @scalar_keys;
+
+ while ($i = shift @scalar_keys)
+ {
+ $val = &gst_xml_quote ($$h{$i});
+ &gst_xml_print_line ("<$i>$val</$i>\n") if exists $$h{$i};
+ }
+
+}
+
+# Print the @$array using <$tag>val</$tag> foreach val in the array.
+# Actually lets print_structure do that now. Just print sequentially
+# the given elements, using as $tag as the surrounding tags.
+sub gst_xml_print_array
+{
+ my ($array, $tag) = @_;
+ my ($i, $val);
+
+ return if (scalar @$array <= 0);
+
+ &gst_xml_print_vspace ();
+ foreach $i (@$array)
+ {
+ &gst_xml_print_structure ($i, $tag);
+ }
+}
+
+# Pass a hash and the keys whose items are arrays. Print <key>val</key> foreach val
+# in the array at hash{key}
+sub gst_xml_print_arrays
+{
+ my ($h, @array_keys) = @_;
+ my ($i, $j, $val);
+
+ foreach $i (sort @array_keys)
+ {
+ &gst_xml_print_array ($$h{$i}, $i) if (exists $$h{$i})
+ }
+}
+
+# Pass a hash, create a parent tag $tag and print <key>val</key> for every
+# value pair in the hash. If structure refs are found, these are recursively
+# printed with print_structure.
+sub gst_xml_print_hash
+{
+ my ($hash, $tag) = @_;
+ my ($j, $val);
+
+ &gst_xml_print_vspace ();
+ if (defined $tag) {
+ &gst_xml_print_line ("<$tag>\n");
+ &gst_xml_enter ();
+ }
+
+ foreach $j (sort keys (%$hash))
+ {
+ &gst_xml_print_structure ($$hash{$j}, $j);
+ }
+
+ if (defined $tag) {
+ &gst_xml_leave ();
+ &gst_xml_print_line ("</$tag>\n");
+ }
+}
+
+# Call the corresponding function depending on the reference
+# type of $x. If just a scalar, print <$tag>$x</$tag>.
+sub gst_xml_print_structure
+{
+ my ($x, $tag) = @_;
+
+ if (ref $x eq "ARRAY") { &gst_xml_print_array ($x, $tag); }
+ elsif (ref $x eq "HASH") { &gst_xml_print_hash ($x, $tag); }
+ else
+ {
+ &gst_xml_print_line ("<$tag>" . &gst_xml_quote ($x) . "</$tag>\n");
+ }
+}
+
+# Treats hash as an array: doesn't use the keys as tags for its
+# elements, but the given tag.
+sub gst_xml_print_hash_hash
+{
+ my ($h, $tag) = @_;
+ my $i;
+
+ foreach $i (sort keys %$h)
+ {
+ &gst_xml_print_hash ($$h{$i}, $tag);
+ }
+}
+
+
+sub gst_xml_container_enter # (name)
+{
+ my ($container) = @_;
+
+ ## gst_xml_stack is not my, as it is defined at top,
+ ## so it is global
+ push @gst_xml_stack, $container;
+
+ &gst_xml_print_line ("<$container>");
+ &gst_xml_enter();
+}
+
+
+sub gst_xml_container_leave
+{
+ ## checks if there is a start tag
+ if ($#gst_xml_stack >= 0)
+ {
+ my $current_container = pop @gst_xml_stack;
+
+ &gst_xml_leave ();
+ &gst_xml_print_line ("</$current_container>");
+ }
+}
+
+
+sub gst_xml_print_container # (name, @strings)
+{
+ my ($name, @strings) = @_;
+
+ if (@strings) {
+ &gst_xml_container_enter ($name);
+ foreach $tag (@strings) {
+ &gst_xml_print_line ("$tag");
+ }
+ &gst_xml_container_leave ();
+ }
+}
+
+# --- XML printing from in-memory model --- #
+
+sub gst_xml_model_print_attributes
+{
+ my ($tree) = @_;
+ my ($attrs, $string);
+
+ $attrs = @$tree [0];
+
+ for $attr (keys %$attrs)
+ {
+ $string .= " " . $attr . "=\"" . $$attrs{$attr} . "\"";
+ }
+
+ return $string;
+}
+
+sub gst_xml_model_print_recurse
+{
+ my ($tree, $indent) = @_;
+ my ($string);
+
+ my @children = @$tree;
+ shift @children; # Attributes
+
+ while (@children)
+ {
+ my $branch = $children [1];
+
+ if ($children [0] eq "__unparsed__")
+ {
+ $string .= "<" . $children [1] . ">";
+ }
+ elsif ($children [0] eq "0")
+ {
+ $string .= $children [1];
+ }
+ elsif (@$branch == 1) # Empty tag.
+ {
+ $string .= "<" . $children [0] . &gst_xml_model_print_attributes ($branch) . "/>";
+ }
+ else
+ {
+ $string .= "<" . $children [0] . &gst_xml_model_print_attributes ($branch) . ">";
+ $string .= &gst_xml_model_print_recurse ($branch);
+ $string .= "</" . $children [0] . ">";
+ }
+
+ shift @children;
+ shift @children;
+ }
+
+# if ($branch)
+# {
+# return &gst_xml_get_attribute ($branch, $property) if $property ne "";
+# return &gst_xml_get_pcdata ($branch);
+# }
+
+ return $string;
+}
+
+sub gst_xml_model_print
+{
+ my ($tree) = @_;
+ my ($string);
+
+ $string = &gst_xml_model_print_recurse ($tree);
+ chomp $string;
+ $string .= "\n";
+
+ return $string;
+}
+
+# --- XML scanning --- #
+
+
+# This code tries to replace XML::Parser scanning from stdin in tree mode.
+
+sub gst_xml_scan_make_kid_array
+{
+ my $line = shift;
+ my (%hash, @sublist, @attr, @list);
+
+ # Remove < and />
+ $line =~ s/^[ \t]*<//;
+ $line =~ s/[\/]?>[ \t]*$//;
+
+ my @list = &quotewords ('[ \t]+', 1, $line);
+ shift @list; # push tag name.
+
+ foreach (@list)
+ {
+ my @tmp = split '[ \t]*=[ \t]*';
+ if (scalar @tmp == 2 && $tmp[1] =~ s/[\"\']//g)
+ {
+ push @attr, @tmp;
+ }
+ }
+
+ %hash = @attr;
+
+ push (@sublist, \%hash);
+ return \@sublist;
+}
+
+
+sub gst_xml_scan_recurse
+{
+ my ($gst_xml_scan_list, $list_arg) = @_;
+ my @list;
+ if ($list_arg ne undef) { @list = $$list_arg[0]; }
+
+ while (@$gst_xml_scan_list)
+ {
+ $el = shift @$gst_xml_scan_list;
+
+ if (($el eq "") || $el =~ /^\<[!?].*\>$/s) { next; } # Empty strings, PI and DTD must go.
+ if ($el =~ /^\<.*\/\>$/s) # Empty.
+ {
+ $el =~ /^\<([a-zA-Z0-9_-]+).*\/\>$/s;
+ push (@list, $1);
+ push (@list, &gst_xml_scan_make_kid_array ($el));
+ }
+ elsif ($el =~ /^\<\/.*\>$/s) # End.
+ {
+ last;
+ }
+ elsif ($el =~ /^\<.*\>$/s) # Start.
+ {
+ $el =~ /^\<([a-zA-Z0-9_-]+).*\>$/s;
+ push (@list, $1);
+ $sublist = &gst_xml_scan_make_kid_array ($el);
+ push (@list, &gst_xml_scan_recurse ($gst_xml_scan_list, $sublist));
+ next;
+ }
+ elsif ($el ne "") # PCDATA.
+ {
+ push (@list, 0);
+ push (@list, "$el");
+ }
+ }
+
+ return \@list;
+}
+
+
+sub gst_xml_read_file
+{
+ my ($file) = @_;
+ my ($doc, $i);
+ local *INPUT_FILE;
+
+ open INPUT_FILE, $file;
+ $doc .= $i while ($i = <INPUT_FILE>);
+ close INPUT_FILE;
+
+ return $doc;
+}
+
+
+sub gst_xml_read_compressed_file
+{
+ my ($file) = @_;
+ my ($doc, $i, $fd);
+
+ $fd = &gst_file_run_pipe_read ("gunzip -c $file");
+ return undef if $fd eq undef;
+ $doc .= $i while ($i = <$fd>);
+ &gst_file_close ($fd);
+
+ if (length ($doc) < 4) # Allow for one blank line from gzip, '\n\r'.
+ {
+ $doc = undef;
+ }
+
+ return $doc;
+}
+
+
+sub gst_xml_read_stdin
+{
+ my ($i, $doc);
+
+ do {
+ $i = <STDIN>;
+
+ if ($i ne undef)
+ {
+ $doc .=$i;
+ }
+ } while (! ($i =~ /^<!-- GST: end of request -->$/));
+
+ return $doc;
+}
+
+# (file, tool) If no file specified, reads stdin.
+# file could also contain xml document.
+# If tool is an gst_tool, stores the read buffer in
+# $$tool{"xml_doc"}.
+sub gst_xml_scan
+{
+ my ($file, $tool) = @_;
+ my ($doc, @tree, @gst_xml_scan_list);
+
+ $file = $gst_input_file unless $file;
+
+ if ($file && stat ($file))
+ {
+ $doc = &gst_xml_read_file ($file);
+ }
+ elsif ($file)
+ {
+ $doc = $file;
+ }
+ else
+ {
+ $doc = &gst_xml_read_stdin ();
+ }
+
+ # remove any blank or carriage return at the beginning of the xml
+ $doc =~ s/^[ \n]*//;
+
+ &gst_debug_print_log_to_file ("in.xml", $doc);
+
+ $$tool{"xml_doc"} = $doc if (&gst_is_tool ($tool));
+
+ @gst_xml_scan_list = ($doc =~ /([^\<]*)(\<[^\>]*\>)[ \t\n\r]*/mg); # pcdata, tag, pcdata, tag, ...
+ $tree = &gst_xml_scan_recurse (\@gst_xml_scan_list);
+
+ return $tree;
+}
+
+# XML scanning that preserves more exact attributes of the scanned XML.
+
+sub gst_xml_model_scan_recurse
+{
+ my @list;
+ if (@_) { @list = $_[0]->[0]; }
+
+ while (@gst_xml_scan_list)
+ {
+ $el = $gst_xml_scan_list[0]; shift @gst_xml_scan_list;
+
+ if ($el eq "") # Empty strings.
+ {
+ next;
+ }
+ elsif ($el =~ /^\<[!?].*\>$/s) # PI and DTD.
+ {
+ $el =~ /^\<([^\>]+)\>$/s;
+ push (@list, "__unparsed__");
+ push (@list, $1);
+ }
+ elsif ($el =~ /^\<.*\/\>$/s) # Empty.
+ {
+ $el =~ /^\<([a-zA-Z0-9_-]+).*\/\>$/s;
+ push (@list, $1);
+ push (@list, &gst_xml_scan_make_kid_array ($el));
+ }
+ elsif ($el =~ /^\<\/.*\>$/s) # End.
+ {
+ last;
+ }
+ elsif ($el =~ /^\<.*\>$/s) # Start.
+ {
+ $el =~ /^\<([a-zA-Z0-9_-]+).*\>$/s;
+ push (@list, $1);
+ $sublist = &gst_xml_scan_make_kid_array ($el);
+ push (@list, &gst_xml_model_scan_recurse ($sublist));
+ next;
+ }
+ elsif ($el ne "") # PCDATA.
+ {
+ push (@list, 0);
+ push (@list, "$el");
+ }
+ }
+
+ return \@list;
+}
+
+sub gst_xml_model_scan # (file) If no file specified, reads stdin.
+{
+ my ($file) = @_;
+ my ($doc, $tree, $compressed);
+
+ $file = $gst_input_file if $file eq undef;
+
+ if ($file)
+ {
+ $doc = &gst_xml_read_compressed_file ($file);
+ if (!$doc)
+ {
+ $doc = &gst_xml_read_file ($file);
+ $compressed = 0;
+ }
+ else
+ {
+ $compressed = 1;
+ }
+ }
+ else
+ {
+ return undef, 0;
+ }
+
+ @gst_xml_scan_list = ($doc =~ /([^\<]*)(\<[^\>]*\>)/mg); # pcdata, tag, pcdata, tag, ...
+ $tree = &gst_xml_model_scan_recurse;
+
+ return $tree, $compressed;
+}
+
+sub gst_xml_model_save
+{
+ my ($model, $file, $compressed) = @_;
+ my $fd;
+
+ if ($compressed == 1)
+ {
+ $fd = &gst_file_open_write_compressed ($file);
+ }
+ else
+ {
+ $fd = &gst_file_open_write_from_names ($file);
+ }
+
+ if ($fd == -1) { return -1; }
+
+ print $fd &gst_xml_model_print ($model);
+ &gst_file_close ($fd);
+
+ return 0;
+}
+
+# Quote/unquote.
+
+@gst_xml_entities = ( "&lt;", '<', "&gt;", '>', "&apos;", '\'', "&quot;", '"', "&amp;", '&' );
+
+
+sub gst_xml_quote
+{
+ my $in = $_[0];
+ my $out = "";
+ my @xe;
+ my $joined = 0;
+
+ my @clist = split (//, $in);
+
+ while (@clist)
+ {
+ # Find character and join its entity equivalent.
+ # If none found, simply join the character.
+
+ $joined = 0; # Cumbersome.
+
+ for (@xe = @gst_xml_entities; @xe && !$joined; )
+ {
+ if ($xe [1] eq $clist [0]) { $out = join ('', $out, $xe [0]); $joined = 1; }
+ shift @xe; shift @xe;
+ }
+
+ if (!$joined) { $out = join ('', $out, $clist [0]); }
+ shift @clist;
+ }
+
+ return $out;
+}
+
+
+sub gst_xml_unquote
+{
+ my $ret = $_[0];
+ my $i;
+
+ #print STDERR "INI U: $ret\n";
+
+ for ($i = 0; $gst_xml_entities[$i] ne undef; $i += 2)
+ {
+ $ret =~ s/$gst_xml_entities[$i]/$gst_xml_entities[$i + 1]/g;
+ }
+
+ while ($ret =~ /&#([0-9]+);/)
+ {
+ $num = $1;
+ $c = chr ($num);
+ $ret =~ s/&#$num;/$c/g;
+ }
+
+ #print STDERR "END U: $ret\n";
+
+ return $ret;
+}
+
+
+# --- XML parsing --- #
+
+
+sub gst_xml_get_pcdata
+{
+ my $tree = $_[0];
+ my $retval;
+
+ shift @$tree; # Skip attributes.
+
+ while (@$tree)
+ {
+ if ($$tree[0] == 0)
+ {
+ $retval = &gst_xml_unquote ($$tree[1]);
+ &gst_debug_print_line ("gst_xml_get_pcdata: $retval");
+ return ($retval);
+ }
+
+ shift @$tree;
+ shift @$tree;
+ }
+
+ return "";
+}
+
+# Compresses node into a word and returns it.
+
+sub gst_xml_get_word
+{
+ my $tree = $_[0];
+ my $retval;
+
+ $retval = &gst_xml_get_pcdata ($tree);
+ $retval =~ tr/ \n\r\t\f//d;
+ return $retval;
+}
+
+
+# Compresses node into a size and returns it.
+
+sub gst_xml_get_size
+{
+ my $tree = $_[0];
+ my $retval;
+
+ $retval = &gst_xml_get_word ($tree);
+ if ($retval =~ /Mb$/)
+ {
+ $retval =~ tr/ Mb//d;
+ $retval *= 1024;
+ }
+
+ return $retval;
+}
+
+
+# Replaces misc. whitespace with spaces and returns text.
+
+sub gst_xml_get_text
+{
+ my $tree = $_[0];
+ my $retval;
+
+ $retval = &gst_xml_get_pcdata ($tree);
+ my $type = ref ($retval);
+
+ if (!$type) { $retval =~ tr/\n\r\t\f/ /; }
+
+ return $retval;
+}
+
+sub gst_xml_get_attribute
+{
+ my ($tree, $attr) = @_;
+
+ return $$tree[0]->{$attr};
+}
+
+sub gst_xml_get_state
+{
+ my ($tree) = @_;
+
+ # Check attribute; 'yes', 'true', 'no', 'false'.
+ return &gst_util_read_boolean ($$tree[0]->{state});
+}
+
+# XML model operations.
+
+# Locate a node from the branch leading up to it.
+sub gst_xml_model_find
+{
+ my ($model, $varpath) = @_;
+ my ($branch, @path);
+
+ $branch = $model;
+ @path = split /\//, $varpath;
+
+ for $elem (@path)
+ {
+ next if ($elem eq "");
+ my @children = @$branch;
+ shift @children; # Attributes
+ $branch = undef;
+
+ while (@children)
+ {
+ if ($children [0] eq $elem)
+ {
+ shift @children;
+ $branch = shift @children;
+ last;
+ }
+
+ shift @children;
+ shift @children;
+ }
+
+ last if ($branch == undef);
+ }
+
+ return $branch;
+}
+
+# Add a branch to another branch. Allows duplicates.
+sub gst_xml_model_add
+{
+ my ($model, $varpath, $addpath) = @_;
+ my ($branch, @path);
+
+ @path = split /\//, $addpath;
+ $branch = &gst_xml_model_find ($model, $varpath);
+ if ($branch == undef)
+ {
+ return -1;
+ }
+
+ for $elem (@path)
+ {
+ my %hash;
+ my @list = ();
+
+ push @list, \%hash;
+
+ push @$branch, $elem;
+ push @$branch, \@list;
+
+ $branch = \@list;
+ }
+
+ return 0;
+}
+
+# Ensure a branch exists, by extending the branch with given elements, if needed.
+sub gst_xml_model_ensure
+{
+ my ($model, $varpath) = @_;
+ my ($branch, @path);
+
+ $branch = $model;
+ @path = split /\//, $varpath;
+
+ for $elem (@path)
+ {
+ next if ($elem eq "");
+
+ my @children = @$branch;
+ my $parent_branch = $branch;
+
+ shift @children; # Attributes
+ $branch = undef;
+
+ while (@children)
+ {
+ if ($children [0] eq $elem)
+ {
+ shift @children;
+ $branch = shift @children;
+ last;
+ }
+
+ shift @children;
+ shift @children;
+ }
+
+ if ($branch == undef)
+ {
+ my %hash;
+ my @list = ();
+
+ $branch = \@list;
+
+ push @list, \%hash;
+
+ push @$parent_branch, $elem;
+ push @$parent_branch, $branch;
+ }
+ }
+
+ return $branch;
+}
+
+sub gst_xml_model_remove
+{
+ my ($model, $varpath, $tag) = @_;
+ my ($branch, $i);
+
+ @path = split /\//, $addpath;
+ $branch = &gst_xml_model_find ($model, $varpath);
+ if ($branch == undef)
+ {
+ return -1;
+ }
+
+ for ($i = 1; $i < @$branch; $i += 2)
+ {
+ if (@$branch [$i] eq $tag)
+ {
+ @$branch = (@$branch [0 .. $i - 1], @$branch [$i + 2 .. @$branch - 1]);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+sub gst_xml_model_get_children
+{
+ my ($branch) = @_;
+ my (@children);
+
+ if (!$branch) { return \@children; }
+
+ for ($i = 1; $i < @$branch; $i += 2)
+ {
+ if (@$branch [$i] ne "__unparsed__" && @$branch [$i] ne "0")
+ {
+ push @children, @$branch [$i + 1];
+ }
+ }
+
+ return \@children;
+}
+
+sub gst_xml_model_get_pcdata
+{
+ my ($branch) = @_;
+ my ($i);
+
+ for ($i = 1; $i < @$branch; $i += 2)
+ {
+ if ($$branch [$i] == 0)
+ {
+ my $retval = &gst_xml_unquote ($$branch [$i + 1]);
+ return ($retval);
+ }
+ }
+
+ return "";
+}
+
+sub gst_xml_model_set_pcdata
+{
+ my ($branch, $pcdata) = @_;
+
+ @$branch = (@$branch [0]);
+
+ $$branch [1] = 0;
+ $$branch [2] = &gst_xml_quote ($pcdata);
+}
+
+sub gst_xml_model_get_attribute
+{
+ my ($branch, $attr) = @_;
+
+ return $$branch[0]->{$attr};
+}
+
+sub gst_xml_model_set_attribute
+{
+ my ($branch, $attr, $value) = @_;
+
+ return $$branch[0]->{$attr} = $value;
+}
+
+1;
diff --git a/knetworkconf/config.h.in b/knetworkconf/config.h.in
new file mode 100644
index 0000000..3e565ad
--- /dev/null
+++ b/knetworkconf/config.h.in
@@ -0,0 +1,204 @@
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if you have the CoreAudio API */
+#undef HAVE_COREAUDIO
+
+/* Define to 1 if you have the <crt_externs.h> header file. */
+#undef HAVE_CRT_EXTERNS_H
+
+/* Defines if your system has the crypt function */
+#undef HAVE_CRYPT
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define if you have libjpeg */
+#undef HAVE_LIBJPEG
+
+/* Define if you have libpng */
+#undef HAVE_LIBPNG
+
+/* Define if you have a working libpthread (will enable threaded code) */
+#undef HAVE_LIBPTHREAD
+
+/* Define if you have libz */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if your system needs _NSGetEnviron to set up the environment */
+#undef HAVE_NSGETENVIRON
+
+/* Define to 1 if you have the <pthread/linuxthreads/pthread.h> header file.
+ */
+#undef HAVE_PTHREAD_LINUXTHREADS_PTHREAD_H
+
+/* Define if you have the res_init function */
+#undef HAVE_RES_INIT
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have strlcat */
+#undef HAVE_STRLCAT
+
+/* Define if you have the strlcat prototype */
+#undef HAVE_STRLCAT_PROTO
+
+/* Define if you have strlcpy */
+#undef HAVE_STRLCPY
+
+/* Define if you have the strlcpy prototype */
+#undef HAVE_STRLCPY_PROTO
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Suffix for lib directories */
+#undef KDELIBSUFF
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of a `char *', as computed by sizeof. */
+#undef SIZEOF_CHAR_P
+
+/* The size of a `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of a `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of a `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of a `unsigned long', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/*
+ * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system
+ * headers and I'm too lazy to write a configure test as long as only
+ * unixware is related
+ */
+#ifdef _UNIXWARE
+#define HAVE_BOOLEAN
+#endif
+
+
+
+/*
+ * AIX defines FD_SET in terms of bzero, but fails to include <strings.h>
+ * that defines bzero.
+ */
+
+#if defined(_AIX)
+#include <strings.h>
+#endif
+
+
+
+#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H)
+# include <sys/time.h>
+# include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#endif
+
+
+
+#if !defined(HAVE_STRLCAT_PROTO)
+#ifdef __cplusplus
+extern "C"
+#endif
+unsigned long strlcat(char*, const char*, unsigned long);
+#endif
+
+
+
+#if !defined(HAVE_STRLCPY_PROTO)
+#ifdef __cplusplus
+extern "C"
+#endif
+unsigned long strlcpy(char*, const char*, unsigned long);
+#endif
+
+
+
+/*
+ * On HP-UX, the declaration of vsnprintf() is needed every time !
+ */
+
+#if !defined(HAVE_VSNPRINTF) || defined(hpux)
+#if __STDC__
+#include <stdarg.h>
+#include <stdlib.h>
+#else
+#include <varargs.h>
+#endif
+#ifdef __cplusplus
+extern "C"
+#endif
+int vsnprintf(char *str, size_t n, char const *fmt, va_list ap);
+#ifdef __cplusplus
+extern "C"
+#endif
+int snprintf(char *str, size_t n, char const *fmt, ...);
+#endif
+
+
+
+#if defined(__SVR4) && !defined(__svr4__)
+#define __svr4__ 1
+#endif
+
+
+/* Compatibility define */
+#undef ksize_t
+
+/* Define the real type of socklen_t */
+#undef socklen_t
diff --git a/knetworkconf/knetworkconf-mdk.spec b/knetworkconf/knetworkconf-mdk.spec
new file mode 100644
index 0000000..ce65b36
--- /dev/null
+++ b/knetworkconf/knetworkconf-mdk.spec
@@ -0,0 +1,159 @@
+%define name knetworkconf
+%define version 0.6.1
+%define release 1mdk
+#%define _unpackaged_files_terminate_build 0
+
+Summary: A KDE Control Center Module to configure Network settings.
+Name: %{name}
+Version: %{version}
+Release: %{release}
+License: GPL
+Url: http://www.merlinux.org/knetworkconf/
+Group: Networking/Other
+Source: %{name}-%{version}.tar.bz2
+BuildRoot: %{_tmppath}/%{name}-buildroot
+Requires: %_bindir/kdesu
+Patch1: knetworkconf-0.6-fix-menu.patch.bz2
+
+%description
+KNetworkConf is a KDE Control Center module to configure the Network
+settings in a Linux machine. I developed it because I couldn't find any
+application to do this from within KDE, and I think this is a "must have"
+app for a serious Desktop Enviroment like KDE.
+KNetworkConf can configure installed network devices (you can't
+add new ones for now), the default gateway,host and domain names,
+add/remove DNS servers and add/remove static hosts.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup -q
+%patch1 -p0 -b .fix_menu
+
+%build
+make -f Makefile.cvs
+QTDIR=%qtdir
+export LD_LIBRARY_PATH=$QTDIR/%_lib:$LD_LIBRARY_PATH
+
+# Search for qt/kde libraries in the right directories (avoid patch)
+# NOTE: please don't regenerate configure scripts below
+perl -pi -e "s@/lib(\"|\b[^/])@/%_lib\1@g if /(kde|qt)_(libdirs|libraries)=/" configure
+
+
+%{?__cputoolize: %{__cputoolize} }
+
+
+%ifarch %ix86
+CFLAGS="%optflags" CXXFLAGS="`echo %optflags |sed -e 's/-fomit-frame-pointer//'`" \
+%else
+CFLAGS="%optflags" CXXFLAGS="%optflags" \
+%endif
+ %configure --disable-debug
+
+%make
+
+%install
+
+%makeinstall_std
+
+%find_lang %name
+
+mkdir -p %buildroot/{%_miconsdir,%{_prefix}/share/pixmaps/}
+install -m 644 %{name}/lo16-app-%{name}.png %buildroot/%{_miconsdir}/%{name}.png
+install -m 644 %{name}/lo32-app-%{name}.png %buildroot/%{_iconsdir}/%{name}.png
+install -m 644 %{name}/network_card.png %buildroot/%{_prefix}/share/pixmaps/network_card.png
+
+mkdir -p %{buildroot}/%{_menudir}
+kdedesktop2mdkmenu.pl %{name} System/Configuration/KDE/Network $RPM_BUILD_ROOT%{_datadir}/applications/kde/kcm_knetworkconfmodule.desktop $RPM_BUILD_ROOT%{_menudir}/%{name}
+
+
+%post
+/sbin/ldconfig
+%{update_menus}
+
+%postun
+/sbin/ldconfig
+%{clean_menus}
+
+%clean
+rm -rf $RPM_BUILD_ROOT/*
+
+%files -f %name.lang
+
+#Quick Hack: for some reason the %find_lang command doesn't find
+#the translations files, it outputs a knetworkconf.lang file full
+#of empty lines instead of the following ones:
+%lang(de) /usr/share/locale/de/LC_MESSAGES/knetworkconfmodule.mo
+%lang(es) /usr/share/locale/es/LC_MESSAGES/knetworkconfmodule.mo
+%lang(eu) /usr/share/locale/eu/LC_MESSAGES/knetworkconfmodule.mo
+%lang(fr) /usr/share/locale/fr/LC_MESSAGES/knetworkconfmodule.mo
+%lang(hu) /usr/share/locale/hu/LC_MESSAGES/knetworkconfmodule.mo
+%lang(no) /usr/share/locale/no/LC_MESSAGES/knetworkconfmodule.mo
+%lang(pl) /usr/share/locale/pl/LC_MESSAGES/knetworkconfmodule.mo
+%lang(pt_BR) /usr/share/locale/pt_BR/LC_MESSAGES/knetworkconfmodule.mo
+
+%defattr(-,root,root,0755)
+%doc README COPYING AUTHORS LEAME
+
+%{_libdir}/menu/*
+
+%{_libdir}/kde3/*.la
+%{_libdir}/kde3/*.so
+%{_libdir}/pkgconfig/*.pc
+%{_iconsdir}/*.png
+%{_miconsdir}/%{name}.png
+%_datadir/applications/kde/*.desktop
+%_datadir/pixmaps/network_card.png
+
+%_datadir/icons/locolor/16x16/apps/*.png
+%_datadir/icons/locolor/22x22/apps/*.png
+%_datadir/icons/locolor/32x32/apps/*.png
+%_datadir/icons/hicolor/22x22/actions/*.png
+
+#%dir %_docdir/HTML/en/%{name}/
+%_docdir/HTML/en/%{name}/
+#%dir %_docdir/HTML/de/%{name}/
+%_docdir/HTML/de/%{name}/
+#%dir %_docdir/HTML/es/%{name}/
+%_docdir/HTML/es/%{name}/
+
+%dir %_datadir/apps/%{name}/backends/
+%_datadir/apps/%{name}/backends/*
+
+%dir %_datadir/apps/%{name}/pixmaps/
+%_datadir/apps/%{name}/pixmaps/*.png
+
+
+%changelog
+* Sun Feb 20 2005 Juan Luis Baptiste <juan.baptiste@kdemail.net> 0.6.1-1mdk
+- 0.6.1
+
+* Tue Feb 08 2005 Laurent MONTEL <lmontel@mandrakesoft.com> 0.6-3mdk
+- Fix section
+
+* Thu Sep 30 2004 Laurent MONTEL <lmontel@mandrakesoft.com> 0.6-2mdk
+- Fix menu
+
+* Tue Aug 10 2004 Lenny Cartier <lenny@mandrakesoft.com> 0.6-1mdk
+- from Juan Luis Baptiste <juan.baptiste@kdemail.net> :
+ - 0.6
+
+* Tue Jun 15 2004 Lenny Cartier <lenny@mandrakesoft.com> 0.5-2mdk
+- rebuild
+
+* Thu Feb 26 2004 Lenny Cartier <lenny@mandrakesoft.com> 0.5-1mdk
+- 0.5
+
+* Thu Oct 02 2003 Lenny Cartier <lenny@mandrakesoft.com> 0.4.2-1mdk
+- 0.4.2
+
+* Fri Jul 18 2003 Laurent MONTEL <lmontel@mandrakesoft.com> 0.4.1-2mdk
+- Rebuild
+
+* Thu Apr 10 2003 Lenny Cartier <lenny@mandrakesoft.com> 0.4.1-1mdk
+- 0.4.1
+- find lang macro
+
+* Fri Mar 28 2003 Lenny Cartier <lenny@mandrakesoft.com> 0.4-1mdk
+- from Juan Luis Baptiste <juancho@linuxmail.org> :
+ - Initial release.
diff --git a/knetworkconf/knetworkconf.lsm b/knetworkconf/knetworkconf.lsm
new file mode 100644
index 0000000..ef293fc
--- /dev/null
+++ b/knetworkconf/knetworkconf.lsm
@@ -0,0 +1,14 @@
+Begin3
+Title: KNetworkConf
+Version: 0.1
+Entered-date:
+Description:
+Keywords:
+Author: Juan Luis Baptiste <jbaptiste@merlinux.org>
+Maintained-by: Juan Luis Baptiste <jbaptiste@merlinux.org>
+Primary-site:
+Home-page: http://
+Original-site:
+Platforms: Linux and other Unices
+Copying-policy: GNU Public License
+End
diff --git a/knetworkconf/knetworkconf.spec b/knetworkconf/knetworkconf.spec
new file mode 100644
index 0000000..9b0e7eb
--- /dev/null
+++ b/knetworkconf/knetworkconf.spec
@@ -0,0 +1,110 @@
+# This spec file was generated using Kpp
+# If you find any problems with this spec file please report
+# the error to ian geiser <geiseri@msoe.edu>
+%define name knetworkconf
+%define version 0.5
+%define release 1mdk
+
+Summary: A KDE application to configure TCP/IP settings.
+Name: %{name}
+Version: %{version}
+Release: %{release}
+License: GPL
+Url: http://www.merlinux.org/knetworkconf/
+Group: Networking/Other
+Source: %{name}-%{version}.tar.bz2
+BuildRoot: %{_tmppath}/%{name}-buildroot
+Requires: %_bindir/kdesu
+
+%description
+KNetworkConf is a KDE application to configure TCP/IP settings
+in a Linux machine. I developed it because I couldn't find any
+application to configure TCP/IP settings from within KDE, and I
+think this is a "must have" app for a serious Desktop Enviroment
+like KDE.
+KNetworkConf can configure installed network devices (you can't
+add new ones for now), the default gateway,host and domain names,
+and add/remove DNS servers. This first version is a standalone
+application, but the idea is to make it a KDE Control Center
+module and a KApplet to have a fast access to it from the KDE
+panel.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup
+
+./configure --prefix=%_prefix --mandir=%_mandir --datadir=%_datadir --libdir=%_libdir
+
+%build
+
+%make
+
+%install
+#icons
+mkdir -p %buildroot/{%_miconsdir,%{_prefix}/share/pixmaps/}
+#cd $RPM_BUILD_DIR/%{name}-%{version}
+install -m 644 %{name}/lo16-app-%{name}.png %buildroot/%{_miconsdir}/%{name}.png
+install -m 644 %{name}/lo32-app-%{name}.png %buildroot/%{_iconsdir}/%{name}.png
+install -m 644 %{name}/network_card.png %buildroot/%{_prefix}/share/pixmaps/network_card.png
+
+# Menu
+mkdir -p %buildroot/%_menudir
+cat <<EOF > %buildroot/%_menudir/%name
+?package(%name): command="kdesu %_bindir/%name" needs="X11" \
+icon="%name.png" section="Configuration/Networking" \
+title="KNetworkConf" longtitle="Configure TCP/IP settings under KDE"
+EOF
+
+make DESTDIR=$RPM_BUILD_ROOT bitsdata=$RPM_BUILD_ROOT/%{_datadir} bitssysconf=$RPM_BUILD_ROOT/%{_sysconfdir} install
+
+%find_lang %name
+
+%post
+%{update_menus}
+
+%postun
+%{clean_menus}
+
+%clean
+rm -rf $RPM_BUILD_ROOT/*
+
+
+%files -f %name.lang
+%defattr(-,root,root,0755)
+%doc README COPYING AUTHORS LEAME
+%{_libdir}/menu/*
+%{_bindir}/knetworkconf
+%{_iconsdir}/*.png
+%{_miconsdir}/%{name}.png
+%_datadir/pixmaps/network_card.png
+%_datadir/applnk-mdk/Configuration/Networking/*
+%_datadir/applnk/System/*
+#%_datadir/applnk/Internet/*
+%_datadir/icons/locolor/16x16/apps/*
+%_datadir/icons/locolor/32x32/apps/*
+%_docdir/HTML/en/knetworkconf
+%_docdir/HTML/de/knetworkconf
+%_docdir/HTML/es/knetworkconf
+%_datadir/apps/knetworkconf/backends/*
+%_datadir/apps/knetworkconf/pixmaps/*
+%{_libdir}/pkgconfig/system-tools-backends.pc
+
+
+%changelog
+* Sun Feb 22 2004 Juan Luis Baptiste <juan.baptiste@kdemail.net> 0.5-1mdk
+- 0.5
+
+* Thu Oct 02 2003 Lenny Cartier <lenny@mandrakesoft.com> 0.4.2-1mdk
+- 0.4.2
+
+* Fri Jul 18 2003 Laurent MONTEL <lmontel@mandrakesoft.com> 0.4.1-2mdk
+- Rebuild
+
+* Thu Apr 10 2003 Lenny Cartier <lenny@mandrakesoft.com> 0.4.1-1mdk
+- 0.4.1
+- find lang macro
+
+* Fri Mar 28 2003 Lenny Cartier <lenny@mandrakesoft.com> 0.4-1mdk
+- from Juan Luis Baptiste <juancho@linuxmail.org> :
+ - Initial release.
diff --git a/knetworkconf/knetworkconf/Makefile.am b/knetworkconf/knetworkconf/Makefile.am
new file mode 100644
index 0000000..f72b527
--- /dev/null
+++ b/knetworkconf/knetworkconf/Makefile.am
@@ -0,0 +1,41 @@
+# set the include path for X, qt and KDE
+#INCLUDES= $(all_includes)
+AM_CPPFLAGS = $(all_includes)
+
+# We use deprecated routines in QButton, undefine QT_NO_COMPAT.
+KDE_CXXFLAGS = -UQT_NO_COMPAT
+
+METASOURCES = AUTO
+#bin_PROGRAMS = knetworkconf
+
+kde_module_LTLIBRARIES = kcm_knetworkconfmodule.la
+
+kcm_knetworkconfmodule_la_LIBADD = $(LIB_KDEUI)
+
+# the library search path.
+kcm_knetworkconfmodule_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+
+## INCLUDES were found outside kdevelop specific part
+
+kcm_knetworkconfmodule_la_SOURCES = kselectdistrodlg.ui kknownhostinfo.cpp \
+ kinterfaceupdowndlg.ui kaddknownhostdlg.ui kdetectdistrodlg.ui knetworkconfmodule.cpp \
+ kroutinginfo.cpp kreloadnetworkdlg.ui kaddressvalidator.cpp kdnsinfo.cpp \
+ knetworkinfo.cpp kadddevicedlg.ui kadddnsserverdlg.ui knetworkconfigparser.cpp \
+ knetworkinterface.cpp knetworkconfdlg.ui knetworkconf.cpp main.cpp kadddevicedlgextension.ui \
+ knetworkconfiface.skel kwirelessinterface.cpp kadddevicewifiext.ui kadddevicecontainer.cpp \
+ kprofileslistviewtooltip.cpp
+
+
+EXTRA_DIST = main.cpp knetworkconf.cpp knetworkconf.h knetworkconf.desktop cr16-app-knetworkconf.png cr22-app-knetworkconf.png cr32-app-knetworkconf.png knetworkconfdlg.ui knetworkinterface.cpp knetworkinterface.h knetworkconfigparser.cpp knetworkconfigparser.h kadddnsserverdlg.ui kadddevicedlg.ui knetworkinfo.cpp knetworkinfo.h kdnsinfo.cpp kdnsinfo.h kaddressvalidator.cpp kaddressvalidator.h kreloadnetworkdlg.ui network_card.png kroutinginfo.cpp kroutinginfo.h knetworkconfmodule.cpp knetworkconfmodule.h kdetectdistrodlg.ui kaddknownhostdlg.ui kinterfaceupdowndlg.ui kadddnsserverdlg.ui.h kadddevicedlg.ui.h kaddknownhostdlg.ui.h kknownhostinfo.cpp kknownhostinfo.h kselectdistrodlg.ui kcm_knetworkconfmodule version.h
+
+xdg_apps_DATA = kcm_knetworkconfmodule.desktop
+
+KDE_ICON = AUTO
+
+messages: rc.cpp
+ LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o -name \*.C`; \
+ if test -n "$$LIST"; then \
+ $(XGETTEXT) $$LIST -o $(podir)/knetworkconf.pot; \
+ fi
+
+noinst_HEADERS = kprofileslistviewtooltip.h
diff --git a/knetworkconf/knetworkconf/hi16-app-knetworkconf.png b/knetworkconf/knetworkconf/hi16-app-knetworkconf.png
new file mode 100644
index 0000000..34a5b4b
--- /dev/null
+++ b/knetworkconf/knetworkconf/hi16-app-knetworkconf.png
Binary files differ
diff --git a/knetworkconf/knetworkconf/hi22-app-knetworkconf.png b/knetworkconf/knetworkconf/hi22-app-knetworkconf.png
new file mode 100644
index 0000000..aabf851
--- /dev/null
+++ b/knetworkconf/knetworkconf/hi22-app-knetworkconf.png
Binary files differ
diff --git a/knetworkconf/knetworkconf/hi32-app-knetworkconf.png b/knetworkconf/knetworkconf/hi32-app-knetworkconf.png
new file mode 100644
index 0000000..0aba00e
--- /dev/null
+++ b/knetworkconf/knetworkconf/hi32-app-knetworkconf.png
Binary files differ
diff --git a/knetworkconf/knetworkconf/kadddevicecontainer.cpp b/knetworkconf/knetworkconf/kadddevicecontainer.cpp
new file mode 100644
index 0000000..7ed7e0f
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddevicecontainer.cpp
@@ -0,0 +1,205 @@
+
+/***************************************************************************
+ kadddevicecontainer.cpp - description
+ -------------------
+ begin : Wed Jun 15 00:40:33 UTC 2005
+ copyright : (C) 2005 by Juan Luis Baptiste
+ email : juan.baptiste@kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "kadddevicecontainer.h"
+
+KAddDeviceContainer::KAddDeviceContainer(QWidget *parent, const char *name)
+ : KDialog(parent, name)
+{
+ _modified = false;
+ _advanced = false;
+
+ //Setup extension dialog
+ setExtension( new KAddDeviceDlgExtension( this ) );
+ setOrientation( Vertical );
+
+ //Create dialog that contains the KAddDeviceDlg and KAddDeviceWifiExt (when
+ //configuring a wireless interface) widgets
+ QPixmap activeEthernetDeviceImg(BarIcon("network_connected_lan_knc"));
+ setIcon(activeEthernetDeviceImg);
+ //First create a main QHBoxLayout
+ mainLayout = new QVBoxLayout( this, 10, 2, "mainLayout");
+
+ //Create the Addvanced settings, Ok and Cancel buttons and add them to a QHBoxLayout
+ buttonsLayout = new QHBoxLayout( 0, 0, 4, "buttonsLayout");
+ kpbAdvanced = new KPushButton( this, "kpbAdvanced" );
+ buttonsLayout->addWidget( kpbAdvanced );
+ buttonsSpacer = new QSpacerItem( 70, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ buttonsLayout->addItem( buttonsSpacer );
+
+ kpbApply = new KPushButton( this, "kpbApply" );
+ kpbApply->setEnabled( FALSE );
+ kpbApply->setDefault( TRUE );
+ buttonsLayout->addWidget( kpbApply );
+
+ kpbCancel = new KPushButton( this, "kpbCancel" );
+ buttonsLayout->addWidget( kpbCancel );
+
+ setCaption( QString::null );
+ kpbAdvanced->setText( i18n( "&Advanced Settings" ) );
+ QToolTip::add( kpbAdvanced, i18n( "Toggle between advanced and basic settings" ) );
+ QWhatsThis::add( kpbAdvanced, i18n( "Toggle between advanced and basic settings" ) );
+ kpbApply->setText( i18n( "&OK" ) );
+ QToolTip::add( kpbApply, i18n( "Apply changes" ) );
+ kpbCancel->setText( i18n( "&Cancel" ) );
+ QToolTip::add( kpbCancel, i18n( "Forget changes" ) );
+
+ //Creat and add the KAddDeviceDlg widget to the main layout
+ addDlg = new KAddDeviceDlg(this);
+ mainLayout->addWidget(addDlg);
+ mainLayout->setResizeMode(QLayout::Auto);
+
+ //Setup connections
+ connect((KAddDeviceDlgExtension*)extension(),SIGNAL(valueChangedSignal(int)),this,SLOT(toggleApplyButtonSlot(int)));
+ connect(addDlg->kleIPAddress,SIGNAL(textChanged(const QString&)),this,SLOT(toggleApplyButtonSlot(const QString&)));
+// connect(addDlg->kleGateway,SIGNAL(textChanged(const QString&)),this,SLOT(toggleApplyButtonSlot(const QString&)));
+ connect(addDlg->kcbNetmask,SIGNAL(activated(int)),this,SLOT(toggleApplyButtonSlot(int)));
+ connect(addDlg->kcbAutoBootProto,SIGNAL(activated(const QString&)),this,SLOT(toggleApplyButtonSlot(const QString&)));
+ connect(addDlg->kcbstartAtBoot,SIGNAL(stateChanged(int)),this,SLOT(toggleApplyButtonSlot(int)));
+ connect(addDlg->rbBootProtoAuto,SIGNAL(toggled(bool)),this,SLOT(toggleAdvancedOptionsSlot(bool)));
+ connect(addDlg->rbBootProtoAuto,SIGNAL(toggled(bool)),kpbAdvanced,SLOT(setDisabled(bool)));
+ connect(addDlg->rbBootProtoAuto,SIGNAL(stateChanged(int)),this,SLOT(toggleApplyButtonSlot(int)));
+ // connect(addDlg->rbBootProtoAuto,SIGNAL(toggled(bool)),addDlg->kleIPAddress,SLOT(setDisabled(bool)));
+ // connect(addDlg->rbBootProtoAuto,SIGNAL(toggled(bool)),addDlg->kcbNetmask,SLOT(setDisabled(bool)));
+ // connect(addDlg->rbBootProtoManual,SIGNAL(toggled(bool)),addDlg->kcbAutoBootProto,SLOT(setDisabled(bool)));
+ connect(kpbCancel,SIGNAL(clicked()),this,SLOT(cancelSlot()));
+ connect(kpbApply,SIGNAL(clicked()),this,SLOT(verifyDeviceInfoSlot()));
+ connect(kpbAdvanced,SIGNAL(clicked()),this,SLOT(advancedOptionsSlot()));
+
+}
+
+void KAddDeviceContainer::addWirelessWidget(){
+ extDlg = new KAddDeviceWifiExt(this);
+ mainLayout->addWidget( extDlg );
+ connect(extDlg->kleEssid,SIGNAL(textChanged(const QString&)),this,SLOT(toggleApplyButtonSlot(const QString&)));
+ connect(extDlg->kleWepKey,SIGNAL(textChanged(const QString&)),this,SLOT(toggleApplyButtonSlot(const QString&)));
+ connect(extDlg->qcbKeyType,SIGNAL(activated(const QString&)),this,SLOT(toggleApplyButtonSlot(const QString&)));
+}
+void KAddDeviceContainer::toggleApplyButtonSlot( const QString & )
+{
+ toggleApplyButtonSlot(0);
+}
+
+void KAddDeviceContainer::toggleApplyButtonSlot( int )
+{
+ _modified = true;
+ kpbApply->setEnabled(true);
+}
+
+void KAddDeviceContainer::toggleAdvancedOptionsSlot(bool enabled )
+{
+ KAddDeviceDlgExtension *advancedOptions = (KAddDeviceDlgExtension *)this->extension();
+
+ if (enabled)
+ advancedOptions->gbAdvancedDeviceInfo->setEnabled(false);
+ else
+ advancedOptions->gbAdvancedDeviceInfo->setEnabled(true);
+
+ _modified = true;
+ kpbApply->setEnabled(true);
+}
+
+void KAddDeviceContainer::verifyDeviceInfoSlot()
+{
+ KAddDeviceDlgExtension *advancedOptions = (KAddDeviceDlgExtension *)this->extension();
+
+ if (addDlg->rbBootProtoManual->isChecked())
+ {
+ QString ipAddress = addDlg->kleIPAddress->text();
+ QString netmask = addDlg->kcbNetmask->currentText();
+ QString broadcast = advancedOptions->kleBroadcast->text();
+ QString gateway = advancedOptions->kleGateway->text();
+
+ if (!KAddressValidator::isValidIPAddress(ipAddress))
+ {
+ KMessageBox::error(this,i18n("The format of the specified IP address is not valid."),i18n("Invalid IP Address"));
+ }
+ else if (_advanced && !KAddressValidator::isNetmaskValid(netmask))
+ KMessageBox::error(this,i18n("The format of the specified netmask is not valid."),i18n("Invalid IP Address"));
+
+ else if (!broadcast.isEmpty() && _advanced && !KAddressValidator::isBroadcastValid(broadcast))
+ KMessageBox::error(this,i18n("The format of the specified broadcast is not valid."),i18n("Invalid IP Address"));
+
+ else if (!gateway.isEmpty() && _advanced && !KAddressValidator::isValidIPAddress(gateway))
+ KMessageBox::error(this,i18n("The format of the specified Gateway is not valid."),i18n("Invalid IP Address"));
+
+ else
+ {
+ _modified = true;
+ close();
+ }
+ }
+ else if (addDlg->rbBootProtoAuto->isChecked())
+ {
+ _modified = true;
+ close();
+ }
+}
+
+void KAddDeviceContainer::makeButtonsResizeable()
+{
+ kpbApply->setAutoResize(true);
+ kpbAdvanced->setAutoResize(true);
+ kpbCancel->setAutoResize(true);
+}
+
+bool KAddDeviceContainer::modified()
+{
+ return _modified;
+}
+bool KAddDeviceContainer::advanced()
+{
+ return _advanced;
+}
+
+
+void KAddDeviceContainer::advancedOptionsSlot()
+{
+ if (!_advanced)
+ {
+ kpbAdvanced->setText(i18n("Basic Settings"));
+ addDlg->kcbNetmask->setEditable(true);
+ }
+ else
+ {
+ kpbAdvanced->setText(i18n("Advanced Settings"));
+ addDlg->kcbNetmask->setEditable(false);
+ }
+ _advanced = !_advanced;
+ showExtension(_advanced );
+}
+
+
+void KAddDeviceContainer::cancelSlot()
+{
+ _modified = false;
+ close();
+}
+
+
+KAddDeviceContainer::~KAddDeviceContainer()
+{
+}
+
+void KAddDeviceContainer::addButtons()
+{
+ widgetHSpacer = new QSpacerItem( 20, 16, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ mainLayout->addItem( widgetHSpacer );
+ mainLayout->addLayout( buttonsLayout );
+}
+
+#include "kadddevicecontainer.moc"
diff --git a/knetworkconf/knetworkconf/kadddevicecontainer.h b/knetworkconf/knetworkconf/kadddevicecontainer.h
new file mode 100644
index 0000000..5b1f6a6
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddevicecontainer.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ kadddevicecontainer.h - description
+ -------------------
+ begin : Wed Jun 15 00:40:33 UTC 2005
+ copyright : (C) 2005 by Juan Luis Baptiste
+ email : juan.baptiste@kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KADDDEVICECONTAINER_H
+#define KADDDEVICECONTAINER_H
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <kcombobox.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <kpassdlg.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+
+#include "kadddevicedlg.h"
+#include "kadddevicedlgextension.h"
+#include "kadddevicewifiext.h"
+#include "kaddressvalidator.h"
+
+/**
+Network interface configuration dialog. This dialog contains the KAddDeviceDlg and KAddDeviceWifiExt widgets.
+
+@author Juan Luis Baptiste
+*/
+class KAddDeviceContainer : public KDialog
+{
+ Q_OBJECT
+ public:
+ KAddDeviceContainer(QWidget *parent = 0, const char *name = 0);
+
+ ~KAddDeviceContainer();
+ KPushButton* kpbAdvanced;
+ KPushButton* kpbApply;
+ KPushButton* kpbCancel;
+ void addButtons();
+ KAddDeviceDlg *addDlg;
+ KAddDeviceWifiExt *extDlg;
+ void addWirelessWidget();
+ bool modified();
+ bool advanced();
+
+ private:
+ void makeButtonsResizeable();
+
+ protected:
+ QVBoxLayout* mainLayout;
+ QHBoxLayout* buttonsLayout;
+ QSpacerItem* buttonsSpacer;
+ QSpacerItem* widgetHSpacer;
+ bool _modified;
+ bool _advanced;
+
+ protected slots:
+ void toggleApplyButtonSlot( const QString & );
+ void toggleApplyButtonSlot( int );
+ void toggleAdvancedOptionsSlot(bool enabled );
+ void verifyDeviceInfoSlot();
+ void advancedOptionsSlot();
+ void cancelSlot();
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/kadddevicedlg.ui b/knetworkconf/knetworkconf/kadddevicedlg.ui
new file mode 100644
index 0000000..eecf497
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddevicedlg.ui
@@ -0,0 +1,411 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAddDeviceDlg</class>
+<comment>Dialog to add/configure an network device.</comment>
+<author>Juan Luis Baptiste</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAddDeviceDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>299</width>
+ <height>167</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Configure Interface</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>gbBasicDeviceInfo</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>TCP/IP Address</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="1" column="2" rowspan="1" colspan="3">
+ <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>130</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox" row="0" column="3">
+ <item>
+ <property name="text">
+ <string>dhcp</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>bootp</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcbAutoBootProto</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The boot protocol this network device should use</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The boot protocol this network device should use</string>
+ </property>
+ </widget>
+ <spacer row="0" column="4">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QRadioButton" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>rbBootProtoManual</cstring>
+ </property>
+ <property name="text">
+ <string>Manual:</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Use a static IP address. Use the fields below to enter the values</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Sets this interface to use static IP settings.&lt;/p&gt;
+&lt;p&gt;In this case, please use the fields below to enter the desired values manually.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>rbBootProtoAuto</cstring>
+ </property>
+ <property name="text">
+ <string>Automatic:</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Use a dynamic IP address</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Using an dynamic IP address causes this device to get a free IP address automatically.&lt;/p&gt;
+&lt;p&gt;The interface will try to contact an DHCP- or BOOTP-Server during the boot process.&lt;/p&gt;
+&lt;p&gt;Rendevouz is not supported yet.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>kcbstartAtBoot</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Activate when the computer starts</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Ensures that this interface gets activated during boot time</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Ensures that this interface gets activated during boot time.&lt;/p&gt;
+&lt;p&gt;Otherwise, you will have to active the interface manually after you have logged in after the boot process.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="3" rowspan="1" colspan="2">
+ <item>
+ <property name="text">
+ <string>255.255.255.0</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>255.255.0.0</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>255.0.0.0</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>255.255.255.128</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>255.255.255.192</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>255.255.255.240</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>255.255.255.248</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcbNetmask</cstring>
+ </property>
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Subnetmask of the network device</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Please enter the desired subnetmask for the interface here.&lt;/p&gt;
+&lt;p&gt;For small private networks, 255.255.255.0 will most often be a reasonable default value.&lt;/p&gt;
+&lt;p&gt;This field will change from a popup box to a combo box as soon as you enable the advanced settings below.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer11_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="3" column="2">
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Netmask:</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The netmask defines a range of IP numbers which will build a subnet inside the network.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The netmask defines a range of IP numbers which will build a subnet inside the network.</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kleIPAddress</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>IP address for the network device</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Here you should enter the IP address for the network interface.&lt;/p&gt;
+&lt;p&gt;Please note: If your network is connected to the internet, you should only enter IP addresses you have been given by your provider.&lt;/p&gt;
+&lt;p&gt;Otherwise, you should enter one of the IP addresses which are explicitly reserved for private use.&lt;/p&gt;
+&lt;p&gt;Most small private networks use class C networks, which allow up to 255 computers in your network. So simply use addresses like 192.168.1.1, 192.168.1.2, 192.168.1.171 and so on for your computers.&lt;/p&gt;
+&lt;p&gt;Cass C networks: 192.168.0.0 to 192.168.255.25, for example 192.168.0.13.&lt;/p&gt;
+&lt;p&gt;Class B networks: 172.16.0.0 to 172.31.255.255, for example 172.28.2.5&lt;/p&gt;
+&lt;p&gt;Class A networks: 10.0.0.0 to 10.255.255.255, for example 10.5.12.14&lt;/p&gt;
+&lt;p&gt;Please ensure that all IP addresses you give to your computers are unique; you will have many problems if the same address is assigned to more than one network device.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <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>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>IP address:</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>An IP address is an unique identifier of a networking device in an TCP/IP network</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>An IP address is an unique identifier of a networking device in an TCP/IP network</string>
+ </property>
+ </widget>
+ <spacer row="2" column="0">
+ <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>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </hbox>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="789">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000002dc49444154388ded953f881c551cc73f77f79417988419509807296e20ca2d88ba7b09648514b7100857990b69fc53b8d7e5fc53d819cb04d28be99254bb6062568c70290e6ebb150cdca231792709cc6a1666c4c179c5c0fe8a81b5b88b4ad8d1e2c0ca5ff378ff3e7ce1f37e3cf8bff66bae6ae3cb9b0f7e9547327de7e2f29bfa0c0ffcf380ec6faabd410394fbf3727fa1603afa8842558125499f88a797c333fa4aeb93f0e5e8858038138c179167101413b6551fe3415ef868df479c90e0042567e7abc0ddadce9d9008b43efcf1a90dd3f2eba613d7ccc6589b8dc50b66722f32fa1826f1306f9f5c35c68b4cebf89a914c4794bc5699b87df65335ca7234ba8c49894c83db2706049ecf4ed9a3f19ec1954d5afe2adc3548d921a9a704be4f8a9bab04bb3227442308068d9b68dc31b0ce214ab099a5ee19e251423e8ab1654cf39421cf0414d34a70e81946ce42a0f11f251c5a6cb29d399ab2862d2c511861b39895a36f30aa3b1a5e0351b0e96d4209aacabe2d769e078394b2108c5336a58b3e1a32bc95607d8bff529343bacd30ed93f427586d59fd601529f65e89aab2efbceb87f331ac47f557cfc936c669f2b1263a61885d82b63bb8dd75e47487c92b201a821f03b4af01165477ab73e7c2e94bcb4fedbbc4d2bae78803c897da5cbbd17b8e77fbc485b0bef416837142ebf526d7ee77496f5cfe81afb88f621ea0470f4ae6814c1dc87ee6be23e3c3bf5a06d86bbaa93aa0fd9f2999cc92af0e68ff97a7099f05cfa7454248888860c68ec1e32ebeb788fd26c70e2d761482b4198e863cec3fa4b3759b899efc697f16f46f8973b486eda508e3d588b301adf3357abb97a98fdb0c9fa4b8da6cfb557da0f6126b2858386742c8635a51037efb96c1ca452eddfa9cab9ff5ef02bfcfb25f098e5eac69eb864842b17ef57a5153a8b8d0d348fba40a06630b8fb9097c31cb7e1578ae79726dc53979dfee6e7e0da4c091672e2c003f01df5741fea98e00c1bf9ca9fc14fed3fa03e75097599478d74a0000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>rbBootProtoManual</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcbAutoBootProto</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>rbBootProtoAuto</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kleIPAddress</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>rbBootProtoAuto</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcbNetmask</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>rbBootProtoAuto</tabstop>
+ <tabstop>kcbAutoBootProto</tabstop>
+ <tabstop>rbBootProtoManual</tabstop>
+ <tabstop>kleIPAddress</tabstop>
+ <tabstop>kcbNetmask</tabstop>
+ <tabstop>kcbstartAtBoot</tabstop>
+</tabstops>
+<includes>
+ <include location="local" impldecl="in implementation">kadddevicedlg.ui.h</include>
+</includes>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kadddevicedlg.ui.h b/knetworkconf/knetworkconf/kadddevicedlg.ui.h
new file mode 100644
index 0000000..bf3f21b
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddevicedlg.ui.h
@@ -0,0 +1,13 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+
+void KAddDeviceDlg::init()
+{
+}
diff --git a/knetworkconf/knetworkconf/kadddevicedlgextension.ui b/knetworkconf/knetworkconf/kadddevicedlgextension.ui
new file mode 100644
index 0000000..35d4927
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddevicedlgextension.ui
@@ -0,0 +1,156 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAddDeviceDlgExtension</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAddDeviceDlgExtension</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>298</width>
+ <height>131</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Advanced Options</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>gbAdvancedDeviceInfo</cstring>
+ </property>
+ <property name="title">
+ <string>Advanced Device Information</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Set advanced setting for the network device</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>IP address of the network device</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kleDescription</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Simply enter a short human-readable description for this device</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Simply enter a short human-readable description for this device</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>kleBroadcast</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>IP address of the network device</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The Broadcast is a special address. All devices of a network respond if packages are sent to this address.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Gateway:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kleGateway</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>An IP address is an unique identifier of a networking device in an TCP/IP network</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>An IP address is an unique identifier of a networking device in an TCP/IP network</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>kleGateway</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Default gateway for the network device</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Here you should enter the default gateway for the network device.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Broadcast:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kleBroadcast</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KAddDeviceDlgExtension</receiver>
+ <slot>valueChanged(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>kleDescription</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KAddDeviceDlgExtension</receiver>
+ <slot>valueChanged(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>kleGateway</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KAddDeviceDlgExtension</receiver>
+ <slot>valueChanged(const QString&amp;)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">kadddevicedlgextension.ui.h</include>
+</includes>
+<signals>
+ <signal>valueChangedSignal(int)</signal>
+</signals>
+<slots>
+ <slot access="private">valueChanged( const QString &amp; s )</slot>
+</slots>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kadddevicedlgextension.ui.h b/knetworkconf/knetworkconf/kadddevicedlgextension.ui.h
new file mode 100644
index 0000000..455cabf
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddevicedlgextension.ui.h
@@ -0,0 +1,18 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+void KAddDeviceDlgExtension::init()
+{
+
+}
+
+
+void KAddDeviceDlgExtension::valueChanged( const QString &s )
+{
+ emit valueChangedSignal(0);
+}
diff --git a/knetworkconf/knetworkconf/kadddevicewifiext.ui b/knetworkconf/knetworkconf/kadddevicewifiext.ui
new file mode 100644
index 0000000..d8d728a
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddevicewifiext.ui
@@ -0,0 +1,96 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAddDeviceWifiExt</class>
+<comment>Extension to the KAddDeviceDlg dialog to configure wireless settings.</comment>
+<author>Juan Luis Baptiste</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KAddDeviceWifiExt</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>186</width>
+ <height>104</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Wireless Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>gbWirelessSettings</cstring>
+ </property>
+ <property name="title">
+ <string>Wireless Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>WEP key:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kleEssid</cstring>
+ </property>
+ </widget>
+ <widget class="KPasswordEdit" row="1" column="1">
+ <property name="name">
+ <cstring>kleWepKey</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>ESSID:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Key type:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>ASCII</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Hexadecimal</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>qcbKeyType</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpassdlg.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kadddnsserverdlg.ui b/knetworkconf/knetworkconf/kadddnsserverdlg.ui
new file mode 100644
index 0000000..2df997e
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddnsserverdlg.ui
@@ -0,0 +1,166 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAddDNSServerDlg</class>
+<widget class="KDialog">
+ <property name="name">
+ <cstring>KAddDNSServerDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>234</width>
+ <height>81</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Add New DNS Server</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KLineEdit" row="0" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kleNewServer</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>IP address of the new DNS server</string>
+ </property>
+ </widget>
+ <spacer row="0" column="1">
+ <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>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lIPAddress</cstring>
+ </property>
+ <property name="text">
+ <string>IP address:</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="2" column="2">
+ <property name="name">
+ <cstring>kpbAddServer</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Add the server to the list</string>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="2" column="3">
+ <property name="name">
+ <cstring>kpbCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Forget it</string>
+ </property>
+ </widget>
+ <spacer row="1" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer13</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1073">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003f84944415418959d9541681d4518c7ff9b6e9aefc9a6cec0537645211b5aec8ba2264dc13cad90e2a9a508f556bc786cf0a2201e8a88470d150a012dbc8b20b9350791d04349413116f56541db6eb1f18dd887b34d9ebb2359df7ed66dc743c84b2d496afd6018e6303fbef9ff8619586bb1d50080993333e3692b6da6ad2ea7bf75396d75b9bb72ef6cb9fb6b97bba92d9a8bcd85e977a7f701808b1d6aa83ab49709e1fc4533a0fb19a1ef834b862f249276067209baa3505913a0c104c7c76b23a69c1b02707d473083fb842b9db96b8b205143a4196120b1a8015991d0ab05500aa85f140eef0fc0861d4162d77d3b968312096b14b980ce154435042b052281a43440299019059313545b030890e40900a06f2770c6197c0a608c823680e928a024e80ea3e0f518c012fa860281a0730ddff371df8e032f80e10c4401b8a3912104b30251006334c0eb27412991e409248530b959073b8e83993333e3278e9d380bd05320000c7457bae01c7d44e86fbc5943e08d015c80bc0ae6be5fc27c14203680f44264a5c2900851e480f0c466c7ffc5fefcb54dfb479eab61fec70841b586cc28a0eac3200348f63276ff8f7d62c6a94901788074c3db9c33e0c251edf84fe18a6e0ffca0f61901544761c4abd8a56b573bacf9eba44c7466b2388aa3b8772b1edc7e86117f04c215ced1178f3e1c8e8603c4f4e9c2c585c6a9b74e757ae07fd9cf353243506d05ce1949a2c086a092bbecbb15e85c833c82326a1781a4326a776d5fedd681970ed85e14599961d493208a51f343b05b81a84a8033480aa10cdf6bdf6637b23f66afcf4654d295e872f4b9beae7f983d3f6b37ae6a1f0048928ee10c52046062045501e931023f04bcf5b5a00cb2671fb7e376dc8e2fab8f55477f32397efce7daa13a4d7ff099b301760140adaaac4ef5b57327e59ec20d2d180e48f6b12900f2a10d43baa1edd94fe25df5d1fa934aeb8f0219ac162edf098cb8b07069e17d00c52678597d77eec2b90f032fa8e95c0f8ded1d3b04c2a02001ddd1a8b815bb7879e92fbec1bfeb52134adc61e69c725a8dca6f5ae4893b6a39be69564d2f0a00406bb1e54cbd3e35d038db984c5be95776c5deb2a9b576c55a9b5a9bfe945a9bdaa2f96df38bc6e9c6c1c99727079a5f361d005bbee5d6daf58c87ebc3367c3afcdbf77c28a3060a148ece350a145046ed687fbb72ee5e4c9d9c1a1cdb3ff63c08af848f84cf0a219e61668e757ce52efb9766cfcfae6decd9f86db6054f9f6ef405108fc2c7434830a8cbe485578f1d7f63fee2fcaa5a5633a22aae8e3e5e2fa276b446aee8bcfdce6b7627f0e6b39973c554cd7b134f4c1cd483dc5ff3c2c70acec49189c3c38bded2f076f6b7ab1e385a5eba2d3a52e944ef1190bb233703111994000cd21ded6f51ff00b4d6ba80c75184550000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>kpbAddServer</sender>
+ <signal>clicked()</signal>
+ <receiver>KAddDNSServerDlg</receiver>
+ <slot>validateAddressSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KAddDNSServerDlg</receiver>
+ <slot>close()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">kadddnsserverdlg.ui.h</include>
+</includes>
+<slots>
+ <slot access="private">validateAddressSlot()</slot>
+ <slot access="private">makeButtonsResizeable()</slot>
+</slots>
+<functions>
+ <function specifier="non virtual">setAddingAlias( bool add )</function>
+ <function returnType="bool">modified()</function>
+ <function access="private" specifier="non virtual">init()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kdialog.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kadddnsserverdlg.ui.h b/knetworkconf/knetworkconf/kadddnsserverdlg.ui.h
new file mode 100644
index 0000000..0d34f67
--- /dev/null
+++ b/knetworkconf/knetworkconf/kadddnsserverdlg.ui.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+#include "kaddressvalidator.h"
+#include <kmessagebox.h>
+
+bool _modified2;
+bool addingAlias;
+
+void KAddDNSServerDlg::setAddingAlias(bool add)
+{
+ addingAlias = add;
+}
+
+bool KAddDNSServerDlg::modified()
+{
+ return _modified2;
+}
+void KAddDNSServerDlg::init()
+{
+ _modified2 = false;
+ addingAlias = false;
+ makeButtonsResizeable();
+}
+
+void KAddDNSServerDlg::validateAddressSlot()
+{
+ if (!addingAlias)
+ {
+ if (KAddressValidator::isValidIPAddress(kleNewServer->text()))
+ {
+ _modified2 = true;
+ close();
+ }
+ else
+ {
+ KMessageBox::error(this,i18n("The format of the specified IP address is not valid."),i18n("Invalid IP Address"));
+ }
+ }
+ else
+ {
+ if (kleNewServer->text() !="")
+ {
+ _modified2 = true;
+ close();
+ }
+ else
+ {
+ KMessageBox::error(this,i18n("You have to type an alias first."),i18n("Invalid Text"));
+ }
+ }
+}
+
+
+void KAddDNSServerDlg::makeButtonsResizeable()
+{
+ kpbAddServer->setAutoResize(true);
+ kpbCancel->setAutoResize(true);
+}
diff --git a/knetworkconf/knetworkconf/kaddknownhostdlg.ui b/knetworkconf/knetworkconf/kaddknownhostdlg.ui
new file mode 100644
index 0000000..22782ba
--- /dev/null
+++ b/knetworkconf/knetworkconf/kaddknownhostdlg.ui
@@ -0,0 +1,303 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KAddKnownHostDlg</class>
+<widget class="KDialog">
+ <property name="name">
+ <cstring>KAddKnownHostDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>324</width>
+ <height>210</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Add New Static Host</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>IP address:</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>kleIpAddress</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer16</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>80</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer row="3" column="0">
+ <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>180</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>kpbCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ <spacer row="2" column="1">
+ <property name="name">
+ <cstring>spacer51</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>kpbAdd</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer51_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>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Aliases</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListBox">
+ <property name="name">
+ <cstring>klbAliases</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout25</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbAddHost</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Add...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbEditHost</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Edit...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbRemoveHost</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1012">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003bb49444154189595954f681d451cc73f9b6c9adf93973a0b0f794f3cf495886eeb9f1a5a685a7a48f0d25c84debd14415a4490209e8a781215052120855c04cf39a83c7a90f4505ac55a1525ddd204b7d092599b676724ebdb9f75dbf590e6352d49205f1866e630dff9f1fd0cbf09aaaa62330541c0cce733074f1c3f719650f61302258880eac659a05410a9d2a5e4fbce379d37cf7c786631dcd4f5819a8de6287569cf9df7c36e085a0d0380a90b5e1500e7335815a211cfd481f63e45f700db1b030382049d6b16ea6dc42acd8641011912bc5354057bcb72643462725403096510605b63a909bef414b9e0738b69b450cd1011b4542805e72d3e079b392823bcfab58ab633d65231a1c17b8bed2abe6b29146c572972b05d8be682bd69a104a70e236b716d5b7124115a2a2211da7538df42d52262f0a507155c9e4159c3ab47c226fa20fb702bfa7796efa0ca80840ccdbe13133da02f22747e4d98bb6c487388a4892b339af5e6c357b25ef14ee94fbed0a6f37b424bda386fa161d05021947ec6eb51ec88fed4f3caf431410cd468dd2bd62e0fb22cfd47905edf78a7f4b58cb0ded2ae4b75f546daf5d65ff4a5b7cebb24594c92feabd839fd8276a34d2451307978f2c9f89578989c2fe7cfcfcf4ebf3ddded1b3f425f1dce439659342fc8ba16f560bb1be8c3da2c42966783944436b7bbe267e3bb47278f56fd280a0a442244a0dd688108c6445016d4c216362f1ea75fd9d4fe9d2c26bfa02c24d792afd3c5f4b7b97373fdc61302d4c25aa0a52332069f2b2d13217545c2165a7a5a123d4eff5e9aa5b7b2cc7f611ae6eaf8c1a9c23413199f98cadf7def8d87155b67dd7838befad5a9f66e858a92809001cd154283cb951aadaa4fbf9b0e8ebd38f69c6dbacfcc48b482703feaca77977ebaf40150f48dd3a5f47267a8f3712451ecd4ed89f7c4c76af5da888482cb1d40f5f352f2afbfe9ff72a5134aeeab6a4ece8a2ffd1f5237f7d3a5e44fbfe21fedc10b97168293af9f1c9e3d3b3bb17c7df942ef76ef6eef76af5a1fcbd797abdeed5e71e5c72bdfce7c347368e2d589e18bf3170380aaaa361d0300fb8fecafe203f17fa66eb0b91dd65203af1e2d952ccfb6a5bf95828d9bd3a74e8fec1bdd7758eaf25a336abe1c35a29734574d57d2850df47f983b37b7ba7e66cb1f687df1c9a7b30311f29434e509cd74c495fee8d4f1a9b7ce5f985f4997d219d33057e367c68ae456b22aa174d7e96f65dc6f9bea5d4d9bd1fb712b3ee4467428169ea62cccc4a1f1bda66ef66e457f2bf58d931bc93de3a3d46676b720bb081511f194a05eef6c4b7f13fd0f228d8a497c524ca50000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>kpbCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KAddKnownHostDlg</receiver>
+ <slot>close()</slot>
+ </connection>
+ <connection>
+ <sender>kpbAdd</sender>
+ <signal>clicked()</signal>
+ <receiver>KAddKnownHostDlg</receiver>
+ <slot>validateAddressSlot()</slot>
+ </connection>
+ <connection>
+ <sender>klbAliases</sender>
+ <signal>doubleClicked(QListBoxItem*)</signal>
+ <receiver>KAddKnownHostDlg</receiver>
+ <slot>editHostSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbAddHost</sender>
+ <signal>clicked()</signal>
+ <receiver>KAddKnownHostDlg</receiver>
+ <slot>addHostSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbEditHost</sender>
+ <signal>clicked()</signal>
+ <receiver>KAddKnownHostDlg</receiver>
+ <slot>editHostSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbRemoveHost</sender>
+ <signal>clicked()</signal>
+ <receiver>KAddKnownHostDlg</receiver>
+ <slot>removeHostSlot()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>kleIpAddress</tabstop>
+ <tabstop>kpbAdd</tabstop>
+ <tabstop>kpbCancel</tabstop>
+</tabstops>
+<includes>
+ <include location="local" impldecl="in implementation">kaddknownhostdlg.ui.h</include>
+</includes>
+<slots>
+ <slot access="private">validateAddressSlot()</slot>
+ <slot access="private">makeButtonsResizeable()</slot>
+ <slot access="private">editHostSlot()</slot>
+ <slot access="private">removeHostSlot()</slot>
+ <slot access="private">addHostSlot()</slot>
+</slots>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+ <function specifier="non virtual" returnType="bool">modified()</function>
+</functions>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kdialog.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klistbox.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kaddknownhostdlg.ui.h b/knetworkconf/knetworkconf/kaddknownhostdlg.ui.h
new file mode 100644
index 0000000..49ea4b7
--- /dev/null
+++ b/knetworkconf/knetworkconf/kaddknownhostdlg.ui.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+#include "kaddressvalidator.h"
+#include "kadddnsserverdlg.h"
+
+#include <kmessagebox.h>
+
+bool _modifiedhost;
+
+void KAddKnownHostDlg::init()
+{
+ _modifiedhost = false;
+ makeButtonsResizeable();
+}
+void KAddKnownHostDlg::validateAddressSlot()
+{
+ if (!KAddressValidator::isValidIPAddress(kleIpAddress->text()))
+ {
+ KMessageBox::error(this,i18n("The format of the specified IP address is not valid."),i18n("Invalid IP Address"));
+ }
+ else if ((klbAliases->firstItem() == 0))
+ {
+ KMessageBox::error(this,i18n("You must add at least one alias for the specified IP address."),i18n("Insufficient Aliases"));
+ }
+ else
+ {
+ _modifiedhost = true;
+ close();
+ }
+
+}
+
+
+void KAddKnownHostDlg::makeButtonsResizeable()
+{
+ kpbAdd->setAutoResize(true);
+ kpbCancel->setAutoResize(true);
+ kpbAddHost->setAutoResize(true);
+ kpbEditHost->setAutoResize(true);
+ kpbRemoveHost->setAutoResize(true);
+}
+
+
+bool KAddKnownHostDlg::modified()
+{
+ return _modifiedhost;
+}
+
+
+void KAddKnownHostDlg::editHostSlot()
+{
+ KAddDNSServerDlg dlg(this, 0);
+
+ if (klbAliases->currentItem() >= 0)
+ {
+ int currentPos = klbAliases->currentItem();
+ dlg.setCaption(i18n("Edit Alias"));
+ dlg.lIPAddress->setText(i18n("Alias:"));
+ dlg.setAddingAlias(true);
+ QListBoxItem *item = klbAliases->item(currentPos);
+ QString currentText = item->text();
+ dlg.kleNewServer->setText(currentText);
+ dlg.kpbAddServer->setText(i18n("&OK"));
+ dlg.exec();
+
+ if(dlg.modified())
+ {
+ klbAliases->changeItem(dlg.kleNewServer->text(),currentPos);
+// enableApplyButtonSlot();
+ }
+ }
+}
+
+
+void KAddKnownHostDlg::removeHostSlot()
+{
+ if (klbAliases->currentItem() >= 0)
+ klbAliases->removeItem(klbAliases->currentItem());
+}
+
+
+void KAddKnownHostDlg::addHostSlot()
+{
+ KAddDNSServerDlg addDlg(this, 0);
+ addDlg.setCaption(i18n("Add New Alias"));
+ addDlg.lIPAddress->setText(i18n("Alias:"));
+ addDlg.setAddingAlias(true);
+
+ addDlg.exec();
+ if(addDlg.modified())
+ {
+ klbAliases->insertItem(addDlg.kleNewServer->text());
+// enableApplyButtonSlot();
+ }
+
+}
diff --git a/knetworkconf/knetworkconf/kaddressvalidator.cpp b/knetworkconf/knetworkconf/kaddressvalidator.cpp
new file mode 100644
index 0000000..b80e737
--- /dev/null
+++ b/knetworkconf/knetworkconf/kaddressvalidator.cpp
@@ -0,0 +1,240 @@
+/***************************************************************************
+ kaddressvalidator.cpp - description
+ -------------------
+ begin : Wed Jan 22 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kaddressvalidator.h"
+
+/*
+ Class for validating IP address and netmasks, and to calculate network and broadcast values.
+ The functions to do the last two things where taken from the code of ipcalc.c, made by
+ Erik Troan <ewt@redhat.com> and Preston Brown <pbrown@redhat.com> from Red Hat Inc. .
+*/
+
+KAddressValidator::KAddressValidator(){
+}
+KAddressValidator::~KAddressValidator(){
+}
+/** Validates if the address written by the user is a valid one. Return true if it is and false if not. */
+bool KAddressValidator::isValidIPAddress(QString addr){
+ QString s = "";
+ int i;
+ int number;
+ bool ok;
+ if ((addr.contains('.') > 3) || (addr.length() > 15))
+ return false;
+ for (i = 0; i < 4; i++)
+ {
+ s = addr.section('.',i,i);
+ number = s.toInt(&ok);
+ if (!ok)
+ return false;
+ if ((i == 0) && (number == 0))
+ return false;
+ if ((number < 0) || (number > 255))
+ return false;
+ if ((i == 3) && (number == 0))
+ return false;
+ }
+ if (i == 4)
+ return true;
+ else
+ return false;
+}
+bool KAddressValidator::isNetmaskValid(QString addr){
+ QString s = "";
+ int i;
+ int number;
+ bool ok;
+ for (i = 0; i < 4; i++)
+ {
+ s = addr.section('.',i,i);
+ number = s.toInt(&ok);
+ if (!ok)
+ return false;
+ if ((i == 0) && (number == 0))
+ return false;
+ if ((number < 0) || (number > 255))
+ return false;
+ }
+ if (i == 4)
+ return true;
+ else
+ return false;
+
+}
+
+bool KAddressValidator::isNetworkValid(const QString &addr){
+ QString s = "";
+ int i;
+ int number;
+ bool ok;
+ for (i = 0; i < 4; i++)
+ {
+ s = addr.section('.',i,i);
+ number = s.toInt(&ok);
+ if (!ok)
+ return false;
+ if ((i == 0) && (number == 0))
+ return false;
+ if ((number < 0) || (number >= 255))
+ return false;
+ }
+ if (i == 4)
+ return true;
+ else
+ return false;
+
+}
+bool KAddressValidator::isBroadcastValid(QString addr){
+ QString s = "";
+ int i;
+ int number;
+ bool ok;
+ for (i = 0; i < 4; i++)
+ {
+ s = addr.section('.',i,i);
+ number = s.toInt(&ok);
+ if (!ok)
+ return false;
+ if ((i == 0) && (number == 0))
+ return false;
+ if ((number < 0) || (number > 255))
+ return false;
+ if ((i == 3) && (number == 0))
+ return false;
+ }
+ if (i == 4)
+ return true;
+ else
+ return false;
+
+}
+
+/** \fn unsigned long int prefix2mask(int bits)
+ \brief creates a netmask from a specified number of bits
+
+ This function converts a prefix length to a netmask. As CIDR (classless
+ internet domain internet domain routing) has taken off, more an more IP
+ addresses are being specified in the format address/prefix
+ (i.e. 192.168.2.3/24, with a corresponding netmask 255.255.255.0). If you
+ need to see what netmask corresponds to the prefix part of the address, this
+ is the function. See also \ref mask2prefix.
+
+ \param prefix is the number of bits to create a mask for.
+ \return a network mask, in network byte order.
+ */
+unsigned long int KAddressValidator::prefix2mask(int prefix){
+ return htonl(~((2 << (31 - prefix)) - 1));
+}
+/** \fn int mask2prefix(unsigned long int mask)
+ \brief calculates the number of bits masked off by a netmask.
+
+ This function calculates the significant bits in an IP address as specified by
+ a netmask. See also \ref prefix2mask.
+
+ \param mask is the netmask, specified as an unsigned long integer in network byte order.
+ \return the number of significant bits. */
+int KAddressValidator::mask2prefix(unsigned long int mask){
+ unsigned i;
+ int count = IPBITS;
+
+ for (i = 0; i < IPBITS; i++)
+ {
+ if (!(ntohl(mask) & ((2 << i) - 1)))
+ count--;
+ }
+
+ return count;
+}
+/*!
+ \fn unsigned long int calc_broadcast(unsigned long int addr, int prefix)
+
+ \brief calculate broadcast address given an IP address and a prefix length.
+
+ \param addr an IP address in network byte order.
+ \param prefix a prefix length.
+
+ \return the calculated broadcast address for the network, in network byte
+ order. */
+unsigned long int KAddressValidator::calc_broadcast(unsigned long int addr, int prefix){
+ return (addr & prefix2mask(prefix)) | ~prefix2mask(prefix);
+}
+/** \fn unsigned long int calc_network(unsigned long int addr, int prefix)
+ \brief calculates the network address for a specified address and prefix.
+
+ \param addr an IP address, in network byte order
+ \param prefix the network prefix
+ \return the base address of the network that addr is associated with, in
+ network byte order. */
+unsigned long int KAddressValidator::calc_network(unsigned long int addr, int prefix){
+ return (addr & prefix2mask(prefix));
+}
+/** Is a wrapper function to calc_network that receives the IP address and netsmask as QString and
+returns the network value also as a QString, or NULL if it couldn't be calculated. */
+QString KAddressValidator::calculateNetwork(QString addr,QString netmask){
+ struct in_addr _addr, _netmask, _network;
+ int prefix = 0;
+ QString s;
+ if (addr.isNull() || netmask.isNull())
+ return NULL; //bad address
+ if (!inet_pton(AF_INET,addr.latin1(),&_addr))
+ return NULL; //bad address
+ else
+ {
+ if (!inet_pton(AF_INET,netmask.latin1(),&_netmask))
+ return NULL; //bad address
+ else
+ {
+ prefix = mask2prefix(_netmask.s_addr);
+ _network.s_addr = calc_network(_addr.s_addr, prefix);
+ char * char_network = new char[20];
+ if (!inet_ntop(AF_INET,&_network,char_network,20))
+ return NULL;
+ else
+ s = char_network;
+ }
+ }
+ return s;
+}
+
+/** Is a wrapper function to calc_broadcast that receives the IP address and netsmask as QString and
+returns the broadcast value also as a QString, or NULL if it couldn't be calculated. */
+QString KAddressValidator::calculateBroadcast(QString addr, QString netmask){
+ struct in_addr _addr, _netmask, _network;
+ int prefix = 0;
+ QString s;
+ if (addr.isNull() || netmask.isNull())
+ return NULL; //bad address
+ if (!inet_pton(AF_INET,addr.latin1(),&_addr))
+ return NULL; //bad address
+ else
+ {
+ if (!inet_pton(AF_INET,netmask.latin1(),&_netmask))
+ return NULL; //bad address
+ else
+ {
+ prefix = mask2prefix(_netmask.s_addr);
+ _network.s_addr = calc_broadcast(_addr.s_addr, prefix);
+ char * char_network = new char[20];
+ if (!inet_ntop(AF_INET,&_network,char_network,20))
+ return NULL;
+ else
+ s = char_network;
+ }
+ }
+ return s;
+
+}
diff --git a/knetworkconf/knetworkconf/kaddressvalidator.h b/knetworkconf/knetworkconf/kaddressvalidator.h
new file mode 100644
index 0000000..32dcc37
--- /dev/null
+++ b/knetworkconf/knetworkconf/kaddressvalidator.h
@@ -0,0 +1,116 @@
+/***************************************************************************
+ kaddressvalidator.h - description
+ -------------------
+ begin : Wed Jan 22 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KADDRESSVALIDATOR_H
+#define KADDRESSVALIDATOR_H
+
+/*
+ Class for validating IP address and netmasks, and to calculate network and broadcast values.
+ The functions to do the last two things where taken from the code of ipcalc.c, made by
+ Erik Troan <ewt@redhat.com> and Preston Brown <pbrown@redhat.com> from Red Hat Inc.
+*/
+
+
+
+/*!
+ \def IPBITS
+ \brief the number of bits in an IP address.
+*/
+#define IPBITS (sizeof(Q_UINT32) * 8)
+/*!
+ \def IPBYTES
+ \brief the number of bytes in an IP address.
+*/
+#define IPBYTES (sizeof(Q_UINT32))
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <qstring.h>
+
+/**Class that has simple methods for validating IP addresses, netmasks, calculating
+ broadcast and network addresses.
+
+ *@author Juan Luis Baptiste
+ */
+
+class KAddressValidator {
+public:
+ KAddressValidator();
+ ~KAddressValidator();
+ /** Validates if the address written by the user is a valid one. Return true if it is and false if not. */
+ static bool isValidIPAddress(QString addr);
+ /** Validates if the Netmask written by the user is a valid one. Return true if it is and false if not. */
+ static bool isNetmaskValid(QString addr);
+/** Validates if the Network written by the user is a valid one. Return true if it is and false if not. */
+ static bool isNetworkValid(const QString &addr);
+/** Validates if the Broadcast written by the user is a valid one. Return true if it is and false if not. */
+ static bool isBroadcastValid(QString addr);
+
+ /** Is a wrapper function to calc_network that receives the IP address and netsmask as QString and
+ returns the network value also as a QString, or NULL if it couldn't be calculated. */
+ static QString calculateNetwork(QString addr,QString netmask);
+/** Is a wrapper function to calc_broadcast that receives the IP address and netsmask as QString and
+returns the broadcast value also as a QString, or NULL if it couldn't be calculated. */
+ static QString calculateBroadcast(QString addr, QString netmask);
+
+private: // Private methods
+/** \fn unsigned long int calc_broadcast(unsigned long int addr, int prefix)
+
+ \brief calculate broadcast address given an IP address and a prefix length.
+
+ \param addr an IP address in network byte order.
+ \param prefix a prefix length.
+
+ \return the calculated broadcast address for the network, in network byte
+ order. */
+ static unsigned long int calc_broadcast(unsigned long int addr, int prefix);
+ /** \fn unsigned long int calc_network(unsigned long int addr, int prefix)
+ \brief calculates the network address for a specified address and prefix.
+
+ \param addr an IP address, in network byte order
+ \param prefix the network prefix
+ \return the base address of the network that addr is associated with, in
+ network byte order. */
+ static unsigned long int calc_network(unsigned long int addr, int prefix);
+ /** \fn unsigned long int prefix2mask(int bits)
+ \brief creates a netmask from a specified number of bits
+
+ This function converts a prefix length to a netmask. As CIDR (classless
+ internet domain internet domain routing) has taken off, more an more IP
+ addresses are being specified in the format address/prefix
+ (i.e. 192.168.2.3/24, with a corresponding netmask 255.255.255.0). If you
+ need to see what netmask corresponds to the prefix part of the address, this
+ is the function. See also \ref mask2prefix.
+
+ \param prefix is the number of bits to create a mask for.
+ \return a network mask, in network byte order.
+ */
+ static unsigned long int prefix2mask(int prefix);
+ /** \fn int mask2prefix(unsigned long int mask)
+ \brief calculates the number of bits masked off by a netmask.
+
+ This function calculates the significant bits in an IP address as specified by
+ a netmask. See also \ref prefix2mask.
+
+ \param mask is the netmask, specified as an unsigned long integer in network byte order.
+ \return the number of significant bits. */
+ static int mask2prefix(unsigned long int mask);
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/kcm_knetworkconfmodule b/knetworkconf/knetworkconf/kcm_knetworkconfmodule
new file mode 100644
index 0000000..857c4a2
--- /dev/null
+++ b/knetworkconf/knetworkconf/kcm_knetworkconfmodule
@@ -0,0 +1 @@
+?package(local.kcm_knetworkconfmodule.desktop):needs="x11" kde_filename="kcm_knetworkconfmodule" section="System/Configuration/KDE/Network" command="kcmshell kcm_knetworkconfmodule" icon="locolor/32x32/apps/knetworkconf.png" longtitle="Configure your Network settings" title="Network Settings" kde_opt="Encoding=UTF-8\\nX-KDE-RootOnly=true\\nX-KDE-ModuleType=Library\\nX-KDE-Library=knetworkconfmodule\\nX-KDE-FactoryName=knetworkconfmodule\\nX-KDE-ParentApp=kcontrol\\nType=Application\\nDocPath=knetworkconf/index.docbook\\nComment[es]=Configurar las propiedades de Red\\nComment[de]=Netzwerkschnittstellen konfigurieren\\nTerminal=0\\nName[es]=Propiedades de Red\\nName[de]=Netzwerkschnittstellen konfigurieren\\nGenericName=Configure TCP/IP settings\\nGenericName[es]=Configurar las propiedades de red\\nKeywords=Network,DNS,routes,interfaces\\n"
diff --git a/knetworkconf/knetworkconf/kcm_knetworkconfmodule.desktop b/knetworkconf/knetworkconf/kcm_knetworkconfmodule.desktop
new file mode 100644
index 0000000..e648042
--- /dev/null
+++ b/knetworkconf/knetworkconf/kcm_knetworkconfmodule.desktop
@@ -0,0 +1,178 @@
+# KDE Config File
+[Desktop Entry]
+X-KDE-RootOnly=true
+Categories=Qt;KDE;Settings;X-KDE-settings-network;
+X-KDE-ModuleType=Library
+X-KDE-Library=knetworkconfmodule
+X-KDE-FactoryName=knetworkconfmodule
+Type=Application
+Exec=kcmshell kcm_knetworkconfmodule
+Icon=knetworkconf
+DocPath=knetworkconf/index.html
+
+Comment=Configure Network Settings
+Comment[ar]=إعداد تعيينات الشبكة
+Comment[be]=Наставіць сетку
+Comment[bg]=Настройване на мрежата
+Comment[bn]=নেটওয়ার্ক মানসমূহ কনফিগার করে
+Comment[br]=Kefluniañ dibarzhoù ar rouedad
+Comment[bs]=Podesi postavke mreže
+Comment[ca]=Configura els paràmetres de la xarxa
+Comment[cs]=Nastavení sítě
+Comment[da]=Indstil netværksopsætning
+Comment[de]=Netzwerkeinstellungen einrichten
+Comment[el]=Διαμόρφωση ρυθμίσεων δικτύου
+Comment[es]=Configure los parámetros de red
+Comment[et]=Võrguseadistuste seadistamine
+Comment[eu]=Konfiguratu sareko ezarpenak
+Comment[fa]=پیکربندی تنظیمات شبکه
+Comment[fi]=Aseta tietoverkon asetukset
+Comment[fr]=Configuration des paramètres réseau
+Comment[ga]=Cumraigh na Socruithe Líonra
+Comment[gl]=Configuración da Rede
+Comment[he]=שינוי הגדרות רשת
+Comment[hr]=Konfiguriranje mrežnih postavki
+Comment[hu]=A hálózat beállításai
+Comment[is]=Umsjón netstillinga
+Comment[it]=Configura le impostazioni di rete
+Comment[ja]=ネットワーク設定
+Comment[ka]=ქსელის პარამეტრების კონფიგურაცია
+Comment[kk]=Желінің параметрлерін баптау
+Comment[km]=កំណត់​រចនា​សម្ព័ន្ធ​ការ​កំណត់​បណ្ដាញ
+Comment[ko]=네트워크 설정
+Comment[lt]=Konfigūruoti tinklo nustatymus
+Comment[mk]=Конфигурирајте ги поставуањата за мрежата
+Comment[nb]=Sett opp nettverksinnstillinger
+Comment[nds]=Nettwark-Instellen fastleggen
+Comment[ne]=सञ्जाल सेटिङ कन्फिगर गर्नुहोस्
+Comment[nl]=Netwerk instellen
+Comment[nn]=Set opp nettverket
+Comment[pa]=ਨੈੱਟਵਰਕ ਸਥਾਪਨ ਸੰਰਚਨਾ
+Comment[pl]=Konfiguracja ustawień sieci
+Comment[pt]=Configurar Opções de Rede
+Comment[pt_BR]=Configurar rede
+Comment[ro]=Configurează setările de reţea
+Comment[ru]=Утилита настройки сети
+Comment[se]=Heivet fierpmádaga
+Comment[sk]=Konfigurácia sieťových nastavení
+Comment[sl]=Nastavite omrežne nastavitve
+Comment[sr]=Подешавање поставки мреже
+Comment[sr@Latn]=Podešavanje postavki mreže
+Comment[sv]=Anpassa nätverksinställningar
+Comment[th]=ตั้งค่าการปรับแต่งเครือข่าย
+Comment[tr]=Ağ Ayarlarını Yapılandır
+Comment[uk]=Налаштувати мережні параметри
+Comment[vi]=Cấu hình thiết lập mạng
+Comment[wa]=Apontiaedjes del rantoele
+Comment[zh_CN]=配置网络设置
+Comment[zh_HK]=設定網絡設置
+Comment[zh_TW]=設定網路
+Terminal=false
+Name=Network Settings
+Name[ar]=تعيينات الشبكة
+Name[be]=Наставіць сетку
+Name[bg]=Мрежови настройки
+Name[bn]=নেটওয়ার্ক মানসমূহ
+Name[br]=Kefluniadur ar Rouedad
+Name[bs]=Postavke mreže
+Name[ca]=Paràmetres de xarxa
+Name[cs]=Nastavení sítě
+Name[cy]=Gosodiadau Rhwydwaith
+Name[da]=Netværksopsætning
+Name[de]=Netzwerkeinstellungen
+Name[el]=Ρυθμίσεις δικτύου
+Name[es]=Parámetros de red
+Name[et]=Võrguseadistused
+Name[eu]=Sareko ezarpenak
+Name[fa]=تنظیمات شبکه
+Name[fi]=Verkkoasetukset
+Name[fr]=Paramètres réseau
+Name[ga]=Socruithe Líonra
+Name[gl]=Configuración da Rede
+Name[he]=הגדרות רשת
+Name[hr]=Mrežne postavke
+Name[hu]=Hálózati beállítások
+Name[is]=Netstillingar
+Name[it]=Impostazioni di rete
+Name[ja]=ネットワーク設定
+Name[ka]=ქსელის პარამეტრები
+Name[kk]=Желінің параметрлері
+Name[km]=ការ​កំណត់​បណ្ដាញ
+Name[ko]=네트워크 설정
+Name[lt]=Tinklo nustatymai
+Name[mk]=Поставувања на мрежа
+Name[nb]=Nettverksoppsett
+Name[nds]=Nettwark-Instellen
+Name[ne]=सञ्जाल सेटिङ
+Name[nl]=Netwerkinstellingen
+Name[nn]=Nettverksinnstillingar
+Name[pa]=ਨੈੱਟਵਰਕ ਸਥਾਪਨ
+Name[pl]=Ustawienia sieci
+Name[pt]=Configuração da Rede
+Name[pt_BR]=Configurações de Rede
+Name[ro]=Setări de reţea
+Name[ru]=Настройка сети
+Name[se]=Fierpmádatheivehusat
+Name[sk]=Sieťové nastavenia
+Name[sl]=Omrežne nastavitve
+Name[sr]=Поставке мреже
+Name[sr@Latn]=Postavke mreže
+Name[sv]=Nätverksinställningar
+Name[th]=ตั้งค่าเครือข่าย
+Name[tr]=Ağ Ayarları
+Name[uk]=Мережні параметри
+Name[vi]=Thiết lập mạng
+Name[wa]=Apontiaedjes del rantoele
+Name[zh_CN]=网络设置
+Name[zh_HK]=網絡設置
+Name[zh_TW]=網路設定
+Keywords=Network,DNS,routes,interfaces
+Keywords[ar]=الشبكة,خادم اسماء المجال,الطرق,الواجهات
+Keywords[bg]=мрежа, рутер, интерфейс, мрежова, карта, Network, DNS, routes, interfaces
+Keywords[br]=Rouedad,DNS,hentoù,etrefasoù
+Keywords[bs]=Network,DNS,routes,interfaces,mreža,interfejsi
+Keywords[ca]=Xarxa,DNS,rutes,interfícies
+Keywords[cs]=síť,DNS,route,rozhraní
+Keywords[da]=Netværk,DNS,routes,grænseflader
+Keywords[de]=Netzwerk,DNS,Routen,Schnittstellen
+Keywords[el]=Δίκτυο,DNS,routes,διεπαφές
+Keywords[es]=Red, DNS, rutas, interfaces
+Keywords[et]=Võrk,DNS,marsruudid,liidesed
+Keywords[eu]=Sarea,DNS,bideak, iterfazeak
+Keywords[fa]=شبکه، خدمت نام دامنه، مسیرها، واسطها
+Keywords[fi]=tietoverkko,DNS,reitit,rajapinnat
+Keywords[fr]=réseau,DNS,serveur de noms,routes,interfaces
+Keywords[ga]=Líonra,DNS,róid,comhéadain
+Keywords[gl]=Rede,DNS,rutas,interfaces
+Keywords[he]=Network,DNS,routes,interfaces,רשת,כתובתשמות,ממשקים,נתיבים
+Keywords[hr]=Network,DNS,routes,interfaces,mreža,preusmjeravanje,sučelja
+Keywords[hu]=Hálózat,DNS,útvonalak,hálózati csatolók
+Keywords[it]=Rete,DNS,route,interfacce
+Keywords[ja]=ネットワーク,DNS,ルート,インターフェース
+Keywords[ka]=ქსელი,DNS,ბილიკები,ინტერფეისი
+Keywords[km]=បណ្ដាញ,DNS,ផ្លូវ,ចំណុច​ប្រទាក់
+Keywords[ko]=네트워크,DNS,인터페이스
+Keywords[lt]=Network,DNS,routes,interfaces,tinklas,DNS,maršrutai,sąsajos
+Keywords[mk]=Network,DNS,routes,interfaces,Мрежа,рути,интерфејси
+Keywords[nb]=Nettverk,DNS,ruter,grensesnitt
+Keywords[nds]=Nettwark,DNS,route,Anslüss,Koppelsteed,Nettweg
+Keywords[ne]=सञ्जाल, डीएनएस, मार्ग, इन्टरफेस
+Keywords[nl]=netwerk,DNS,routes,interfaces,netwerkkaart
+Keywords[nn]=nettverk,DNS,ruter,grensesnitt
+Keywords[pa]=ਨੈੱਟਵਰਕ,DNS,ਰੂਟ,ਇੰਟਰਫੇਸ
+Keywords[pl]=sieć,Internet,DNS,trasy,routowanie,rutowanie,interfejsy
+Keywords[pt]=Rede,DNS,rotas,interfaces
+Keywords[pt_BR]=Rede,DNS,rotas,interfaces
+Keywords[ro]=Reţea,DNS,rute,interfeţe
+Keywords[se]=Fierpmádat,DNS,routes,lavttat
+Keywords[sl]=Network,DNS,routes,interfaces,omrežje,vmesniki,poti,usmerjanje
+Keywords[sr]=Мрежа,DNS,руте,интерфејси
+Keywords[sr@Latn]=Mreža,DNS,rute,interfejsi
+Keywords[sv]=Nätverk,DNS,route,gränssnitt
+Keywords[th]=เครือข่าย,DNS,routes,interfaces
+Keywords[tr]=Ağ,DNS,routes,arayüzler
+Keywords[uk]=Network,DNS,routes,interfaces,мережа,інтерфейси
+Keywords[vi]=Network,mạng,DNS,routes,tuyến,interfaces,giao diện
+Keywords[zh_CN]=Network,DNS,routes,interfaces,网络,路由,接口
+Keywords[zh_HK]=Network,DNS,routes,interfaces,網絡,路由,介面
+Keywords[zh_TW]=網路,DNS,路由,介面
diff --git a/knetworkconf/knetworkconf/kdetectdistrodlg.ui b/knetworkconf/knetworkconf/kdetectdistrodlg.ui
new file mode 100644
index 0000000..bb97b4c
--- /dev/null
+++ b/knetworkconf/knetworkconf/kdetectdistrodlg.ui
@@ -0,0 +1,73 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KDetectDistroDlg</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KDetectDistroDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>415</width>
+ <height>56</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Detecting Your Current Platform</string>
+ </property>
+ <vbox>
+ <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>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>pixmapLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="pixmap">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>text</cstring>
+ </property>
+ <property name="text">
+ <string>Please wait while detecting your current platform...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="983">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000039e4944415418959595cd6b1d5518c67f934e9a776452cf40948e74915b2af6aa2897a6602a2e6e6a5d74e3dafe03d28f8d0b71292eba312808052964e34297154442119b2e44234aaca8ed151332c586ccd85cef1cc9e8bcd6938e8b9b7b136b6e4b5e18e683f33ef39ce77738c7abaa8a9dcaf33c2ebc7761e2e48993171179aaf75d7c50b7fd2e80822f557a3399bff4f1a557cf4f9f5ff47754dd2c33660e8931b50fafa6233a1c1019417c41a42baa4e290b8bae433caa4c3d1d3f89cf38707f6141867078577fb6941210858a31029b5d5a802d20cf721ae3c2e4213c600ff4870ca8615094b2005be44084aaed3bc6416e736ca1d876371175ca8385bbaeb13627d5a0eb3214284000ab8a1690decaa99b685be60f10ee0d1209d0a224b742a08a88609d82425e28b89e5301d7edf507d15ffd7515750c810ecfbc5627d8a42fbe30f753c247f342aa10f942eec088e9c6b369d587ddd39f3c1c33fb6302614ceee75da7b209747bc6bba53f7518ce4e8219035cb4a1ae048767dbd99f38fedaca7897f44b85bcc89150aa74256d6769f6a53a4d739bb7922469010cfd8f7e66b1ed9cbc2849db25a52d49db39d676e9ab2aea203631511879c7268e3ddc6834464a5b7e3077756ee6ec99b3edad28764bdf29eaba20adda3daa1a59b57beb8fd7ef1c7fe978b515850ff88288101b4142c184d29f8b55bd977e952c267fb4165bd7b4d0ebc952f2496bb1f5c3ece5d9fec6d35bc71e289111ac0fb18990b03b13754aa0c1bdf437d276ba9265f67d33666e34269aa5d95f9366f364f1fa1be7b61cdb759b0baccf9caeed5347d5fd1143aadd455faa828baa3e7d9beda9d7eb4fc4fbf55d09644dc2e0ae647c7eedfbefde02cabe70b2947c3b373cf7b6f85257a7e3b503b51722138d0294ae449d56c9cde4efec56f67be94ac17157550b2d744d9d2e4b68ee264baddfec9afdef1ebcf0d58277ea9553233317679acb3796bfe8dceedce9ac76aaceed4ed559ed54cbbf2c579dd54eb9f0cdc2a7d3e7a78f365f6c8e5cf9ec8a075055d58ed710c0916347aac644e31f09855cf31155f5d429aa8a557b5ffa83cadbfe72e6f499d1da78edb9c8442f9bd03c1bc5d133a52d35cbb3ebdbe87f3d7b7976bdd733f004ea3d4cbf333314c0a366bf79c86676b474fafcd489e6b9f9f9f9b56429b960c6cc8dda817a99acdc5c179f768ffe20e1feb669db69101c88df8c1f898f9ad16838f0794cc04c361a074d680e0ea23fa8fac2c94ab291173649b3741fb0577c10118b036b6de7bef477a87f018b9f681dd4db618a0000000049454e44ae426082</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/knetworkconf/knetworkconf/kdnsinfo.cpp b/knetworkconf/knetworkconf/kdnsinfo.cpp
new file mode 100644
index 0000000..357bc49
--- /dev/null
+++ b/knetworkconf/knetworkconf/kdnsinfo.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ kdnsinfo.cpp - description
+ -------------------
+ begin : Sat Jan 18 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kdnsinfo.h"
+
+KDNSInfo::KDNSInfo(){
+}
+KDNSInfo::~KDNSInfo(){
+}
+QStringList KDNSInfo::getNameServers(){
+ return nameServers;
+}
+QString KDNSInfo::getDomainName(){
+ return domainName;
+}
+QString KDNSInfo::getMachineName(){
+ return machineName;
+}
+
+QStringList KDNSInfo::getSearchDomains(){
+ return searchDomains;
+}
+void KDNSInfo::setNameServers(const QStringList &nameServers){
+ KDNSInfo::nameServers = nameServers;
+}
+void KDNSInfo::setDomainName(const QString &domain){
+ KDNSInfo::domainName = domain;
+}
+void KDNSInfo::setMachineName(const QString &machine){
+ KDNSInfo::machineName = machine;
+}
+
+void KDNSInfo::setSearchDomains(const QStringList &searchDomains){
+ KDNSInfo::searchDomains = searchDomains;
+}
+QPtrList<KKnownHostInfo> KDNSInfo::getKnownHostsList(){
+ return knownHosts;
+}
+void KDNSInfo::addKnownHost(KKnownHostInfo *host){
+ knownHosts.append(host);
+}
+bool KDNSInfo::removeKnownHost(int index){
+ return knownHosts.remove(index);
+}
+void KDNSInfo::setKnownHostsList(QPtrList<KKnownHostInfo> hostsList){
+ KDNSInfo::knownHosts = hostsList;
+}
diff --git a/knetworkconf/knetworkconf/kdnsinfo.h b/knetworkconf/knetworkconf/kdnsinfo.h
new file mode 100644
index 0000000..e81a7cb
--- /dev/null
+++ b/knetworkconf/knetworkconf/kdnsinfo.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ kdnsinfo.h - description
+ -------------------
+ begin : Sat Jan 18 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KDNSINFO_H
+#define KDNSINFO_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include "kknownhostinfo.h"
+
+/**
+ *@author Juan Luis Baptiste
+ */
+
+class KDNSInfo {
+public:
+ KDNSInfo();
+ ~KDNSInfo();
+ QString getDomainName();
+ QString getMachineName();
+ QStringList getNameServers();
+ QStringList getSearchDomains();
+ void setNameServers(const QStringList &nameServer);
+ void setSearchDomains(const QStringList &searchDomains);
+ void setDomainName(const QString &domain);
+ void setMachineName(const QString &machine);
+ QPtrList<KKnownHostInfo> getKnownHostsList();
+ void addKnownHost(KKnownHostInfo *host);
+ bool removeKnownHost(int index);
+ void setKnownHostsList(QPtrList<KKnownHostInfo> hostsList);
+private: // Private attributes
+ QStringList nameServers;
+ QStringList searchDomains;
+ QString domainName;
+ QString machineName;
+ /** List of known hosts (/etc/hosts). */
+ QPtrList<KKnownHostInfo> knownHosts;
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/kinterfaceupdowndlg.ui b/knetworkconf/knetworkconf/kinterfaceupdowndlg.ui
new file mode 100644
index 0000000..68285c4
--- /dev/null
+++ b/knetworkconf/knetworkconf/kinterfaceupdowndlg.ui
@@ -0,0 +1,104 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KInterfaceUpDownDlg</class>
+<widget class="KDialog">
+ <property name="name">
+ <cstring>KInterfaceUpDownDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>253</width>
+ <height>44</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Changing Interface State</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>pixmapLabel1</cstring>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer12</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>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>label</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Bringing up interface &lt;b&gt;eth0&lt;/b&gt;...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer14</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>
+ </hbox>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1012">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003bb49444154189595954f681d451cc73f9b6c9adf93973a0b0f794f3cf495886eeb9f1a5a685a7a48f0d25c84debd14415a4490209e8a781215052120855c04cf39a83c7a90f4505ac55a1525ddd204b7d092599b676724ebdb9f75dbf590e6352d49205f1866e630dff9f1fd0cbf09aaaa62330541c0cce733074f1c3f719650f61302258880eac659a05410a9d2a5e4fbce379d37cf7c786631dcd4f5819a8de6287569cf9df7c36e085a0d0380a90b5e1500e7335815a211cfd481f63e45f700db1b030382049d6b16ea6dc42acd8641011912bc5354057bcb72643462725403096510605b63a909bef414b9e0738b69b450cd1011b4542805e72d3e079b392823bcfab58ab633d65231a1c17b8bed2abe6b29146c572972b05d8be682bd69a104a70e236b716d5b7124115a2a2211da7538df42d52262f0a507155c9e4159c3ab47c226fa20fb702bfa7796efa0ca80840ccdbe13133da02f22747e4d98bb6c487388a4892b339af5e6c357b25ef14ee94fbed0a6f37b424bda386fa161d05021947ec6eb51ec88fed4f3caf431410cd468dd2bd62e0fb22cfd47905edf78a7f4b58cb0ded2ae4b75f546daf5d65ff4a5b7cebb24594c92feabd839fd8276a34d2451307978f2c9f89578989c2fe7cfcfcf4ebf3ddded1b3f425f1dce439659342fc8ba16f560bb1be8c3da2c42966783944436b7bbe267e3bb47278f56fd280a0a442244a0dd688108c6445016d4c216362f1ea75fd9d4fe9d2c26bfa02c24d792afd3c5f4b7b97373fdc61302d4c25aa0a52332069f2b2d13217545c2165a7a5a123d4eff5e9aa5b7b2cc7f611ae6eaf8c1a9c23413199f98cadf7def8d87155b67dd7838befad5a9f66e858a92809001cd154283cb951aadaa4fbf9b0e8ebd38f69c6dbacfcc48b482703feaca77977ebaf40150f48dd3a5f47267a8f3712451ecd4ed89f7c4c76af5da888482cb1d40f5f352f2afbfe9ff72a5134aeeab6a4ece8a2ffd1f5237f7d3a5e44fbfe21fedc10b97168293af9f1c9e3d3b3bb17c7df942ef76ef6eef76af5a1fcbd797abdeed5e71e5c72bdfce7c347368e2d589e18bf3170380aaaa361d0300fb8fecafe203f17fa66eb0b91dd65203af1e2d952ccfb6a5bf95828d9bd3a74e8fec1bdd7758eaf25a336abe1c35a29734574d57d2850df47f983b37b7ba7e66cb1f687df1c9a7b30311f29434e509cd74c495fee8d4f1a9b7ce5f985f4997d219d33057e367c68ae456b22aa174d7e96f65dc6f9bea5d4d9bd1fb712b3ee4467428169ea62cccc4a1f1bda66ef66e457f2bf58d931bc93de3a3d46676b720bb081511f194a05eef6c4b7f13fd0f228d8a497c524ca50000000049454e44ae426082</data>
+ </image>
+ <image name="image1">
+ <data format="PNG" length="762">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000002c1494441541895ed9531885c451880bfbb1be53fd80bf3e08a3770c53d30920d415d63c08da4b80521ac08e6c4c2159b9c9da28556c6d280bd90ee62212798e813536c0ae1b6bb8045163de28be4e0ad26304f387c532cec5f3c588bdb88987b5a1c58f9373f33ffccc70fdffc0cfc1fb398ab2b7c75edce6fe15e98be75e98557e43c77ec6b80ce8ae6200940355b57b38d31d3d17b8c4d1d38dccfefd3884ec7e7e593ce87f193ce46f8a05889d1b0888409b764801550b548c3a263c55741317a61be0e9c0ed21b1607224b6f9fdb70dde596dbca9bee8322721b2b171dc3c4c92a2e58dcfa735de76ce23acfac3b0d9250f1746dc7bd97df37452811a4f204dc7293afcf0c111132fa9c7c3322d0e66ca3837c971074137fa6206a580ac25c2d5851ec2c47085a4514ab508e1545c9aa8ca671f80725e5c893579ef85c4219140cd35ab09588821c96047bcf232b2db643a035ee926b8e5b8ec943413b7e96a2a59c9426c8227de94305a6ce7eae3f3d0e118a2e44a3826d4d913826bb5992d90c7bbccda2e9908d6fe1071332c9e89ee8a27af04a4c9dfd42ae2c4d0aa1b7d27aea8d6a9b685f983c105ccb918f3decde46f736d0b52d26a7400d447723a421000b261da4372ebef8d1e987f6d5e77486813c02ff448fadcffb8ff1fa00af4aef448f61e1e9acb6d9dcfd82e2b3cb3ff20dbb18e6015252a89807f6cd91ecef87efd9e75dfe1c19e060e8a6e688f67fa16272987c7344fbbf3eecf01170d0128b452bc58d02db558a8d57c9af4fc86c46d45c03eaed533d0afd4bc7256260e7548295843cdce6ec858474ef32cd518fcc07c2f1c3edd7cdc1ac63405978d5c5507a5e5a694218b2b376898faf6f72f5d3c14de0f7c3ecd782e3289151c850cf78e3cad57102c6ab4c9d1182083ba30cf6b8067c7998fd3af05cfbf9f5b510f49dec6eff5ba0008efdedc202f033f0431de49fe21810fdcb99da4fe13f8d3f00866a861c3ad7f9ad0000000049454e44ae426082</data>
+ </image>
+</images>
+<includes>
+ <include location="local" impldecl="in implementation">kinterfaceupdowndlg.ui.h</include>
+</includes>
+<slots>
+ <slot>close()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kdialog.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kinterfaceupdowndlg.ui.h b/knetworkconf/knetworkconf/kinterfaceupdowndlg.ui.h
new file mode 100644
index 0000000..4a5fc41
--- /dev/null
+++ b/knetworkconf/knetworkconf/kinterfaceupdowndlg.ui.h
@@ -0,0 +1,16 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+
+
+
+void KInterfaceUpDownDlg::close()
+{
+ accept();
+}
diff --git a/knetworkconf/knetworkconf/kknownhostinfo.cpp b/knetworkconf/knetworkconf/kknownhostinfo.cpp
new file mode 100644
index 0000000..7e779f1
--- /dev/null
+++ b/knetworkconf/knetworkconf/kknownhostinfo.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ KKnownHostInfo.cpp - description
+ -------------------
+ begin : Sun May 11 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : juancho@linuxmail.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kknownhostinfo.h"
+
+KKnownHostInfo::KKnownHostInfo(){
+}
+KKnownHostInfo::~KKnownHostInfo(){
+}
+/** No descriptions */
+QString KKnownHostInfo::getIpAddress(){
+ return ipAddress;
+}
+
+QStringList KKnownHostInfo::getAliases(){
+ return aliases;
+}
+void KKnownHostInfo::setIpAddress(QString ipAddress){
+ KKnownHostInfo::ipAddress = ipAddress;
+}
+
+void KKnownHostInfo::addAlias(QString alias){
+ KKnownHostInfo::aliases.append(alias);
+}
+
+void KKnownHostInfo::setAliases(QStringList aliases){
+ KKnownHostInfo::aliases = aliases;
+}
diff --git a/knetworkconf/knetworkconf/kknownhostinfo.h b/knetworkconf/knetworkconf/kknownhostinfo.h
new file mode 100644
index 0000000..584639e
--- /dev/null
+++ b/knetworkconf/knetworkconf/kknownhostinfo.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ KKnownHostInfo.h - description
+ -------------------
+ begin : Sun May 11 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : juancho@linuxmail.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KKNOWNHOSTINFO_H
+#define KKNOWNHOSTINFO_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+/**Class that represents an entry in the /etc/hosts file.
+ *@author Juan Luis Baptiste
+ */
+
+class KKnownHostInfo {
+public:
+ KKnownHostInfo();
+ ~KKnownHostInfo();
+ QStringList getAliases();
+ QString getIpAddress();
+ void setAliases(QStringList aliases);
+ void addAlias(QString alias);
+ void setIpAddress(QString ipAddress);
+private: // Private attributes
+ /** IP address of the known Host. */
+ QString ipAddress;
+ /** Lists of aliases of the known host. */
+ QStringList aliases;
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/knetworkconf.cpp b/knetworkconf/knetworkconf/knetworkconf.cpp
new file mode 100644
index 0000000..bc39c0e
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconf.cpp
@@ -0,0 +1,1186 @@
+/***************************************************************************
+ knetworkconf.cpp - description
+ -------------------
+ begin : Sun Jan 12 8:54:19 UTC 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kiconloader.h>
+
+#include "knetworkconf.h"
+
+KNetworkConf::KNetworkConf(QWidget *parent, const char *name) : DCOPObject("KNetworkConfIface"), KNetworkConfDlg(parent, name)
+{
+ netInfo = 0L;
+ makeButtonsResizeable();
+ config = new KNetworkConfigParser();
+ klvCardList->setAllColumnsShowFocus(true);
+ klvKnownHosts->setAllColumnsShowFocus(true);
+ klvProfilesList->setAllColumnsShowFocus(true);
+ klvProfilesList->setRenameable(0,true);
+ klvProfilesList->setRenameable(1,true);
+ QToolTip::remove( &(QListView)klvProfilesList );
+ tooltip = new KProfilesListViewToolTip(klvProfilesList);
+
+ //Connect signals emmitted by the backend to know when data is ready to be painted.
+ connect(config,SIGNAL(readyLoadingNetworkInfo()),this,SLOT(getNetworkInfoSlot()));
+ connect(config,SIGNAL(readyLoadingNetworkInfo()),this,SLOT(showMainWindow()));
+ connect(config,SIGNAL(readyLoadingNetworkInfo()),this,SLOT(enableSignals()));
+ connect(config, SIGNAL(setReadOnly(bool)),this,SLOT(setReadOnlySlot(bool)));
+ connect(klvCardList,
+ SIGNAL(contextMenu(KListView*,QListViewItem*,const QPoint&)),
+ this,
+ SLOT(showInterfaceContextMenuSlot(KListView*,QListViewItem*, const QPoint&)));
+
+ // Register with DCOP - No longer needed as now we are a kcontrol module?
+ if ( !kapp->dcopClient()->isRegistered() ) {
+ kapp->dcopClient()->registerAs( "knetworkconf" );
+ kapp->dcopClient()->setDefaultObject( objId() );
+ }
+
+ //Temporarly added while gst supports routing option.
+// cbEnableRouting->hide();
+}
+
+KNetworkConf::~KNetworkConf()
+{
+ delete config;
+}
+
+void KNetworkConf::getNetworkInfoSlot()
+{
+ netInfo = config->getNetworkInfo();
+ if (netInfo == NULL)
+ {
+ KMessageBox::error(this,
+ i18n("Could not load network configuration information."),
+ i18n("Error Reading Configuration File"));
+ //kapp->quit();
+ //exit(1);
+ }
+ else
+ {
+ //QPtrList<KNetworkInterface> deviceList;
+ routingInfo = netInfo->getRoutingInfo();
+ dnsInfo = netInfo->getDNSInfo();
+ profilesList = netInfo->getProfilesList();
+
+ loadNetworkDevicesInfo();
+ loadRoutingInfo();
+ loadDNSInfo();
+ loadNetworkProfiles();
+ nameServersModified = false;
+ devicesModified = false;
+ modified = false;
+// kpbApply->setEnabled(false);
+ }
+
+}
+
+/**
+ Fill the Listview with the info of the network interfaces.
+*/
+void KNetworkConf::loadNetworkDevicesInfo()
+{
+ KNetworkInterface *device;
+ QPixmap activeEthernetDeviceImg(locate("icon","hicolor/22x22/actions/network_connected_lan_knc.png"));
+ QPixmap inactiveEthernetDeviceImg(locate("icon","hicolor/22x22/actions/network_disconnected_lan.png"));
+ QPixmap activeWirelessDeviceImg(locate("icon","hicolor/22x22/actions/network_traffic_wlan.png"));
+ QPixmap inactiveWirelessDeviceImg(locate("icon","hicolor/22x22/actions/network_disconnected_wlan.png"));
+
+ klvCardList->clear();
+ QPtrList<KNetworkInterface> deviceList = netInfo->getDeviceList();
+ for (device = deviceList.first(); device; device = deviceList.next())
+ {
+ if ( device->getType() != "loopback" )
+ {
+ if (klvCardList->findItem(device->getDeviceName(),0,CaseSensitive|ExactMatch) == 0)
+ {
+ QListViewItem * item = new QListViewItem( klvCardList, 0 );
+
+ if (device->isActive())
+ {
+ if (device->getType() == "ethernet")
+ item->setPixmap(0,activeEthernetDeviceImg);
+ else if (device->getType() == "wireless")
+ item->setPixmap(0,activeWirelessDeviceImg);
+
+ item->setText(3,i18n("Enabled"));
+ item->setPixmap(3,SmallIcon("ok"));
+ }
+ else
+ {
+ if (device->getType() == "ethernet")
+ item->setPixmap(0,inactiveEthernetDeviceImg);
+ else if (device->getType() == "wireless")
+ item->setPixmap(0,inactiveWirelessDeviceImg);
+
+ item->setText(3,i18n("Disabled"));
+ item->setPixmap(3,SmallIcon("stop"));
+ if (device->getBootProto().lower() == "dhcp")
+ item->setText(1,"");
+ }
+
+ item->setText(0,device->getDeviceName());
+ item->setText(1,device->getIpAddress());
+ if (device->getBootProto() == "none")
+ item->setText(2,i18n("Manual"));
+ else
+ item->setText(2,device->getBootProto());
+ item->setText(4,device->getDescription());
+ QStringList l = deviceNamesList.grep(device->getDeviceName());
+ if (l.size() == 0)
+ deviceNamesList.append(device->getDeviceName());
+ }
+ }
+ }
+}
+
+
+/** Terminates the application
+ */
+void KNetworkConf::quitSlot(){
+ int code = 0;
+ connect( config, SIGNAL(readyLoadingNetworkInfo()), this, SLOT(quitSlot()) );
+ if (modified)
+ {
+ code = KMessageBox::warningYesNoCancel(this,
+ i18n("The new configuration has not been saved.\nDo you want to apply changes before quitting?"),
+ i18n("New Configuration Not Saved"),KStdGuiItem::apply(),KStdGuiItem::quit());
+ if (code == KMessageBox::Yes)
+ saveInfoSlot();
+ else if (code == KMessageBox::No)
+ kapp->quit();
+ }
+ else
+ kapp->quit();
+}
+/** Enables the configure and remove buttons. */
+void KNetworkConf::enableButtonsSlot(){
+ if (!readOnly)
+ {
+ kpbConfigureNetworkInterface->setEnabled(true);
+ QListViewItem *item = klvCardList->currentItem();
+ QString currentDevice = item->text(0);
+ KNetworkInterface *dev = getDeviceInfo(currentDevice);
+
+ if (dev->isActive())
+ {
+ kpbUpButton->setEnabled(false);
+ kpbDownButton->setEnabled(true);
+ }
+ else
+ {
+ kpbUpButton->setEnabled(true);
+ kpbDownButton->setEnabled(false);
+ }
+ }
+}
+/** opens the add server dialog. */
+void KNetworkConf::addServerSlot(){
+ KAddDNSServerDlg addDlg(this, 0);
+ addDlg.exec();
+ if(addDlg.modified())
+ {
+ klbDomainServerList->insertItem(addDlg.kleNewServer->text());
+ nameServersModified = true;
+ enableApplyButtonSlot();
+ }
+}
+/** opens the edit server dialog. */
+void KNetworkConf::editServerSlot(){
+ KAddDNSServerDlg dlg(this, 0);
+ if (klbDomainServerList->currentItem() >= 0)
+ {
+ int currentPos = klbDomainServerList->currentItem();
+ dlg.setCaption(i18n("Edit Server"));
+ QListBoxItem *item = klbDomainServerList->item(currentPos);
+ QString currentText = item->text();
+ dlg.kleNewServer->setText(currentText);
+ dlg.kpbAddServer->setText(i18n("&OK"));
+ dlg.exec();
+
+ if(dlg.modified())
+ {
+ klbDomainServerList->changeItem(dlg.kleNewServer->text(),currentPos);
+ nameServersModified = true;
+ enableApplyButtonSlot();
+ }
+ }
+}
+
+/** Pops up the window for adding a new interface. */
+void KNetworkConf::configureDeviceSlot(){
+ QListViewItem *item = klvCardList->currentItem();
+ KWirelessInterface *wifiDev = NULL;
+
+ //KAddDeviceContainer *configDlg = new KAddDeviceContainer(this,0);
+ KAddDeviceContainer configDlg(this,0);
+
+ if (item != NULL)
+ {
+ QString currentDevice = item->text(0);
+ configDlg.setCaption(i18n("Configure Device %1").arg(currentDevice));
+ KNetworkInterface *dev = getDeviceInfo(currentDevice);
+ KAddDeviceDlgExtension *advancedOptions = (KAddDeviceDlgExtension *)configDlg.extension();
+
+ if (dev->getBootProto() == "none")
+ {
+ configDlg.addDlg->rbBootProtoManual->setChecked(true);
+ configDlg.addDlg->rbBootProtoAuto->setChecked(false);
+ }
+ else if (dev->getBootProto().lower() == "dhcp")
+ {
+ configDlg.addDlg->kcbAutoBootProto->setCurrentItem(0);
+ configDlg.addDlg->rbBootProtoManual->setChecked(false);
+ configDlg.addDlg->rbBootProtoAuto->setChecked(true);
+ configDlg.addDlg->kleIPAddress->setEnabled(false);
+ configDlg.addDlg->kcbNetmask->setEnabled(false);
+ configDlg.kpbAdvanced->setEnabled(false);
+ }
+ else if (dev->getBootProto().lower() == "bootp")
+ {
+ configDlg.addDlg->kcbAutoBootProto->setCurrentItem(1);
+ configDlg.addDlg->rbBootProtoManual->setChecked(false);
+ configDlg.addDlg->rbBootProtoAuto->setChecked(true);
+ configDlg.kpbAdvanced->setEnabled(false);
+ }
+ if (dev->getOnBoot() == "yes")
+ configDlg.addDlg->kcbstartAtBoot->setChecked(true);
+ else
+ {
+ configDlg.addDlg->kcbstartAtBoot->setChecked(false);
+ }
+ configDlg.addDlg->kleIPAddress->setText(dev->getIpAddress());
+ advancedOptions->kleDescription->setText(dev->getDescription());
+ if (!dev->getBroadcast().isEmpty())
+ advancedOptions->kleBroadcast->setText(dev->getBroadcast());
+ else
+ advancedOptions->kleBroadcast->setText(KAddressValidator::calculateBroadcast(dev->getIpAddress(),dev->getNetmask()));
+
+ advancedOptions->kleGateway->setText(dev->getGateway());
+
+ if (!dev->getNetmask().isEmpty())
+ configDlg.addDlg->kcbNetmask->setCurrentText(dev->getNetmask());
+
+ if (readOnly)
+ {
+ configDlg.addDlg->kcbAutoBootProto->setEnabled(false);
+ configDlg.addDlg->kcbstartAtBoot->setEnabled(false);
+ advancedOptions->gbAdvancedDeviceInfo->setEnabled(false);
+ }
+
+ //If the interface is wireless, then add the wireless configuration widget
+ if (dev->getType() == WIRELESS_IFACE_TYPE){
+ wifiDev = static_cast<KWirelessInterface*>(dev);
+ configDlg.addWirelessWidget();
+ configDlg.extDlg->kleEssid->setText(wifiDev->getEssid());
+ configDlg.extDlg->kleWepKey->setText(wifiDev->getWepKey());
+ if (wifiDev->getKeyType() == WIRELESS_WEP_KEY_TYPE_ASCII)
+ configDlg.extDlg->qcbKeyType->setCurrentItem(0);
+ else if (wifiDev->getKeyType() == WIRELESS_WEP_KEY_TYPE_HEXADECIMAL)
+ configDlg.extDlg->qcbKeyType->setCurrentItem(1);
+ }
+
+ configDlg.addButtons();
+ //Disable Apply button so it only is enabled when a change is made
+ configDlg.kpbApply->setEnabled(false);
+ configDlg.exec();
+
+ if (configDlg.modified())
+ {
+ if(configDlg.addDlg->rbBootProtoManual->isChecked())
+ {
+ item->setText(2,i18n("Manual"));
+ dev->setBootProto("none");
+ }
+ //If the selected boot protocol is dhcp or bootp (Auto), then we don't need the
+ //past IP address, netmask, network and broadcast, as a new one will be assigned by
+ //the dhcp server.
+ else if (configDlg.addDlg->rbBootProtoAuto->isChecked())
+ {
+ if (configDlg.addDlg->kcbAutoBootProto->currentText() != dev->getBootProto())
+ {
+ dev->setIpAddress("");
+ configDlg.addDlg->kleIPAddress->setText("");
+ dev->setGateway("");
+ dev->setNetmask("");
+ dev->setNetwork("");
+ dev->setBroadcast("");
+ }
+ item->setText(2,configDlg.addDlg->kcbAutoBootProto->currentText());
+ dev->setBootProto(configDlg.addDlg->kcbAutoBootProto->currentText());
+ }
+ item->setText(1,configDlg.addDlg->kleIPAddress->text());
+ item->setText(4,advancedOptions->kleDescription->text());
+
+ if (valuesChanged(dev,
+ configDlg.addDlg->kcbAutoBootProto->currentText(),
+ configDlg.addDlg->kcbNetmask->currentText(),
+ configDlg.addDlg->kleIPAddress->text(),
+ advancedOptions->kleGateway->text(),
+ configDlg.addDlg->kcbstartAtBoot->isChecked(),
+ advancedOptions->kleDescription->text(),
+ advancedOptions->kleBroadcast->text()))
+ {
+ dev->setIpAddress(configDlg.addDlg->kleIPAddress->text().stripWhiteSpace());
+ dev->setGateway(advancedOptions->kleGateway->text().stripWhiteSpace());
+ dev->setNetmask(configDlg.addDlg->kcbNetmask->currentText().stripWhiteSpace());
+ QString network = KAddressValidator::calculateNetwork(dev->getIpAddress().stripWhiteSpace(),dev->getNetmask().stripWhiteSpace());
+ dev->setNetwork(network);
+ QString broadcast = advancedOptions->kleBroadcast->text().stripWhiteSpace();
+ if (broadcast.isEmpty())
+ broadcast = KAddressValidator::calculateBroadcast(dev->getIpAddress().stripWhiteSpace(),dev->getNetmask().stripWhiteSpace());
+ dev->setBroadcast(broadcast);
+ dev->setDescription(advancedOptions->kleDescription->text());
+
+ if (configDlg.addDlg->kcbstartAtBoot->isChecked())
+ dev->setOnBoot("yes");
+ else
+ dev->setOnBoot("no");
+ }
+ //If the interface is wireless, then save the wireless configuration options
+ if (dev->getType() == WIRELESS_IFACE_TYPE){
+ wifiDev->setEssid(configDlg.extDlg->kleEssid->text());
+ wifiDev->setWepKey(configDlg.extDlg->kleWepKey->password());
+ wifiDev->setKeyType(configDlg.extDlg->qcbKeyType->currentText());
+ dev = wifiDev;
+ }
+ devicesModified = true;
+ enableApplyButtonSlot();
+ }
+ }
+}
+
+/**Returns the info of the network device 'device or NULL if not found.'*/
+KNetworkInterface * KNetworkConf::getDeviceInfo(QString device){
+ QPtrList<KNetworkInterface> deviceList = netInfo->getDeviceList();
+ QPtrListIterator<KNetworkInterface> i(deviceList);
+ KNetworkInterface *temp;
+ while ((temp = i.current()) != 0)
+ {
+ if (temp->getDeviceName() == device)
+ {
+ return temp;
+ }
+ ++i;
+ }
+ return NULL;
+}
+
+/**Returns the name of the network device that corresponds to the IP address 'ipAddr' or NULL if not found.'*/
+QString KNetworkConf::getDeviceName(QString ipAddr){
+ QPtrList<KNetworkInterface> deviceList = netInfo->getDeviceList();
+ QPtrListIterator<KNetworkInterface> i(deviceList);
+ KNetworkInterface *temp;
+ while ((temp = i.current()) != 0)
+ {
+ if (temp->getIpAddress().compare(ipAddr) == 0)
+ {
+ return temp->getDeviceName();
+ }
+ ++i;
+ }
+ return NULL;
+}
+
+
+/** Looks in the output returned by ifconfig to see if there are the devices up or down.*/
+void KNetworkConf::readFromStdout(){
+ commandOutput = "";
+ commandOutput += procUpdateDevice->readStdout();
+}
+
+/** Loads the info about the default gateway and host and domain names. */
+void KNetworkConf::loadRoutingInfo(){
+ //routingInfo = config->getNetworkInfoSlot();
+ if (!routingInfo->getGateway().isEmpty())
+ kleDefaultRoute->setText(routingInfo->getGateway());
+ else
+ {
+ //Take the default gateway from the gateway field of the default gateway interface
+ //because some platforms (Debian-like ones) seems that don't handle the concept of a default
+ //gateway, instead a gateway per interface.
+ KNetworkInterface *device;
+ QString defaultGwDevice = routingInfo->getGatewayDevice();
+ QPtrList<KNetworkInterface> deviceList = netInfo->getDeviceList();
+ for (device = deviceList.first(); device; device = deviceList.next())
+ {
+ if ( device->getDeviceName() == defaultGwDevice )
+ {
+ if ( !device->getGateway().isEmpty() )
+ {
+ kleDefaultRoute->setText(device->getGateway());
+ }
+ }
+ }
+ }
+
+ kcbGwDevice->clear();
+ kcbGwDevice->insertStringList(deviceNamesList);
+ if (!routingInfo->getGatewayDevice().isEmpty())
+ kcbGwDevice->setCurrentText(routingInfo->getGatewayDevice());
+/* if (routingInfo->isForwardIPv4Enabled().compare("yes") == 0)
+ cbEnableRouting->setChecked(true);
+ else
+ cbEnableRouting->setChecked(false);*/
+}
+
+void KNetworkConf::loadDNSInfo(){
+ QStringList nameServers;
+ if (dnsInfo == NULL)
+ KMessageBox::error(this,i18n("Could not open file '/etc/resolv.conf' for reading."),
+ i18n("Error Loading Config Files"));
+ else
+ {
+ kleHostName->setText(dnsInfo->getMachineName());
+ kleDomainName->setText(dnsInfo->getDomainName());
+ klbDomainServerList->clear();
+ nameServers = dnsInfo->getNameServers();
+ for ( QStringList::Iterator it = nameServers.begin(); it != nameServers.end(); ++it)
+ {
+ klbDomainServerList->insertItem(*it);
+ }
+ klvKnownHosts->clear();
+ knownHostsList = dnsInfo->getKnownHostsList();
+ QPtrListIterator<KKnownHostInfo> it(knownHostsList);
+ KKnownHostInfo *host;
+ while ((host = it.current()) != 0)
+ {
+ ++it;
+ if (!(host->getIpAddress().isEmpty()))
+ {
+ QListViewItem * item = new QListViewItem( klvKnownHosts, 0 );
+ item->setText(0,host->getIpAddress());
+ QStringList aliasesList = host->getAliases();
+ QString aliases;
+ for ( QStringList::Iterator it = aliasesList.begin(); it != aliasesList.end(); ++it )
+ {
+ aliases += *it+" ";
+ }
+ item->setText(1,aliases);
+ }
+ }
+ }
+}
+
+void KNetworkConf::loadNetworkProfiles(){
+ QPtrListIterator<KNetworkInfo> it(profilesList);
+ KNetworkInfo *profile = NULL;
+
+ klvProfilesList->clear();
+ while ((profile = it.current()) != 0)
+ {
+ ++it;
+ if (!profile->getProfileName().isEmpty())
+ {
+ QListViewItem * item = new QListViewItem( klvProfilesList, 0 );
+ item->setText(0,profile->getProfileName());
+ }
+ }
+}
+
+/** Shows the help browser. Hopefully some day it will be one :-). */
+void KNetworkConf::helpSlot(){
+ kapp->invokeHelp();
+}
+
+/** No descriptions */
+void KNetworkConf::aboutSlot(){
+ KAboutApplication *about = new KAboutApplication(kapp->aboutData(),0);
+
+ // about->setLogo(locate("icon","knetworkconf.png"));
+ //qDebug("locate icon= %s",locate("icon","knetworkconf.png").latin1());
+
+ about->show();
+}
+/** No descriptions */
+void KNetworkConf::enableApplyButtonSlot(){
+ //if (!readOnly)
+ //kpbApply->setEnabled(true);
+ modified = true;
+ emit networkStateChanged(true);
+}
+/** Puts the application in read-only mode. This happens when the user runing
+the application t root. */
+void KNetworkConf::setReadOnly(bool state){
+ KNetworkConf::readOnly = state;
+}
+/** No descriptions */
+void KNetworkConf::enableApplyButtonSlot(const QString &text){
+ enableApplyButtonSlot();
+}
+/** No descriptions */
+void KNetworkConf::enableApplyButtonSlot(bool){
+ enableApplyButtonSlot();
+}
+/** No descriptions */
+void KNetworkConf::removeServerSlot(){
+ if (klbDomainServerList->currentItem() >= 0)
+ {
+ klbDomainServerList->removeItem(klbDomainServerList->currentItem());
+ enableApplyButtonSlot();
+ }
+}
+void KNetworkConf::moveUpServerSlot(){
+ int curPos = klbDomainServerList->currentItem();
+ int antPos = klbDomainServerList->currentItem() - 1;
+
+ if (antPos >= 0)
+ {
+ QListBoxItem *current = klbDomainServerList->item(curPos);
+ QListBoxItem *ant = current->prev();
+ QString antText = ant->text();
+ klbDomainServerList->removeItem(antPos);
+ klbDomainServerList->insertItem(antText,curPos);
+ enableApplyButtonSlot();
+ }
+}
+void KNetworkConf::moveDownServerSlot(){
+ int curPos = klbDomainServerList->currentItem();
+ unsigned nextPos = klbDomainServerList->currentItem() + 1;
+
+ if (curPos != -1)
+ {
+ if (klbDomainServerList->count() >= nextPos)
+ {
+ QListBoxItem *current = klbDomainServerList->item(curPos);
+ QString curText = current->text();
+ klbDomainServerList->removeItem(curPos);
+ klbDomainServerList->insertItem(curText,nextPos);
+ klbDomainServerList->setSelected(nextPos,true);
+ enableApplyButtonSlot();
+ }
+ }
+}
+/** Disables all buttons a line edit widgets when the user has read only access. */
+void KNetworkConf::disableAll(){
+ kleHostName->setReadOnly(true);
+ kleDomainName->setReadOnly(true);
+ tlDomainName->setEnabled(false);
+ tlHostName->setEnabled(false);
+ disconnect(klvCardList,SIGNAL(doubleClicked(QListViewItem *)),this,SLOT(configureDeviceSlot()));
+ klvCardList->setEnabled(false);
+ kpbUpButton->setEnabled(false);
+ kpbDownButton->setEnabled(false);
+ kpbConfigureNetworkInterface->setEnabled(false);
+ gbDefaultGateway->setEnabled(false);
+ gbDNSServersList->setEnabled(false);
+ gbKnownHostsList->setEnabled(false);
+// gbNetworkOptions->setEnabled(false);
+}
+
+/** Saves all the modified info of devices, routes,etc. */
+void KNetworkConf::saveInfoSlot(){
+ config->setProgramVersion(getVersion());
+
+ if (!KAddressValidator::isValidIPAddress(kleDefaultRoute->text()) && (!(kleDefaultRoute->text().isEmpty())))
+ {
+ KMessageBox::error(this,i18n("The default Gateway IP address is invalid."),i18n("Invalid IP Address"));
+ }
+ else
+ {
+ //Update DNS info
+ routingInfo->setDomainName(kleDomainName->text());
+ routingInfo->setHostName(kleHostName->text());
+ dnsInfo->setDomainName(kleDomainName->text());
+ dnsInfo->setMachineName(kleHostName->text());
+ dnsInfo->setNameServers(getNamserversList(klbDomainServerList));
+ dnsInfo->setKnownHostsList(getKnownHostsList(klvKnownHosts));
+
+ //Update routing info
+ routingInfo->setGateway(kleDefaultRoute->text());
+ if (routingInfo->getGateway().isEmpty())
+ routingInfo->setGatewayDevice("");
+
+ if (!kleDefaultRoute->text().isEmpty())
+ routingInfo->setGatewayDevice(kcbGwDevice->currentText());
+
+ //Save all info
+ //netInfo->setDeviceList(deviceList);
+ netInfo->setRoutingInfo(routingInfo);
+ netInfo->setDNSInfo(dnsInfo);
+
+ //Add the default gateway to the gateway field of the default gateway interface
+ //because some platforms (Debian-like ones) get the default gateway from there
+ //instead from the default gateway field. funny huh?
+ KNetworkInterface *device;
+ QString defaultGwDevice = routingInfo->getGatewayDevice();
+ QString defaultGwAddress = routingInfo->getGateway();
+ QPtrList<KNetworkInterface> deviceList = netInfo->getDeviceList();
+ for (device = deviceList.first(); device; device = deviceList.next())
+ {
+ if ( device->getGateway().length() == 0 )
+ {
+ if ( device->getDeviceName() == defaultGwDevice )
+ {
+ device->setGateway(defaultGwAddress);
+ }
+ }
+ }
+
+ config->saveNetworkInfo(netInfo);
+ modified = false;
+ }
+}
+/** Creates a QStringList with the IP addresses contained in the QListBox of name servers. */
+QStringList KNetworkConf::getNamserversList(KListBox * serverList){
+ QStringList list;
+ for (unsigned i = 0; i < serverList->count(); i++)
+ {
+ list.append(serverList->text(i));
+ }
+ return list;
+}
+/** Creates a QPtrList<KKownHostInfo> with the info contained in the KListView of name servers. */
+QPtrList<KKnownHostInfo> KNetworkConf::getKnownHostsList(KListView * hostsList){
+ QPtrList<KKnownHostInfo> list;
+ QListViewItem *it = hostsList->firstChild();
+ for (int i = 0; i < hostsList->childCount(); i++)
+ {
+ KKnownHostInfo *host = new KKnownHostInfo();
+
+ if (!(it->text(0).isEmpty()))
+ {
+ host->setIpAddress(it->text(0));
+// host->setHostName(it->text(1));
+ host->setAliases(QStringList::split(" ",it->text(1)));
+ it = it->nextSibling();
+ list.append(host);
+ }
+ }
+ return list;
+}
+
+QString KNetworkConf::getVersion(){
+ return version;
+}
+void KNetworkConf::setVersion(QString ver){
+ KNetworkConf::version = ver;
+}
+
+/** Changes the state of device 'dev' to DEVICE_UP or DEVICE_DOWN.
+Return true on success, false on failure. */
+void KNetworkConf::changeDeviceState(const QString &dev, int state){
+ // If the text "Changing device state" is user visible it cannot be the
+ // name parameter to the constructor.
+ KInterfaceUpDownDlg* dialog = new KInterfaceUpDownDlg(this,"Changing device state");
+
+ if (state == DEVICE_UP)
+ dialog->label->setText(i18n("Enabling interface <b>%1</b>").arg(dev));
+ else
+ dialog->label->setText(i18n("Disabling interface <b>%1</b>").arg(dev));
+
+ dialog->setModal(true);
+ dialog->show();
+
+ procDeviceState = new QProcess(this);
+ QString cmd;
+ procDeviceState->addArgument( locate("data",BACKEND_PATH) );
+
+ //If the platform couldn't be autodetected specify it manually
+ if (netInfo->getPlatformName() != QString::null)
+ {
+ procDeviceState->addArgument( "--platform" );
+ procDeviceState->addArgument( netInfo->getPlatformName() );
+ }
+ procDeviceState->addArgument( "-d" );
+
+ if (state == DEVICE_UP)
+ procDeviceState->addArgument("enable_iface::"+dev+"::1" );
+ else if (state == DEVICE_DOWN)
+ procDeviceState->addArgument("enable_iface::"+dev+"::0" );
+
+ connect( procDeviceState, SIGNAL(readyReadStdout()),this, SLOT(readFromStdoutUpDown()) );
+ connect( procDeviceState, SIGNAL(readyReadStderr()),this, SLOT(readFromStdErrUpDown()) );
+ connect( procDeviceState, SIGNAL(processExited()),this, SLOT(verifyDeviceStateChanged()) );
+ connect( procDeviceState, SIGNAL(processExited()), dialog, SLOT(close()) );
+
+ currentDevice = dev;
+ commandOutput = "";
+
+ if ( !procDeviceState->start() )
+ {
+ // error handling
+ KMessageBox::error(this,
+ i18n("Could not launch backend to change network device state. You will have to do it manually."),
+ i18n("Error"));
+ dialog->close();
+ }
+
+}
+void KNetworkConf::readFromStdoutUpDown(){
+ commandOutput.append(procDeviceState->readStdout());
+}
+
+void KNetworkConf::verifyDeviceStateChanged(){
+ KNetworkInterface *dev;
+ QPixmap activeEthernetDeviceImg(BarIcon("network_connected_lan_knc"));
+ QPixmap inactiveEthernetDeviceImg(BarIcon("network_disconnected_lan"));
+ QPixmap activeWirelessDeviceImg(BarIcon("network_traffic_wlan"));
+ QPixmap inactiveWirelessDeviceImg(BarIcon("network_disconnected_wlan"));
+
+ commandOutput = commandOutput.section('\n',1);
+ if (commandErrOutput.length() > 0)
+ {
+ KMessageBox::error(this,
+ i18n("There was an error changing the device's state. You will have to do it manually."),
+ i18n("Could Not Change Device State"));
+
+ }
+ else if (commandOutput == "\n<!-- GST: end of request -->")
+ {
+ QListViewItem *item = klvCardList->findItem(currentDevice,0,ExactMatch);
+ if (item != NULL)
+ {
+ dev = getDeviceInfo(currentDevice);
+ if (!dev->isActive())
+ {
+ dev->setActive(true);
+ if (dev->getType() == "ethernet")
+ item->setPixmap(0,activeEthernetDeviceImg);
+ else if (dev->getType() == "wireless")
+ item->setPixmap(0,activeWirelessDeviceImg);
+
+ item->setText(3,i18n("Enabled"));
+ item->setPixmap(3,SmallIcon("ok"));
+// config->runDetectionScript(netInfo->getPlatformName());
+ config->listIfaces(netInfo->getPlatformName());
+// item->setText(1,dev->getIpAddress());
+ }
+ else
+ {
+ dev->setActive(false);
+ if (dev->getType() == "ethernet")
+ item->setPixmap(0,inactiveEthernetDeviceImg);
+ else if (dev->getType() == "wireless")
+ item->setPixmap(0,inactiveWirelessDeviceImg);
+
+ item->setText(3,i18n("Disabled"));
+ item->setPixmap(3,SmallIcon("stop"));
+ if (dev->getBootProto().lower() == "dhcp")
+ item->setText(1,"");
+ }
+ enableButtonsSlot();
+ }
+ }
+}
+/** Returns a list of strings of all the configured devices. */
+QStringList KNetworkConf::getDeviceList(){
+ QStringList list;
+ KNetworkInterface * device;
+ QPtrList<KNetworkInterface> deviceList = netInfo->getDeviceList();
+ for (device = deviceList.first(); device; device = deviceList.next())
+ {
+ list.append(device->getDeviceName());
+ }
+ return list;
+}
+/** No descriptions */
+bool KNetworkConf::valuesChanged(KNetworkInterface *dev,
+ QString bootProto,
+ QString netmask,
+ QString ipAddr,
+ QString gateway,
+ bool onBoot,
+ QString desc,
+ QString broadcast){
+ if ((dev->getBootProto() != bootProto) ||
+ (dev->getNetmask() != netmask) ||
+ (dev->getIpAddress() != ipAddr) ||
+ (dev->getGateway() != gateway) ||
+ ((dev->getOnBoot() == "yes") && !(onBoot)) ||
+ ((dev->getOnBoot() == "no") && (onBoot)) ||
+ (dev->getDescription() != desc) ||
+ (dev->getBroadcast() != broadcast))
+ return true;
+ else
+ return false;
+}
+
+/** Sets the QPushButton::autoResize() in true for all buttons. */
+void KNetworkConf::makeButtonsResizeable(){
+ kpbConfigureNetworkInterface->setAutoResize(true);
+ kcbGwDevice->setAutoResize(true);
+ kpbAddDomainServer->setAutoResize(true);
+ kpbEditDomainServer->setAutoResize(true);
+ kpbRemoveDomainServer->setAutoResize(true);
+ kpbUpButton->setAutoResize(true);
+ kpbDownButton->setAutoResize(true);
+ kpbAddKnownHost->setAutoResize(true);
+ kpbEditKnownHost->setAutoResize(true);
+ kpbRemoveKnownHost->setAutoResize(true);
+}
+
+void KNetworkConf::enableInterfaceSlot()
+{
+ if (modified) {
+ if (KMessageBox::warningContinueCancel(this,
+ i18n("The new configuration has not been saved.\nApply changes?"),
+ i18n("New Configuration Not Saved"),
+ KStdGuiItem::apply()) == KMessageBox::Continue)
+ saveInfoSlot();
+ else
+ return;
+ }
+
+ KNetworkInterface *dev = getDeviceInfo(klvCardList->currentItem()->text(0));
+ if (dev->isActive())
+ changeDeviceState(dev->getDeviceName(),DEVICE_DOWN);
+ else
+ changeDeviceState(dev->getDeviceName(),DEVICE_UP);
+}
+
+void KNetworkConf::disableInterfaceSlot()
+{
+ if (modified) {
+ if (KMessageBox::warningContinueCancel(this,
+ i18n("The new configuration has not been saved.\nApply changes?"),
+ i18n("New Configuration Not Saved"),
+ KStdGuiItem::apply()) == KMessageBox::Continue)
+ saveInfoSlot();
+ else
+ return;
+ }
+
+ KNetworkInterface *dev = getDeviceInfo(klvCardList->currentItem()->text(0));
+ if (dev->isActive())
+ changeDeviceState(dev->getDeviceName(),DEVICE_DOWN);
+ else
+ changeDeviceState(dev->getDeviceName(),DEVICE_UP);
+}
+
+/** Adds a new host to the KListView that has the known hosts. */
+void KNetworkConf::addKnownHostSlot(){
+ KAddKnownHostDlg dlg(this,0);
+ dlg.setCaption(i18n("Add New Static Host"));
+ QString aliases;
+
+ dlg.exec();
+
+ if (!dlg.kleIpAddress->text().isEmpty() && dlg.klbAliases->firstItem() > 0 )
+ {
+ QListViewItem * item = new QListViewItem( klvKnownHosts, 0 );
+
+ item->setText(0,dlg.kleIpAddress->text());
+
+ for ( uint i = 0; i < dlg.klbAliases->count(); i++ )
+ aliases += dlg.klbAliases->text(i) + " ";
+
+ item->setText(1,aliases);
+ enableApplyButtonSlot();
+ }
+}
+
+/** Removes a known host from the list view */
+void KNetworkConf::removeKnownHostSlot()
+{
+ if (klvKnownHosts->currentItem() != 0)
+ {
+ klvKnownHosts->removeItem(klvKnownHosts->currentItem());
+ enableApplyButtonSlot();
+ }
+}
+
+/** Edits the info about a known host. */
+void KNetworkConf::editKnownHostSlot()
+{
+ KAddKnownHostDlg dlg(this,0);
+ dlg.setCaption(i18n("Edit Static Host"));
+ QListViewItem *item = klvKnownHosts->currentItem();
+ dlg.kleIpAddress->setText(item->text(0));
+
+ QStringList aliases = QStringList::split( " ", item->text(1) );
+ int n = 0;
+ for ( QStringList::Iterator it = aliases.begin(); it != aliases.end(); ++it, ++n )
+ {
+ QString alias = *it;
+ dlg.klbAliases->insertItem(alias,n);
+ }
+
+ dlg.exec();
+
+ QString _aliases;
+ if (!dlg.kleIpAddress->text().isEmpty() && dlg.klbAliases->firstItem() > 0 )
+ {
+ QListViewItem * item = klvKnownHosts->currentItem();
+
+ item->setText(0,dlg.kleIpAddress->text());
+
+ for ( uint i = 0; i < dlg.klbAliases->count(); i++ )
+ _aliases += dlg.klbAliases->text(i) + " ";
+
+ item->setText(1,_aliases);
+ enableApplyButtonSlot();
+ }
+
+}
+
+/** Shows the main window after the network info has been loaded. */
+void KNetworkConf::showMainWindow()
+{
+ show();
+}
+/** No descriptions */
+void KNetworkConf::readFromStdErrUpDown()
+{
+ commandErrOutput.append(procDeviceState->readStderr());
+}
+/** Sees if a device is active or not in the ifconfig output. Not very nice, but it works. Inthe future, this has to be managed by gst. */
+bool KNetworkConf::isDeviceActive(const QString &device, const QString &ifconfigOutput){
+ QString temp = ifconfigOutput.section(device,1,1);
+ if (temp.isEmpty())
+ return false;
+ else
+ {
+ QString temp2 = temp.section("UP",0,0); //two firts lines of the device info.
+ QString temp3 = temp2.section("\n",0,0); //Link encap:Ethernet HWaddr 00:00:21:C5:99:A0
+ QString temp4 = temp2.section("\n",1,1); //inet addr:192.168.1.1 Bcast:192.255.255.255 Mask:255.0.0.0
+ temp3 = temp3.stripWhiteSpace();
+ temp4 = temp4.stripWhiteSpace();
+ QString temp5 = temp3.section(" ",4,4); //00:00:21:C5:99:A0
+ QString temp6 = temp4.section(" ",1,1); // addr:192.168.1.1
+ temp6 = temp6.section(":",1,1); //192.168.1.1
+ QString temp7 = temp4.section(" ",3,3); //Bcast:192.255.255.255
+ temp7 = temp7.section(":",1,1); //192.255.255.255
+ QString temp8 = temp4.section(" ",5,5); // Mask:255.0.0.0
+ temp8 = temp8.section(":",1,1); //255.0.0.0
+
+ //If the ip address is empty it must be a dhcp interface, so fill these fields:
+ if (temp6.isEmpty())
+ return false;
+ }
+ return true;
+}
+void KNetworkConf::setReadOnlySlot(bool state)
+{
+ state = !state;
+ gbDefaultGateway->setEnabled(state);
+ kleDomainName->setEnabled(state);
+ kleHostName->setEnabled(state);
+ gbDNSServersList->setEnabled(state);
+ gbKnownHostsList->setEnabled(state);
+ klvCardList->setEnabled(state);
+ kpbUpButton->setEnabled(state);
+ kpbDownButton->setEnabled(state);
+ kpbConfigureNetworkInterface->setEnabled(state);
+}
+
+/*Shows a context menu when right-clicking in the interface list*/
+void KNetworkConf::showInterfaceContextMenuSlot(KListView* lv, QListViewItem* lvi, const QPoint& pt)
+{
+ KPopupMenu *context = new KPopupMenu( this );
+ Q_CHECK_PTR( context );
+ context->insertItem( "&Enable Interface", this, SLOT(enableInterfaceSlot()));
+ context->insertItem( "&Disable Interface", this, SLOT(disableInterfaceSlot()));
+ QListViewItem *item = klvCardList->currentItem();
+ QString currentDevice = item->text(0);
+ KNetworkInterface *dev = getDeviceInfo(currentDevice);
+
+ if (dev->isActive())
+ {
+ context->setItemEnabled(0,false);
+ context->setItemEnabled(1,true);
+ }
+ else
+ {
+ context->setItemEnabled(0,true);
+ context->setItemEnabled(1,false);
+ }
+ context->insertSeparator(2);
+ context->insertItem( "&Configure Interface...", this, SLOT(configureDeviceSlot()));
+ context->popup(pt);
+ //context->insertItem( "About &Qt", this, SLOT(aboutQt()) );
+}
+
+void KNetworkConf::enableSignals()
+{
+ tooltip->setProfiles(netInfo->getProfilesList());
+ connect(kleDefaultRoute,SIGNAL(textChanged(const QString&)),this,SLOT(enableApplyButtonSlot(const QString&)));
+ connect(kleDomainName,SIGNAL(textChanged(const QString&)),this,SLOT(enableApplyButtonSlot(const QString&)));
+ connect(kleHostName,SIGNAL(textChanged(const QString&)),this,SLOT(enableApplyButtonSlot(const QString&)));
+}
+
+void KNetworkConf::enableProfileSlot()
+{
+ //Get selected profile
+ QListViewItem *item = klvProfilesList->currentItem();
+
+ if (item != NULL)
+ {
+ QString selectedProfile = item->text(0);
+
+ //And search for it in the profiles list
+ KNetworkInfo *profile = getProfile(netInfo->getProfilesList(),selectedProfile);
+ if (profile != NULL)
+ {
+ profile->setProfilesList(netInfo->getProfilesList());
+ config->saveNetworkInfo(profile);
+ modified = false;
+ //connect( config, SIGNAL(readyLoadingNetworkInfo()), this, SLOT(showSelectedProfile(selectedProfile)) );
+ }
+ else
+ KMessageBox::error(this,
+ i18n("Could not load the selected Network Profile."),
+ i18n("Error Reading Profile"));
+ }
+}
+
+KNetworkInfo *KNetworkConf::getProfile(QPtrList<KNetworkInfo> profilesList, QString selectedProfile)
+{
+ QPtrListIterator<KNetworkInfo> it(profilesList);
+ KNetworkInfo *net = NULL;
+
+ while ((net = it.current()) != 0)
+ {
+ ++it;
+ if (net->getProfileName() == selectedProfile)
+ break;
+ }
+ return net;
+}
+
+void KNetworkConf::createProfileSlot()
+{
+ if (!netInfo)
+ return;
+ bool ok;
+ QString newProfileName = KInputDialog::getText(i18n("Create New Network Profile"),
+ i18n("Name of new profile:"),
+ QString::null, &ok, this );
+ if ( ok && !newProfileName.isEmpty() )
+ {
+ QPtrList<KNetworkInfo> profiles = netInfo->getProfilesList();
+ KNetworkInfo *currentProfile = getProfile(profiles,newProfileName);
+ KNetworkInfo *newProfile = new KNetworkInfo();
+
+ //If there isn't a profile with the new name we add it to the list.
+ if (currentProfile == NULL)
+ {
+ QListViewItem *newItem = new QListViewItem( klvProfilesList,newProfileName);
+
+ //memcpy(newProfile,netInfo,sizeof(netInfo) + sizeof(KRoutingInfo) + sizeof(KDNSInfo));
+ //Is there a better way to copy an object? the above memcpy doesn't do the trick
+ newProfile->setProfileName(newProfileName);
+ newProfile->setDNSInfo(netInfo->getDNSInfo());
+ newProfile->setDeviceList(netInfo->getDeviceList());
+ newProfile->setNetworkScript(netInfo->getNetworkScript());
+ newProfile->setPlatformName(netInfo->getPlatformName());
+ newProfile->setProfilesList(netInfo->getProfilesList());
+ newProfile->setRoutingInfo(netInfo->getRoutingInfo());
+
+ profiles.append(newProfile);
+ netInfo->setProfilesList(profiles);
+ enableApplyButtonSlot();
+ }
+ else
+ KMessageBox::error(this,
+ i18n("There is already another profile with that name."),
+ i18n("Error"));
+ }
+
+}
+
+/*void KNetworkConf::updateProfileNameSlot(QListViewItem *item)
+{
+ QString newName = item->text(0);
+
+ if (newName.isEmpty())
+ KMessageBox::error(this,
+ i18n("The profile name can't be left blank."),
+ i18n("Error"));
+ else
+ {
+ KNetworkInfo *currentProfile = getProfile(netInfo->getProfilesList(),newName);
+ KNetworkInfo *newProfile = new KNetworkInfo();
+
+ //If there is a profile with that name we rename it to the new name.
+ if (currentProfile != NULL)
+ {
+ currentProfile->setProfileName(item->text(0));
+ modified = false;
+ enableApplyButtonSlot();
+ }
+ }
+}*/
+
+void KNetworkConf::removeProfileSlot()
+{
+ QListViewItem *item= klvProfilesList->selectedItem();
+ if (item != NULL)
+ {
+/* if (KMessageBox::warningContinueCancel(this,
+ i18n("Are you sure you want to delete the selected network profile?"),
+ i18n("Delete Profile"),KStdGuiItem::del()) == KMessageBox::Continue)*/
+ {
+ QString selectedProfile = item->text(0);
+ QPtrList<KNetworkInfo> profiles = netInfo->getProfilesList();
+ KNetworkInfo *profileToDelete = NULL;
+
+ for ( profileToDelete = profiles.first(); profileToDelete; profileToDelete = profiles.next() )
+ {
+ QString profileName = profileToDelete->getProfileName();
+ if (profileName == selectedProfile)
+ {
+ profiles.remove(profileToDelete);
+ netInfo->setProfilesList(profiles);
+ klvProfilesList->takeItem(item);
+ modified = false;
+ enableApplyButtonSlot();
+ break;
+ }
+ }
+ }
+ }
+}
+
+void KNetworkConf::updateProfileSlot()
+{
+ QListViewItem *item= klvProfilesList->selectedItem();
+ if (item != NULL)
+ {
+ QString selectedProfile = item->text(0);
+ QPtrList<KNetworkInfo> profiles = netInfo->getProfilesList();
+ KNetworkInfo *profileToUpdate = NULL;
+ KNetworkInfo *newProfile = new KNetworkInfo();
+
+ for ( profileToUpdate = profiles.first(); profileToUpdate; profileToUpdate = profiles.next() )
+ {
+ QString profileName = profileToUpdate->getProfileName();
+ if (profileName == selectedProfile)
+ {
+ qDebug("profile updated");
+ newProfile->setProfileName(profileName);
+ newProfile->setDNSInfo(netInfo->getDNSInfo());
+ newProfile->setDeviceList(netInfo->getDeviceList());
+ newProfile->setNetworkScript(netInfo->getNetworkScript());
+ newProfile->setPlatformName(netInfo->getPlatformName());
+ newProfile->setProfilesList(netInfo->getProfilesList());
+ newProfile->setRoutingInfo(netInfo->getRoutingInfo());
+
+
+ profileToUpdate = netInfo;
+ int curPos = profiles.at();
+ // profileToUpdate->setProfileName(profileName);
+ profiles.remove();
+ profiles.insert(curPos,newProfile);
+ netInfo->setProfilesList(profiles);
+ modified = false;
+ enableApplyButtonSlot();
+ break;
+ }
+ }
+ }
+}
+
+#include "knetworkconf.moc"
diff --git a/knetworkconf/knetworkconf/knetworkconf.desktop b/knetworkconf/knetworkconf/knetworkconf.desktop
new file mode 100644
index 0000000..31b113f
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconf.desktop
@@ -0,0 +1,128 @@
+# KDE Config File
+[Desktop Entry]
+Type=Application
+Exec=kdesu knetworkconf -caption "%c" %i %m
+Icon=knetworkconf
+DocPath=knetworkconf/index.html
+Comment=Configure TCP/IP settings
+Comment[ar]=إعداد تعيينات ميفاق التحكم بلنقل/ميفاق الإنترنت
+Comment[be]=Наставіць TCP/IP
+Comment[bg]=Настройване настройките на TCP/IP
+Comment[bn]=টিসিপি/আইপি মানসমূহ কনফিগার করে
+Comment[br]=Kefluniañ an dibarzhoù TCP/IP
+Comment[bs]=Podesi postavke TCP/IP
+Comment[ca]=Configura els paràmetres TCP/IP
+Comment[cs]=Nastavení TCP/IP
+Comment[da]=Indstil opsætning af TCP/IP
+Comment[de]=TCP/IP-Einstellungen einrichten
+Comment[el]=Διαμόρφωση των ρυθμίσεων TCP/IP
+Comment[es]=Configure los parámetros TCP/IP
+Comment[et]=TCP/IP seadistuste seadistamine
+Comment[eu]=Konfiguratu TCP/IP ezarpenak
+Comment[fa]=پیکربندی تنظیمات TCP/IP
+Comment[fi]=Aseta TCP/IP-asetukset
+Comment[fr]=Configuration des paramètres TCP/IP
+Comment[ga]=Cumraigh Socruithe TCP/IP
+Comment[gl]=Configuración de TCP/IP
+Comment[he]=שינוי הגדרות TCP/IP
+Comment[hr]=Konfiguriranje TCP/IP postavki
+Comment[hu]=A TCP/IP beállításai
+Comment[is]=Umsjón TCP/IP stillinga
+Comment[it]=Configura le impostazioni TCP/IP
+Comment[ja]=TCP/IP の設定
+Comment[ka]=TCP/IP პარამეტრების კონფიგურაცია
+Comment[kk]=TCP/IP параметрлерін баптау
+Comment[km]=កំណត់​រចនា​សម្ព័ន្ធ​ការ​កំណត់ TCP/IP
+Comment[ko]=TCP/IP 설정
+Comment[lt]=Konfigūruoti TCP/IP nustatymus
+Comment[mk]=Конфигурирајте поставувања за TCP/IP
+Comment[nb]=Sett opp TCP/IP-innstillinger
+Comment[nds]=TCP/IP-Instellen fastleggen
+Comment[ne]=टीसीपी/आईपी सेटिङ कन्फिगर गर्नुहोस्
+Comment[nl]=TCP/IP instellen
+Comment[nn]=Set opp TCP/IP
+Comment[pa]=TCP/IP ਸਥਾਪਨ ਸੰਰਚਨਾ
+Comment[pl]=Konfiguracja ustawień TCP/IP
+Comment[pt]=Configurar opções TCP/IP
+Comment[pt_BR]=Configura os ajustes TCP/IP
+Comment[ro]=Configurează setările TCP/IP
+Comment[ru]=Настройка параметров TCP/IP
+Comment[se]=Heivet TCP/IP:a
+Comment[sk]=Konfigurácia nastavení TCP/IP
+Comment[sl]=Nastavite TCP/IP nastavitve
+Comment[sr]=Подесите TCP/IP поставке
+Comment[sr@Latn]=Podesite TCP/IP postavke
+Comment[sv]=Anpassa TCP/IP-inställningar
+Comment[th]=ปรับแต่งการตั้งค่า TCP/IP
+Comment[tr]=TCP /IP Ayarlarını Yapılandır
+Comment[uk]=Налаштувати параметри TCP/IP
+Comment[vi]=Cấu hình thiết lập TCP/IP
+Comment[wa]=Apontiaedjes TCP/IP
+Comment[zh_CN]=配置 TCP/IP 设置
+Comment[zh_HK]=設定 TCP/IP 設置
+Comment[zh_TW]=設定 TCP/IP
+Terminal=false
+Name=KNetworkConf
+Name[ar]=برنامج KNetworkConf
+Name[bn]=কে-নেটওয়ার্ক-কন্ফ
+Name[ne]=केडीई सञ्जाल कन्फिगरेसन
+Name[pa]=ਕੇ-ਨੈੱਟਵਰਕ-ਸੰਰਚਨਾ
+Name[pt_BR]=KNetworkConf
+Name[sv]=Knetworkconf
+Name[th]=ปรับแต่งเครือข่าย - K
+GenericName=Configure TCP/IP Settings
+GenericName[ar]=إعداد تعيينات ميفاق التحكم بلنقل/ميفاق الإنترنت
+GenericName[bg]=Настройване на TCP/IP
+GenericName[bn]=টিসিপি/আইপি মানসমূহ কনফিগারেশন
+GenericName[br]=Kefluniañ an dibarzhoù TCP/IP
+GenericName[bs]=Podesi TCP/IP postavke
+GenericName[ca]=Configura els paràmetres TCP/IP
+GenericName[cs]=Nastavení TCP/IP možností
+GenericName[da]=Indstil opsætning af TCP/IP
+GenericName[de]=TCP/IP-Einstellungen einrichten
+GenericName[el]=Διαμορφώστε τις ρυθμίσεις TCP/IP
+GenericName[es]=Configure los parámetros TCP/IP
+GenericName[et]=TCP/IP seadistuste seadistamine
+GenericName[eu]=Konfiguratu TCP/IP ezarpenak
+GenericName[fa]=پیکربندی تنظیمات TCP/IP
+GenericName[fi]=Aseta TCP/IP-asetukset
+GenericName[fr]=Configuration des paramètres TCP/IP
+GenericName[ga]=Cumraigh Socruithe TCP/IP
+GenericName[gl]=Configuración de TCP/IP
+GenericName[he]=שינוי הגדרות TCP/IP
+GenericName[hr]=Konfiguriranje TCP/IP postavki
+GenericName[hu]=TCP/IP-beállítások
+GenericName[is]=Umsjón TCP/IP stillinga
+GenericName[it]=Configura le impostazioni TCP/IP
+GenericName[ja]=TCP/IP の設定
+GenericName[ka]=TCP/IP პარამეტრების კონფიგურაცია
+GenericName[kk]=TCP/IP параметрлерін баптау
+GenericName[km]=កំណត់​រចនា​សម្ព័ន្ធ​ការ​កំណត់ TCP/IP
+GenericName[ko]=TCP/IP 설정
+GenericName[lt]=Konfigūruoti TCP/IP nustatymus
+GenericName[mk]=Конфигурирајте поставувања за TCP/IP
+GenericName[nb]=Sett opp TCP/IP-innstillinger
+GenericName[nds]=TCP/IP-Instellen setten
+GenericName[ne]=टीसीपी/आईपी सेटिङ कन्फिगर गर्नुहोस्
+GenericName[nl]=TCP/IP instellen
+GenericName[nn]=Set opp TCP/IP
+GenericName[pa]=TCP/IP ਸਥਾਪਨ ਸੰਰਚਨਾ
+GenericName[pl]=Konfiguracja ustawień TCP/IP
+GenericName[pt]=Configurar opções TCP/IP
+GenericName[pt_BR]=Configura os ajustes TCP/IP
+GenericName[ro]=Configurează setările TCP/IP
+GenericName[ru]=Конфигурация TCP/IP
+GenericName[se]=Heivet TCP/IP:a
+GenericName[sk]=Konfigurácia nastavení TCP/IP
+GenericName[sl]=Nastavite TCP/IP nastavitve
+GenericName[sr]=Подеси TCP/IP поставке
+GenericName[sr@Latn]=Podesi TCP/IP postavke
+GenericName[sv]=Anpassa TCP/IP-inställningar
+GenericName[th]=ปรับแต่งการตั้งค่า TCP/IP
+GenericName[tr]=TCP /IP Ayarları Yapılandırıcı
+GenericName[uk]=Налаштувати параметри TCP/IP
+GenericName[vi]=Cấu hình thiết lập TCP/IP
+GenericName[wa]=Apontiaedjes TCP/IP
+GenericName[zh_CN]=配置 TCP/IP 设置
+GenericName[zh_HK]=設定 TCP/IP 設置
+GenericName[zh_TW]=設定 TCP/IP
diff --git a/knetworkconf/knetworkconf/knetworkconf.h b/knetworkconf/knetworkconf/knetworkconf.h
new file mode 100644
index 0000000..3416776
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconf.h
@@ -0,0 +1,211 @@
+/***************************************************************************
+ knetworkconf.h - description
+ -------------------
+ begin : Sun Jan 12 00:54:19 UTC 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNETWORKCONF_H
+#define KNETWORKCONF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define DEVICE_UP 0
+#define DEVICE_DOWN 1
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <kapp.h>
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qprocess.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <qstring.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qradiobutton.h>
+#include <qlayout.h>
+#include <kdialog.h>
+#include <kinputdialog.h>
+#include <kpopupmenu.h>
+#include <kpushbutton.h>
+#include <klistview.h>
+#include <klineedit.h>
+#include <klistbox.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+#include <kaboutapplication.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+
+#include <dcopclient.h>
+
+#include "knetworkconfdlg.h"
+#include "kadddnsserverdlg.h"
+#include "kadddevicecontainer.h"
+#include "kadddevicedlg.h"
+#include "kadddevicewifiext.h"
+#include "knetworkinfo.h"
+#include "kroutinginfo.h"
+#include "knetworkconfigparser.h"
+#include "kdnsinfo.h"
+#include "kaddknownhostdlg.h"
+#include "kknownhostinfo.h"
+#include "knetworkinterface.h"
+#include "kadddevicedlgextension.h"
+#include "knetworkconfiface.h"
+#include "kprofileslistviewtooltip.h"
+
+/** KNetworkConf is the base class of the project */
+class KNetworkConf : public KNetworkConfDlg, virtual public KNetworkConfIface
+{
+ Q_OBJECT
+ public:
+ /** construtor */
+ KNetworkConf(QWidget* parent=0, const char *name=0);
+ /** destructor */
+ ~KNetworkConf();
+ /** Puts the application in read-only mode. This happens when the user runing the application isn't root. */
+ void setReadOnly(bool state);
+ void setVersion(QString ver);
+ QString getVersion();
+ /** Disables all buttons a line edit widgets when the user has read only access. */
+ void disableAll();
+
+ /**
+ Fill the Listview with the info of the network interfaces.
+ */
+ void loadNetworkDevicesInfo();
+ void loadRoutingInfo();
+ void loadDNSInfo();
+ void loadNetworkProfiles();
+
+ private: // Private attributes
+ /** */
+ KNetworkConfigParser *config;
+ KNetworkInterface * getDeviceInfo(QString device);
+ QString getDeviceName(QString ipAddr);
+ /** Creates a QStringList with the IP addresses contained in the QListBox of name servers. */
+ QStringList getNamserversList(KListBox * serverList);
+/** Creates a QPtrList<KKownHostInfo> with the info contained in the KListView of name servers. */
+ QPtrList<KKnownHostInfo> getKnownHostsList(KListView * hostsList);
+ QString currentDevice;
+ KRoutingInfo *routingInfo;
+ KDNSInfo *dnsInfo;
+ bool reloaded;
+ QString commandOutput;
+ QProcess *procUpdateDevice;
+ QProcess *procDeviceState;
+ QStringList deviceNamesList;
+ bool devicesModified;
+ bool readOnly;
+ QPtrList<KKnownHostInfo> knownHostsList;
+ QPtrList<KNetworkInfo> profilesList;
+ bool nameServersModified;
+ /** The program's version. */
+ QString version;
+ bool modified;
+ bool devStateChanged;
+ /** */
+ KNetworkInfo * netInfo;
+ /** Has the errors throwed by GST when executed. */
+ QString commandErrOutput;
+ /** Changes the state of device 'dev' to DEVICE_UP or DEVICE_DOWN.
+ Return true on success, false on failure. */
+ void changeDeviceState(const QString &dev, int state);
+ KNetworkInfo *getProfile(QPtrList<KNetworkInfo> profilesList, QString selectedProfile);
+ void showSelectedProfile(QString profile);
+ KProfilesListViewToolTip *tooltip;
+
+ public slots:
+ virtual void saveInfoSlot();
+/** Puts the application in read-only mode. This happens when the user runing the application isn't root. */
+ void setReadOnlySlot(bool state);
+
+ private slots:
+ /** Enables the configure and remove buttons. */
+ virtual void enableButtonsSlot();
+ /** opens the add server dialog. */
+ virtual void addServerSlot();
+ /** opens the edit server dialog. */
+ virtual void editServerSlot();
+ /** Terminates the application*/
+ virtual void quitSlot();
+ virtual void readFromStdout();
+ virtual void readFromStdoutUpDown();
+ virtual void enableInterfaceSlot();
+ virtual void disableInterfaceSlot();
+ /** Pops up the window for adding a new interface. */
+ virtual void configureDeviceSlot();
+ void enableApplyButtonSlot();
+ /** Shows the help browser. Hopefully some day it will be one :-). */
+ virtual void helpSlot();
+ virtual void enableApplyButtonSlot(bool);
+ virtual void enableApplyButtonSlot(const QString &text);
+ /** Saves all the modified info of devices, routes,etc. */
+ virtual void moveDownServerSlot();
+ virtual void moveUpServerSlot();
+ virtual void removeServerSlot();
+ bool valuesChanged(KNetworkInterface *dev,
+ QString bootProto,
+ QString netmask,
+ QString ipAddr,
+ QString gateway,
+ bool onBoot,
+ QString desc,
+ QString broadcast);
+ /** Returns a list of strings of all the configured devices. */
+ QStringList getDeviceList();
+ /** Sets the QPushButton::autoResize() in true for all buttons. */
+ void makeButtonsResizeable();
+
+ /** Adds a new host to the KListView that has the known hosts. */
+ void addKnownHostSlot();
+ void aboutSlot();
+ /** Edits the info about a known host. */
+ void editKnownHostSlot();
+ /** Removes a known host from the list view */
+ void removeKnownHostSlot();
+ /** No descriptions */
+ void readFromStdErrUpDown();
+ void getNetworkInfoSlot();
+ /** Shows the main window after the network info has been loaded. */
+ void showMainWindow();
+ void verifyDeviceStateChanged();
+ /** Sees if a device is active or not in the ifconfig output. Not very nice, but it works. Inthe future, this has to be managed by gst. */
+ bool isDeviceActive(const QString &device, const QString &ifconfigOutput);
+
+ /*Shows a context menu when right-clicking in the interface list*/
+ void showInterfaceContextMenuSlot(KListView*, QListViewItem*, const QPoint&);
+
+ /** Enable some signals in the GUI that need to be enabled *after* the loading of the network info is done.*/
+ void enableSignals ();
+ virtual void enableProfileSlot();
+ virtual void createProfileSlot();
+ //virtual void updateProfileNameSlot(QListViewItem *item);
+ virtual void removeProfileSlot();
+ virtual void updateProfileSlot();
+
+ signals:
+ //Signal used to tell kcontrol that the network configuration has been changed.
+ void networkStateChanged(bool);
+
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/knetworkconfdlg.ui b/knetworkconf/knetworkconf/knetworkconfdlg.ui
new file mode 100644
index 0000000..d738479
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconfdlg.ui
@@ -0,0 +1,1101 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KNetworkConfDlg</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KNetworkConfDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>510</width>
+ <height>410</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>510</width>
+ <height>410</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Network Settings</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="iconText">
+ <string>Configure your TCP/IP settings</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Change TCP/IP settings</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget</cstring>
+ </property>
+ <property name="tabShape">
+ <enum>Rounded</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Network Interfaces</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Available Network Interfaces</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer24</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>301</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Interface</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>IP Address</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Protocol</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>State</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Comment</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>klvCardList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>List of configured network devices</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbConfigureNetworkInterface</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Configure Interface...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Change the settings of the selected device</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbUpButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Enable Interface</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbDownButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Disable Interface</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer23</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>230</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Routes</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>gbDefaultGateway</cstring>
+ </property>
+ <property name="title">
+ <string>Default Gateway</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="QLayoutWidget">
+ <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>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>IP address:</string>
+ </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>181</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout27</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="KLineEdit">
+ <property name="name">
+ <cstring>kleDefaultRoute</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Default Gateway IP address</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Device:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>kcbGwDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>70</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>65</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Network device where to send packets</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>90</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Domain Name System</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>gbDNSServersList</cstring>
+ </property>
+ <property name="title">
+ <string>Domain Name Servers</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="KListBox">
+ <property name="name">
+ <cstring>klbDomainServerList</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <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>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbUpDomainServerList</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Move up the selected server on the list (higher priority)</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbDownDomainServerList</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>image2</pixmap>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Move down the selected server on the list (less priority)</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout25</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer27</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbAddDomainServer</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Add...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbEditDomainServer</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Edit...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbRemoveDomainServer</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer27_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>21</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>gbKnownHostsList</cstring>
+ </property>
+ <property name="title">
+ <string>Static Hosts</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>IP Address</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Aliases</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>klvKnownHosts</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbAddKnownHost</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Add...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbEditKnownHost</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Edit...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbRemoveKnownHost</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>tlHostName</cstring>
+ </property>
+ <property name="text">
+ <string>Host name:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kleHostName</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>kleDomainName</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>tlDomainName</cstring>
+ </property>
+ <property name="text">
+ <string>Domain name:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Network Profiles</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Available Network Profiles</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView" row="0" column="0" rowspan="2" colspan="1">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>klvProfilesList</cstring>
+ </property>
+ <property name="itemsRenameable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout28</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbEnableProfile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Load Selected</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbSaveProfile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Save Selected</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbCreateProfile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Create New...</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbDeleteProfile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Delete Selected</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer25</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>51</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer18</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>150</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </widget>
+ </hbox>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1108">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000041b49444154388d9d956148a3751cc7bff3ecb6bb149e8186c2f56290912b38f6908417058b043d7b9504a5f522f5459d16c8cda2d45e9441748b38721dd2f6227208ea2c74d338ce5d4c9ca0ee913aa671ca1ed263cfdcd69ee76ae9d2e9b717534f421df58387df9b872f9fe7fbf93fcf039238ee0280beeb7d4f930c31c20cc9cc897b8d19925ba160c8cf9bac008063430f82e9e6abd1682a4537f9c9508424e9f4a7723b90dbd7c622a49b748e454832d6f541574ddee011f7482349f572cf0c4373e4cbd7c954946c7693a938d9d84f867f21ab3b43dcbc4b72891bf4b316000a70ca34d435405e57b095be84d641096a1a78fd3b195a727f6b40eba0042d2da27550022a01dba40d79833db73c303d5a0e4df341794a849694d0556d829204b6aa4c509212baaa4428eb3ef43e27429a9760afb3e70f6ea86d80b2aec260a847e6471f544d44eb60109934101b0e22a389681df603d97ab44ffa215689e89eec7e10708afd6d920cdf656e72fe3830116238405a3ac9ca51b2ec952946032483ffeab8ada4ed3145514d9885be7758d6c304bdebb6aa87090fb9a655982b00fbb80ccc02ae71194d75223e9d0da2bc0410e625184b5e806d5a02aa1f74fcffecef3f4178892499a5c42cc9dda989a90827f83c00e800802936ca69c5d1f265b9a041825022e25ca10c83c1844c5606b226a89a044d13612993e0fe48846fd287faba7afac67df17aa57ec6917528aaa62e2fce2f0e8dfe309ac8110fe5882d6f7a59e6222d1d21ce04c8ea1ed21a202d9d217a4749e1252f237e32248573c839f2add05cc8cb3956595fb4ea49ea0e3bfecff62d6604a783400520cbf219b14a34768f779fadaca8dcd6e9743cecd83be66d24a95a3b66e81d222d1d39526b4f98a1e3edef718daad3e5f473895f5d7de76a4db8365c7cf4a8e63ade6493a2a97deddf1805392da15c106128926128cc759cc91ce9f88204f78762d6feb9fdd7584cfb58281196ba2fd8b67aef39fe3414b6253bdf3f423ce01eb84c728d71ee92cc32cadda3e776dffe1e25ee91e4d4cda93d6e727be0db9175a6287927a61628f1b3c6d79acf1d649e0100cb458b968827ee9b9f30ffe619f3fc6e7ec65c2e2fcb7a6385114b7796607eb2949eef3d7f9bef98e3f619fb8e1255fef207fcc9f67b6f6dd87eb2adc6e289a4cbdbbfa22592f32b9195ec213183d4455d51bdb3df692539cd78ee8d639c79ed9ff4752c0000dd251ddd9a7ba7a5a805d2a2a4472974caba029402b22ce7b79f6faebc7da598126b9cfdce3ec6394d3feff30f6e9c66ff2462ddc10dd7be7016d8d0f288bbcc73be29d6506ccf3a9eb5bdd7d6eef8da959057e5be93ec1ffc144e1cfaf9709fc37983e482778c3f739b89b014de219939cd7e5ee2c6379a0d82607cd72808177bd17db6b7b0f77183c1701e59c0a6d952b6ac2d622812f6e4d5e5052da1dd98b83591398df81f24eff65ce00de8ce0000000049454e44ae426082</data>
+ </image>
+ <image name="image1">
+ <data format="PNG" length="989">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003a449444154388d759541485c5714863fed13e6818579904266d185d0453320e5cd6e062cb5e0c2580b66c8a2912e7498c2d8a690362d485da5d2459a2e52e8a2c5879bd82c125d8cc68245179679598d168bcf454b84363812429e94c1199a81bf8b3b4ee68de66cfe7bee39f7dcff9e7bef394842be9044c92fd1aebb855d955725b720b9ab925b281b3d2fb945a9d3bf5def2af92532e90cfe433f82a9a940900402a2b805a40c3652b8e4f07ef2ba3ad79fdac930db55794d4a7f213d0ba4294f92a4b95549ff4a57be931ef9cd93142537bf2e15a576e6ada025bf845b3041ddabd2e4ed6792a4477f1f4b928e0db4707de758f2a4f4b547720b523abfaec9fc642b3da798ee6e4a5f2f99c57ad244b387ee6f46751d18b8386dee20ddc6bc95e3d45420ac24970642662e3b04ffd448be6eb7b0533aed99cff6a957fb70c9190773fb6595d7a4c9db86413968323ac1ff74b634eda51d733af7aa942e4a93f949bd527cf2be20c5dae37d8a330e1bdb21997e9b8ded90be7e9bda73e8e93945d8c86bb0b11df2f65b36de66853f0f5fa5fabb4f57e3084edee9c18e7467ad23972f63da21577e30af273d2d958bd2e0c41d75b985b22085fb6688f7a983f74b85dc70825a0decd3a93d25b5e760f740e606d080fad32de28d14dd8ca680006fcce1d63dc8bd93808ea08bbf45832db4e976334deb13cd89d114b04837cb5b4092f17b21d743b87eb7026d41677eaeb1fa4734f0fe008cdc8cce8ddc6d0e9603204bf7dc680a80ca9043b60a5fa513646f42b807ef7e03b97e9bc36ac7f997211c32c70fb60dd6878c696e38092cd0e5e6cbc24a41bc46bcf7eca4da163cf8323a97b9f1621cb30c1e5581688eb7981bb2b12d581823828c9ede6876d9d86316c4dafca99b1c3bcc989ff7c97c46c40212e793c47b6b9824bfc09865e34d45838f7f1ff53baa86541e3bc4ea8b5cb056e9cea433e61b0e27a91d052c5cb649f4c2c207516c17efd7a83d1e83da80030d1f7f2c0bd0562b3ef2859521712ee0c11b4966ad0a90002acc90c0734272c30e8b0f43b2fb0eb3187bbd5161fbaf0495439f7823439fd5562b4a7e0915a5747e45eeaa74717a573a90be5d32bfef65f8f98fd2812fb9f9920e964c8d50b3b3443a8837ef698f4bd41921d6bb45e25c8a0be7f7897fd887bd12f2f17b0eb7562a1c8509f60e032a4f93d4ab51a6b9895c57ab83447a56b33aa58b8649b9686ac9e08634782ddaf3d213f775e2af8e1e7866cff3e63d011c36faa8d107d638b008648105688ce33043dcaab42ef484e9499cff01b1f34611a3ab60c70000000049454e44ae426082</data>
+ </image>
+ <image name="image2">
+ <data format="PNG" length="1020">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003c349444154388d75954d481c6718c77fca1e1cf0b00316b2d01e8404e242a133b75928d4d01c4c2bd4480e4de821bb6c41f30121ed21d45e9adc620f1642697190827b091acad66e20a91e5276bc74152cbb425a0cd8b22325b812c45dcac2bf87776775347d2eff79bf9ef9bdcffbbecf832414084994833247dbce44559592e44c484e4972262aa69d979ca2747cfed1764f392893f13204ab414cddc99a200dd488eb1ae01a6dbb38e4f0bff77b8eaf3ff127435655e589e47d2eedd6a4495f92a4d992a457d2e5afa5ada0b393a2e4e497a5a27494bcebb41c9471268c53e786949dd995246d6d1f48920e8c747579e340f225efd6969c09c9cb2f2b9bcf76c37382b4fa4cbafbc82cd63f715d0a8ef5d78d5cb863cec03b42de258e48ef3e34a4d50e69a4bbaf8c93adfac16bc7bd5b5b72f252369f55369f8d4ebfa2ca13293b6316576a1da2483b6491559ec7c7cb1b6617ce0dc92b1ae7bdeee49ac0e5fad317f8376165bd813b64944853c4cc3d131fcfbc0dfe6f21c97e68fd14b0d31e84e89ed637a4f9278660e1595cf55c315be8c47a7e45d2bfd2e507e6f67877a44a511abe3aaf1e67a2227071ce36f06fdaf88f4372efa798feb1011fd9d8bf84e4468e2103fee390f0bd14ebdf3609f72dd3d986d6cb35926d97ee6dd0b674ffa1a457d2ec4a87e899a40369792d4efcc50f92b6256d98f6c519a9ba26795f9adb319c5f38241e3adda0d06f33fd4683cfc6ec2ed9e26a9371cf8ad18e7f03b7472073e6b02ff355445c23d94ed33b3bea02109eb719df876befd8f0c711279e057fc5c3b0381a77fae029306abe6747d240811e275f110917924d92fd86cc4ac0ed5138377422b4276cfa3194d6cdf7de3ed089712fa326a1cc9eb7b012501833939c0431f2d7d983a7507a93c3752d60d4c566ca64b7eb7319d15723752a4db2bf09584093649f456ed8dcdbe356f8b5c9caef16adb699bfb7df20fcdba6afb5c850a2446fc6cbe090839134cdbd1a854b16a97e287c6c76e00e7032c6ab70e5ac85dd67e625fba0f9ae0ded80606c1ce0301fbb9f062291213550e3e7d369ee2542cc930b99ba94a2b6d324fd96c5ca7a93739b16f730e3ad76c8fa9f29c29d80643bc3602267feae281f17252fbf24a7245db85395ead2fd47e665fd9fdefe4eaa0792932fabfec8e408752a4bac82f873be36b9488b0fe8eb5f2335e03274ea05c94f06b1961a5cfbd0667a2964af916273a746f8324d6b3f4e9abb9aebe9569058cdea6427af68482a45934b8657a4e15bf19ae75d5d50345fc76ae06b6b9e3fe70b60a73d489341485c01168171a000ed2bd84c914c84dd038d48233fff01da21be2465fed86a0000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>kpbDownButton</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>disableInterfaceSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbUpButton</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>enableInterfaceSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbConfigureNetworkInterface</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>configureDeviceSlot()</slot>
+ </connection>
+ <connection>
+ <sender>klvCardList</sender>
+ <signal>rightButtonClicked(QListViewItem*,const QPoint&amp;,int)</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>showInterfaceContextMenuSlot()</slot>
+ </connection>
+ <connection>
+ <sender>klvCardList</sender>
+ <signal>doubleClicked(QListViewItem*)</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>configureDeviceSlot()</slot>
+ </connection>
+ <connection>
+ <sender>klvCardList</sender>
+ <signal>selectionChanged()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>enableButtonsSlot()</slot>
+ </connection>
+ <connection>
+ <sender>klbDomainServerList</sender>
+ <signal>doubleClicked(QListBoxItem*)</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>editServerSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbEditDomainServer</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>editServerSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbUpDomainServerList</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>moveUpServerSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbRemoveKnownHost</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>removeKnownHostSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbRemoveDomainServer</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>removeServerSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbEditKnownHost</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>editKnownHostSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbDownDomainServerList</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>moveDownServerSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbAddKnownHost</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>addKnownHostSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbAddDomainServer</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>addServerSlot()</slot>
+ </connection>
+ <connection>
+ <sender>klvKnownHosts</sender>
+ <signal>doubleClicked(QListViewItem*)</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>editKnownHostSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kcbGwDevice</sender>
+ <signal>activated(const QString&amp;)</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>enableApplyButtonSlot(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>klvProfilesList</sender>
+ <signal>itemRenamed(QListViewItem*)</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>updateProfileNameSlot(QListViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>kpbCreateProfile</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>createProfileSlot()</slot>
+ </connection>
+ <connection>
+ <sender>klvProfilesList</sender>
+ <signal>itemRenamed(QListViewItem*)</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>updateProfileNameSlot(QListViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>kpbDeleteProfile</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>removeProfileSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbEnableProfile</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>enableProfileSlot()</slot>
+ </connection>
+ <connection>
+ <sender>kpbSaveProfile</sender>
+ <signal>clicked()</signal>
+ <receiver>KNetworkConfDlg</receiver>
+ <slot>updateProfileSlot()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">knetworkconfdlg.ui.h</include>
+</includes>
+<slots>
+ <slot access="private">enableButtonsSlot()</slot>
+ <slot access="private">quitSlot()</slot>
+ <slot access="private">moveUpServerSlot()</slot>
+ <slot access="private">moveDownServerSlot()</slot>
+ <slot>helpSlot()</slot>
+ <slot access="private">configureDeviceSlot()</slot>
+ <slot access="private">enableApplyButtonSlot( bool )</slot>
+ <slot access="private">enableApplyButtonSlot( const QString &amp; )</slot>
+ <slot>aboutSlot()</slot>
+ <slot access="private">addServerSlot()</slot>
+ <slot access="private">removeServerSlot()</slot>
+ <slot access="private">saveInfoSlot()</slot>
+ <slot access="private">upDownInterfaceSlot()</slot>
+ <slot access="private">addKnownHostSlot()</slot>
+ <slot access="private">removeKnownHostSlot()</slot>
+ <slot access="private">editKnownHostSlot()</slot>
+ <slot access="private">startNetworkSlot()</slot>
+ <slot access="private">stopNetworkSlot()</slot>
+ <slot access="private">enableInterfaceSlot()</slot>
+ <slot access="private">disableInterfaceSlot()</slot>
+ <slot access="private">editServerSlot()</slot>
+ <slot access="private">showInterfaceContextMenuSlot()</slot>
+ <slot access="private">enableProfileSlot()</slot>
+ <slot access="private">createProfileSlot()</slot>
+ <slot>updateProfileNameSlot()</slot>
+ <slot access="private">updateProfileNameSlot(QListViewItem *item)</slot>
+ <slot access="private">removeProfileSlot()</slot>
+ <slot access="private">updateProfileSlot()</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>klineedit.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klistbox.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klistview.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klistview.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/knetworkconfdlg.ui.h b/knetworkconf/knetworkconf/knetworkconfdlg.ui.h
new file mode 100644
index 0000000..69a1275
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconfdlg.ui.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename slots use Qt Designer which will
+** update this file, preserving your code. Create an init() slot in place of
+** a constructor, and a destroy() slot in place of a destructor.
+*****************************************************************************/
+
+
+void KNetworkConfDlg::enableButtonsSlot()
+{
+
+}
+
+void KNetworkConfDlg::quitSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::moveUpServerSlot()
+{
+
+}
+
+void KNetworkConfDlg::moveDownServerSlot()
+{
+
+}
+
+void KNetworkConfDlg::helpSlot()
+{
+
+}
+
+void KNetworkConfDlg::configureDeviceSlot()
+{
+
+}
+
+void KNetworkConfDlg::enableApplyButtonSlot( bool )
+{
+
+}
+
+void KNetworkConfDlg::enableApplyButtonSlot( const QString & )
+{
+
+}
+
+void KNetworkConfDlg::aboutSlot()
+{
+
+}
+
+void KNetworkConfDlg::addServerSlot()
+{
+
+}
+
+void KNetworkConfDlg::removeServerSlot()
+{
+
+}
+
+void KNetworkConfDlg::saveInfoSlot()
+{
+
+}
+
+
+
+
+
+
+void KNetworkConfDlg::upDownInterfaceSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::addKnownHostSlot()
+{
+
+}
+
+void KNetworkConfDlg::removeKnownHostSlot()
+{
+
+}
+
+void KNetworkConfDlg::editKnownHostSlot()
+{
+
+}
+
+
+
+void KNetworkConfDlg::startNetworkSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::stopNetworkSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::enableInterfaceSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::disableInterfaceSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::editServerSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::showInterfaceContextMenuSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::enableProfileSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::createProfileSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::updateProfileNameSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::updateProfileNameSlot( QListViewItem *item )
+{
+
+}
+
+
+void KNetworkConfDlg::removeProfileSlot()
+{
+
+}
+
+
+void KNetworkConfDlg::updateProfileSlot()
+{
+
+}
diff --git a/knetworkconf/knetworkconf/knetworkconfiface.h b/knetworkconf/knetworkconf/knetworkconfiface.h
new file mode 100644
index 0000000..2e6106e
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconfiface.h
@@ -0,0 +1,34 @@
+/* -*- c++ -*-
+ *
+ * knetworkconfiface.h
+ *
+ * Copyright (C) 2004 Juan Luis Baptiste <juan.baptiste@kdemail.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef knetworkconf_iface_h
+#define knetworkconf_iface_h
+
+#include <dcopobject.h>
+
+class KNetworkConfIface: virtual public DCOPObject
+{
+ K_DCOP
+ k_dcop:
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/knetworkconfigparser.cpp b/knetworkconf/knetworkconf/knetworkconfigparser.cpp
new file mode 100644
index 0000000..2e2351d
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconfigparser.cpp
@@ -0,0 +1,1239 @@
+/***************************************************************************
+ knetworkconfigparser.cpp - description
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "knetworkconfigparser.h"
+#include "knetworkconfigparser.moc"
+
+KNetworkConfigParser::KNetworkConfigParser(){
+ networkInfo = new KNetworkInfo();
+
+ QString platform;
+ bool askAgain = readAskAgain(platform);
+
+ if (!askAgain || platform.length() > 0)
+ runDetectionScript(platform);
+ else
+ runDetectionScript(QString::null);
+}
+/** Runs the gst backend to get network values. You can pass to the script a specific platform to load using the platform parameter. */
+void KNetworkConfigParser::runDetectionScript(QString platform){
+ KDetectDistroDlg* dialog = new KDetectDistroDlg(0, 0);
+ dialog->show();
+ procDetect = new QProcess(this);
+ QString pathToProgram = locate("data",BACKEND_PATH);
+ if (pathToProgram.isEmpty())
+ {
+ KMessageBox::error(0,
+ i18n("Could not find the backend script for the network configuration detection. Something is wrong with your installation.\n Please check that \n{KDE_PATH}/%1 \nfile is present.").arg(BACKEND_PATH),
+ i18n("Could Not Find Network Configuration Backend Script"));
+ dialog->close();
+ //kapp->quit();
+ }
+ else
+ {
+ procDetect->addArgument( pathToProgram );
+ if (platform != QString::null)
+ {
+ procDetect->addArgument( "--platform" );
+ procDetect->addArgument( platform );
+ }
+ procDetect->addArgument( "--get" );
+ connect( this, SIGNAL(readyLoadingNetworkInfo()), dialog, SLOT(close()) );
+ connect( this, SIGNAL(errorDetectingPlatform()), dialog, SLOT(close()) );
+ connect( procDetect, SIGNAL(processExited()), this, SLOT(readNetworkInfo()) );
+ connect( procDetect, SIGNAL(readyReadStdout()),this, SLOT(concatXMLOutputSlot()));
+ connect( procDetect, SIGNAL(readyReadStderr()),this, SLOT(readXMLErrSlot()));
+
+ if ( !procDetect->start() )
+ {
+ // error handling
+ KMessageBox::error(0,
+ i18n("Could not execute backend script for the network configuration detection. Something is wrong with your installation."),
+ i18n("Could Not Launch Network Configuration Backend Script"));
+ dialog->close();
+ }
+ }
+}
+/** runs gst to find out the state of network devices.It runs the command:
+$knetworkconf_home/backends/networkconf [--platform platform] -d list_ifaces. */
+void KNetworkConfigParser::listIfaces(const QString &platform){
+ procDetect = new QProcess(this);
+ procDetect->addArgument( locate("data",BACKEND_PATH) );
+ if (platform != QString::null)
+ {
+ procDetect->addArgument( "--platform" );
+ procDetect->addArgument( platform );
+ }
+ //procDetect->addArgument( "--get" );
+ procDetect->addArgument( "-d" );
+ procDetect->addArgument( "list_ifaces" );
+
+ connect( procDetect, SIGNAL(processExited()), this, SLOT(readListIfacesSlot()) );
+ connect( procDetect, SIGNAL(readyReadStdout()),this, SLOT(concatXMLOutputSlot()));
+ connect( procDetect, SIGNAL(readyReadStderr()),this, SLOT(readXMLErrSlot()));
+
+ xmlOuput = "";
+ xmlErr = "";
+ if ( !procDetect->start() )
+ {
+// error handling
+ KMessageBox::error(0,
+ i18n("Could not execute backend script for the network configuration detection. Something is wrong with your installation."),
+ i18n("Could Not Launch Network Configuration Backend Script"));
+ }
+}
+
+void KNetworkConfigParser::readListIfacesSlot(){
+ QPtrList<KNetworkInterface> tempDeviceList;
+
+ //The gst backend puts a \n at the beginning of the xml output, so
+ //we have to erase it first before we parse it.
+ xmlOuput = xmlOuput.section('\n',1);
+ qDebug("XML -d list_ifaces: %s",xmlOuput.latin1());
+ QString err;
+ int x,y;
+ QDomDocument doc( "network-ifaces");
+ if ( !doc.setContent( xmlOuput.utf8(),false,&err,&x,&y ) )
+ {
+ KMessageBox::error(0,
+ i18n("Could not parse the XML output from the network configuration backend."),
+ i18n("Error While Listing Network Interfaces"));
+// qDebug("error: %s %d,%d",err.latin1(),x,y);
+ }
+ QDomElement root = doc.documentElement();
+ QDomNode node = root.firstChild();
+
+ while( !node.isNull() )
+ {
+ if ( node.isElement() && node.nodeName() == "interface" )
+ {
+ QDomElement interface = node.toElement();
+ KNetworkInterface *tempDevice = new KNetworkInterface();
+ tempDevice = getInterfaceInfo(interface,QString::null);
+
+ if (tempDevice->getType().lower() != LOOPBACK_IFACE_TYPE)
+ {
+ KNetworkInterface *originalDevice = getDeviceInfo(tempDevice->getDeviceName());
+ if (originalDevice == NULL)
+ {
+ node = node.nextSibling();
+ continue;
+ }
+ originalDevice->setActive(tempDevice->isActive());
+ if (!tempDevice->getBroadcast().isEmpty())
+ originalDevice->setBroadcast(tempDevice->getBroadcast());
+ if (!tempDevice->getDescription().isEmpty())
+ originalDevice->setDescription(tempDevice->getDescription());
+ if (!tempDevice->getIpAddress().isEmpty())
+ originalDevice->setIpAddress(tempDevice->getIpAddress());
+ if (!tempDevice->getMacAddress().isEmpty())
+ originalDevice->setMacAddress(tempDevice->getMacAddress());
+ if (!tempDevice->getNetmask().isEmpty())
+ originalDevice->setNetmask(tempDevice->getNetmask());
+ if (!tempDevice->getNetwork().isEmpty())
+ originalDevice->setNetwork(tempDevice->getNetwork());
+ }
+ }
+ node = node.nextSibling();
+ }
+ //networkInfo->setDeviceList(deviceList);
+ //Tell to interested parties when the network info is ready.
+ emit readyLoadingNetworkInfo();
+}
+
+KNetworkConfigParser::~KNetworkConfigParser(){
+}
+
+/** return tyhe number of configured devices. */
+unsigned KNetworkConfigParser::numDevices(){
+ return _numDevices;
+}
+
+void KNetworkConfigParser::setProgramVersion(QString ver)
+{
+ KNetworkConfigParser::programVersion = ver;
+}
+
+
+void KNetworkConfigParser::readIfconfigOutput(){
+ QString s = proc->readStdout();
+ ifconfigOutput = s;
+}
+
+/**
+ Reads /proc/net/route looking for the default gateway.
+
+ NOTE:We should use the gateway reported by gst, but if there's a
+ gw in a config file and one of the network interfaces is
+ configured to use dhcp, gst returns the value of the config
+ file instead of the gw configured by dhcp.
+*/
+void KNetworkConfigParser::loadRoutingInfo( KRoutingInfo *routingInfo){
+#ifndef Q_OS_FREEBSD
+ QFile f( "/proc/net/route");
+ if ( !f.open(IO_ReadOnly) )
+ {
+ KMessageBox::error(0,
+ i18n("Could not open file /proc/net/route."),
+ i18n("Could Not Open File"));
+ }
+ else
+ {
+ QTextStream t( &f ); // use a text stream
+ QString s;
+ while (!t.eof())
+ {
+ s = t.readLine(); // line of text excluding '\n'
+ QString interface = s.section('\t',0,0);
+ QString destination = s.section('\t',1,1);
+ QString gw = s.section('\t',2,2);
+
+ if (destination == "00000000")
+ {
+ routingInfo->setGateway(hexIPv4ToDecIPv4(gw));
+ routingInfo->setGatewayDevice(interface);
+ }
+ }
+ }
+ f.close();
+#endif
+}
+QString
+KNetworkConfigParser::hexIPv4ToDecIPv4(const QString &hex)
+{
+ bool ok;
+ QString dec = "";
+ QString dec2 = "";
+ QString temp = "";
+ QString temp2 = "";
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ temp = hex.mid(6,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+ dec.append('.');
+ temp = hex.mid(4,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+ dec.append('.');
+ temp = hex.mid(2,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+ dec.append('.');
+ temp = hex.mid(0,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+#else
+ temp = hex.mid(0,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+ dec.append('.');
+ temp = hex.mid(2,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+ dec.append('.');
+ temp = hex.mid(4,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+ dec.append('.');
+ temp = hex.mid(6,2);
+ temp2 = temp2.setNum(temp.toInt(&ok,16));
+ dec.append(temp2);
+#endif
+
+ dec2 = dec;
+ if (ok)
+ return dec2;
+ else
+ return "";
+}
+
+void KNetworkConfigParser::saveNetworkInfo(KNetworkInfo *networkInfo)
+{
+ this->networkInfo = networkInfo;
+ QPtrList<KNetworkInterface> devList = networkInfo->getDeviceList();
+ QPtrList<KNetworkInfo> profileList = networkInfo->getProfilesList();
+ dnsInfo = networkInfo->getDNSInfo();
+ routingInfo = networkInfo->getRoutingInfo();
+
+ //Start xml file
+ QDomDocument doc( "network []" );
+ QDomProcessingInstruction instr = doc.createProcessingInstruction("xml","version=\"1.0\" ");
+ doc.appendChild(instr);
+ QDomElement root = doc.createElement( "network" );
+ doc.appendChild( root );
+
+ addRoutingInfoToXMLDoc(&doc, &root, routingInfo);
+ addDNSInfoToXMLDoc(&doc, &root, dnsInfo);
+ addNetworkInterfacesToXMLDoc(&doc, &root, devList);
+ addNetworkProfilesToXMLDoc(&doc, &root, profileList);
+
+ //If we don't add this comment to the end of the xml file, the gst process never exits!
+ QDomComment endComment = doc.createComment(" GST: end of request ");
+ doc.appendChild( endComment );
+
+ QString xml = doc.toString();
+ qDebug("--set XML:\n%s",xml.latin1());
+ procSaveNetworkInfo = new QProcess(this);
+ procSaveNetworkInfo->addArgument( locate("data",BACKEND_PATH) );
+
+ if (!networkInfo->getPlatformName().isEmpty())
+ {
+ procSaveNetworkInfo->addArgument( "--platform" );
+ procSaveNetworkInfo->addArgument( networkInfo->getPlatformName() );
+ }
+ procSaveNetworkInfo->addArgument( "--set" );
+
+// KDetectDistroDlg* dialog = new KDetectDistroDlg(0, 0, true,QDialog::WStyle_Customize|QDialog::WStyle_NormalBorder|QDialog::WStyle_Title|QDialog::WStyle_SysMenu); //made it semi-modal
+ KDetectDistroDlg* dialog = new KDetectDistroDlg((QWidget*)parent(), 0, true);
+ dialog->setCaption(i18n("Reloading Network"));
+ dialog->text->setText(i18n("%1Please wait while saving the network settings...%2").arg("<center>").arg("</center>"));
+ dialog->show();
+
+ xmlOuput = "";
+
+ connect( this, SIGNAL(readyLoadingNetworkInfo()), dialog, SLOT(close()) );
+ connect(procSaveNetworkInfo,SIGNAL(readyReadStdout()),this,SLOT(readFromStdoutSaveNetworkInfo()));
+ connect(procSaveNetworkInfo,SIGNAL(wroteToStdin()),this,SLOT(sendNetworkInfoSavedSignalSlot()));
+ connect(procSaveNetworkInfo,SIGNAL(processExited()),this,SLOT(listIfacesSlot()));
+
+ processRunning = true;
+ connect( procSaveNetworkInfo, SIGNAL(processExited()), this, SLOT(processExitedSlot()) );
+
+ if ( !procSaveNetworkInfo->start() )
+ {
+ KMessageBox::error(0,
+ i18n("Could not execute backend script for the network configuration detection. Something is wrong with your installation."),
+ i18n("Could Not Launch Network Configuration Backend Script"));
+ }
+
+ procSaveNetworkInfo->writeToStdin(xml);
+
+ //wait around until the process has finished, otherwise it becomes a zombie
+ while (processRunning) {
+ kapp->processEvents();
+ }
+}
+
+void KNetworkConfigParser::processExitedSlot() {
+ processRunning = false;
+}
+
+void KNetworkConfigParser::addNetworkProfilesToXMLDoc(QDomDocument *doc, QDomNode *root, QPtrList<KNetworkInfo> profileList)
+{
+ QPtrListIterator<KNetworkInfo> profileIt(profileList);
+ KNetworkInfo *profile;
+ QDomElement tag = doc->createElement( "profiledb" );
+ root->appendChild( tag );
+
+ while ( (profile = profileIt.current()) != 0)
+ {
+ ++profileIt;
+ QPtrList<KNetworkInterface> devList = profile->getDeviceList();
+ KDNSInfo *dnsInfo = profile->getDNSInfo();
+ KRoutingInfo *routingInfo = profile->getRoutingInfo();
+
+ QDomElement profileTag = doc->createElement( "profile" );
+ tag.appendChild( profileTag );
+ QDomElement innerTag = doc->createElement( "name" );
+ profileTag.appendChild( innerTag );
+ QDomText t = doc->createTextNode( profile->getProfileName() );
+ innerTag.appendChild( t );
+
+ addRoutingInfoToXMLDoc(doc, &profileTag, routingInfo);
+ addDNSInfoToXMLDoc(doc, &profileTag, dnsInfo);
+ addNetworkInterfacesToXMLDoc(doc, &profileTag, devList);
+ }
+}
+
+void KNetworkConfigParser::addNetworkInterfacesToXMLDoc(QDomDocument *doc, QDomNode *root, QPtrList<KNetworkInterface> devList)
+{
+ KNetworkInterface *device;
+ QPtrListIterator<KNetworkInterface> devIt(devList);
+
+ //Save in the configuration file the description of the interfaces as
+ //the backend no longer handles this
+ KSimpleConfig cfg("knetworkconfrc");
+ cfg.setGroup("Interfaces");
+
+ //Add the network interfaces list
+ while ( (device = devIt.current()) != 0 )
+ {
+ ++devIt;
+ // if protocol is not specified, then should not have entry in config
+ if (device->getBootProto().isEmpty())
+ continue;
+
+ QDomElement tag = doc->createElement( "interface" );
+ tag.setAttribute("type",device->getType());
+ root->appendChild( tag );
+ QDomElement configurationTag;
+ configurationTag = doc->createElement( "configuration" );
+ tag.appendChild( configurationTag );
+
+ QDomElement innerTag;
+ QDomText t;
+ if ((device->getBootProto().lower() != "dhcp") && (device->getBootProto().lower() != "bootp"))
+ {
+ if (!device->getIpAddress().isEmpty())
+ {
+ innerTag = doc->createElement( "address" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( device->getIpAddress() );
+ innerTag.appendChild( t );
+ }
+ if (!device->getGateway().isEmpty())
+ {
+ innerTag = doc->createElement( "gateway" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( device->getGateway() );
+ innerTag.appendChild( t );
+ }
+ if (!device->getBroadcast().isEmpty())
+ {
+ innerTag = doc->createElement( "broadcast" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( device->getBroadcast() );
+ innerTag.appendChild( t );
+ }
+ if (!device->getNetmask().isEmpty())
+ {
+ innerTag = doc->createElement( "netmask" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( device->getNetmask() );
+ innerTag.appendChild( t );
+ }
+ if (!device->getNetwork().isEmpty())
+ {
+ innerTag = doc->createElement( "network" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( device->getNetwork() );
+ innerTag.appendChild( t );
+ }
+ }
+ innerTag = doc->createElement( "auto" );
+ configurationTag.appendChild( innerTag );
+
+ if (device->getOnBoot().lower() == "yes")
+ t = doc->createTextNode( "1" );
+ else
+ t = doc->createTextNode( "0" );
+
+ innerTag.appendChild( t );
+
+ innerTag = doc->createElement( "bootproto" );
+ configurationTag.appendChild( innerTag );
+ if (device->getBootProto().lower() == "manual")
+ t = doc->createTextNode( "none" );
+ else
+ t = doc->createTextNode( device->getBootProto().lower() );
+ innerTag.appendChild( t );
+
+ innerTag = doc->createElement( "file" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( device->getDeviceName() );
+ innerTag.appendChild( t );
+
+ innerTag = doc->createElement( "dev" );
+ tag.appendChild( innerTag );
+ t = doc->createTextNode( device->getDeviceName() );
+ innerTag.appendChild( t );
+
+ innerTag = doc->createElement( "enabled" );
+ tag.appendChild( innerTag );
+ if (device->isActive())
+ t = doc->createTextNode( "1" );
+ else
+ t = doc->createTextNode( "0" );
+ innerTag.appendChild( t );
+
+ innerTag = doc->createElement( "hwaddr" );
+ tag.appendChild( innerTag );
+ t = doc->createTextNode( device->getMacAddress() );
+ innerTag.appendChild( t );
+
+ //Wireless settings
+
+ if (device->getType() == WIRELESS_IFACE_TYPE)
+ {
+ KWirelessInterface *wifiDev = static_cast<KWirelessInterface*>(device);
+
+ if (!wifiDev->getEssid().isEmpty())
+ {
+ innerTag = doc->createElement( "essid" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( wifiDev->getEssid() );
+ innerTag.appendChild( t );
+ }
+ if (!wifiDev->getWepKey().isEmpty())
+ {
+ innerTag = doc->createElement( "key" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( wifiDev->getWepKey() );
+ innerTag.appendChild( t );
+ }
+ if (!wifiDev->getKeyType().isEmpty())
+ {
+ innerTag = doc->createElement( "key_type" );
+ configurationTag.appendChild( innerTag );
+ t = doc->createTextNode( wifiDev->getKeyType().lower() );
+ innerTag.appendChild( t );
+ }
+
+ }
+ if (!device->getDescription().isEmpty() && device->getDeviceName()!= "lo")
+ cfg.writeEntry(device->getDeviceName(),device->getDescription());
+
+ cfg.sync();
+ }
+}
+
+void KNetworkConfigParser::addDNSInfoToXMLDoc(QDomDocument *doc, QDomNode *root, KDNSInfo *dnsInfo)
+{
+ QStringList nameServerList = dnsInfo->getNameServers();
+ QPtrList<KKnownHostInfo> knownHostsList = dnsInfo->getKnownHostsList();
+ QPtrListIterator<KKnownHostInfo> knownHostsIt(knownHostsList);
+ KKnownHostInfo *host;
+
+ QDomElement tag = doc->createElement( "hostname" );
+ root->appendChild( tag );
+ QDomText t = doc->createTextNode( dnsInfo->getMachineName() );
+ tag.appendChild( t );
+ tag = doc->createElement( "domain" );
+ root->appendChild( tag );
+ t = doc->createTextNode( dnsInfo->getDomainName() );
+ tag.appendChild( t );
+
+ //Add the list of name servers
+ for ( QStringList::Iterator it = nameServerList.begin(); it != nameServerList.end(); ++it ) {
+ tag = doc->createElement( "nameserver" );
+ root->appendChild( tag );
+ t = doc->createTextNode( *it );
+ tag.appendChild( t );
+ }
+
+ //Add the list of static hosts
+ while ( (host = knownHostsIt.current()) != 0 )
+ {
+ ++knownHostsIt;
+ tag = doc->createElement( "statichost" );
+ root->appendChild( tag );
+ QDomElement innerTag;
+ if (!host->getIpAddress().isEmpty())
+ {
+ innerTag = doc->createElement( "ip" );
+ tag.appendChild( innerTag );
+ t = doc->createTextNode( host->getIpAddress() );
+ innerTag.appendChild( t );
+ }
+ QStringList aliases = host->getAliases();
+
+ for ( QStringList::Iterator it = aliases.begin(); it != aliases.end(); ++it )
+ {
+ innerTag = doc->createElement( "alias" );
+ tag.appendChild( innerTag );
+ t = doc->createTextNode( *it );
+ innerTag.appendChild( t );
+ }
+ }
+}
+
+void KNetworkConfigParser::addRoutingInfoToXMLDoc(QDomDocument *doc, QDomNode *root, KRoutingInfo *routingInfo)
+{
+ QDomElement tag = doc->createElement( "gateway" );
+ root->appendChild( tag );
+ QDomText t = doc->createTextNode( routingInfo->getGateway() );
+ tag.appendChild( t );
+
+ tag = doc->createElement( "gatewaydev" );
+ root->appendChild( tag );
+ t = doc->createTextNode( routingInfo->getGatewayDevice() );
+ tag.appendChild( t );
+}
+/** Loads the network info from a xml file generated by the gnome system tools
+network backends that are included with this app. */
+KNetworkInfo * KNetworkConfigParser::getNetworkInfo(){
+
+ return networkInfo;
+}
+
+/** Parses all of the <interface>...</interface> entries in the xml configuration file. Returns a KWirelessInterface
+ object that contains all the info of the wireless interface. */
+KWirelessInterface * KNetworkConfigParser::getWirelessInterfaceInfo(QDomElement interface, const QString &type){
+ KWirelessInterface *wifiDevice = new KWirelessInterface();
+ KNetworkInterface *tempDevice = NULL;
+
+ //first we get the standard network information
+ tempDevice = getInterfaceInfo(interface,type);
+ //Then we copy the network interface info to the wireless object. I don't
+ //know why it doesn't work with static_cast, after doing the cast, I can't
+ //write to the KWirelessInterface memebers.
+ memcpy(wifiDevice,tempDevice,sizeof(KNetworkInterface));
+ //wifiDevice = static_cast<KWirelessInterface*>(tempDevice);
+
+ QDomNode node = interface.firstChild();
+
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() )
+ {
+ QString nodeName =node.nodeName();
+
+ //Parsing --get interfaces configuration
+ if ( node.isElement() && node.nodeName() == "configuration" )
+ {
+ QDomNode configNode = node.firstChild();
+ while ( !configNode.isNull() )
+ {
+ if ( configNode.isElement() )
+ {
+ QString configNodeName =configNode.nodeName();
+
+ if ( configNodeName == "key" )
+ {
+ QDomElement e = configNode.toElement();
+ wifiDevice->setWepKey(e.text());
+ }
+ else if ( configNodeName == "essid" )
+ {
+ QDomElement e = configNode.toElement();
+ wifiDevice->setEssid(e.text());
+ }
+ else if ( configNodeName == "key_type" )
+ {
+ QDomElement e = configNode.toElement();
+ wifiDevice->setKeyType(e.text());
+ }
+ configNode = configNode.nextSibling();
+ }
+ }
+ }
+ }
+ node = node.nextSibling();
+ }
+
+ return wifiDevice;
+}
+
+/** Parses all of the <interface>...</interface> entries in the xml configuration file. Returns a KNetworkInterface
+ object with all the info of the interface.*/
+KNetworkInterface * KNetworkConfigParser::getInterfaceInfo(QDomElement interface, const QString &type){
+ QDomNode node = interface.firstChild();
+ KNetworkInterface *tempDevice = new KNetworkInterface();
+ //tempDevice->setDescription(i18n("Ethernet Network Device"));
+
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() )
+ {
+ QString nodeName =node.nodeName();
+
+ //Parsing --get interfaces configuration
+ if ( node.isElement() && node.nodeName() == "configuration" )
+ {
+ QDomNode configNode = node.firstChild();
+ while ( !configNode.isNull() )
+ {
+ if ( configNode.isElement() )
+ {
+ QString configNodeName =configNode.nodeName();
+
+ if ( configNodeName == "auto" )
+ {
+ QDomElement e = configNode.toElement();
+ if (e.text() == "1")
+ tempDevice->setOnBoot("yes");
+ else
+ tempDevice->setOnBoot("no");
+ }
+ else if ( configNodeName == "bootproto" )
+ {
+ QDomElement e = configNode.toElement();
+ tempDevice->setBootProto(e.text());
+ }
+ if ( configNodeName == "address" || configNodeName == "addr")
+ {
+ QDomElement e = configNode.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setIpAddress(e.text());
+ }
+ else if ( configNodeName == "gateway")
+ {
+ QDomElement e = configNode.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setGateway(e.text());
+ }
+ else if ( configNodeName == "netmask" || configNodeName == "mask")
+ {
+ QDomElement e = configNode.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setNetmask(e.text());
+ }
+ else if ( configNodeName == "network" )
+ {
+ QDomElement e = configNode.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setNetwork(e.text());
+ }
+ else if ( configNodeName == "broadcast" || configNodeName == "bdcast")
+ {
+ QDomElement e = configNode.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setBroadcast(e.text());
+ }
+ configNode = configNode.nextSibling();
+ }
+ }
+ }
+
+ //Parse -d list_ifaces interfaces configuration
+ if ( nodeName == "addr")
+ {
+ QDomElement e = node.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setIpAddress(e.text());
+ }
+ else if ( nodeName == "mask")
+ {
+ QDomElement e = node.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setNetmask(e.text());
+ }
+ else if ( nodeName == "bdcast")
+ {
+ QDomElement e = node.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setBroadcast(e.text());
+ }
+
+
+ //These ones are common for both --get and -d list_ifaces
+ else if ( nodeName == "dev" )
+ {
+ QDomElement e = node.toElement();
+ tempDevice->setDeviceName(e.text());
+ }
+ //we had to add the OR because the xml sintax when listing the interfaces
+ //is different than when loading the network info. ie.: enabled->active
+ //address->addr, etc...
+ else if ( nodeName == "enabled" || nodeName == "active")
+ {
+ QDomElement e = node.toElement();
+ if (e.text() == "1")
+ tempDevice->setActive(true);
+ else
+ tempDevice->setActive(false);
+ }
+ else if ( nodeName == "hwaddr" )
+ {
+ QDomElement e = node.toElement();
+ if (!e.text().isEmpty())
+ tempDevice->setMacAddress(e.text());
+ }
+ }
+ node = node.nextSibling();
+ }
+ if (type != QString::null)
+ tempDevice->setType(type);
+
+ QString description;
+ KSimpleConfig cfg("knetworkconfrc");
+ cfg.setGroup("Interfaces");
+ description = cfg.readEntry(tempDevice->getDeviceName());
+ if (!description.isEmpty())
+ tempDevice->setDescription(description);
+ else
+ {
+ if (tempDevice->getType() == ETHERNET_IFACE_TYPE)
+ tempDevice->setDescription(i18n("Ethernet Network Device"));
+ else if (tempDevice->getType() == WIRELESS_IFACE_TYPE)
+ tempDevice->setDescription(i18n("Wireless Network Device"));
+ }
+
+ //Clear IP address settings if boot protocol is dhcp or bootp, in case that they are
+ //setted in the config files.
+ if ((tempDevice->getBootProto().lower() == "dhcp") || (tempDevice->getBootProto().lower() == "bootp"))
+ {
+ tempDevice->setIpAddress("");
+ tempDevice->setNetmask("");
+ tempDevice->setNetwork("");
+ tempDevice->setBroadcast("");
+ }
+
+ return tempDevice;
+}
+
+/** Parses all of the <statichost>...</statichost> entries in the xml configuration file. */
+KKnownHostInfo * KNetworkConfigParser::getStaticHostInfo(QDomElement host)
+{
+ QDomNode node = host.firstChild();
+ KKnownHostInfo *tempHost = new KKnownHostInfo();
+
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() )
+ {
+ QString nodeName =node.nodeName();
+
+ if ( nodeName == "ip")
+ {
+ QDomElement e = node.toElement();
+ if (!e.text().isEmpty())
+ tempHost->setIpAddress(e.text());
+ }
+ else if ( nodeName == "alias")
+ {
+ QDomElement e = node.toElement();
+ if (!e.text().isEmpty())
+ tempHost->addAlias(e.text());
+ }
+ }
+ node = node.nextSibling();
+ }
+
+ return tempHost;
+}
+
+/** Reads the xml with the network info. */
+void KNetworkConfigParser::readNetworkInfo()
+{
+ QPtrList<KNetworkInfo> profilesList;
+ //deviceList.clear();
+ //The gst backend puts a \n at the beginning of the xml output, so
+ //we have to erase it first before we can parse it.
+ xmlOuput = xmlOuput.section('\n',1);
+ qDebug("--get XML:\n%s",xmlOuput.latin1());
+
+ //If the platform where knetworkconf is running isn't supported, show the
+ //user a dialog with all the supported platforms to choose.
+ if (xmlErr.contains("platform_unsup::"))
+ {
+ connect( this, SIGNAL(readyLoadingSupportedPlatforms()), this, SLOT(showSupportedPlatformsDialogSlot()) );
+ loadSupportedPlatforms();
+ emit errorDetectingPlatform();
+ }
+ else //parse the XML file
+ {
+ QString err;
+ int x,y;
+ QDomDocument doc( "network");
+ if ( !doc.setContent( xmlOuput.utf8(),false,&err,&x,&y ) )
+ {
+ KMessageBox::error(0,
+ i18n("Could not parse the XML output from the network configuration backend."),
+ i18n("Error Loading The Network Configuration"));
+// qDebug("error: %s %d,%d",err.latin1(),x,y);
+ }
+
+ QDomElement root = doc.documentElement();
+ QDomNode node = root.firstChild();
+
+ //Load first the network information
+ parseNetworkInfo(node, networkInfo, false);
+
+ //Then, load the network profiles
+ node = root.firstChild();
+ while( !node.isNull() )
+ {
+ if ( node.isElement())
+ {
+ QString nodeName = node.nodeName();
+
+ if ( nodeName == "profiledb" )
+ {
+ QDomNode profileNode = node.firstChild();
+
+ while( !profileNode.isNull() )
+ {
+ if ( profileNode.isElement())
+ {
+ QString profileName = profileNode.nodeName();
+
+ if (profileNode.isElement() && profileName == "profile")
+ {
+ KNetworkInfo * networkProfile = new KNetworkInfo();
+ QDomNode profileConfigurationNode = profileNode.firstChild();
+ parseNetworkInfo(profileConfigurationNode, networkProfile, true);
+ profilesList.append(networkProfile);
+ }
+ }
+ profileNode = profileNode.nextSibling();
+ }
+ }
+ }
+ node = node.nextSibling();
+ }
+ networkInfo->setProfilesList(profilesList);
+ }
+}
+
+void KNetworkConfigParser::parseNetworkInfo(QDomNode node, KNetworkInfo *_networkInfo, bool isProfile){
+ QPtrList<KNetworkInterface> deviceList;
+ KDNSInfo *_dnsInfo = new KDNSInfo();
+ KRoutingInfo *_routingInfo = new KRoutingInfo();
+ QStringList serverList;
+ QPtrList<KNetworkInterface> tempDeviceList;
+ QPtrList<KKnownHostInfo> knownHostsList;
+
+ while( !node.isNull() )
+ {
+ if ( node.isElement())
+ {
+ QString nodeName = node.nodeName();
+
+ //Get the gatway
+ if ( nodeName == "gateway" )
+ {
+ QDomElement gateway = node.toElement();
+ _routingInfo->setGateway(gateway.text());
+ }
+ else if ( nodeName == "gatewaydev" )
+ {
+ QDomElement gatewaydev = node.toElement();
+ _routingInfo->setGatewayDevice(gatewaydev.text());
+ }
+ //The name of the profile, in the case it's a profile ;)
+ else if ( nodeName == "name" && isProfile)
+ {
+ QDomElement profileName = node.toElement();
+ _networkInfo->setProfileName(profileName.text());
+ }
+
+ //Get the network interfaces
+ else if ( nodeName == "interface" )
+ {
+ QDomElement interface = node.toElement();
+
+ QString attr = interface.attribute("type").lower();
+ //We have hardcoded to load only the supported interface types,
+ //for now, ethernet, loopback and wireless, thus loopback interfaces
+ //aren't shown.
+ if ( attr == ETHERNET_IFACE_TYPE || attr == LOOPBACK_IFACE_TYPE )
+ {
+ KNetworkInterface *tempDevice = NULL;
+ tempDevice = getInterfaceInfo(interface,attr);
+ deviceList.append(tempDevice);
+ }
+ else if (attr == WIRELESS_IFACE_TYPE)
+ {
+ KWirelessInterface *wifiDevice = NULL;
+ wifiDevice = getWirelessInterfaceInfo(interface,attr);
+ deviceList.append(wifiDevice);
+ }
+ }
+
+ //Get domain and host names
+ else if ( nodeName == "hostname" )
+ {
+ QDomElement hostname = node.toElement();
+ _dnsInfo->setMachineName(hostname.text());
+ }
+ else if ( nodeName == "domain" )
+ {
+ QDomElement domainname = node.toElement();
+ _dnsInfo->setDomainName(domainname.text());
+ }
+
+ //Get the nameServers
+ else if ( nodeName == "nameserver" )
+ {
+ QDomElement nameserver = node.toElement();
+ serverList.append(nameserver.text());
+ }
+
+ //Get the static hosts
+ else if ( nodeName == "statichost" )
+ {
+ QDomElement host = node.toElement();
+ KKnownHostInfo *tempHost = getStaticHostInfo(host);
+ knownHostsList.append(tempHost);
+ }
+ }
+ node = node.nextSibling();
+ }
+ _dnsInfo->setNameServers(serverList);
+ _dnsInfo->setKnownHostsList(knownHostsList);
+
+ _networkInfo->setDeviceList(deviceList);
+ loadRoutingInfo(_routingInfo);
+ _networkInfo->setRoutingInfo(_routingInfo);
+ _networkInfo->setDNSInfo(_dnsInfo);
+
+ //if we are loading a profile, don't try to find the IP address of DHCP
+ //interfaces and their states
+ if (!isProfile)
+ {
+ listIfaces(_networkInfo->getPlatformName());
+ }
+ //return _networkInfo;
+}
+void KNetworkConfigParser::readFromStdoutReloadScript(){
+ QString s = procReloadNetwork->readStdout();
+ reloadScriptOutput.append(s);
+}
+/** emits a signal when the network changes have benn saved. */
+void KNetworkConfigParser::sendNetworkInfoSavedSignalSlot(){
+ procSaveNetworkInfo->closeStdin();
+}
+
+/** Concatenates into a QString the xml output of the network backend. */
+void KNetworkConfigParser::concatXMLOutputSlot(){
+ xmlOuput.append(procDetect->readStdout());
+}
+
+void KNetworkConfigParser::readXMLErrSlot(){
+ xmlErr.append(procDetect->readStderr());
+}
+/** lists all platforms supported by GST. */
+void KNetworkConfigParser::loadSupportedPlatforms(){
+ procDetect = new QProcess(this);
+ procDetect->addArgument( locate("data",BACKEND_PATH) );
+ procDetect->addArgument( "-d" );
+ procDetect->addArgument( "platforms" );
+ connect( procDetect, SIGNAL(processExited()), this, SLOT(readSupportedPlatformsSlot()) );
+ xmlOuput = "";
+ connect( procDetect, SIGNAL(readyReadStdout()),this, SLOT(concatXMLOutputSlot()));
+// connect( procDetect, SIGNAL(readyReadStderr()),this, SLOT(readXMLErrSlot()));
+
+ if ( !procDetect->start() )
+ {
+// error handling
+ KMessageBox::error(0,
+ i18n("Could not execute backend script for the network configuration detection. Something is wrong with your installation."),
+ i18n("Could Not Launch Network Configuration Backend Script"));
+ }
+
+}
+/** Parses the xml ouput generated by GST that has all the supported platforms. */
+void KNetworkConfigParser::readSupportedPlatformsSlot(){
+ //The gst backend puts a \n at the beginning of the xml output, so
+ //we have to erase it first before we parse it.
+ xmlOuput = xmlOuput.section('\n',1);
+ QDomDocument doc( "platforms" );
+ if ( !doc.setContent( xmlOuput.utf8() ) )
+ {
+ KMessageBox::error(0,
+ i18n("Could not parse the list of supported platforms from the network configuration backend."),
+ i18n("Error Obtaining Supported Platforms List"));
+ }
+ QDomElement root = doc.documentElement();
+ QDomNode node = root.firstChild();
+ QString s;
+ while( !node.isNull() )
+ {
+ if ( node.isElement() && node.nodeName() == "platform" )
+ {
+ QDomElement platform = node.toElement();
+ s = getPlatformInfo(platform);
+ }
+ supportedPlatformsList << s;
+ node = node.nextSibling();
+ }
+ emit readyLoadingSupportedPlatforms();
+}
+/** Returns the info of a platform in the form of 'key:value' . */
+QString KNetworkConfigParser::getPlatformInfo(QDomElement platform){
+ QDomNode node = platform.firstChild();
+ QString s;
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() )
+ {
+ if ( node.nodeName() == "key" )
+ {
+ QDomElement e = node.toElement();
+ s += e.text();
+ s += ":";
+ }
+ else if ( node.nodeName() == "name" )
+ {
+ QDomElement e = node.toElement();
+ s += e.text();
+ }
+
+ }
+ node = node.nextSibling();
+ }
+
+ return s;
+}
+/** Shows the dialog with all the supported platforms by GST. */
+void KNetworkConfigParser::showSupportedPlatformsDialogSlot(){
+ KSelectDistroDlg* dialog = new KSelectDistroDlg(0, 0);
+
+ for ( QStringList::Iterator it = supportedPlatformsList.begin(); it != supportedPlatformsList.end(); ++it )
+ {
+ QString key = (*it);
+ key = key.section(":",0,0);
+ QString name = (*it);
+ name = name.section(":",1,1);
+ if (key.contains("debian"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/debian.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("mandriva"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/mandriva.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("conectiva"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/conectiva.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("pld"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/pld.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("redhat"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/redhat.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("suse"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/suse.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("turbolinux"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/turbolinux.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("fedora"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/fedora.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("openna"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/openna.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("slackware"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/slackware.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("freebsd"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/freebsd.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("gentoo"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/gentoo.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("blackpanther"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/blackpanther.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("rpath"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/rpath.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("vine"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/vine.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("ubuntu"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/kubuntu.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("yoper"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/yoper.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ else if (key.contains("ark"))
+ {
+ QPixmap distroImg(locate("data","knetworkconf/pixmaps/ark.png"));
+ dialog->klbDistroList->insertItem(distroImg, name);
+ }
+ }
+
+ if (!dialog->exec())
+ emit setReadOnly(true);
+ else
+ {
+ int i = 0;
+ QStringList::Iterator it = supportedPlatformsList.begin();
+ while (i < dialog->klbDistroList->currentItem())
+ {
+ i++;
+ ++it;
+ }
+ QString key = (*it);
+ key = key.section(":",0,0);
+ //clean variables and run again the detection script but now don't
+ //auto-detect.
+ xmlErr = "";
+ xmlOuput = "";
+ networkInfo->setPlatformName(key);
+ runDetectionScript(key);
+ if (dialog->cbAskAgain->isChecked())
+ saveAskAgain(key,!dialog->cbAskAgain->isChecked());
+ }
+}
+
+void KNetworkConfigParser::saveAskAgain(const QString &platform, bool askAgain)
+{
+ KSimpleConfig cfg("knetworkconfrc");
+ cfg.setGroup("General");
+ cfg.writeEntry("detectedPlatform",platform);
+ cfg.writeEntry("askAgainPlatform",askAgain);
+ cfg.sync();
+}
+
+bool KNetworkConfigParser::readAskAgain(QString &platform)
+{
+ KSimpleConfig cfg("knetworkconfrc");
+ cfg.setGroup("General");
+ platform = cfg.readEntry("detectedPlatform");
+ return cfg.readBoolEntry("askAgainPlatform");
+}
+
+/** No descriptions */
+void KNetworkConfigParser::readFromStdoutSaveNetworkInfo(){
+ xmlOuput.append(procSaveNetworkInfo->readStdout());
+}
+/** Calls runDetectionScript(). */
+void KNetworkConfigParser::listIfacesSlot(){
+ listIfaces(networkInfo->getPlatformName());
+}
+/**Returns the info of the network device 'device or NULL if not found.'*/
+KNetworkInterface * KNetworkConfigParser::getDeviceInfo(QString device){
+ QPtrList<KNetworkInterface> deviceList = networkInfo->getDeviceList();
+ QPtrListIterator<KNetworkInterface> i(deviceList);
+ KNetworkInterface *temp;
+ while ((temp = i.current()) != 0)
+ {
+ if (temp->getDeviceName() == device)
+ {
+ return temp;
+ }
+ ++i;
+ }
+ return NULL;
+}
diff --git a/knetworkconf/knetworkconf/knetworkconfigparser.h b/knetworkconf/knetworkconf/knetworkconfigparser.h
new file mode 100644
index 0000000..0c2254e
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconfigparser.h
@@ -0,0 +1,181 @@
+/***************************************************************************
+ knetworkconfigparser.h - description
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNETWORKCONFIGPARSER_H
+#define KNETWORKCONFIGPARSER_H
+
+#define BACKEND_PATH "knetworkconf/backends/network-conf"
+#define ETHERNET_IFACE_TYPE "ethernet"
+#define WIRELESS_IFACE_TYPE "wireless"
+#define LOOPBACK_IFACE_TYPE "loopback"
+
+#define WIRELESS_WEP_KEY_TYPE_ASCII "ascii"
+#define WIRELESS_WEP_KEY_TYPE_HEXADECIMAL "hexadecimal"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <kapp.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <qobject.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qstring.h>
+#include <qprocess.h>
+#include <qdom.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+
+#include <klistbox.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+
+#include "knetworkinfo.h"
+#include "kdetectdistrodlg.h"
+#include "kreloadnetworkdlg.h"
+#include "kinterfaceupdowndlg.h"
+#include "kselectdistrodlg.h"
+
+/**
+ *@author Juan Luis Baptiste
+ */
+
+class KNetworkConfigParser : public QObject {
+ Q_OBJECT
+ public:
+ KNetworkConfigParser();
+ ~KNetworkConfigParser();
+ /** return tyhe number of configured devices. */
+ unsigned numDevices();
+ void setProgramVersion(QString ver);
+ /** Reads /proc/net/route looking for the default gateway. */
+ void loadRoutingInfo(KRoutingInfo *routingInfo);
+ /** Saves the new network configuration. */
+ void saveNetworkInfo(KNetworkInfo *networkInfo);
+ /** Loads the network info from a xml file generated by the gnome system tools
+ network backends that are included with this app. */
+ KNetworkInfo * getNetworkInfo();
+ QProcess * proc;
+ QProcess * procDetect;
+ QProcess * procSaveNetworkInfo;
+ /** Variable to know if there is an dhcp device configured, so we can know if we need to save the defauilt gw info or not. */
+ bool dhcpDevice;
+ KNetworkInterface * getDeviceInfo(QString device);
+
+
+ public slots:
+ /** runs gst to find out the state of network devices.It runs the command:
+ $knetworkconf_home/backends/networkconf [--platform platform] -d list_ifaces */
+ void listIfaces(const QString &platform);
+
+ private slots:
+ /** Runs the gst backend to get network values. You can pass to the script a specific platform to load using the platform parameter. */
+ void runDetectionScript(QString platform);
+ void readIfconfigOutput();
+ void readNetworkInfo();
+ void readFromStdoutReloadScript();
+ /** emits a signal when the network changes have benn saved. */
+ void sendNetworkInfoSavedSignalSlot();
+ /** Concatenates into a QString the xml output of the network backend. */
+ void concatXMLOutputSlot();
+ void readXMLErrSlot();
+ /** Shows the dialog with all the supported platforms by GST. */
+ void showSupportedPlatformsDialogSlot();
+ /** Parses the xml ouput generated by GST that has all the supported platforms. */
+ void readSupportedPlatformsSlot();
+ /** No descriptions */
+ void readListIfacesSlot();
+ void readFromStdoutSaveNetworkInfo();
+ /** Calls runDetectionScript(). */
+ void listIfacesSlot();
+ /** save process has exited */
+ void processExitedSlot();
+
+ private:
+ //QPtrList<KNetworkInterface> deviceList;
+ QPtrList<KNetworkInterface> tempList;
+ KNetworkInterface *newDevice;
+ bool isUp;
+ /** Counts the number of configured devices that had been found. */
+ unsigned _numDevices;
+ KRoutingInfo *routingInfo;
+ KDNSInfo *dnsInfo;
+ QString programVersion;
+ /** The output of ifconfig command that needs to be parsed in readIfconfigOutput()*/
+ QString ifconfigOutput;
+ KNetworkInfo * networkInfo;
+ QPtrList<KKnownHostInfo> knownHostsList;
+ QString hexIPv4ToDecIPv4(const QString &hex);
+ /** lists all platforms supported by GST. */
+ void loadSupportedPlatforms();
+ /** Returns the info of a platform in the form of 'key:value' . */
+ QString getPlatformInfo(QDomElement platform);
+ /** save process is running */
+ bool processRunning;
+
+ /** Shows a progress dialog while the networl is being reloaded. */
+ KInterfaceUpDownDlg * kpdReloadStatusDlg;
+ QProcess *procReloadNetwork;
+ QString reloadScriptOutput;
+ /** Contains the network configuration en xml format. */
+ /** List of supported platforms. */
+ QStringList supportedPlatformsList;
+ QString xmlOuput;
+ QString xmlErr;
+ /** Temporal device list to be used when loading the dhcp devices info */
+ QPtrList<KNetworkInterface> tempDevList;
+ /** Parses all of the <statichost>...</statichost> entries in the xml configuration file. */
+ KKnownHostInfo * getStaticHostInfo(QDomElement host);
+ /** Saves the option to show again or not the platform using KSimpleConfig*/
+ void saveAskAgain(const QString &platform, bool askAgain);
+ /**Returns if the show platform should be shown again or not and the saved platform*/
+ bool readAskAgain(QString &platform);
+ void parseNetworkInfo(QDomNode node, KNetworkInfo *networkInfo, bool isProfile);
+ void addRoutingInfoToXMLDoc(QDomDocument *doc, QDomNode *root, KRoutingInfo *routingInfo);
+ void addDNSInfoToXMLDoc(QDomDocument *doc, QDomNode *root, KDNSInfo *dnsInfo);
+ void addNetworkInterfacesToXMLDoc(QDomDocument *doc, QDomNode *root, QPtrList<KNetworkInterface> devList);
+ void addNetworkProfilesToXMLDoc(QDomDocument *doc, QDomNode *root, QPtrList<KNetworkInfo> profileList);
+
+ protected: // Protected methods
+ /** Parses all of the <interface>...</interface> entries in the xml configuration file. */
+ virtual KNetworkInterface *getInterfaceInfo(QDomElement interface, const QString &type);
+ /** Parses all of the <interface>...</interface> entries in the xml configuration file. Returns a KWirelessInterface
+ object that contains all the info of the wireless interface. */
+ virtual KWirelessInterface *getWirelessInterfaceInfo(QDomElement interface, const QString &type);
+
+ signals: // Signals
+ /** emmited when the xml file is finished reading. */
+ void readyLoadingNetworkInfo();
+
+ /** emmited when the xml file saved and the backend has finished executing. */
+// void readySavingNetworkInfo();
+
+ /** Signal that is sent when fillDevices() has finished fllind the dhcp devices. */
+ void readyIfconfigOutputSignal();
+ /** Signal emmited when the platform can't be auto-detected. */
+ void errorDetectingPlatform();
+ /** signal emmited when the parsing of the xml of the supported platform list. */
+ void readyLoadingSupportedPlatforms();
+ /** signal emmited when the config parser needs to set read only the GUI because
+ some error in the parsing, or the platform isn't supported.*/
+ void setReadOnly(bool);
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/knetworkconfmodule.cpp b/knetworkconf/knetworkconf/knetworkconfmodule.cpp
new file mode 100644
index 0000000..03b8554
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconfmodule.cpp
@@ -0,0 +1,118 @@
+/***************************************************************************
+ knetworkconfmodule.cpp - description
+ -------------------
+ begin : Tue Apr 1 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : juancho@linuxmail.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <klocale.h>
+#include <kcmodule.h>
+#include <qlayout.h>
+#include <version.h>
+#include "knetworkconfmodule.h"
+
+
+
+KNetworkConfModule::KNetworkConfModule(QWidget* parent, const char *name/*, QStringList list*/)
+ : KCModule(parent,name)
+{
+ QVBoxLayout *top = new QVBoxLayout(this);
+
+ conf = new KNetworkConf(this);
+ conf->setVersion(QString(VERSION));
+ conf->setReadOnly(false);
+
+ top->addWidget(conf);
+
+ if (getuid() != 0){
+ conf->setReadOnlySlot(true);
+ conf->setReadOnly(true);
+ }
+
+ connect(conf,SIGNAL(networkStateChanged(bool)),SLOT(configChanged(bool)));
+ setButtons(KCModule::Apply|KCModule::Help);
+}
+
+KNetworkConfModule::~KNetworkConfModule()
+{
+}
+
+void KNetworkConfModule::configChanged(bool b)
+{
+ emit changed(b);
+}
+
+void KNetworkConfModule::load()
+{
+ // conf->loadNetworkDevicesInfo();
+ //conf->loadRoutingAndDNSInfo();
+ //conf->loadDNSInfoTab();
+}
+
+void KNetworkConfModule::save()
+{
+ conf->saveInfoSlot();
+}
+/*
+int KNetworkConfModule::buttons()
+{
+ return KCModule::Ok|KCModule::Apply|KCModule::Help;
+}
+*/
+bool KNetworkConfModule::useRootOnlyMsg() const
+{
+ return true;
+}
+
+QString KNetworkConfModule::rootOnlyMsg() const
+{
+ return "Changing the network configuration requires root access";
+}
+
+KAboutData* KNetworkConfModule::aboutData() const
+{
+ /*KAboutData* data = new KAboutData( "knetworkconf", I18N_NOOP("KNetworkConf"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 2003, Juan Luis Baptiste", 0, "http://www.merlinux.org/knetworkconf/", "jbaptiste@merlinux.org");
+ data->addAuthor("Juan Luis Baptiste",I18N_NOOP("Lead Developer"),
+ "jbaptiste@merlinux.org");
+ data->addCredit("David Sansome",I18N_NOOP("Various bugfixes and features"),
+ "me@davidsansome.com");
+
+ return data; // Memory leak, oh well...*/
+
+KAboutData *aboutData = new KAboutData( "knetworkconf", I18N_NOOP("KNetworkConf"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 2003 - 2005, Juan Luis Baptiste", 0, "http://www.merlinux.org/knetworkconf/", "juan.baptiste@kdemail.net");
+ aboutData->addAuthor("Juan Luis Baptiste",I18N_NOOP("Lead Developer"),
+ "juan.baptiste@kdemail.net");
+ aboutData->addCredit("Carlos Garnacho and the Gnome System Tools Team",I18N_NOOP("Provided the Network backend which KNetworkConf relies on."),
+ "garnacho@tuxerver.net","http://www.gnome.org/projects/gst/");
+ aboutData->addCredit("Helio Chissini de Castro",I18N_NOOP("Conectiva Linux Support"),
+ "helio@conectiva.com.br");
+ aboutData->addCredit("Christoph Eckert",I18N_NOOP("Documentation maintainer, and German translator"),
+ "mchristoph.eckert@t-online.de ");
+ aboutData->addCredit("David Sansome",I18N_NOOP("Various bugfixes and features"),
+ "me@davidsansome.com");
+ aboutData->addCredit("Gustavo Pichorim Boiko",I18N_NOOP("Various bugfixes and Brazilian Portuguese translator"),"gustavo.boiko@kdemail.net");
+ return aboutData;// Memory leak, oh well...
+}
+
+QString KNetworkConfModule::quickHelp() const
+{
+ return i18n("%1Network configuration%2This module allows you to configure your TCP/IP settings.%3").arg("<h1>").arg("</h1><p>").arg("</p>");
+}
+
+//#include "knetworkconfmodule.moc"
+
+#include "knetworkconfmodule.moc"
diff --git a/knetworkconf/knetworkconf/knetworkconfmodule.h b/knetworkconf/knetworkconf/knetworkconfmodule.h
new file mode 100644
index 0000000..424dc94
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkconfmodule.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ knetworkconfmodule.h - description
+ -------------------
+ begin : Tue Apr 1 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : juancho@linuxmail.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNETWORKCONFMODULE_H
+#define KNETWORKCONFMODULE_H
+
+#include "knetworkconf.h"
+#include <kaboutdata.h>
+#include <kcmodule.h>
+
+class KNetworkConfModule : public KCModule
+{
+ Q_OBJECT
+
+public:
+ KNetworkConfModule(QWidget* parent, const char *name/*, QStringList list*/);
+ ~KNetworkConfModule();
+
+ void load();
+ void save();
+ int buttons();
+
+ bool useRootOnlyMsg() const;
+ QString rootOnlyMsg() const;
+ KAboutData* aboutData() const;
+ QString quickHelp() const;
+
+private slots:
+ void configChanged(bool);
+
+private:
+ KNetworkConf* conf;
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/knetworkinfo.cpp b/knetworkconf/knetworkconf/knetworkinfo.cpp
new file mode 100644
index 0000000..182bc14
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkinfo.cpp
@@ -0,0 +1,76 @@
+/***************************************************************************
+ knetworkinfo.cpp - description
+ -------------------
+ begin : Fri Jan 17 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "knetworkinfo.h"
+
+KNetworkInfo::KNetworkInfo(){
+}
+KNetworkInfo::~KNetworkInfo(){
+}
+void KNetworkInfo::setDeviceList(QPtrList<KNetworkInterface> deviceList){
+ KNetworkInfo::deviceList = deviceList;
+}
+void KNetworkInfo::setRoutingInfo(KRoutingInfo *routingInfo){
+ KNetworkInfo::routingInfo = routingInfo;
+}
+void KNetworkInfo::setDNSInfo(KDNSInfo *dnsInfo){
+ KNetworkInfo::dnsInfo = dnsInfo;
+
+}
+QPtrList<KNetworkInterface> KNetworkInfo::getDeviceList(){
+ return deviceList;
+}
+KRoutingInfo * KNetworkInfo::getRoutingInfo(){
+ return routingInfo;
+}
+KDNSInfo * KNetworkInfo::getDNSInfo(){
+ return dnsInfo;
+}
+
+void KNetworkInfo::setNetworkScript(QString script){
+ KNetworkInfo::networkScript = script;
+}
+QString KNetworkInfo::getNetworkScript(){
+ return networkScript;
+}
+/** Returns the platform name KnetworkConf is running on. */
+QString KNetworkInfo::getPlatformName(){
+ return platformName;
+}
+/** Sets the platform name KNetworkConf is running on. */
+void KNetworkInfo::setPlatformName(QString name){
+ KNetworkInfo::platformName = name;
+}
+
+void KNetworkInfo::setProfilesList(QPtrList<KNetworkInfo> profilesList){
+ KNetworkInfo::profilesList = profilesList;
+}
+
+QPtrList<KNetworkInfo> KNetworkInfo::getProfilesList(){
+ return profilesList;
+}
+
+/** Returns the platform name KnetworkConf is running on. */
+QString KNetworkInfo::getProfileName(){
+ return profileName;
+}
+/** Sets the platform name KNetworkConf is running on. */
+void KNetworkInfo::setProfileName(QString profileName){
+ KNetworkInfo::profileName = profileName;
+}
+
+
diff --git a/knetworkconf/knetworkconf/knetworkinfo.h b/knetworkconf/knetworkconf/knetworkinfo.h
new file mode 100644
index 0000000..7ae8b25
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkinfo.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ knetworkinfo.h - description
+ -------------------
+ begin : Fri Jan 17 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNETWORKINFO_H
+#define KNETWORKINFO_H
+
+#include <qstring.h>
+#include <qptrlist.h>
+#include "knetworkinterface.h"
+#include "kwirelessinterface.h"
+#include "kaddressvalidator.h"
+#include "kroutinginfo.h"
+#include "kdnsinfo.h"
+
+/**Represents the network information
+ *@author Juan Luis Baptiste
+ */
+
+class KNetworkInfo {
+ public:
+ KNetworkInfo();
+ ~KNetworkInfo();
+ private: // Private attributes
+ QPtrList<KNetworkInterface> deviceList;
+ KRoutingInfo *routingInfo;
+ /** Path to the network script that permits starting/stopping/reloading the
+ network. */
+ QString networkScript;
+ KDNSInfo *dnsInfo;
+ /** Platform name. */
+ QString platformName;
+ QPtrList<KNetworkInfo> profilesList;
+ QString profileName;
+
+ public: // Public attributes
+ void setDeviceList(QPtrList<KNetworkInterface> deviceList);
+ void setRoutingInfo(KRoutingInfo *routingInfo);
+ void setDNSInfo(KDNSInfo *dnsInfo);
+ QPtrList<KNetworkInterface> getDeviceList();
+ KRoutingInfo *getRoutingInfo();
+ KDNSInfo *getDNSInfo();
+ QString getNetworkScript();
+ void setNetworkScript(QString script);
+ /** Returns the platform name KnetworkConf is running on. */
+ QString getPlatformName();
+ /** Sets the platform name KNetworkConf is running on. */
+ void setPlatformName(QString name);
+ void setProfilesList(QPtrList<KNetworkInfo> profilesList);
+ QPtrList<KNetworkInfo> getProfilesList();
+ void setProfileName(QString profileName);
+ QString getProfileName();
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/knetworkinterface.cpp b/knetworkconf/knetworkconf/knetworkinterface.cpp
new file mode 100644
index 0000000..4e48c27
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkinterface.cpp
@@ -0,0 +1,104 @@
+/***************************************************************************
+ knetworkinterface.cpp - description
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "knetworkinterface.h"
+
+KNetworkInterface::KNetworkInterface(){
+}
+KNetworkInterface::~KNetworkInterface(){
+}
+
+QString KNetworkInterface::getBootProto(){
+ return bootProto;
+}
+QString KNetworkInterface::getBroadcast(){
+ return broadcast;
+}
+QString KNetworkInterface::getDeviceName(){
+ return deviceName;
+}
+QString KNetworkInterface::getIpAddress(){
+ return ipAddress;
+}
+QString KNetworkInterface::getNetmask(){
+ return netmask;
+}
+QString KNetworkInterface::getNetwork(){
+ return network;
+}
+QString KNetworkInterface::getOnBoot(){
+ return onBoot;
+}
+QString KNetworkInterface::getGateway(){
+ return gateway;
+}
+
+void KNetworkInterface::setBootProto(const QString &bootProto){
+ KNetworkInterface::bootProto = bootProto;
+}
+void KNetworkInterface::setBroadcast(const QString &broadcast){
+ KNetworkInterface::broadcast = broadcast;
+}
+void KNetworkInterface::setDeviceName(const QString &deviceName){
+ KNetworkInterface::deviceName = deviceName;
+}
+void KNetworkInterface::setIpAddress(const QString &ipAddress){
+ KNetworkInterface::ipAddress = ipAddress;
+}
+void KNetworkInterface::setNetmask(const QString &netmask){
+ KNetworkInterface::netmask = netmask;
+}
+void KNetworkInterface::setNetwork(const QString &network){
+ KNetworkInterface::network = network;
+}
+void KNetworkInterface::setOnBoot(const QString &onBoot){
+ KNetworkInterface::onBoot = onBoot;
+}
+void KNetworkInterface::setGateway(const QString &gateway){
+ KNetworkInterface::gateway = gateway;
+}
+bool KNetworkInterface::isActive(){
+ return active;
+}
+void KNetworkInterface::setActive(bool active){
+ KNetworkInterface::active = active;
+}
+/** No descriptions */
+QString KNetworkInterface::getMacAddress(){
+ return hwAddress;
+}
+/** No descriptions */
+void KNetworkInterface::setMacAddress(const QString &addr){
+ KNetworkInterface::hwAddress = addr;
+}
+/** No descriptions */
+QString KNetworkInterface::getDescription(){
+ return description;
+}
+/** No descriptions */
+void KNetworkInterface::setDescription(const QString &desc){
+ KNetworkInterface::description = desc;
+}
+
+/** No descriptions */
+QString KNetworkInterface::getType(){
+ return type;
+}
+/** No descriptions */
+void KNetworkInterface::setType(const QString &type){
+ KNetworkInterface::type = type;
+}
diff --git a/knetworkconf/knetworkconf/knetworkinterface.h b/knetworkconf/knetworkconf/knetworkinterface.h
new file mode 100644
index 0000000..859afc6
--- /dev/null
+++ b/knetworkconf/knetworkconf/knetworkinterface.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ knetworkinterface.h - description
+ -------------------
+ begin : Mon Jan 13 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KNETWORKINTERFACE_H
+#define KNETWORKINTERFACE_H
+
+#include <qstring.h>
+
+/**This class has all the values associated with a network interface.
+ *@author Juan Luis Baptiste
+ */
+
+class KNetworkInterface {
+ public:
+ KNetworkInterface();
+ ~KNetworkInterface();
+
+ QString getBootProto();
+ QString getBroadcast();
+ QString getDeviceName();
+ QString getIpAddress();
+ QString getNetmask();
+ QString getNetwork();
+ QString getOnBoot();
+ QString getGateway();
+ void setBootProto(const QString &bootProto);
+ void setBroadcast(const QString &broadcast);
+ void setDeviceName(const QString &deviceName);
+ void setIpAddress(const QString &ipAddress);
+ void setNetmask(const QString &netmask);
+ void setNetwork(const QString &network);
+ void setOnBoot(const QString &onBoot);
+ void setGateway(const QString &gateway);
+ bool isActive();
+ void setActive(bool active);
+ void setMacAddress(const QString &addr);
+ QString getMacAddress();
+ void setDescription(const QString &desc);
+ QString getDescription();
+ void setType(const QString &type);
+ QString getType();
+
+ private: // Private attributes
+ /** Interface name (i.e. eth0, eth1, etc). */
+ QString deviceName;
+ /** Boot protocol of the device (static, dhcp). */
+ QString bootProto;
+ /** IPv4 address of the interface. */
+ QString ipAddress;
+ /** The Netmask. */
+ QString netmask;
+ /** The network. */
+ QString network;
+ /** The broadcast. */
+ QString broadcast;
+ /** thetermines if this device is configured at boot time. */
+ QString onBoot;
+ /** default gateway for this device. */
+ QString gateway;
+ bool active;
+ /** The MAC address. */
+ QString hwAddress;
+ /** A little description about the network device. */
+ QString description;
+ /** Type of interface (ethernet,wireless,loopback or modem)*/
+ QString type;
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/kprofileslistviewtooltip.cpp b/knetworkconf/knetworkconf/kprofileslistviewtooltip.cpp
new file mode 100644
index 0000000..a326e23
--- /dev/null
+++ b/knetworkconf/knetworkconf/kprofileslistviewtooltip.cpp
@@ -0,0 +1,16 @@
+//
+// C++ Implementation: %{MODULE}
+//
+// Description:
+//
+//
+// Author: %{AUTHOR} <%{EMAIL}>, (C) %{YEAR}
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "kprofileslistviewtooltip.h"
+
+KProfilesListViewToolTip::~KProfilesListViewToolTip()
+{
+}
diff --git a/knetworkconf/knetworkconf/kprofileslistviewtooltip.h b/knetworkconf/knetworkconf/kprofileslistviewtooltip.h
new file mode 100644
index 0000000..c0c6bce
--- /dev/null
+++ b/knetworkconf/knetworkconf/kprofileslistviewtooltip.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+ kprofileslistviewtooltip.h - description
+ -------------------
+ begin : Wed Aug 24 2005
+ copyright : (C) 2005 by Juan Luis Baptiste
+ email : juan.baptiste@kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KPROFILESLISTVIEWTOOLTIP_H
+#define KPROFILESLISTVIEWTOOLTIP_H
+
+#include <qtooltip.h>
+#include <qlistview.h>
+#include <qheader.h>
+#include <qptrlist.h>
+
+#include "knetworkinfo.h"
+#include "knetworkconfigparser.h"
+
+class KProfilesListViewToolTip : public QToolTip
+{
+public:
+ KProfilesListViewToolTip(QListView* parent);
+ void setProfiles(QPtrList<KNetworkInfo> profiles_);
+ ~KProfilesListViewToolTip();
+
+protected:
+ void maybeTip( const QPoint& p );
+ KNetworkInfo *getProfile(QPtrList<KNetworkInfo> profilesList, QString selectedProfile);
+private:
+ QListView* listView;
+ //KNetworkConf* conf;
+ QPtrList<KNetworkInfo> profiles;
+
+};
+
+inline void KProfilesListViewToolTip::setProfiles(QPtrList<KNetworkInfo> profiles_)
+{
+ profiles = profiles_;
+}
+
+inline KProfilesListViewToolTip::KProfilesListViewToolTip( QListView* parent ):QToolTip( parent->viewport() ), listView( parent ) {}
+
+inline void KProfilesListViewToolTip::maybeTip( const QPoint& p )
+{
+
+ if ( !listView )
+ return;
+
+ const QListViewItem* item = listView->itemAt( p );
+
+ if ( !item )
+ return;
+
+ const QRect itemRect = listView->itemRect( item );
+
+ if ( !itemRect.isValid() )
+ return;
+
+ const int col = listView->header()->sectionAt( p.x() );
+
+ if ( col == -1 )
+ return;
+
+ const QRect headerRect = listView->header()->sectionRect( col );
+
+ if ( !headerRect.isValid() )
+ return;
+
+ const QRect cellRect( headerRect.left(), itemRect.top(),headerRect.width() + 60, itemRect.height() );
+
+ QString tipStr;
+
+ if( col == 0 )
+ {
+ tipStr = QString(i18n("<b>Network Configuration of this Profile:</b>" ));
+ KNetworkInfo *profile = getProfile(profiles,item->text(0));
+ if (profile != NULL)
+ {
+ QPtrList<KNetworkInterface> devices = profile->getDeviceList();
+ KNetworkInterface *device = NULL;
+ for (device = devices.first(); device; device = devices.next())
+ {
+ if (device->getType() != LOOPBACK_IFACE_TYPE)
+ {
+ tipStr.append(i18n("<p><b>Interface:</b> %1").arg(device->getDeviceName().latin1()));
+ tipStr.append(i18n("<br><b>Type:</b> %1").arg(device->getType()));
+ QString bootProto;
+ if (device->getBootProto() == "none")
+ bootProto = "Manual";
+ else
+ bootProto = device->getBootProto();
+ tipStr.append(i18n("<br><b>Boot Protocol:</b> %1").arg(bootProto));
+ if (bootProto != "dhcp")
+ {
+ tipStr.append(i18n("<br><b>IP Address:</b> %1").arg(device->getIpAddress()));
+ tipStr.append(i18n("<br><b>Broadcast Address:</b> %1").arg(device->getBroadcast()));
+ }
+ tipStr.append(i18n("<br><b>On Boot:</b> %1").arg(device->getOnBoot()));
+ }
+ }
+ KRoutingInfo *route = profile->getRoutingInfo();
+ tipStr.append(i18n("</p><p><b>Default Gateway:</b> %1").arg(route->getGateway()));
+ KDNSInfo *dns = profile->getDNSInfo();
+ tipStr.append(i18n("<br><b>Domain Name:</b> %1").arg(dns->getDomainName()));
+ tipStr.append(i18n("<br><b>Machine Name:</b> %1").arg(dns->getMachineName()));
+ QStringList nameServers = dns->getNameServers();
+ for ( QStringList::Iterator it = nameServers.begin(); it != nameServers.end(); ++it)
+ {
+ tipStr.append(i18n("<br><b>DNS Name Server:</b> %1").arg((*it)));
+ }
+ }
+ }
+ tip( cellRect, tipStr );
+}
+
+inline KNetworkInfo *KProfilesListViewToolTip::getProfile(QPtrList<KNetworkInfo> profilesList, QString selectedProfile)
+{
+ QPtrListIterator<KNetworkInfo> it(profilesList);
+ KNetworkInfo *net = NULL;
+
+ while ((net = it.current()) != 0)
+ {
+ ++it;
+ if (net->getProfileName() == selectedProfile)
+ break;
+ }
+ return net;
+}
+
+#endif
diff --git a/knetworkconf/knetworkconf/kreloadnetworkdlg.ui b/knetworkconf/knetworkconf/kreloadnetworkdlg.ui
new file mode 100644
index 0000000..3041186
--- /dev/null
+++ b/knetworkconf/knetworkconf/kreloadnetworkdlg.ui
@@ -0,0 +1,137 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>KReloadNetworkDlg</class>
+<widget class="KDialog">
+ <property name="name">
+ <cstring>KReloadNetworkDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>2</x>
+ <y>0</y>
+ <width>342</width>
+ <height>130</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>342</width>
+ <height>130</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>342</width>
+ <height>130</height>
+ </size>
+ </property>
+ <property name="caption">
+ <string>Reloading Network</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>tlNetworkStatus</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>72</y>
+ <width>273</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <bold>1</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>kpbOk</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>139</x>
+ <y>96</y>
+ <width>58</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoResize">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>PixmapLabel1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>20</y>
+ <width>40</width>
+ <height>40</height>
+ </rect>
+ </property>
+ <property name="pixmap">
+ <pixmap>image1</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>73</x>
+ <y>20</y>
+ <width>291</width>
+ <height>46</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Please wait while the network is reloaded so
+the changes can take effect.</string>
+ </property>
+ </widget>
+</widget>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="8846">789cedd8596f23b91107f0f7fd1483e1db22e04a2d75ab1b411e7cdff7ed200f7550be0fd996652bc8774f8bf52fcd6633bb3b405e331e60fc1b36c962f1684abffcfce57c7fe7cbcfbffcf4fa466f37f245aee9e5cbcf3a7e78f8fcfb3ffef6cf9fbef68a2feddf7eb7ffa5f8fa979fbe1ebc7d912fbb4f8f6906aa5a844efe3333776031cbe6dcf5cc71dd3c5029670e1b66ae86c35cae664d6659300f876635d7f3fe2ee07e373b8de0dafa4b7730fa971b73b763e67518cf478bbf1e944d3f8f2fd76f4b3b858d67df3cfbc9f5afcc45dfca696a2e1b8b2f26f33cfe9d998b4ea76fe57a6eee623cfa08633cbc060bfabf35178887d05ed1b77868d7dcc3f371c33c24f49ff353346dbc4d6e7fd5ddcb4e6fb0a0fcdcddeb663f9b7b5ebe64aebb66da9eb9d79db7a7708dfa2bb0f4b3b534f7fa562e57735bfb5d18fdc5a9b9eff3b1067bfbcbb058fdc0e6b263e5f1186e10efc85c299ecff9e8353e1f6cf59ba263f1ca078cf6e9d2dc43fbfc34772e9737779f723ebcbc8ff676e01ae35518f98927e63ed657b870e37981519f3ae612fdd32d5c9a756c1e74b1be97ccbe3e25e7afdff5f8f9d66df1f0238cf84263ee77b01fc85de6f1c62318e30d4b708df6a6ee321f2e7a3777ae4f7bb0207f8f6e2be70573595a7b74012bfa5373d5c08bb0cf37e21da09c7ae6baa19c9f78062b49f6b9799eaf836c6ae733c72387b0603c7d731ff32f2b6e8b3fbdc3a81fc45c22dfa1823dde64ae4a3c3f86d54c9fe601c62f23b7c54336bfd4746d7ce1c69c70fe6ace4f59f46a9c1f0b73db7a2acdbebed2d88df11670698e87e6aa6be30da8eff90e6fe6ba8b78cfdd03cef50fe006ed2d9ba914cdf5afe0a4f97d42d65e9bdf2a3f2feb70bfb2fe0730d61b6dbaad9cb761ac3749e612f345fb6e6b9f0ee0d2cc616e9bdf09dca07ed76dcfc74f18f393d2dc168fcd07555edff24903cf6734d75d8ce71946fbe1de4c5dcef9a23e4c9adfdf71094ec8e79a990bf801aecc11f16b81f592df375551e07d96a2b98ff390c6e6365f16ff03dc0c7af9f96b18e3a57b379e3f73d7f979be33fb7ad22537c6bbe2b6f66908fb7aab61b5f5c5886780fcf1b51bf3f939b79d67886f80fd2727b0cfcf861bf15f996b9c4f710fc67c33ea37180f217f4dc9763e239ea6b1fea29813d97a171bff7c3dc92aac18ff87d9f3131f60bc0fd2d48d781760c4cf43b7b5271b30da677880f54f4f6eec5ff45f7b3e0fdd563f7cc2a81fd07fad7030371eff9b993c5f182f119ecff10e7a25cedbb00c37160f1d9bab12eb29c24d9dcbc339ece32bcd3eff3c7263fd0a5c223f9f73e7f6e4d5dde4f707ddc0982ffe30d7bebed01f91c51776e064fb372e9a7d7ff29b59fd7eb762f6f71359ffecfb497ae6aab4fcc991dbfa936d18eb996fdc584f8f6ebb3f6817f6fd94dc964fb9300f709ea70f18f9a1018cf9119b1ff6f38c37dde8ff1cf6f576eac6fb0cf1d41eef96dbe289964f6ed05f1cc3c84fdc3793cf47e5b6fc68ce4fddf3f1f0115cda799716ddc8e7c45c7b7d85514e276edc2f6ad8e35f3737a81f0ad8d7ef018c7c47f447fefebc857d7d2eba6d3d09c309eb7f646e27d8ce1f9433d9e7b57803276b5fd1be909d57e1da3cbf1fe5f74dddae07acb78e7980fdcd369e76feb05eae61df8fa85f637da9b8ad9cefcd8daf2f86fdfe7607a33e356eb46ff967c2fe0c5b6eecb76d9890cf7737e6e3d5cc15fc31b78da7326b61f949397f4ddfdf47fa60f6f345a76eac9fdaecf9d0037383fb7be8c1d88ff1d46deb890a5871feac9809eb270ee6b67c5cbad15e0327ab1f9fcced7ab0f583fea4b2724de6f9e7ddbcff1be9fbe75d32fb7a50eb4f067eff2b60ac7f3d83fdfd3f36fb79905e611fdf9ab969b0df96dd562e258cf6b463f6fb911ec378ffc65d3317964f41fc4c582f2fe6f6e36936231ef5ef337a30f247c19c8a6195dbc3f88615eeafb9bdf63aeae76b03fb793a343738eff818c6fb2a4ccd84fbbd3ec164f1f33e8c78c29eb97d9fd8febe8231bff1024ef8bee6d0ecf31dfb6eecb72db312fc684eb82fcac03c447e388f9fdaf9407c3b66c2fae67737c613619c973481d11f5fc2c9cab572dbfc865d335736bf7a0de3fce25338e13cdb364b81f3600857767f0e4f30fa0ffb6edcaf6d3ec5bf7f4979feb93f28f1792a99fdbc123113ee3bf40e633da60518f1a54f33e37cd12bd8c7378131fff2ecb6727934cfe76fd56deb31ac9be7fb39af17d6c6cfa30d73db9f7dbe588409fbe9c82c95ad1f79715bfbfa0a63bd8503b326cb1f9179de7f3e0fa5f4f7b7bc9bfdfdc43d18eb55d7cde2f7a5018c78f5d08dfe6fdd88ef1e46bea89e3b3f9f866ed43f36abe7ffc68d7c6ec2ed27eeec2373427be1d13cf4f97c8131fe94f321eaf7115137d64f6366e45b8730d68baeb9311fddb9ed3cdf327b3e640f46791cb96d3c3c312bce0f798291df18cca948793ed5e6a79d4f9cafd76e9c0ff97dd8be1c70bec99dd9cf5ffd304b81f14f617c1ed25518eb273e9bb5302bc3d8bfe90af6f9c0f3a932c7c23c1c22fe7c3eb4a77983ef2befdd781f4fcc8cfd1fdecd52587b5cc3c88fec9a3dbef40c233e0d3059ffe905f6fd71644e783ebe9a3ddec86eec9fbcfe52c515eeaf7b66cf5fe8c0685fdfcc1e1f57b0e77be0c6f85e60d4e72db3cf7f7a70dbfb2f9cc29eef1518dfffc735f3d0bf6fc8f7b594c4cfe73bf33cbe06f6fbc9a51bf37b0627eb5f9fcdf3f5f90e57660970b2fabaefc6e7abbcff86957f7f96ee61c2fb3dc2e82f6e9ae7f391f3331c6a81fbf02eecf7ed4b7342fc24e621f2c7fdb9adbd4f18efa374eb463ce3b92dbf04239e83b7ffede7ff6dfc771b31448af4a33566cfb63f1c256a4cf33686f1aafddfeb1faa4bf126dec6bb781f1fe2a3d5c96d3cc5e7388a2f7f52ff35bec5717c8f93f8113fe3342ec4c5b814156d2cc795b81ad7e27adcf86eedcdb815b7e34edc8d7b713f1ec4c378148fe3493c8d67f1dc73da8eee225ec64eecfe26f222f6623f96b18a8358c726c41002050e1234a4300c57e1dadb0837e136dc85fbf0e0a30e8fe1293c87517809afe12d8cc37b98848ff019a661212c86a5b01c56c26a580bebf33636c266d80adb6127ec86bdb01f0ec261380ac7e1249c86b3701e2ec265e8846e28422ff44319aa30087568669d7d5b1fedddb3bd7e507bc4d090aee89a6ee896ee82d23d3dd0233dd1338de8855ee98dc6f44e13faa04f9ad2022dfeaa8d255a8ea7b442abb446ebb4419bb445dbb443bbb447fb7440877444c77442a774d6d63ca70bbaa44efbd62fbeb511957aedcdbea48a065453c391437b0f63169ebdff877cc5d77c430b7ccb777ccf0ffcc84ffccc237ef9551bd7fcca6f3ce6f7483ce10ffee4292ff0222ff132aff02aafcd4adab275de085ddee4adac6dde99cfedccbb7193f76c56789f0ff8908ff8984ff894cff89c2ff8329774b8dbde5b7bf9f73e975c7d6b8307dc7e488f2471562aa1bd5fb1c8ecde913d942bb9cebfddc8ad451489166c9f791b7227f7d2ae0e7a97477992679ac8485ee455de667dca58de6592dbf8904f6b41a66deeaa6f7b5f16c2baed4659942559961559953559a74dd9904dbe932d5a90ed5c734776f3bf7bb2ff7be74758a77d399043399263399153399373b9903617d299ef5c92aec7f0dd36aedb9b6c4ffaf9c63a68efcd75fbd1296a7bc268aead9cdb186b9b2a556be9b76db4efe6a15ee9b5dee8added9f3dcd3fbb676de4bfaa84ff9df671db56513d9fade59a82ffaaa6d96754c95e619d0897ee8a74ef3ef0bba184ef36f5197e2912e7fb78d155dd5b57686665f283fb731aceb866eea96e69cea8eeeea9eeee7bd7ddeb671f0bd36a2eaa11ef9f94aedbd4a8ff5444ff52cb771ae177aa939bfe154bb5a7c378e9ee51eeae7fbe1406b6d66ff9b620a69f6017290d55e8dfefcddd0de50c669186ed355ba9e8d2edda45bde928d74a7a3ff5c637fd0c67d9e9b771d259c71e9313da5e7bcd67fb00d1ee9527b1bde4f7769945ed26b7a4bed7ca5f734491f3f1cc747fae44276da7a5369f77b9af2e3ec8c490b61fa7bebf40f5a5be4914cdafcecfcb6e4ebbffefad3bf0156bfa7ba</data>
+ </image>
+ <image name="image1">
+ <data format="XPM.GZ" length="8910">789cedd9c992e4b61106e0bb9e6262705338a02a56914586c387def77d6f870f8904d8fbbeb7c3ef6e16fe3f39b23c9226c2576ba498f9064422b1126cfdf2f397e3ed8d2f3ffff2d3d3b33c5fe8173d97c72f3fc7979b9b8fbfffe36ffffce9eba8f8d2fd3b1ed65f8aaf7ff9e9ebcef317fdb279779ba690b2831be47fa60e035a615ded5d4fed97e1ba8ce5d48e0ea96d737984232d433855b07ec26d0bc799ecba6fff841e0fb3d3035da3fd7449331f3d878703382cd37cde9fc293b219e77cf2f35de9a040ffb6e1e9af5cbf858b31cae50dae86c8cf27b8cf7f63ea623018a33c1ec143f627ded2ec4f58a495ed5fc005f391357a8c7c641d1ef179bf02b7c2f6f3f8144d976f93e32f9847d9e99956961f9b47c3ec3b7864e5b3703d8425cfff6868f1c23cade35c3f8ee1d118f1b4ed8de78734e3fb4f786ce3bf44d7cc678e56d47702970394fb3db8b2fc6ee9c8e773ff478d8d7f40fda618205f3986478c176e7be7faba41d7cc5f69f6d7efc363ae0f776cc6f37202978c27677409c717783214ac478c4763eb29e5fd331e1635dad379d8f24b7334f371353c1e70fd3a732539df5d7acce76769c60f1fe6321f0ef1d28cfab241eb383bdd9acbecf0099725c7f7888e6c4fe1aaa167e009c7c331df09cba580eb06e3e30fe9289acdf8365e9af7e7580ae6a7cff06880fcd21d3d46ff7497567a011edbf3aff418f142a06bd8d125d7932b695b7f983fa94a3ecf7caa080be34f383efa60463e82f191661872ffdd396ce767c8e7455974fdc37ccdd235cf8799de58bf3734fb2b63d8d6677a3133de902e61c7e76d7ef408ae879390dbdba61b3edfc2a14a557e7e277b3afeb9ff7104db78eb323dc67a7315cdf52856cef518d6699bef08978c279be60af5b7e8120ebe37e6fb8d6e58ffd48ce7fd07cdf949a937f2c1784b65f5311e3219c2be81eb21c767110e85c6ec6bba82fd9c39e6f7b31fc0d1cefbdcbfaa28f8bee95ef5d925f7bb5cd2cd6494f33da799af1c98eb5c1ef87cc57ce39c19fd77f366c413a5b91efc8e99f337a1639dd747b88627ec7f3833733ede7b23bf25dae23dc1b5b5c7fed79c0fd7c04da9f93e22896eb03e3cf397c4f164fe6d81f52979ff55dd7a44ff14fdefe75f17e988728ffe74fb9bfb67c6ccfcdf69e61f9299f15768c60bf484eb53aecddc5f8c57db78ed9a51df5939ebbb4f3ad21e6e585f6ecceccf332c9c7f99a785f5afcc589f32824391f278c63cfe93d1d8cec30477e723e25dc015fb23bb66ac3f7744db788c615b0fe1deccf5ac74c9f17cef9de3eb93b9c1fbe28ab6fdfa06d7b6de22cdf5140ee086f3e7998f08f2f5b370bf7fd769eedfc0f6fbfdba00dbfb4ad09f5046c4d702ae4a8eff0b6dfb77968ee85f427f83f5572aba61fff7613b6fc2aa99fbd7ca4bbc5fdd80667bb262c6fef5e85f6818df33bf86f9bbbc5fea5135c4f3711d9ef0fd208d19f311b769cebfb4b0e5a7af669447a5f9bc9fd096ef22dcf07937a4f9bccec252863c3f2a70a890afbb37f3fbc0d182f3c49fd309fd8917b00adfcf67707f1f41ff83bd0fe280e679a87b66b417103f4c98bf5c99313f21d25ccf7a4c737ef494e67e4f1f6694cb216ce7839ed1ac1f03cde713c6a79b6fdebf2e69ae3fa9cd5c1f252c43f4c7edd325ef6b5bb470fdbc9a395f8f70371f982fc68b1cff94c7bb19dbfb26dec0763ea4459adf77618fe6fd4ae8dae67f42b3ffae809b86f33f6b46fe32a023cf933758b8de7d45978c7762663e3bbd519ffd91c4f55c9b597e07079eb77a006bc5f9cfe76fa315cfb388f67432e4f9cb729bcf5098513f5cc18dcdffbc99f1c734ef0711e3a7ddfec1fcae9a795f598343c1f5e868413cf7465bff984fa4c5c3a968f3fb38e6f79774f38bf18b356cfd893bb0adcfb04ff3fd911660e1fef10766ccbfccd19c9f78470be63b6cd396ef196cf3e18fe984f5e9988fcd8f5f85a3a07dade096f7f71869fbf901e2e9d87e7ee0609b5f1dc2139e77f190b6fbdb336ce7677aa2f9bd24188fe97ce3f90dd8f66b783123df786ae6fa6b68ee67617bc2fe057b3ea1dc317ea8b05ee219cdf3d26ff4c6fb92fd0989eb6b0dd602e5ee96667beea137dadb32e37e171e61fbf993327edbe2be97f27a0bdd79c19f1fdcc10dfbaf89e67ad7008bdd873f68f6277dc2a1607fdf68e6a77766f66fd38c9f9fe90dac15d7eb88e678789627de277406b6f513f27db93b2ef9bd188e683befeee13ebf92e67d253ec16aebbba513ee77fe11eeef2f793cba8f7fb6274f34f7439a87bbf8d9b1a5591e9761e5fd295474857ce3ae99f95dd336dead99f92ed209f3ebf6e0c8f5e7566861f912dcefbfbc7eb41b3fde4ff07cecf2c579f1015bbecae795e5fec1ccf97c34a3bdf00ac782f7090727de9fdd365d71bc6fe13ebffcbeea0e03be6fd2356ceb278c686bff05d6028e5774c59fd75ed0cc4f183fb27f51687e7fa6339ae317cf691bef5db8b5fbf00dcdf7777ca4ad3ff93cee4eff863f2f54d8d65372b4f07c4eb09d0f5a9bd9df41ef9cafaec16abe8523e72b3d9a511e0bb86db9df8299fb2d8f77aac4dabf84edfc8aefb0f23ea31f668ed7221c6d7eef6981c31adcaf87039a3f3f717774c2fbd10fe13ebf3cbf29d9fdc5bdc281f1dd0bac82fa6142db78209f64f9859ab6fbc7a699df7b1eeeded7380f76683b2f9ee07ebef3fbb0ad4285fb5fd8826d7cdc296cedc767dadaabccccbf8413bfdf5330a33cddf4c6f9f8405bff1adac673a137feffc512dcb2becbf3ddb6d1be77f7693bdfd668e1f7eba619e57a62e6fd06f15bcbcf1dd2763fb8a7edfbf195b6fc18afb5fe5ef5c67af074c5f63e68be3f45cc8c67e67ced3cff6fbffe1fe3bf6378e7c5cb8fd6983edbfd0a5e7df4a98fd1fab3e9dffe505df1e7fec25ffa2b7fed6ffc6d1fe3cedffb07fff827f59ffcb37ff1affecdbffb0fffe967fcac9ff39131e6fd825ff44b7ed9affc4eebab7ecdaffb0dbfe9b7fcb6dff1bb7ecfeffb037fe88f6c4cbb368efd893ff583dfd41dfac28ffcd897bef2135ffbc679e79cb8e0d445975cebce2c863b7717eed25db96bebb5bb71b7eeceddbb07f7e89edcb37b71afeecdbdbb0ff7e966dcac9b73f36ec12dbaa53ec6b25b71ab6ecdadbb0db7e9b6dcb6db71bb6ecfedbb0377e88edcb13b71a76ee086ae70233776a5abdcc4d5ae11ff6d7df85b7122ee50ba8f04e90e2e69e54cce9dca855cca955ccb8ddcca9ddccb833cca933ccb8bbcca9bbccbc7b718f22933322b73322f0bb2284bb22c2bb22a6bb22e1bb2295bb22d3bb22b7bb22f075dcd4339926339915319fc2ac6500a194dbf6da49289d4d2041f5cf7a60a41bb1b5f0a6d380be7f21e2ec265b80ad7e126dc86bb701f1e7edd97f0189ec27378f1125ec35b780f1fe133cc84d93017e6c342580c4bd3b10ecb61c50dc26a58cb5a0f1bfddc4ebdd9fdb7855909db6127ec86bdb01f0ec261380ac7e1249ce692411876f7d2d1f4cfd3fb7428bfc5e8be1f26a1ee7e6fa6a5eab51b4e0daa1ab393b67a96ff74ae17d35c738c77ec338ba1977aa5ddea9027bdd15bbdd37b7dd0477dd2e7699bdd05fd455f738c377d4704fde8c6aefcb6f7f55367b0277456e7745e17745197745996754557c3a5aec9bbaee79a1bba997fdfd2eddf3b3fdc926cea8eeeea9eee87373dd0433dd2633de96a9df63b577460397c37c6990ebbbbe848c7f9ceac3ad1bafb58f75e623e6522a3c46ec2a322d26f63c4d8dd7eda7816cfe345bcc4e8c7abd88d54bcc9756fe35dfefd3e3e74f9bceadaf7cec2f8189f6237caf145ca98c731bec5f7f8113ff39f67e2ac3bc8b37c14e7fc6e9cff6e8c85b8a8dd2c4ff38c4b5d0ecb7125aec6b598c7346ec4cdb8c5d8db5d8c9defc59061dced4e359eafdd778fc6bdb81f0fe261ae77148fe349cce3eb0ee2200ebf9b478151a346719c6fc0dd47768ed1249f5ceaae80534daf967ffe6e48a97bb27517e92c9d4f7b972eba9158d39574191ffe738dfd418cabdcde757c4837c82fdda6bb749f67ec076384fb3817c7ba9d2ed3437a4c4fe93975f3955ed35b7affe13c3ed2672874a3ab37a3dd7e4fb3696e7ac6a4f9b4f07bebf40fa22d867b7ded6ea01bbf2df9faafbffef46f0190bec5</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>kpbOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KReloadNetworkDlg</receiver>
+ <slot>close()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kdialog.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kroutinginfo.cpp b/knetworkconf/knetworkconf/kroutinginfo.cpp
new file mode 100644
index 0000000..ebf8380
--- /dev/null
+++ b/knetworkconf/knetworkconf/kroutinginfo.cpp
@@ -0,0 +1,60 @@
+/***************************************************************************
+ kroutinginfo.cpp - description
+ -------------------
+ begin : Mon Mar 3 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : juancho@linuxmail.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kroutinginfo.h"
+
+KRoutingInfo::KRoutingInfo(){
+}
+KRoutingInfo::~KRoutingInfo(){
+}
+QString KRoutingInfo::isNetworkingEnabled(){
+ return networking;
+}
+QString KRoutingInfo::isForwardIPv4Enabled(){
+ return forwardIPv4;
+}
+QString KRoutingInfo::getHostName(){
+ return hostName;
+}
+QString KRoutingInfo::getDomainName(){
+ return domainName;
+}
+QString KRoutingInfo::getGateway(){
+ return gateway;
+}
+QString KRoutingInfo::getGatewayDevice(){
+ return gatewayDevice;
+}
+void KRoutingInfo::setNetworkingEnabled(const QString &networking){
+ KRoutingInfo::networking = networking;
+}
+void KRoutingInfo::setForwardIPv4Enabled(const QString &forwardIPv4){
+ KRoutingInfo::forwardIPv4 = forwardIPv4;
+}
+void KRoutingInfo::setHostName(const QString &hostName){
+ KRoutingInfo::hostName = hostName;
+}
+void KRoutingInfo::setDomainName(const QString &domainName){
+ KRoutingInfo::domainName = domainName;
+}
+void KRoutingInfo::setGateway(const QString &gateway){
+ KRoutingInfo::gateway = gateway;
+}
+void KRoutingInfo::setGatewayDevice(const QString &gatewayDevice){
+ KRoutingInfo::gatewayDevice = gatewayDevice;
+}
+
diff --git a/knetworkconf/knetworkconf/kroutinginfo.h b/knetworkconf/knetworkconf/kroutinginfo.h
new file mode 100644
index 0000000..1092f88
--- /dev/null
+++ b/knetworkconf/knetworkconf/kroutinginfo.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ kroutinginfo.h - description
+ -------------------
+ begin : Mon Mar 3 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : juancho@linuxmail.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KROUTINGINFO_H
+#define KROUTINGINFO_H
+
+#include <qstring.h>
+
+
+/**Has all the routing info of the machine, like default gateway, default gateway device,
+ routes to other hosts and networks, etc.
+
+ *@author Juan Luis Baptiste
+ */
+
+class KRoutingInfo {
+public:
+ KRoutingInfo();
+ ~KRoutingInfo();
+private: // Private attributes
+ QString networking;
+ QString forwardIPv4;
+ QString hostName;
+ QString domainName;
+ QString gateway;
+ QString gatewayDevice;
+
+public: // Public attributes
+ QString isNetworkingEnabled();
+ QString isForwardIPv4Enabled();
+ QString getHostName();
+ QString getGatewayDevice();
+ QString getGateway();
+ QString getDomainName();
+ void setNetworkingEnabled(const QString &networking);
+ void setForwardIPv4Enabled(const QString &forwardIPv4);
+ void setHostName(const QString &hostName);
+ void setDomainName(const QString &domainName);
+ void setGateway(const QString &gateway);
+ void setGatewayDevice(const QString &gatewayDevice);
+
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/kselectdistrodlg.ui b/knetworkconf/knetworkconf/kselectdistrodlg.ui
new file mode 100644
index 0000000..4bed8ea
--- /dev/null
+++ b/knetworkconf/knetworkconf/kselectdistrodlg.ui
@@ -0,0 +1,142 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSelectDistroDlg</class>
+<widget class="KDialog">
+ <property name="name">
+ <cstring>KSelectDistroDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>372</width>
+ <height>499</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Unsupported Platform</string>
+ </property>
+ <property name="icon">
+ <pixmap>image0</pixmap>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListBox" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>klbDistroList</cstring>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>kpbOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="3" column="3">
+ <property name="name">
+ <cstring>kpbCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>cbAskAgain</cstring>
+ </property>
+ <property name="text">
+ <string>Do not ask again</string>
+ </property>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>130</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;font size="+1"&gt;&lt;p align="center"&gt;&lt;b&gt;Your Platform is Not Supported&lt;/b&gt;&lt;/p&gt;&lt;/font&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>You may choose one of the following supported platforms if you are &lt;b&gt;sure&lt;/b&gt; your platform behaves the same as the chosen one. Please be sure, because your current network configuration could be damaged.</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<images>
+ <image name="image0">
+ <data format="PNG" length="983">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000039e4944415418959595cd6b1d5518c67f934e9a776452cf40948e74915b2af6aa2897a6602a2e6e6a5d74e3dafe03d28f8d0b71292eba312808052964e34297154442119b2e44234aaca8ed151332c586ccd85cef1cc9e8bcd6938e8b9b7b136b6e4b5e18e683f33ef39ce77738c7abaa8a9dcaf33c2ebc7761e2e48993171179aaf75d7c50b7fd2e80822f557a3399bff4f1a557cf4f9f5ff47754dd2c33660e8931b50fafa6233a1c1019417c41a42baa4e290b8bae433caa4c3d1d3f89cf38707f6141867078577fb6941210858a31029b5d5a802d20cf721ae3c2e4213c600ff4870ca8615094b2005be44084aaed3bc6416e736ca1d876371175ca8385bbaeb13627d5a0eb3214284000ab8a1690decaa99b685be60f10ee0d1209d0a224b742a08a88609d82425e28b89e5301d7edf507d15ffd7515750c810ecfbc5627d8a42fbe30f753c247f342aa10f942eec088e9c6b369d587ddd39f3c1c33fb6302614ceee75da7b209747bc6bba53f7518ce4e8219035cb4a1ae048767dbd99f38fedaca7897f44b85bcc89150aa74256d6769f6a53a4d739bb7922469010cfd8f7e66b1ed9cbc2849db25a52d49db39d676e9ab2aea203631511879c7268e3ddc6834464a5b7e3077756ee6ec99b3edad28764bdf29eaba20adda3daa1a59b57beb8fd7ef1c7fe978b515850ff88288101b4142c184d29f8b55bd977e952c267fb4165bd7b4d0ebc952f2496bb1f5c3ece5d9fec6d35bc71e289111ac0fb18990b03b13754aa0c1bdf437d276ba9265f67d33666e34269aa5d95f9366f364f1fa1be7b61cdb759b0baccf9caeed5347d5fd1143aadd455faa828baa3e7d9beda9d7eb4fc4fbf55d09644dc2e0ae647c7eedfbefde02cabe70b2947c3b373cf7b6f85257a7e3b503b51722138d0294ae449d56c9cde4efec56f67be94ac17157550b2d744d9d2e4b68ee264baddfec9afdef1ebcf0d58277ea9553233317679acb3796bfe8dceedce9ac76aaceed4ed559ed54cbbf2c579dd54eb9f0cdc2a7d3e7a78f365f6c8e5cf9ec8a075055d58ed710c0916347aac644e31f09855cf31155f5d429aa8a557b5ffa83cadbfe72e6f499d1da78edb9c8442f9bd03c1bc5d133a52d35cbb3ebdbe87f3d7b7976bdd733f004ea3d4cbf333314c0a366bf79c86676b474fafcd489e6b9f9f9f9b56429b960c6cc8dda817a99acdc5c179f768ffe20e1feb669db69101c88df8c1f898f9ad16838f0794cc04c361a074d680e0ea23fa8fac2c94ab291173649b3741fb0577c10118b036b6de7bef477a87f018b9f681dd4db618a0000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>kpbOk</sender>
+ <signal>clicked()</signal>
+ <receiver>KSelectDistroDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>kpbCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>KSelectDistroDlg</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>klbDistroList</sender>
+ <signal>doubleClicked(QListBoxItem*)</signal>
+ <receiver>KSelectDistroDlg</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>exitSlot()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kdialog.h</includehint>
+ <includehint>klistbox.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/knetworkconf/knetworkconf/kwirelessinterface.cpp b/knetworkconf/knetworkconf/kwirelessinterface.cpp
new file mode 100644
index 0000000..c24d237
--- /dev/null
+++ b/knetworkconf/knetworkconf/kwirelessinterface.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ kwirelessinterface - description
+ -------------------
+ begin : Thu oct 21 2004
+ copyright : (C) 2004 by Juan Luis Baptiste
+ email : juan.baptiste@kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 "kwirelessinterface.h"
+
+KWirelessInterface::KWirelessInterface()
+ : KNetworkInterface()
+{
+}
+
+KWirelessInterface::~KWirelessInterface()
+{
+}
+
+QString KWirelessInterface::getEssid()
+{
+ return essid;
+}
+
+QString KWirelessInterface::getWepKey()
+{
+ return wepKey;
+}
+
+void KWirelessInterface::setWepKey(QString newKey)
+{
+ wepKey = newKey;
+}
+void KWirelessInterface::setEssid(QString newEssid)
+{
+ essid = newEssid;
+}
+
+QString KWirelessInterface::getKeyType()
+{
+ return keyType;
+}
+
+void KWirelessInterface::setKeyType(QString type)
+{
+ keyType = type;
+}
diff --git a/knetworkconf/knetworkconf/kwirelessinterface.h b/knetworkconf/knetworkconf/kwirelessinterface.h
new file mode 100644
index 0000000..982d68b
--- /dev/null
+++ b/knetworkconf/knetworkconf/kwirelessinterface.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ kwirelessinterface - description
+ -------------------
+ begin : jue oct 21 2004
+ copyright : (C) 2004 by Juan Luis Baptiste
+ email : juan.baptiste@kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under 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 KWIRELESSINTERFACE_H
+#define KWIRELESSINTERFACE_H
+
+#include <knetworkinterface.h>
+#include <qstring.h>
+
+/**
+Class that represents a wireless network interface. It inherits from KNetworkInterface.
+
+@author Juan Luis Baptiste
+*/
+class KWirelessInterface : public KNetworkInterface
+{
+ public:
+ KWirelessInterface();
+
+ ~KWirelessInterface();
+
+ QString getEssid();
+ QString getWepKey();
+ void setEssid(QString newEssid);
+ void setWepKey(QString newKey);
+ QString getKeyType();
+ void setKeyType(QString type);
+
+ private:
+ QString essid;
+ QString wepKey;
+ QString keyType;
+};
+
+#endif
diff --git a/knetworkconf/knetworkconf/main.cpp b/knetworkconf/knetworkconf/main.cpp
new file mode 100644
index 0000000..336d33e
--- /dev/null
+++ b/knetworkconf/knetworkconf/main.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Sun Jan 12 00:54:19 UTC 2003
+ copyright : (C) 2003 by Juan Luis Baptiste
+ email : jbaptiste@merlinux.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include <unistd.h>
+#include <sys/types.h>
+#include <kmessagebox.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kuniqueapplication.h>
+#include <dcopclient.h>
+#include <kglobal.h>
+#include <kgenericfactory.h>
+
+//#include "knetworkconf.h"
+#include "knetworkconfmodule.h"
+#include "version.h"
+
+
+static KCmdLineOptions options[] =
+{
+ { 0, 0, 0 }
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+/*typedef KGenericFactory<KNetworkConfModule> KDEDFactory;
+K_EXPORT_COMPONENT_FACTORY( knetworkconfmodule, KDEDFactory( "kcm_knetworkconfmodule" ) ); */
+
+extern "C"
+{
+ KDE_EXPORT KCModule *create_knetworkconfmodule(QWidget *parent, const char *name)
+ {
+ KGlobal::locale()->insertCatalogue("knetworkconf");
+ return new KNetworkConfModule(parent, name);
+ }
+}
+
diff --git a/knetworkconf/knetworkconf/version.h b/knetworkconf/knetworkconf/version.h
new file mode 100644
index 0000000..cfa0b7d
--- /dev/null
+++ b/knetworkconf/knetworkconf/version.h
@@ -0,0 +1,6 @@
+#ifndef KNETWORKVERSION_H
+#define KNETWORKVERSION_H
+
+static const char *description =
+ I18N_NOOP("KNetworkConf - A KDE Control Center module to configure TCP/IP settings.");
+#endif
diff --git a/knetworkconf/pasosRelease.txt b/knetworkconf/pasosRelease.txt
new file mode 100644
index 0000000..9abaa5a
--- /dev/null
+++ b/knetworkconf/pasosRelease.txt
@@ -0,0 +1,14 @@
+PASOS PARA HACER RELEASE DE KNETWORKCONF:
+
+1. Actualizar archivos README, LEAME y ChangeLog
+2. Generar distribucion .bz2
+3. Etiquetar CVS con la version actual
+4. Generar paquetes (rpm y deb)
+5. Subir archivos a sf
+6. Subir rpms a contribs de Mandrake
+7. Actualizar la pagina
+8. Colocar noticia en la pagina de Merlinux
+9. Hacer anuncio en kde-apps.org y freshmeat.net
+10. Hacer anuncios en listas de correo:
+- Merlinux, Colibri y Linux Anuncio en espaniol
+- kde-announce, knetworkconf-announce, kde-debian en ingles \ No newline at end of file
diff --git a/knetworkconf/pixmaps/Makefile.am b/knetworkconf/pixmaps/Makefile.am
new file mode 100644
index 0000000..250a3a7
--- /dev/null
+++ b/knetworkconf/pixmaps/Makefile.am
@@ -0,0 +1,7 @@
+iconsdir = $(kde_datadir)/knetworkconf/pixmaps/
+icons_DATA = ark.png debian.png mandriva.png blackpanther.png pld.png \
+ redhat.png suse.png turbolinux.png conectiva.png fedora.png openna.png \
+ slackware.png freebsd.png gentoo.png vine.png kubuntu.png yoper.png rpath.png
+
+# Install the icons into the global KDE directories
+KDE_ICON = network_connected_lan_knc network_disconnected_lan network_disconnected_wlan network_traffic_wlan
diff --git a/knetworkconf/pixmaps/ark.png b/knetworkconf/pixmaps/ark.png
new file mode 100644
index 0000000..efc7bb9
--- /dev/null
+++ b/knetworkconf/pixmaps/ark.png
Binary files differ
diff --git a/knetworkconf/pixmaps/blackpanther.png b/knetworkconf/pixmaps/blackpanther.png
new file mode 100644
index 0000000..1028639
--- /dev/null
+++ b/knetworkconf/pixmaps/blackpanther.png
Binary files differ
diff --git a/knetworkconf/pixmaps/conectiva.png b/knetworkconf/pixmaps/conectiva.png
new file mode 100644
index 0000000..3452ee2
--- /dev/null
+++ b/knetworkconf/pixmaps/conectiva.png
Binary files differ
diff --git a/knetworkconf/pixmaps/debian.png b/knetworkconf/pixmaps/debian.png
new file mode 100644
index 0000000..130a9ea
--- /dev/null
+++ b/knetworkconf/pixmaps/debian.png
Binary files differ
diff --git a/knetworkconf/pixmaps/fedora.png b/knetworkconf/pixmaps/fedora.png
new file mode 100644
index 0000000..651b92c
--- /dev/null
+++ b/knetworkconf/pixmaps/fedora.png
Binary files differ
diff --git a/knetworkconf/pixmaps/freebsd.png b/knetworkconf/pixmaps/freebsd.png
new file mode 100644
index 0000000..d91e38e
--- /dev/null
+++ b/knetworkconf/pixmaps/freebsd.png
Binary files differ
diff --git a/knetworkconf/pixmaps/gentoo.png b/knetworkconf/pixmaps/gentoo.png
new file mode 100644
index 0000000..e283d92
--- /dev/null
+++ b/knetworkconf/pixmaps/gentoo.png
Binary files differ
diff --git a/knetworkconf/pixmaps/hi22-action-network_connected_lan_knc.png b/knetworkconf/pixmaps/hi22-action-network_connected_lan_knc.png
new file mode 100644
index 0000000..6fb9882
--- /dev/null
+++ b/knetworkconf/pixmaps/hi22-action-network_connected_lan_knc.png
Binary files differ
diff --git a/knetworkconf/pixmaps/hi22-action-network_disconnected_lan.png b/knetworkconf/pixmaps/hi22-action-network_disconnected_lan.png
new file mode 100644
index 0000000..90a2d69
--- /dev/null
+++ b/knetworkconf/pixmaps/hi22-action-network_disconnected_lan.png
Binary files differ
diff --git a/knetworkconf/pixmaps/hi22-action-network_disconnected_wlan.png b/knetworkconf/pixmaps/hi22-action-network_disconnected_wlan.png
new file mode 100644
index 0000000..6791d49
--- /dev/null
+++ b/knetworkconf/pixmaps/hi22-action-network_disconnected_wlan.png
Binary files differ
diff --git a/knetworkconf/pixmaps/hi22-action-network_traffic_wlan.png b/knetworkconf/pixmaps/hi22-action-network_traffic_wlan.png
new file mode 100644
index 0000000..b912cd3
--- /dev/null
+++ b/knetworkconf/pixmaps/hi22-action-network_traffic_wlan.png
Binary files differ
diff --git a/knetworkconf/pixmaps/kubuntu.png b/knetworkconf/pixmaps/kubuntu.png
new file mode 100644
index 0000000..f9a39ad
--- /dev/null
+++ b/knetworkconf/pixmaps/kubuntu.png
Binary files differ
diff --git a/knetworkconf/pixmaps/mandriva.png b/knetworkconf/pixmaps/mandriva.png
new file mode 100644
index 0000000..96af9a4
--- /dev/null
+++ b/knetworkconf/pixmaps/mandriva.png
Binary files differ
diff --git a/knetworkconf/pixmaps/openna.png b/knetworkconf/pixmaps/openna.png
new file mode 100644
index 0000000..d7873a4
--- /dev/null
+++ b/knetworkconf/pixmaps/openna.png
Binary files differ
diff --git a/knetworkconf/pixmaps/pld.png b/knetworkconf/pixmaps/pld.png
new file mode 100644
index 0000000..e6a9018
--- /dev/null
+++ b/knetworkconf/pixmaps/pld.png
Binary files differ
diff --git a/knetworkconf/pixmaps/redhat.png b/knetworkconf/pixmaps/redhat.png
new file mode 100644
index 0000000..bb2b3bd
--- /dev/null
+++ b/knetworkconf/pixmaps/redhat.png
Binary files differ
diff --git a/knetworkconf/pixmaps/rpath.png b/knetworkconf/pixmaps/rpath.png
new file mode 100644
index 0000000..a440015
--- /dev/null
+++ b/knetworkconf/pixmaps/rpath.png
Binary files differ
diff --git a/knetworkconf/pixmaps/slackware.png b/knetworkconf/pixmaps/slackware.png
new file mode 100644
index 0000000..c095571
--- /dev/null
+++ b/knetworkconf/pixmaps/slackware.png
Binary files differ
diff --git a/knetworkconf/pixmaps/suse.png b/knetworkconf/pixmaps/suse.png
new file mode 100644
index 0000000..6cf9f22
--- /dev/null
+++ b/knetworkconf/pixmaps/suse.png
Binary files differ
diff --git a/knetworkconf/pixmaps/turbolinux.png b/knetworkconf/pixmaps/turbolinux.png
new file mode 100644
index 0000000..91d8ce4
--- /dev/null
+++ b/knetworkconf/pixmaps/turbolinux.png
Binary files differ
diff --git a/knetworkconf/pixmaps/vine.png b/knetworkconf/pixmaps/vine.png
new file mode 100644
index 0000000..5c230b7
--- /dev/null
+++ b/knetworkconf/pixmaps/vine.png
Binary files differ
diff --git a/knetworkconf/pixmaps/yoper.png b/knetworkconf/pixmaps/yoper.png
new file mode 100644
index 0000000..f9ce326
--- /dev/null
+++ b/knetworkconf/pixmaps/yoper.png
Binary files differ
diff --git a/knetworkconf/update_backends.sh b/knetworkconf/update_backends.sh
new file mode 100755
index 0000000..9b77d13
--- /dev/null
+++ b/knetworkconf/update_backends.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+echo 'Network backend updating script of KNetworkConf'
+echo
+
+if [ $# -eq 0 ]
+then
+ echo "Use: $0 src_path dest_path"
+ echo
+ exit 1
+fi
+
+if [ "$1" = "" ]
+then
+ echo 'You have to specify the source directory of the new scripts'
+ echo
+ exit 1
+elif [ "$2" = "" ]
+then
+ echo 'You have to specify the destination directory for the new scripts'
+ echo
+ exit 1
+fi
+
+if [ ! -d $1 ]
+then
+ echo "$1 Isn't a directory"
+ echo
+ exit 1
+elif [ ! -d $2 ]
+then
+ echo "$2 Isn't a directory"
+ echo
+ exit 1
+fi
+
+diractual=`pwd`
+cd $1;
+cp -f AUTHORS debug.pl.in file.pl.in general.pl.in guess_system.sh mkinstalldirs network-conf.in network.pl.in NEWS parse.pl.in platform.pl.in README replace.pl.in report.pl.in service-list.pl.in service.pl.in system-tools-backends.pc.in type1inst util.pl.in xml.pl.in process.pl.in $2
+
+echo
+echo 'Ready, dont forget to check configure.in.in or Makefile.am to see if they need further updating.'
+echo
diff --git a/kpackage/CHANGES b/kpackage/CHANGES
new file mode 100644
index 0000000..e9a8fb2
--- /dev/null
+++ b/kpackage/CHANGES
@@ -0,0 +1,282 @@
+kpackage-3.5
+------------
+Rewrite kpPty.cpp, now prompt for passwords
+Fix reading and writing APT sources.list
+Allow using sudo for priveleged commands
+Add allow-unathenticated option for debian apt
+Change package info to use QMap
+Convert bsd package handling to remove procbuf
+
+kpackage-3.0
+------------
+RPM will now prompt for root password if not root
+Integrate package type panel
+Fix up Debian Remote Host stuff and add GUI
+Strip surrounding spaces from search stings
+Add wait cursor for find file
+Fix slackware install Divide by Zero <divide@priv.onet.pl>
+
+kpackage-2.1
+------------
+New popup for installing/uninstalling with list of
+ packages and integrated terminal window
+Use PTY's for talking to programs
+Debain APT handling (unfinished)
+RPM 4 support - bero
+Add options panel for which package handlers to use
+Option for using either ssh or su for calling privileged programs
+add --remote option
+Ignore Debian packages with only conf-files installed
+
+kpackage-2.0
+------------
+Only QT2/KDE2
+Only RPM3
+Replace multiple select mode with Shift and
+ Control left-mouse-buttone
+Use HTML widget for package properties display
+Links for pointing to dependency packages
+Debian distribution site handling
+Change toolbar to use XML config, add "configure toolbar" option
+Use tab bar for selecting package display
+Don't write empty entries to config file
+Add subdirs Matthias Mohr <MMohr@SysDesign-EDV.de>
+
+kpackage-1.3.10
+---------------
+Use "rpm --version" for finding RPM version in configure
+Fix for RPM 3.0.3 and 2.5
+
+kpackage-1.3.9.2
+----------------
+Fixes for compiling with g++ 2.95.2
+
+kpackage-1.3.9.1
+----------------
+Fix installing docs with some versions of RPM
+Fix RPM nodeps uninstall flag - Torsten Klein <berlinux@gmx.net>
+Add some null pointer checks - Ilya Stepanov <ilya@tranzit.donetsk.ua>
+
+kpackage-1.3.9
+--------------
+Add configure option to force RPM compile
+Fix rpm compile for debian potato
+Fix kiss and kpkg not found error message on find file
+Czech translation update - Miroslav Flidr <flidr@kky.zcu.cz>
+
+kpackage-1.3.8.1
+----------------
+Fix getuid() check for rpm error messages
+Update Romanian translations - Claudiu Costin <claudiuc@calderon.pcnet.ro>
+
+kpackage-1.3.8
+--------------
+Fix misidentification of package type
+
+kpackage-1.3.7
+--------------
+Full handling of KISS packages
+Korean stuff in kpackage.spec - KIM KyungHeon <tody@tody.sarang.net>
+More Romanian translations and i18n fixes - Claudiu Costin <claudiuc@calderon.pcnet.ro>
+
+kpackage-1.3.6
+--------------
+Romanian translations - Claudiu Costin <claudiuc@calderon.pcnet.ro>
+
+kpackage-1.3.5
+--------------
+Compile with RPM 3.0, 3.0.1, and the latest 3.0.2
+
+kpackage-1.3.4
+--------------
+Compile with RPM 3.0.2
+
+kpackage-1.3.3
+-------------
+Polish translation
+Warning about requiring popt package
+
+kpackage-1.3.2
+-------------
+Fix upgrade flag with RPM
+Fix "need root" error messages with rpm
+Fix installing index-4.html
+
+kpackage-1.3.1
+-------------
+Another try at finding a define that distinguishes rpm3.0
+
+kpackage-1.3
+------------
+FreeBSD package support - Alex Hayward <xelah@ferret.lmh.ox.ac.uk>
+Work with QT2 and latest KDE CVS
+Work with RPM3.0
+Work with glibc2.1
+RPM 3.0 fixes - prigaux@mandrakesoft.com
+Fix rpm verify error messages
+Fix changing package when file selected
+
+kpackage-1.2.1
+--------------
+Fix dependency checking problem for uninstalling RPM packages
+
+kpackage-1.2
+------------
+Use KAccelMenu class to simplify configuring
+ accelerators and allow accelerators to be set by typing the
+ key when the menu item is selected. The ' character is needed
+ to precede the keys. (with post KDE1.1 libraries)
+Add a Keys diaglog as another way of setting
+ accelerators(with post KDE1.1 libraries)
+Add handling of KISS packages
+Add handling of SLACKWARE packages
+Move common functionality for package types into base class
+Replace QString mid with right where appropriate
+Set filter on KFileDialog properly
+Clean up procbuf class
+Compiles with QT2.0 (even works in parts)
+
+kpackage-1.1.3
+--------------
+Give Icons transparent backgrounds (cooper font)
+Russian tranlation update - Serguei Koubouchine <ksi@ksi-linux.com>
+Danish translation - Steen Rabol <rabol@get2net.dk>
+Building update - Stefan Siegel <siegel@informatik.uni-kl.de>
+
+kpackage-1.1.2
+--------------
+Fix duplicated folder problem
+Fix installing English documentation
+
+kpackage-1.1.1
+--------------
+Display file size in package tree if don't have installed size
+Update config to refer to qt 1.4
+Handle RPM serial version number, DEB num:
+fix show tool bar menu item
+Hungarian translations
+
+kpackage-1.1.01
+---------------
+Try to fix compile problem with old gcc
+
+kpackage-1.1
+------------
+Requires QT 1.4
+Use QTreeView, much faster, allows columns, shows version info
+Add multiple selection mode for installing and uninstalling
+ mulitiple packages at the same time
+Speed up list inserting significantly by not doing "insort"
+Speed up exiting by not deleting objects
+Menu items for expanding and collapsing package tree
+Menu item for clearing selections
+Remove quit from tool bar
+Fix for rpmlib 2.5, use supplied rpmlib.h
+Fix specifying a file in panel for reading directories
+Fix clearing directory cache with directories changed
+Fix comparing packge versions
+
+kpackage-1.0.01
+---------------
+German tranlations - Dirk Moebius <moebius@informatik.uni-bonn.de>
+
+kpackage-1.0
+---------------
+Handle uninstalled packages as well as installed
+Cache non-local uninstalled package directories in .kpackage
+Cache packages in .kpackage directory under their names
+Options dialog for package directory caching
+Options dialog for package caching
+Options dialog for display of packages
+Make options dialog tabbed
+Put draggable seperator in main window
+Sort package properties list
+Add Russian translation (Serguei Koubouchin)
+Use standard color map for icons
+Fix Terminate string in KpMsg
+Fix error message for package file no found
+Fix kfm file fetching when file not found
+Fix open of local file with file select dialog
+Fix package properties display when scroll bar disappears
+Fix non file URLs from file open dialog
+Fix zlib linking problem (maybe)
+
+kpackage-0.9.02
+---------------
+Add French translation
+Fix segfault with Options...
+Fix "Check Dependencies" with rpm Uninstall
+Change icons on tree display
+
+kpackage-0.9.01
+---------------
+Add Spanish translation
+Fix compiling without RPM
+
+kpackage-0.9
+------------
+Add searching for package that includes a file (dialog with DND)
+Use kfile file selector
+Only create file list when accessed
+Don't reload package tree after add or delete
+Add toolbar (prevent toolbar envy)
+Add options menu (option for turning off file verification)
+Update automake,autoconf,make stuff
+Fix some fd and memory leaks
+Fix mini-icon
+Save more state on exit
+Fix color of description panel
+Add more internationalisation
+Put more stuff through translation
+
+kpackage-0.8
+--------------
+Display rpm dependency problems in GUI popup
+Display partially installed debian packages
+Update icons
+Don't rebuild package tree if not needed
+Fix other rpm file descriptor leakage
+Try to put tmp files into home directory (/tmp has security problems)
+Add internationalisation
+ Portuguese: Pedro Morais <pmmm@camoes.rnl.ist.utl.pt>
+ Slovakian: Juraj Bednar <bednar@isternet.sk>
+Allow for dropping multiple files
+Add folder pixmap for groups of packages
+Fix searching not to loose package sizes
+Change docs to KDE look
+
+kpackage-0.7
+--------------
+Restructure internals to implement debian and RPM handling as
+ subclasses and allow for adding other types
+Compile without RPM support if the correct libraries aren't available
+Add find function for searching for installed packages
+Use ktreeview widget
+Change rpm errors from STDERR to error popups
+Different color tree icons for deb and rpm
+Fix to work with newer kprocess
+Fix fd leak
+Fix some memory leaks
+
+kpackage-0.6.2
+--------------
+Fix installing .DEB packages with large number of files
+Make handling of libraries more intelligent
+
+kpackage-0.6
+------------
+Fix up pixmaps, add file verify for debian
+add recently opened file menu
+selecting file in file list opens it
+speed up long file list
+fix handling non-file URLs
+Fix crash when no debian installed
+Recognise old Debian format
+
+kpackage-0.5
+------------
+Add handling DEB packages
+Fix problem with loosing text lines in description
+Update for session handling
+Use kfm for network io
+Add open menu item
diff --git a/kpackage/Makefile.am b/kpackage/Makefile.am
new file mode 100644
index 0000000..4f2791f
--- /dev/null
+++ b/kpackage/Makefile.am
@@ -0,0 +1,36 @@
+
+xdg_apps_DATA = kpackage.desktop
+
+# claim, which subdirectories you want to install
+SUBDIRS = pics toolbar icon
+
+bin_PROGRAMS = kpackage
+
+# Which sources should be compiled for kpackage.
+kpackage_SOURCES = kpackage.cpp managementWidget.cpp packageDisplay.cpp \
+ packageProperties.cpp findf.cpp search.cpp \
+ options.cpp pkgOptions.cpp \
+ packageInfo.cpp cache.cpp main.cpp utils.cpp kio.cpp \
+ debInterface.cpp debDpkgInterface.cpp debAptInterface.cpp \
+ updateLoc.cpp procbuf.cpp kplview.cpp \
+ pkgInterface.cpp rpmInterface.cpp kissInterface.cpp \
+ slackInterface.cpp fbsdInterface.cpp gentooInterface.cpp \
+ kpPty.cpp kpTerm.cpp
+
+kpackage_METASOURCES = AUTO
+
+# the library search path
+kpackage_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+# the libraries to link against. Be aware of the order. First the libraries,
+# that depend on the following ones.
+kpackage_LDADD = $(LIB_KFILE) $(LIBINTL) $(LIBZ) $(LIBUTEMPTER)
+
+INCLUDES = $(all_includes)
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kpackage.pot
+
+rcdir = $(kde_datadir)/kpackage
+rc_DATA = kpackageui.rc
+
diff --git a/kpackage/README b/kpackage/README
new file mode 100644
index 0000000..9a843dd
--- /dev/null
+++ b/kpackage/README
@@ -0,0 +1,11 @@
+Kpackage handles RPM, Debian and various other packages, it is used
+for displaying currently installed packages, uninstalling
+them and installing new ones.
+
+For kpackage to work correctly with RPM packages the RPM database
+must be initialised. If typing `rpm -qa' gives an error about
+`unable to open....` then try `rpm --rebuilddb'.
+
+
+Toivo Pedaste (toivo@ucs.uwa.edu.au)
+
diff --git a/kpackage/cache.cpp b/kpackage/cache.cpp
new file mode 100644
index 0000000..1877728
--- /dev/null
+++ b/kpackage/cache.cpp
@@ -0,0 +1,229 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "kpackage.h"
+#include "options.h"
+#include "cache.h"
+#include <klocale.h>
+#include <kdebug.h>
+
+extern Opts *opts;
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+cacheObj::cacheObj(const QString &Pbase, const QString &Plocation, const QString &PcacheFile,
+ const QString &Poption, bool Psubdirs)
+{
+ base = Pbase;
+ location = Plocation;
+ cacheFile = PcacheFile;
+ option = Poption;
+ subdirs = Psubdirs;
+}
+
+cacheObj::~cacheObj()
+{}
+
+QString cacheObj::PDir()
+{
+ struct stat buf;
+ stat(QFile::encodeName(QDir::homeDirPath()), &buf);
+
+ QString tmpd = opts->CacheDir ;
+
+ QDir d(tmpd);
+ if (!d.exists()) {
+ if (!d.mkdir(tmpd)) {
+ KpMsgE(i18n("Cannot create folder %1").arg(tmpd),TRUE);
+ tmpd = "";
+ } else {
+ chown(QFile::encodeName(tmpd),buf.st_uid,buf.st_gid);
+ }
+ }
+ return tmpd;
+}
+
+QString cacheObj::CDir()
+{
+ QString tmpd = PDir();
+ if (!tmpd.isEmpty()) {
+ struct stat buf;
+ stat(QFile::encodeName(tmpd),&buf);
+
+ tmpd += "dir/";
+
+ QDir d(tmpd);
+ if (!d.exists()) {
+ if (!d.mkdir(tmpd)) {
+ KpMsgE(i18n("Cannot create folder %1").arg(tmpd),TRUE);
+ tmpd = "";
+ } else {
+ chown(QFile::encodeName(tmpd),buf.st_uid,buf.st_gid);
+ }
+ }
+ }
+ return tmpd;
+}
+
+int cacheObj::newDCache(const QString &url, const QString &fn, QString &fname) {
+
+ KURL u(url);
+ if ( !u.isValid() ) {
+ KpMsgE(i18n("Malformed URL: %1").arg(url),TRUE);
+ return -1;
+ }
+
+ QString tmpd = cacheObj::CDir();
+ if (tmpd.isEmpty()) {
+ return -1;
+ } else {
+ if (u.protocol() == "file") {
+ fname = u.path();
+ return 0;
+ }
+
+ fname = tmpd + fn;
+
+ if (opts->DCache == Opts::NEVER) {
+ return 1;
+ }
+
+ QFileInfo f(fname);
+
+ if (f.exists() && f.size() > 0) {
+ return 0;;
+ } else {
+ if (f.size() == 0)
+ rmDCache(fname);
+ return 1;
+ }
+ }
+}
+
+void cacheObj::rmDCache(const QString &fn) {
+ QString tmpd = cacheObj::CDir();
+ tmpd += fn;
+
+ if (!tmpd.isEmpty()) {
+ unlink(QFile::encodeName(tmpd));
+ }
+}
+
+void cacheObj::clearDCache() {
+ QString tmpd = cacheObj::CDir();
+
+ if (!tmpd.isEmpty()) {
+ QDir d(tmpd);
+ CacheList cl(d) ;
+ for (CacheList::iterator it = cl.begin() ; it != cl.end() ; ++it) {
+ QString s = tmpd;
+ s += *it;
+ unlink(QFile::encodeName(s));
+ }
+ unlink(QFile::encodeName(cl.getCLFileName())) ; // also delete the kpackage_cachelist file
+ }
+}
+
+void cacheObj::clearPCache() {
+ QString tmpd = cacheObj::PDir();
+
+ if (!tmpd.isEmpty()) {
+ QDir d(tmpd);
+ CacheList cl(d);
+ for (CacheList::iterator it = cl.begin() ; it != cl.end() ; ++it) {
+ QString s = tmpd ;
+ s += *it;
+ unlink(QFile::encodeName(s));
+ }
+ unlink(QFile::encodeName(cl.getCLFileName())) ; // also delete the kpackage_cachelist file
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+LcacheObj::LcacheObj()
+{
+ setAutoDelete(TRUE);
+}
+
+LcacheObj::~LcacheObj()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+CacheList::CacheList (const QDir& dir)
+{
+ CLFile.setName (dir.path() + "/kpackage_cachelist") ;
+ read() ;
+}
+
+void CacheList::read ()
+{
+ kdDebug() << "reading cachelist: " << CLFile.name() << "\n" ;
+ if (CLFile.open (IO_ReadOnly)) {
+ QTextStream stream (&CLFile) ;
+ QString line ;
+ while (!stream.eof()) {
+ line = stream.readLine() ;
+ if (line[0] != '#') { // not a comment
+ append (line) ; // to this QStringList
+ }
+ }
+ CLFile.close() ;
+ }
+ else {
+ // kdDebug() << "could not open cachelist " << CLFile.name() << "!\n" ;
+ }
+}
+
+void CacheList::write ()
+{
+ kdDebug() << "writing cachelist: " << CLFile.name() << "\n" ;
+ if (CLFile.open (IO_WriteOnly)) {
+ QTextStream stream (&CLFile) ;
+ stream << "# This file contains a list of files that have been cached in this folder.\n" ;
+ stream << "# Please only delete this if you want kpackage to forget what it has cached.\n" ;
+ for (QStringList::iterator it = begin() ; it != end() ; ++it) {
+ stream << *it << "\n" ;
+ }
+ CLFile.close() ;
+ }
+ else {
+ kdDebug() << "could not open cachelist " << CLFile.name() << "!\n" ;
+ }
+}
+
+QString CacheList::getCLFileName () const
+{
+ return CLFile.name() ;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
diff --git a/kpackage/cache.h b/kpackage/cache.h
new file mode 100644
index 0000000..02dc830
--- /dev/null
+++ b/kpackage/cache.h
@@ -0,0 +1,114 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#ifndef CACHE_H
+#define CACHE_H
+
+#include <qdir.h>
+#include <qptrlist.h>
+
+#include <kurl.h>
+
+#include "../config.h"
+#include "packageInfo.h"
+
+class Locations;
+class LcacheObj;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class cacheObj
+{
+public:
+ QString base;
+ QString location;
+ QString cacheFile;
+ QString option;
+ bool subdirs;
+
+ cacheObj(const QString &Pbase, const QString &Plocation, const QString &PcacheFile, const QString &Poption = QString::null, bool Psubdirs = FALSE);
+ ~cacheObj();
+
+ static QString PDir();
+ // return path of kpackage cache directory
+
+ static QString CDir();
+ // return path of kpackage directory cache
+
+ static int newDCache(const QString &url, const QString &fn, QString &fname);
+ // Checks directory cache
+ // -1 Cann't get cache file name
+ // 0 Cache file exists
+ // 1 Cache file doesn't exit
+ // fname return file name
+
+ static void rmDCache(const QString &fn);
+
+ static void clearDCache();
+ static void clearPCache();
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class LcacheObj: public QPtrList<cacheObj>
+{
+public:
+ LcacheObj();
+ ~LcacheObj();
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @short the list of cached files in a directory stored in the file "kpackage_cachelist"
+ **/
+class CacheList : public QStringList
+{
+public:
+ /**
+ * create (and read) a cachelist object for the directory dir
+ **/
+ CacheList (const QDir& dir) ;
+
+ /**
+ * write this cachelist to disk
+ **/
+ void write (void) ;
+
+ QString getCLFileName (void) const ;
+
+private:
+ QFile CLFile ;
+
+ void read (void) ;
+} ;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/kpackage/debAptInterface.cpp b/kpackage/debAptInterface.cpp
new file mode 100644
index 0000000..9dffb39
--- /dev/null
+++ b/kpackage/debAptInterface.cpp
@@ -0,0 +1,535 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+#include <stdlib.h>
+
+#include "klocale.h"
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kdebug.h>
+
+#include "kpackage.h"
+#include "updateLoc.h"
+#include "debAptInterface.h"
+#include "cache.h"
+#include "pkgOptions.h"
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+DEBAPT::DEBAPT():DEB()
+{
+ head = "DEBAPT";
+ name = i18n("APT: Debian");
+
+ queryMsg = i18n("Querying DEB APT package list: ");
+ procMsg = i18n("KPackage: Waiting on APT-GET");
+
+ hasRemote = TRUE;
+
+ locatedialog = new Locations(i18n("Location of Debian Packages"));
+
+ locatedialog->aLocations(1, 60, this, i18n("APT sources", "A"),
+ i18n("APT Sources Entries"));
+ locatedialog->dLocations(1, 8, this, i18n("Folders", "F"),
+ "Deb", "*.deb",
+ i18n("Location of Folders Containing Debian Packages"));
+ connect(locatedialog,SIGNAL(returnVal(LcacheObj *)),
+ this,SLOT(setAvail(LcacheObj *)));
+ locatedialog->apply_slot();
+
+ paramsInst.append(new param(i18n("Download only"),FALSE,FALSE,"-d"));
+ paramsInst.append(new param(i18n("No download"),FALSE,FALSE,"--no-download"));
+ paramsInst.append(new param(i18n("Ignore missing"),FALSE,FALSE,"-m"));
+ paramsInst.append(new param(i18n("Ignore hold"),FALSE,FALSE,"--ignore-hold"));
+ paramsInst.append(new param(i18n("Allow Unauthenticated"),FALSE,FALSE,"--allow-unauthenticated"));
+ paramsInst.append(new param(i18n("Assume yes"),TRUE,FALSE,"--yes"));
+ paramsInst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE,"-s"));
+
+ paramsUninst.append(new param(i18n("Purge Config Files"),FALSE,FALSE,"--purge"));
+ paramsUninst.append(new param(i18n("Assume yes"),TRUE,FALSE,"--yes"));
+ paramsUninst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE,"-s"));
+
+ env = "DEBIAN_FRONTEND=readline; export DEBIAN_FRONTEND; ";
+
+ noFetch = TRUE;
+ hasSearchAll = TRUE;
+
+ hasProgram = ifExe("apt-get");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+DEBAPT::~DEBAPT()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+bool DEBAPT::isType(char *, const QString &)
+{
+ return false;
+}
+
+void DEBAPT::makeMenu(KActionCollection* act)
+{
+ updateM = new KAction( i18n("&Update"), QString::null,
+ 0, this,
+ SLOT(updateS()), act, "debapt_update");
+
+ upgradeM = new KAction( i18n("U&pgrade"), QString::null,
+ 0, this,
+ SLOT(upgradeS()), act, "debapt_upgrade");
+
+ fixupM = new KAction( i18n("&Fixup"), QString::null,
+ 0, this,
+ SLOT(fixupS()), act, "debapt_fixup");
+
+ fileM = new KAction( i18n("&Apt-File Update"), QString::null,
+ 0, this,
+ SLOT(fileS()), act, "debapt_file");
+}
+
+void DEBAPT::setMenu(KActionCollection*, bool enable)
+{
+ updateM->setEnabled(enable);
+ upgradeM->setEnabled(enable);
+ fixupM->setEnabled(enable);
+ fileM->setEnabled(enable);
+}
+
+void DEBAPT::updateS()
+{
+ if (kprun->run("apt-get update", "APT update")) {
+ if (kprun->exec())
+ kpackage->management->collectData(TRUE);
+ }
+}
+
+void DEBAPT::upgradeS()
+{
+ if (kprun->run(env + "apt-get dist-upgrade", "APT upgrade")) {
+ if (kprun->exec())
+ kpackage->management->collectData(TRUE);
+ }
+}
+
+void DEBAPT::fixupS()
+{
+ if (kprun->run(env + "apt-get -f install", "APT fixup")) {
+ if (kprun->exec())
+ kpackage->management->collectData(TRUE);
+ }
+}
+
+void DEBAPT::fileS()
+{
+ if (ifExe("apt-file") || !hostName.isEmpty()) {
+ if (kprun->run(env + "apt-file update", "APT file update")) {
+ kprun->exec();
+ }
+ } else {
+ KpMsg("Error",i18n("The %1 program needs to be installed").arg("apt-file"), TRUE);
+ }
+}
+
+void DEBAPT::listPackages(QPtrList<packageInfo> *pki)
+{
+ if (hostName.isEmpty()) {
+ listInstalledPackages(pki);
+ } else {
+ listRemotePackages(pki);
+ }
+ listAvail(pki);
+ if (hostName.isEmpty() && packageLoc) {
+ listUnIPackages(pki, packageLoc);
+ }
+}
+
+void DEBAPT::listRemotePackages(QPtrList<packageInfo> *pki)
+{
+ listRPack(pki);
+}
+
+void DEBAPT::listRPack(QPtrList<packageInfo> *pki)
+{
+ int NLINES = 70000;
+
+ packageInfo *p;
+ QStringList plist;
+
+ kpackage->setStatus(i18n("Querying DEB APT remote package list: %1").arg(hostName));
+ kpackage->setPercent(0);
+
+ QString cmd = "cat " STATUS;
+
+ QStringList list = kpty->run(cmd);
+ kpackage->setStatus(i18n("Processing DEB APT remote package list: %1").arg(hostName));
+ // kdDebug() << "P=" << list.count() <<"\n";
+ kpackage->setPercent(50);
+
+
+ if (list.count() > 0) {
+
+ QString s;
+
+ kpackage->setPercent(50 );
+
+ int cnt = 0;
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ cnt++;
+ if (cnt % (NLINES/20) == 0) {
+ kpackage->setPercent(((cnt * 100)/ NLINES ) + 50);
+ // kdDebug() << cnt << "_" << ((cnt * 100) / NLINES) <<"\n";
+ }
+
+ if (!(*it).isEmpty()) {
+ s = *it;
+ // kdDebug() << s.length() << "<" << s << ">\n";
+ plist << s;
+ } else {
+ // kdDebug() << "---------\n";
+ p = collectInfo(plist);
+ if (p) {
+ if (!p->pkgInsert(pki, typeID, TRUE)) {
+ delete p;
+ }
+ }
+ plist.clear();
+ }
+ }
+ }
+
+ list.clear();
+ kpackage->setStatus(i18n("DEB APT"));
+ kpackage->setPercent(100);
+}
+
+void DEBAPT::listAvail(QPtrList<packageInfo> *pki)
+{
+ int NLINES = 150000;
+
+ packageInfo *p;
+ QStringList plist;
+
+ // kdDebug() << "H=" << hostName << "\n";
+ if (hostName.isEmpty())
+ kpackage->setStatus(i18n("Querying DEB APT available list"));
+ else
+ kpackage->setStatus(i18n("Querying DEB APT available list: %1").arg(hostName));
+ kpackage->setPercent(0);
+
+ QStringList list = kpty->run("apt-cache dumpavail");
+ if (hostName.isEmpty())
+ kpackage->setStatus(i18n("Processing DEB APT available list"));
+ else
+ kpackage->setStatus(i18n("Processing DEB APT available list: %1").arg(hostName));
+
+ // kdDebug() << "A=" << list.count() <<"\n";
+ kpackage->setPercent(50);
+
+ if (list.count() > 0) {
+
+ QString s;
+
+ kpackage->setPercent(50 );
+
+ int cnt = 0;
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ cnt++;
+ if (cnt % (NLINES/20) == 0) {
+ kpackage->setPercent(((cnt * 100)/ NLINES ) + 50);
+ }
+
+ if (!(*it).isEmpty()) {
+ s = *it;
+ plist << s;
+ } else {
+ p = collectInfo(plist);
+ if (p) {
+ if (!p->pkgInsert(pki, typeID, FALSE)) {
+ delete p;
+ }
+ }
+ plist.clear();
+ }
+ }
+ }
+
+ list.clear();
+ kpackage->setStatus(i18n("DEB APT"));
+ kpackage->setPercent(100);
+}
+
+QStringList DEBAPT::listInstalls(const QStringList &packs, bool install, bool &cancel)
+{
+ bool extras=FALSE, found=FALSE;
+
+ QString match;
+ QString s = "apt-get -s ";
+ if (install) {
+ s += "install ";
+ match = " extra packages ";
+ } else {
+ match = "packages will be REMOVED:";
+ s += "remove ";
+ }
+
+ for ( QStringList::ConstIterator it = packs.begin(); it != packs.end(); ++it ) {
+ s += *it;
+ s += " ";
+ }
+
+ QStringList list = kpty->run(s, TRUE, TRUE);
+ if (!kpty->inSession) {
+ cancel = TRUE; // Root login did not work
+ } else {
+ cancel = FALSE;
+ }
+ // kdDebug() << "LS=" << list.count() << "\n";
+
+ QString packAll;
+ for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) {
+ // kdDebug() << "M=" << *it << "\n";
+ if ((*it).find(match) >= 0 || extras) {
+ if (extras) {
+ if ((*it)[0] == ' ') {
+ packAll += *it;
+ found = true;
+ } else {
+ break;
+ }
+ }
+ extras=TRUE;
+ }
+ }
+
+ if (!found) {
+ QStringList nill;
+ return nill;
+ } else {
+ QStringList plist = QStringList::split(' ',packAll);
+ return plist;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QStringList DEBAPT::FindFile(const QString &name, bool searchAll)
+{
+ if (searchAll) {
+ if (ifExe("apt-file") || !hostName.isEmpty()) {
+ QString s = "apt-file search ";
+ s += name;
+
+ QStringList filelist = kpty->run(s);
+
+ for ( QStringList::Iterator it = filelist.begin(); it != filelist.end(); ++it ) {
+ int p = (*it).find(": ");
+ if( p !=-1 )
+ (*it).replace(p, 2, "\t");
+ }
+
+ if (filelist.count() == 1) {
+ QStringList::Iterator it = filelist.begin();
+ if ((*it).find("not found") >= 0) {
+ filelist.remove(it);
+ }
+ }
+
+ return filelist;
+ } else {
+ KpMsg("Error",i18n("The %1 program needs to be installed").arg("apt-file"), TRUE);
+ QStringList nill;
+ return nill;
+ }
+ } else {
+ return DEB::FindFile(name);
+ }
+}
+
+
+QStringList DEBAPT::getFileList(packageInfo *p)
+{
+ QString fn( p->getFilename());
+ if(!fn.isEmpty())
+ return getUFileList(fn);
+ else {
+ if (hostName.isEmpty())
+ return getIFileList(p);
+ else {
+ if (p->packageState == packageInfo::INSTALLED) {
+ return getRFileList(p);
+ } else
+ return "";
+ }
+ }
+}
+
+ QStringList DEBAPT::getRFileList(packageInfo *p)
+{
+ QString from;
+ QString name = p->getProperty("name");
+
+ from = "cat " INFODIR;
+ from += name;
+ from += ".list";
+
+ return kpty->run(from);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString DEBAPT::doUninstall(int uninstallFlags, const QString &packs, bool &test)
+{
+ QString s = env + "apt-get remove ";
+ s += setOptions(uninstallFlags, paramsUninst);
+ s += packs;
+
+ kdDebug() << "uCMD=" << s << "\n";
+
+ if (uninstallFlags>>2 & 1)
+ test = TRUE;
+
+ return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString DEBAPT::install(int installFlags, QPtrList<packageInfo> *p,
+ bool &test)
+{
+ QString packs = "";
+ QString files = "";
+ packageInfo *i;
+
+ for (i = p->first(); i!= 0; i = p->next()) {
+ QString file = i->getFilename();
+ QString fname = i->fetchFilename();
+
+ if (!file.isEmpty()) {
+ files += KProcess::quote(file);
+ files += " ";
+ } else if (!fname.isEmpty()) {
+ packs += KProcess::quote(fname);
+ packs += " ";
+ }
+ }
+
+ if (!files.isEmpty()) { // What if mixed?
+ return DEB::doInstall(installFlags, files, test);
+ } else {
+ return doInstall(installFlags, packs, test);
+ }
+}
+
+QString DEBAPT::doInstall(int installFlags, const QString &packs, bool &test)
+{
+ QString s = env + "apt-get install ";
+ s += setOptions(installFlags, paramsInst);
+ s += packs;
+
+ kdDebug() << "iCMD=" << s << "\n";
+
+ if ((installFlags>>0 & 1) || (installFlags>>5 & 1))
+ test = TRUE;
+
+ return s;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList DEBAPT::readApt()
+{
+ if (hostName.isEmpty()) {
+ return readAptF();
+ } else {
+ return readAptS();
+ }
+}
+
+QStringList DEBAPT::readAptS()
+{
+ QString cmd = "cat -E " APT_SOURCE;
+
+ QStringList list = kpty->run(cmd);
+ if (!kpty->Result) {
+ QString s;
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ (*it).truncate((*it).length() - 1);
+ (*it) = (*it).stripWhiteSpace();
+ }
+ return list;
+ } else {
+ return 0;
+ }
+}
+
+QStringList DEBAPT::readAptF()
+{
+ QStringList lines;
+ QFile file( "/etc/apt/sources.list" );
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine(); // line of text excluding '\n'
+ line = line.stripWhiteSpace();
+ lines += line;
+ }
+ file.close();
+ return lines;
+ } else {
+ return 0;
+ }
+}
+
+void DEBAPT::writeApt(const QStringList &list) {
+ kdDebug() << "writeApt\n";
+ QString cmd = "sh -c \"/bin/echo -e '";
+ for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) {
+ QString s = *it;
+ s.replace("\""," ");
+ s.replace("'"," ");
+ s.replace("!"," ");
+ s.replace("`"," ");
+ cmd += s;
+ cmd += "\n";
+ }
+ cmd += "' > /etc/apt/sources.list.n; if [ $? = 0 ]; then ";
+ cmd += "mv /etc/apt/sources.list /etc/apt/sources.list.b; mv /etc/apt/sources.list.n /etc/apt/sources.list; fi\" ";
+
+
+ QStringList rlist = kpty->run(cmd,TRUE,TRUE);
+ //for ( QStringList::Iterator it = rlist.begin(); it != rlist.end(); ++it ) {
+ // kdDebug() << "SL=" << *it << "\n";
+ //}
+}
+
+
+#include "debAptInterface.moc"
diff --git a/kpackage/debAptInterface.h b/kpackage/debAptInterface.h
new file mode 100644
index 0000000..71e52ea
--- /dev/null
+++ b/kpackage/debAptInterface.h
@@ -0,0 +1,84 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef DEBAPT_IFACE_H
+#define DEBAPT_IFACE_H
+
+#include "../config.h"
+
+#include <kaction.h>
+
+#include "debInterface.h"
+
+#define APT_SOURCE "/etc/apt/sources.list"
+
+class DEBAPT: public DEB
+{
+ Q_OBJECT
+
+public:
+ DEBAPT();
+ ~DEBAPT();
+
+ virtual bool isType(char *buf, const QString &fname);
+
+ void listPackages(QPtrList<packageInfo> *pki);
+ QStringList listInstalls(const QStringList &packs, bool install, bool &cancel);
+
+ QString doUninstall(int uninstallFlags, const QString &packs, bool &test);
+ QString doInstall(int installFlags, const QString &packs, bool &test);
+ QString install(int installFlags, QPtrList<packageInfo> *p,
+ bool &test);
+
+ virtual QStringList FindFile(const QString &name, bool seachAll=false);
+
+ void listRemotePackages(QPtrList<packageInfo> *pki);
+ QStringList getFileList(packageInfo *p);
+
+ KAction *updateM, *upgradeM, *fixupM, *fileM;
+
+ void makeMenu(KActionCollection* act);
+ void setMenu(KActionCollection* act, bool enable);
+
+ QStringList readApt();
+ QStringList readAptS();
+ QStringList readAptF();
+ void writeApt(const QStringList &list);
+
+private slots:
+ void updateS();
+ void upgradeS();
+ void fixupS();
+ void fileS();
+
+private:
+ void listAvail(QPtrList<packageInfo> *pki);
+ void listRPack(QPtrList<packageInfo> *pki);
+ QStringList getRFileList(packageInfo *p);
+
+ QString env;
+};
+#endif
diff --git a/kpackage/debDpkgInterface.cpp b/kpackage/debDpkgInterface.cpp
new file mode 100644
index 0000000..896bdfb
--- /dev/null
+++ b/kpackage/debDpkgInterface.cpp
@@ -0,0 +1,164 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include <unistd.h>
+#include <stdlib.h> // for getenv
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h> // for O_RDONLY
+#include <setjmp.h>
+#include <iostream>
+
+#include <kurl.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include "packageInfo.h"
+#include "debDpkgInterface.h"
+#include "updateLoc.h"
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "utils.h"
+#include "options.h"
+#include "cache.h"
+#include <klocale.h>
+
+
+extern KApplication *app;
+extern Opts *params;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+DEBDPKG::DEBDPKG():DEB()
+{
+ head = "DEBDPKG";
+ name = i18n("DPKG: Debian");
+ defaultHandle = 0;
+
+ queryMsg = i18n("Querying DEB package list: ");
+ procMsg = i18n("Kpackage: Waiting on DPKG");
+
+ locatedialog = new Locations(i18n("Location of Debian Package Archives"));
+ locatedialog->cLocations(3, 2, this, i18n("Location", "L"),
+ "Deb",
+ i18n("Version\nArchitecture"),
+ i18n("Location of Base Folder of Debian Distribution"),
+ "stable frozen unstable\ni386 alpha sparc powerpc arm m68k");
+ locatedialog->pLocations(3, 6, this, i18n("Packages", "P"),
+ "Deb", "*.deb Packages Packages.gz status available",
+ i18n("Location of 'Packages' Files for Sections of Debian Distributions"),
+ i18n("Location of Base Folder of Debian Distribution"));
+ locatedialog->dLocations(2, 6, this, i18n("Folders", "F"),
+ "Deb", "*.deb",
+ i18n("Location of Folders Containing Debian Packages"));
+ connect(locatedialog,SIGNAL(returnVal(LcacheObj *)),
+ this,SLOT(setAvail(LcacheObj *)));
+ locatedialog->apply_slot();
+
+ paramsInst.append(new param(i18n("Allow Downgrade"),TRUE,TRUE,"--refuse-downgrade"));
+ paramsInst.append(new param(i18n("Check Conflicts"),TRUE,TRUE,"--force-conflicts"));
+ paramsInst.append(new param(i18n("Check Dependencies"),TRUE,TRUE,"--force-depends"));
+ paramsInst.append(new param(i18n("Test (do not install)"),FALSE,FALSE,"--no-act"));
+
+ paramsUninst.append(new param(i18n("Purge Config Files"),TRUE,FALSE,
+ "--purge","--remove"));
+ paramsUninst.append(new param(i18n("Check Dependencies"),TRUE,TRUE,"--force-depends"));
+ paramsUninst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE,"--no-act"));
+
+ hasProgram = ifExe("dpkg");
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+DEBDPKG::~DEBDPKG()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void DEBDPKG::distPackages(QPtrList<packageInfo> *pki, cacheObj *cp)
+{
+ LcacheObj *cList = new LcacheObj();
+ QString loc = cp->base;
+
+ QStringList opt = QStringList::split('\n',cp->option);
+ QStringList::Iterator ocIt = opt.begin();
+ QString rel = *ocIt;
+ QString arch = *(++ocIt);
+
+ QString parts[3] = {"main", "contrib", "non-free"};
+ for (int i = 0; i < 3; i++) {
+ QString file = loc + "/dists/";
+ file += rel;
+ file += "/";
+ file += parts[i];
+ file += "/binary-";
+ file += arch;
+ file += "/Packages";
+ QString s;
+ QString tmp = cp->cacheFile;
+ tmp += s.setNum(i);
+ cacheObj *cp = new cacheObj(loc,file,tmp);
+ cList->append(cp);
+ }
+
+ listUnIPackages(pki, cList);
+}
+
+void DEBDPKG::listPackages(QPtrList<packageInfo> *pki)
+{
+ listInstalledPackages(pki);
+ if (packageLoc) {
+ listUnIPackages(pki, packageLoc);
+ }
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Call the script to uninstall packages setting parameters
+// to dpkg dependent on flags, returning whether everyting worked
+//////////////////////////////////////////////////////////////////////////////
+QString DEBDPKG::doUninstall(int uninstallFlags, const QString &packs, bool &test)
+{
+ QString s = "dpkg ";
+ // The -r or -p flag is set by setOptions
+ s += setOptions(uninstallFlags, paramsUninst);
+ s += packs;
+
+ if (uninstallFlags>>3 & 1)
+ test = 1;
+
+ kdDebug() << "uCMD=" << s << "\n";
+
+ return s;
+}
+
+#include "debDpkgInterface.moc"
diff --git a/kpackage/debDpkgInterface.h b/kpackage/debDpkgInterface.h
new file mode 100644
index 0000000..f65ccf0
--- /dev/null
+++ b/kpackage/debDpkgInterface.h
@@ -0,0 +1,65 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef DEBDPKG_IFACE_H
+#define DEBDPKG_IFACE_H
+
+#include "../config.h"
+
+#include "debInterface.h"
+
+class packageInfo;
+class updateLoc;
+class cacheObj;
+
+class DEBDPKG: public DEB
+{
+ Q_OBJECT
+
+public:
+ DEBDPKG();
+ ~DEBDPKG();
+
+ QString doUninstall(int installFlags, const QString &packs, bool &test);
+
+ void listPackList(QPtrList<packageInfo> *pki, const QString &fname,
+ cacheObj *cp);
+
+ void listPackages(QPtrList<packageInfo> *pki);
+ void distPackages(QPtrList<packageInfo> *pki, cacheObj *cp);
+
+public slots:
+
+protected:
+ packageInfo *getIPackageInfo(const QString &name);
+ packageInfo *getUPackageInfo(const QString &name);
+
+};
+
+#endif
+
+
+
diff --git a/kpackage/debInterface.cpp b/kpackage/debInterface.cpp
new file mode 100644
index 0000000..4c79485
--- /dev/null
+++ b/kpackage/debInterface.cpp
@@ -0,0 +1,596 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include <unistd.h>
+#include <stdlib.h> // for getenv
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h> // for O_RDONLY
+#include <setjmp.h>
+#include <iostream>
+
+#include <kurl.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include "packageInfo.h"
+#include "debInterface.h"
+#include "updateLoc.h"
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "utils.h"
+#include "options.h"
+#include "cache.h"
+#include <klocale.h>
+
+extern KApplication *app;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+DEB::DEB():pkgInterface()
+{
+ head = "DEB";
+ icon = "deb";
+
+ pict = UserIcon(icon);
+ bad_pict = UserIcon("dbad");
+ updated_pict = UserIcon("dupdated");
+ new_pict = UserIcon("dnew");
+
+ packagePattern = "*.deb";
+ typeID = "/deb";
+
+ locatedialog = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+DEB::~DEB()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// check if debian file
+bool DEB::isType(char *buf, const QString &)
+{
+ if (hasProgram) {
+ if (!strcmp(buf,"!<arch>\n")) {
+ return true;
+ } else if (!strncmp(buf,"0.9",3)) {
+ return true;
+ } else
+ return false;
+ } else {
+ return false;
+ }
+}
+
+void DEB::distPackages(QPtrList<packageInfo> *, cacheObj *)
+{
+}
+
+void DEB::listUnIPackages(QPtrList<packageInfo> *pki, LcacheObj *pCache)
+{
+ QString s;
+ cacheObj *cp;
+
+ for (cp = pCache->first(); cp != 0; cp = pCache->next()) {
+ kdDebug() << cp->base << ":: " << cp->option << "\n";
+ if (!cp->option.isEmpty()) {
+ distPackages(pki, cp);
+ } else if (!cp->base.isEmpty()) {
+ s = getPackList(cp);
+ if (!s.isEmpty()) {
+ listPackList(pki,s,cp);
+ }
+ } else {
+ s = getDir(cp);
+ if (!s.isEmpty()) {
+ listDir(pki,s,cp->location,cp->subdirs);
+ }
+ }
+ }
+}
+
+bool DEB::parseName(const QString &name, QString *n, QString *v)
+{
+ int d1, d2, s1;
+
+ s1 = name.findRev('.');
+ if (s1 > 0) {
+ d2 = name.findRev('-',s1-1);
+ if (d2 > 0) {
+ d1 = name.findRev('_',d2-1);
+ if (d1 < 0)
+ d1 = d2;
+ *n = name.left(d1);
+ *v = name.mid(d1+1,s1-d1-1);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void DEB::listInstalledPackages(QPtrList<packageInfo> *pki)
+{
+ listPackList(pki,STATUS,0);
+}
+
+void DEB::listPackList(QPtrList<packageInfo> *pki, const QString &fname, cacheObj *cp)
+{
+ bool local = FALSE;
+ packageInfo *p;
+ QStringList list;
+ QString sline( i18n("Querying DEB package list: ")+fname );
+
+ if (cp) {
+ KURL u(cp->base);
+ local = u.isLocalFile();
+ }
+
+ kpackage->setStatus(sline);
+ kpackage->setPercent(0);
+
+ QFile file(STATUS);
+ QString s;
+
+ bool fileOpened= file.open(IO_ReadOnly);
+ if (fileOpened) {
+ QTextStream stream( &file );
+ s = "";
+ while ( !s.isNull() ) {
+ s = stream.readLine();
+ if ( !s.isEmpty() ) {
+ list << s;
+ } else {
+ p = collectInfo(list);
+ if (p) {
+ if (!p->pkgInsert(pki, typeID, cp == 0)) {
+ delete p;
+ } else if (cp) {
+ p->info.insert("base", cp->base);
+ }
+ }
+ list.clear();
+ }
+ }
+ file.close();
+ }
+
+ kpackage->setPercent(100);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+packageInfo *DEB::getPackageInfo(char mode, const QString &name, const QString &)
+{
+ if (mode == 'i') {
+ if (hostName.isEmpty()) {
+ return getIPackageInfo(name);
+ } else {
+ return getIRPackageInfo(name);
+ }
+ } else
+ return getUPackageInfo(name);
+}
+
+packageInfo *DEB::getIPackageInfo( const QString &name)
+{
+ // query an installed package!
+ packageInfo *pki = 0;
+ QString search;
+ QStringList list;
+
+ search = "Package: "+ name;
+
+ QFile f(STATUS);
+ if ( f.open(IO_ReadOnly) ) {
+ QTextStream t( &f );
+ QString s;
+ while ( !t.eof() ) {
+ s = t.readLine();
+
+ if ( s == search) {
+ list << s;
+ break;
+ }
+ }
+
+ while ( !t.eof() ) {
+ s = t.readLine();
+ if (s.length()) {
+ list << s;
+ } else {
+ pki = collectInfo(list);
+ break;
+ }
+ }
+ }
+ f.close();
+ return pki;
+}
+
+packageInfo *DEB::getIRPackageInfo( const QString &name)
+{
+ // query an remote installed package
+ packageInfo *pki = 0;
+
+ QString s = "dpkg --status ";
+ s += name;
+ QStringList list = kpty->run(s);
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ // kdDebug() << "U=" << *it << "\n";
+ if ((*it).find("Package:") >= 0) {
+ kdDebug() << "found\n";
+ while (it != list.begin()) {
+ list.remove(list.begin());
+ }
+ break;
+ }
+ }
+
+ if (list.count() > 1) {
+ pki = DEB::collectInfo(list);
+ if (pki) {
+ pki->updated = TRUE;
+ if (pki->getFilename().isEmpty())
+ pki->setFilename(name);
+ }
+ }
+
+ return pki;
+}
+
+packageInfo *DEB::getUPackageInfo( const QString &name)
+{
+ // query an uninstalled package
+ packageInfo *pki = 0;
+
+ QString s = "dpkg --info ";
+ s += KProcess::quote(name);
+
+ QStringList list = kpty->run(s);
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ // kdDebug() << "U=" << *it << "\n";
+ if ((*it).find("Package:") >= 0) {
+ // kdDebug() << "found\n";
+ while (it != list.begin()) {
+ list.remove(list.begin());
+ }
+ break;
+ }
+ }
+
+ if (list.count() > 1) {
+ pki = DEB::collectInfo(list, kpinterface[0]); // To be fixed up later, assumes order of kpinterface
+ if (pki)
+ pki->updated = TRUE;
+ }
+
+ return pki;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+packageInfo *DEB::collectInfo(QStringList &ln, pkgInterface *pkgInt)
+{
+ if (!pkgInt) {
+ pkgInt = this;
+ }
+
+ QMap<QString, QString> a;
+
+ QString key, val;
+ bool bad_install = FALSE;
+ bool available = FALSE;
+ bool haveName = FALSE;
+
+ for ( QStringList::Iterator it = ln.begin(); it != ln.end(); ++it ) {
+ loop:
+ int col = (*it).find(':');
+ key = ((*it).left(col)).lower();
+ if (key[0] == ' ') {
+ key.remove(0,1);
+ }
+ val = (*it).mid(col+2);
+
+ // val.truncate(val.length() - 1);
+
+ if (key == "conffiles") {
+ while (++it != ln.end()) {
+ if ((*it)[0] == ' ') {
+ } else {
+ goto loop;
+ }
+ }
+ } else if (key == "description") {
+ a.insert("summary", val);
+ QString desc;
+ while (++it != ln.end()) {
+ if ((*it)[0] == ' ') {
+ desc += *it;
+ } else {
+ a.insert("description", desc);
+ goto loop;
+ }
+ }
+ a.insert("description", desc);
+ break;
+ } else if (key == "package") {
+ a.insert("name", val);
+ haveName = TRUE;
+ } else if (key == "md5sum") {
+ available = TRUE;
+ bad_install = FALSE;
+ } else if (key == "section") {
+ a.insert("group", val);
+ } else if (key == "status") {
+ if ((val.find("not-installed") >= 0) || (val.find("config-files") >= 0)) {
+ return 0;
+ }
+ if (val != "install ok installed" &&
+ val != "deinstall ok installed" &&
+ val != "deinstall ok config-files" &&
+ val != "purge ok installed") {
+ bad_install = TRUE;
+ }
+ a.insert("status", val);
+ } else if (key == "version") {
+ a.insert("version", val);
+ } else if (key == "size") {
+ a.insert("file-size", val);
+ } else if (key == "installed-size") {
+ a.insert("size", val + "000");
+ } else {
+ a.insert(key, val);
+ }
+ // kdDebug() << "C=" << key << "," << val <<"\n";
+ }
+
+ if (haveName) {
+ packageInfo *i = new packageInfo(a,pkgInt);
+ if (bad_install) {
+ i->packageState = packageInfo::BAD_INSTALL;
+ } else if (available) {
+ i->packageState = packageInfo::AVAILABLE;
+ } else {
+ i->packageState = packageInfo::INSTALLED;
+ }
+ i->fixup();
+ return i;
+ } else {
+ return 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList DEB::getChangeLog(packageInfo *p) {
+ QString fn( p->getFilename());
+ if(!fn.isEmpty())
+ return 0;
+ else
+ return getIChangeLog(p);
+}
+
+QStringList DEB::getIChangeLog(packageInfo *p)
+{
+ QString from;
+ QStringList ret;
+ QString name = p->getProperty("name");
+
+ from = "zcat /usr/share/doc/";
+ from += name;
+ from += "/changelog.Debian.gz";
+
+ ret = kpty->run(from);
+
+ if (!kpty->Result)
+ return ret;
+ else {
+ from = "zcat /usr/share/doc/";
+ from += name;
+ from += "/changelog.gz";
+
+ ret = kpty->run(from);
+ if (!kpty->Result)
+ return ret;
+ else
+ return 0;
+ }
+}
+
+bool DEB::filesTab(packageInfo *p) {
+ if (p->packageState == packageInfo::INSTALLED) {
+ return true;
+ } else if (p->isFileLocal()) {
+ return true;
+ }
+ return false;
+}
+
+bool DEB::changeTab(packageInfo *p) {
+ if (p->packageState == packageInfo::INSTALLED) {
+ return true;
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList DEB::getFileList(packageInfo *p)
+{
+ QString fn( p->getFilename());
+ if(!fn.isEmpty())
+ return getUFileList(fn);
+ else
+ return getIFileList(p);
+}
+
+// query an installed package
+QStringList DEB::getIFileList(packageInfo *p)
+{
+ FILE *file;
+ QString name = p->getProperty("name");
+ QStringList filelist;
+
+ QString vb( INFODIR + name + ".list");
+ file= fopen(vb.ascii(),"r");
+
+ if (file) {
+ char linebuf[1024];
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ linebuf[strlen(linebuf) - 1] = 0; // remove new line
+ filelist.append(linebuf);
+ }
+ fclose(file);
+ }
+ return filelist;
+}
+
+// query an uninstalled package
+QStringList DEB::getUFileList(const QString &fn)
+{
+ QString s = "dpkg --contents ";
+ s += "'";
+ s += fn;
+ s += "'";
+
+ QStringList filelist = kpty->run(s);
+
+ int pt = -1;
+ for ( QStringList::Iterator it = filelist.begin();
+ it != filelist.end(); ++it ) {
+ // kdDebug() << "F=" << *it << "\n";
+ if (pt < 0) {
+ pt = (*it).findRev(' ');
+ }
+ (*it) = (*it).mid(pt + 1);
+ }
+ return filelist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+QStringList DEB::FindFile(const QString &name, bool)
+{
+ QString s = "dpkg -S ";
+ s += name;
+
+ QStringList filelist = kpty->run(s);
+
+ for ( QStringList::Iterator it = filelist.begin(); it != filelist.end(); ++it ) {
+ int p = (*it).find(": ");
+ if( p !=-1 )
+ (*it).replace(p, 2, "\t");
+ }
+
+ if (filelist.count() == 1) {
+ QStringList::Iterator it = filelist.begin();
+ if ((*it).find("not found") >= 0) {
+ filelist.remove(it);
+ }
+ }
+
+ return filelist;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void DEB::setLocation()
+{
+ locatedialog->restore();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void DEB::setAvail(LcacheObj *slist)
+{
+ if (packageLoc)
+ delete packageLoc;
+ packageLoc = slist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+QString DEB::uninstall(int uninstallFlags, QPtrList<packageInfo> *p,
+ bool &test)
+{
+ QString packs = "";
+ packageInfo *i;
+
+ for (i = p->first(); i!= 0; i = p->next()) {
+ packs += i->getProperty("name");
+ packs += " ";
+ }
+ return doUninstall( uninstallFlags, packs, test);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString DEB::install(int installFlags, QPtrList<packageInfo> *p,
+ bool &test)
+{
+ QString packs = "";
+ packageInfo *i;
+
+ for (i = p->first(); i!= 0; i = p->next()) {
+ QString fname = i->fetchFilename();
+ if (!fname.isEmpty()) {
+ packs += KProcess::quote(fname);
+ packs += " ";
+ }
+ }
+ return doInstall(installFlags, packs, test);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Call the script to install packages setting parameters
+// to dpkg dependent on flags, returning whether everyting worked
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+QString DEB::doInstall(int installFlags, const QString &packs, bool &test)
+{
+ QString s = "dpkg -i ";
+ s += setOptions(installFlags, paramsInst);
+ s += packs;
+
+ kdDebug() << "iCMD=" << s << "\n";
+
+ if (installFlags>>4 & 1)
+ test = 1;
+
+ return s;
+}
+
+#include "debInterface.moc"
diff --git a/kpackage/debInterface.h b/kpackage/debInterface.h
new file mode 100644
index 0000000..98307f8
--- /dev/null
+++ b/kpackage/debInterface.h
@@ -0,0 +1,112 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#ifndef DEB_IFACE_H
+#define DEB_IFACE_H
+
+#include "../config.h"
+
+#include <qptrlist.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qtextstream.h>
+#include <qstringlist.h>
+
+#include <kprocess.h>
+
+#include "pkgInterface.h"
+
+class packageInfo;
+class updateLoc;
+class cacheObj;
+
+#define AVAIL "/var/lib/dpkg/available"
+#define STATUS "/var/lib/dpkg/status"
+
+#define INFODIR "/var/lib/dpkg/info/"
+
+
+class DEB: public pkgInterface
+{
+ Q_OBJECT
+
+public:
+ DEB();
+ ~DEB();
+
+ virtual bool isType(char *buf, const QString &fname);
+
+ virtual packageInfo *getPackageInfo(char mode, const QString &name,
+ const QString &version);
+ virtual QStringList getFileList(packageInfo *p);
+ virtual QStringList getChangeLog(packageInfo *p);
+
+ bool filesTab(packageInfo *p);
+ // If files tab is to be enabled
+
+ bool changeTab(packageInfo *p);
+ // If change log tab is to be enabled
+
+ virtual void listInstalledPackages(QPtrList<packageInfo> *pki);
+
+ virtual QStringList FindFile(const QString &name, bool seachAll=false);
+ virtual bool parseName(const QString &name, QString *n, QString *v);
+
+ virtual packageInfo* collectInfo(QStringList &ln, pkgInterface *pkgInt = 0);
+
+ QString uninstall(int uninstallFlags, QPtrList<packageInfo> *p,
+ bool &test);
+ QString install(int installFlags, QPtrList<packageInfo> *p,
+ bool &test);
+ QString doInstall(int installFlags, const QString &packs, bool &test);
+
+public slots:
+ void setLocation();
+ void setAvail(LcacheObj *);
+
+protected:
+ packageInfo *getIPackageInfo(const QString &name);
+ packageInfo *getIRPackageInfo(const QString &name);
+ packageInfo *getUPackageInfo(const QString &name);
+
+ QStringList getIChangeLog(packageInfo *p);
+
+ void listPackList(QPtrList<packageInfo> *pki,
+ const QString &fname, cacheObj *cp);
+
+ virtual void distPackages(QPtrList<packageInfo> *pki, cacheObj *cp);
+ void listUnIPackages(QPtrList<packageInfo> *pki, LcacheObj *pCache);
+
+ QStringList getIFileList(packageInfo *p);
+ QStringList getUFileList(const QString &fn);
+};
+
+#endif
+
+
+
diff --git a/kpackage/fbsdInterface.cpp b/kpackage/fbsdInterface.cpp
new file mode 100644
index 0000000..980ad36
--- /dev/null
+++ b/kpackage/fbsdInterface.cpp
@@ -0,0 +1,641 @@
+/*
+** Copyright (C) 2000 by Alex Hayward <xelah@xelah.com>
+*/
+
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/utsname.h>
+
+#include <qstringlist.h>
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include "fbsdInterface.h"
+#include "kpackage.h"
+#include "updateLoc.h"
+#include "cache.h"
+#include "options.h"
+
+#define PKG_INFO_BIN "/usr/sbin/pkg_info"
+#define PKG_ADD_BIN "/usr/sbin/pkg_add"
+#define PKG_DELETE_BIN "/usr/sbin/pkg_delete"
+
+#define INFO_SEPARATOR "f;g#z-@IqbX%"
+
+fbsdInterface::fbsdInterface():pkgInterface() {
+ head = "BSD";
+ name = i18n("BSD");
+ icon = "bsd";
+
+ pict = UserIcon(icon);
+ updated_pict = UserIcon("bupdated");
+ new_pict = UserIcon("bnew");
+
+ packagePattern = "*.tgz *.tbz";
+ typeID = "/tbz";
+
+ QDict <bsdPortsIndexItem> ports(17777, false);
+ queryMsg = i18n("Querying package list: ");
+
+ locatedialog = new Locations(i18n("Location of BSD Packages and Ports"));
+ locatedialog->dLocations(1, 1, this, i18n("Ports"), "Pkg", "*.tbz",
+ i18n("Location of Ports Tree (e.g. /usr/ports or /usr/opt)"),FALSE);
+ locatedialog->dLocations(1, 6, this, i18n("Packages"), "Pkg", "*.tbz",
+ i18n("Location of Folders Containing BSD Packages or Package Trees"));
+ connect(locatedialog, SIGNAL(returnVal(LcacheObj *)), this, SLOT(setAvail(LcacheObj *)));
+ locatedialog->apply_slot();
+
+ paramsInst.append(new param(i18n("Ignore Scripts"),FALSE,FALSE,"-I"));
+ paramsInst.append(new param(i18n("Check Dependencies"),TRUE,TRUE,"-f"));
+ paramsInst.append(new param(i18n("Test (do not install)"),FALSE,FALSE,"-n"));
+
+ paramsUninst.append(new param(i18n("Ignore Scripts"),FALSE,FALSE, "-I"));
+ paramsUninst.append(new param(i18n("Check Dependencies"),TRUE,TRUE, "-f"));
+ paramsUninst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE, "-n"));
+
+ hasProgram = ifExe("pkg_info") && ifExe("pkg_add");
+}
+
+fbsdInterface::~fbsdInterface() {
+
+}
+
+bool fbsdInterface::isType(char *, const QString &fname) {
+ // These files are .tgz or .tbz files. Pass it to pkg_info and see whether it
+ // succeeds.
+ if (hasProgram) {
+ QString cmd = PKG_INFO_BIN; // cmd += "_q";
+ cmd += " -q ";
+ cmd += fname;
+ kpty->run(cmd);
+
+ if (!kpty->Result)
+ return true;
+ else
+ return false;
+ } else {
+ return false;
+ }
+}
+
+static void insertGroups(QMap<QString, QString> *a, QString cats)
+{
+ /* Create the list of groups (which is space-separated), and then
+ ** iterate through it with the iterator i. count is just to
+ ** distinguish the first entry (count==0) from the rest, since
+ ** the key used in a->insert() needs to be different.
+ */
+ QStringList grlist = QStringList::split(' ',cats);
+ unsigned int count = 0;
+ for (QStringList::Iterator i = grlist.begin();
+ i != grlist.end(); ++count,++i) {
+ a->insert( (count ? "also in" : "group"), *i);
+ }
+}
+
+packageInfo *fbsdInterface::getPackageInfo(char mode, const QString &pname, const QString &version) {
+ QString name( pname);
+ bool installed = false;
+ kpackage->setStatus(i18n("Getting package info"));
+
+ kdDebug() << "Looking at package " << pname << endl;
+
+ if (mode == 'i' && !version.isEmpty()) {
+ name += "-" + version;
+ }
+
+ QMap<QString, QString> a;
+
+ // Get the package name first (for mode = 'u').
+ if (mode == 'u') {
+ QString cmd = PKG_INFO_BIN; // cmd += "_qf";
+ cmd += " -qf ";
+ cmd += name;
+ QStringList list = kpty->run(cmd);
+
+ int last_dir = name.find('/');
+ if (last_dir != -1) {
+ a["filename"] = name.mid(last_dir+1);
+ a["base"] = name.left(last_dir + 1);
+ } else {
+ a["filename"] = name;
+ a["base"] = "";
+ }
+
+ if (list.count() > 0) {
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ // Look for a line of the form '@name <pkgname>'
+ if ((*it).left(5) == "@name") {
+ QString n = (*it).mid(6);
+ addNV(a, n);
+ break;
+ }
+ }
+ } else addNV(a, name);
+ }
+
+ // Open a pipe to a pkg_info process in order to read the one line comment
+ // and description for the package. This works for both installed packages
+ // and for files.
+ QString cmd = PKG_INFO_BIN; // cmd += "_q";
+ cmd += " -q ";
+ cmd += name;
+ QStringList list = kpty->run(cmd);
+
+ QStringList::Iterator it = list.begin();
+
+
+ if (list.count() > 0) {
+ QStringList::Iterator it = list.begin();
+ a["summary"] = *it;
+ it++;
+ QString desc;
+ int prevlen = 0, len;
+ for ( ; it != list.end(); ++it ) {
+ len = (*it).length();
+ desc += (*it);
+ // kdDebug() << len << " " << prevlen << "=" << *it << "\n";
+ if (len > 0 || prevlen > 0)
+ desc += "<br>\n";
+ prevlen = (*it).length();
+ }
+ // kdDebug( << desc << "\n";
+ bsdPortsIndexItem *inditem = ports[name];
+
+ if (inditem) {
+ installed = inditem->installed;
+ a["maintainer"] = inditem->fields[bsdPortsIndexItem::MAINT];
+
+ insertGroups(&a,inditem->fields[bsdPortsIndexItem::CATS]);
+
+ a["build depends"] = !inditem->fields[bsdPortsIndexItem::BDEPS].isEmpty() ? inditem->fields[bsdPortsIndexItem::BDEPS] : i18n("none");
+ a["available as"] = inditem->bin ? (inditem->port? i18n("binary package and source port") : i18n("binary package")) : i18n("source port");
+ }
+ a["description"] = desc;
+ } else {
+ kpackage->setStatus(QString::null);
+ return 0;
+ }
+
+ packageInfo *ret = new packageInfo(a, this);
+ ret->packageState = installed? packageInfo::INSTALLED : packageInfo::AVAILABLE;
+ ret->fixup();
+ if (!installed) ret->smerge(typeID);
+ kpackage->setStatus(QString::null);
+ return ret;
+}
+
+QStringList fbsdInterface::getChangeLog(packageInfo *) {
+ return 0;
+}
+
+
+bool fbsdInterface::filesTab(packageInfo *) {
+ return TRUE;
+}
+
+bool fbsdInterface::changeTab(packageInfo *) {
+ return FALSE;
+}
+
+QStringList fbsdInterface::getFileList(packageInfo *p) {
+
+ // Run pkg_info on the package name to get the file list.
+ // The file list is returned on stdout, one per line.
+ kpackage->setStatus(i18n("Getting file list"));
+
+ QStringList ret;
+
+ // Find the full name 'name-version', or just 'name' if version is empty.
+ // Check first that it is actually installed.
+ QString name( p->getProperty("filename"));
+
+ if (!name.isEmpty() && (p->packageState != packageInfo::INSTALLED)) {
+ QString qbname( p->getProperty("base"));
+ if (!qbname.isEmpty())
+ name = qbname + "/" + name;
+ } else {
+ if (!p->hasProperty("name")) {
+ ret.append(i18n("Can't find package name!"));
+ kpackage->setStatus(QString::null);
+ return ret;
+ }
+
+ name = p->getProperty("name");
+
+ QString version( p->getProperty("version"));
+ if (!version.isEmpty()) {
+ name = name + "-" + version;
+ }
+ }
+
+ // Open a pipe to a pkg_info process in order to read the file list.
+ // This works for both installed packages and for files.
+ QString cmd = PKG_INFO_BIN; // cmd += "_Lq";
+ cmd += " -L -q ";
+ cmd += name;
+ QStringList list = kpty->run(cmd);
+
+ ret = list;
+
+ kpackage->setStatus(QString::null);
+ return ret;
+}
+
+
+// QPtrList<char> *verify(packageInfo *p, QPtrList<char> *files);
+
+QString fbsdInterface::doUninstall(int uninstallFlags, const QString &packs, bool &)
+{
+
+ QString s = PKG_DELETE_BIN;
+ s += " ";
+ s += setOptions(uninstallFlags, paramsUninst);
+ s += packs;
+
+ kdDebug() << "uCMD=" << s << "\n";
+
+ return s;
+}
+
+
+QString fbsdInterface::doInstall(int installFlags, const QString &packs, bool &)
+{
+
+ QString s = PKG_ADD_BIN;
+ s += " ";
+ s += setOptions(installFlags, paramsInst);
+ s += packs;
+
+ kdDebug() << "iCMD=" << s << "\n";
+
+ return s;
+}
+
+QString fbsdInterface::uninstall(int uninstallFlags, packageInfo *p, bool &test)
+{
+ QString packs( p->getProperty("name"));
+ QString vers( p->getProperty("version"));
+ if (vers.length() > 0) packs += "-" + vers;
+
+ return doUninstall(uninstallFlags, packs, test);
+}
+
+QString fbsdInterface::uninstall(int uninstallFlags, QPtrList<packageInfo> *p, bool &test)
+{
+ QString packs ;
+ packageInfo *i;
+
+ for (i = p->first(); i!= 0; i = p->next()) {
+ packs += i->getProperty("name");
+ QString vers( i->getProperty("version"));
+ if (vers.length() != 0) packs += "-" + vers;
+ packs += " ";
+ }
+ return doUninstall( uninstallFlags, packs, test);
+}
+
+QStringList fbsdInterface::FindFile(const QString &, bool) {
+ QStringList tmp;
+ return tmp;
+}
+
+bool fbsdInterface::parseName(const QString &name, QString *n, QString *v) {
+ int m1;
+
+ m1 = name.findRev('-');
+ if (m1 <= 0) return false;
+ *n = name.left(m1);
+ *v = name.right(name.length() - m1 - 1);
+ return true;
+}
+
+void fbsdInterface::addNV(QMap<QString, QString> &d, const QString &name) {
+ QString n, v;
+
+ if (!parseName(name, &n, &v)) {
+ n = name;
+ v = QString::null;
+ }
+
+ d.insert("name", n);
+ d.insert("version", v);
+}
+
+ //public slots
+void fbsdInterface::setLocation() {
+ locatedialog->restore();
+}
+
+void fbsdInterface::setAvail(LcacheObj *slist) {
+ kdDebug() << k_funcinfo << endl;
+
+ if (packageLoc) delete packageLoc;
+ packageLoc = slist;
+
+ cacheObj *cp = packageLoc->first();
+
+ if (cp && !cp->location.isEmpty()) {
+ for (; cp != 0; cp = packageLoc->next()) {
+ QString oldloc = cp->location;
+ cp->location += "/INDEX";
+ QString s = getPackList(cp);
+ if (!s.isEmpty()) bsdPortsIndexItem::processFile(this, QFile::encodeName(s), true, oldloc);
+ cp->location = oldloc;
+ }
+ }
+
+ // Try /usr/port/INDEX-<major version> on FreeBSD
+ struct utsname fbsdName;
+ if(uname(&fbsdName) != -1 && !strcmp(fbsdName.sysname, "FreeBSD"))
+ bsdPortsIndexItem::processFile(this, QString("/usr/ports/INDEX-").append(*fbsdName.release), false, "/usr/ports");
+
+ // Try the standard ports tree locations.
+ bsdPortsIndexItem::processFile(this, "/usr/ports/INDEX", false, "/usr/ports"); // FreeBSD/OpenBSD
+ bsdPortsIndexItem::processFile(this, "/usr/opt/INDEX", false, "/usr/opt"); // NetBSD
+}
+
+
+void fbsdInterface::listPackages(QPtrList<packageInfo> *pki) {
+ kdDebug() << k_funcinfo << endl;
+
+ listInstalledPackages(pki);
+
+
+ QDictIterator<bsdPortsIndexItem> it( ports ); // See QDictIterator
+ for( ; it.current(); ++it ) {
+ bsdPortsIndexItem *scan = it.current();
+ if (!scan->installed /*&& scan->bin */) {
+ QMap<QString, QString> a;
+
+ addNV(a, scan->fields[bsdPortsIndexItem::NAME]);
+ a["summary"] = scan->fields[bsdPortsIndexItem::COMMENT];
+ a["maintainer"] = scan->fields[bsdPortsIndexItem::MAINT];
+
+ insertGroups(&a,scan->fields[bsdPortsIndexItem::CATS]);
+
+ a["run depends"] = !scan->fields[bsdPortsIndexItem::RDEPS].isEmpty() ? scan->fields[bsdPortsIndexItem::RDEPS] : i18n("none");
+ a["build depends"] = !scan->fields[bsdPortsIndexItem::BDEPS].isEmpty() ? scan->fields[bsdPortsIndexItem::BDEPS] : i18n("none");
+ a["available as"] = scan->bin ? (scan->port? i18n("binary package and source port") : i18n("binary package")) : i18n("source port");
+
+ a["filename"] = scan->bin_filename;
+ a["base"] = scan->bin_filename_base;
+
+ packageInfo *info = new packageInfo(a, this);
+ info->packageState = packageInfo::AVAILABLE;
+ info->smerge(typeID);
+ info->fixup();
+ info->pkgInsert(pki, typeID, false);
+// pki->append(info);
+ }
+ }
+
+}
+
+int fbsdInterface::parseItem(QStringList::Iterator &it, QString &name, QString &value, QString separator, QStringList list ) {
+ if ((*it).left(separator.length()) == separator) {
+ name = *it;
+ name = name.mid(separator.length());
+ } else {
+ return -1;
+ }
+ if (it == list.end())
+ return -1;
+ it++;
+
+ value = "";
+ int prevlen = 0, len;
+ while ((*it).left(separator.length()) != separator) {
+ len = (*it).length();
+ value += *it;
+ if (len > 0 || prevlen > 0)
+ value += "<br>";
+ if (it == list.end())
+ return -1;
+ prevlen = (*it).length();
+ it++;
+ }
+ return 1;
+}
+
+int fbsdInterface::pathInfo(QMap<QString, QString> &a)
+{
+ int pkg_state = packageInfo::INSTALLED;
+ if (a["group"].isEmpty()) {
+ QString s, ps;
+ ps = a["name"];
+ if (ps.isEmpty())
+ s = ps;
+ else
+ s = "<anonymous>";
+
+ ps = a["version"];
+ if (!ps.isEmpty())
+ s.append(QString("-")+(ps));
+
+ kdDebug() << "Package " << (s) << " has no group." << endl;
+
+ /* This must be an installed package with no INDEX entry,
+ ** which usually means that the port has been updated.
+ */
+ QString cmd = PKG_INFO_BIN;
+ // cmd += "2";
+ cmd += " -ol ";
+ cmd += INFO_SEPARATOR;
+ QStringList list = kpty->run(cmd);
+
+ if (list.count() > 0) {
+ QStringList::Iterator it = list.begin();
+ QString name, value;
+ parseItem(it, name, value, INFO_SEPARATOR, list); // Information
+ parseItem(it, name, value, INFO_SEPARATOR, list); // Path
+
+ int pos = value.findRev('/');
+ value.truncate(pos);
+ a["group"] = value;
+ } else {
+ kdDebug() << "Could not read package origin info." << endl;
+ }
+ }
+ return pkg_state;
+}
+
+ void fbsdInterface::listInstalledPackages(QPtrList<packageInfo> *pki) {
+ kdDebug() << k_funcinfo << endl;
+
+ // Open a pipe to a pkg_info process in order to read the comment, name
+ // and description for the packages.
+
+ kpackage->setStatus(i18n("Querying BSD packages database for installed packages"));
+
+ QString cmd = PKG_INFO_BIN;
+ cmd += " -acdl ";
+ cmd += INFO_SEPARATOR;
+ QStringList list = kpty->run(cmd);
+
+ // We should now get:
+ // INFO_SEPARATORInformation for pkgname:
+ //
+ // INFO_SEPARATORComment:
+ // <one line description>
+ //
+ // INFO_SEPARATORDescription:
+ // <description>
+ //
+ //
+ // INFO_SEPARATOR
+ // INFO_SEPARATORInformation for [etc]
+
+ QMap<QString, QString> a;
+ QString name, value;
+ if (list.count() > 0) {
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+
+ parseItem(it, name, value, INFO_SEPARATOR, list); // Information
+ // Find the last word on this line (which should be the package name) minus a trailing :.
+ QString pkg = name.section(' ',-1);
+ if (pkg.isEmpty()) {
+ KpMsgE(i18n("Unexpected output from pkg_info (looking for package name): %1").arg(value), TRUE);
+ kpackage->setStatus(QString::null);
+ return;
+ } else {
+ if (pkg[pkg.length()-1] == ':') {
+ pkg.truncate(pkg.length()-1);
+ }
+ }
+ addNV(a, pkg);
+
+ parseItem(it, name, value, INFO_SEPARATOR, list); //Comment
+ a["summary"] = value;
+
+
+ parseItem(it, name, value, INFO_SEPARATOR, list); //Description
+
+ bsdPortsIndexItem *inditem = ports[pkg];
+
+ if (inditem) {
+ inditem->installed = true;
+
+ a["maintainer"] = inditem->fields[bsdPortsIndexItem::MAINT];
+
+ insertGroups(&a,inditem->fields[bsdPortsIndexItem::CATS]);
+ if (a["group"].isEmpty()) {
+ kdDebug() << "Line <" << name << "=" << value << "> has no group?" << endl;
+ }
+
+ a["run depends"] = !inditem->fields[bsdPortsIndexItem::RDEPS].isEmpty() ?
+ inditem->fields[bsdPortsIndexItem::RDEPS] : i18n("none");
+ a["build depends"] = !inditem->fields[bsdPortsIndexItem::BDEPS].isEmpty() ?
+ inditem->fields[bsdPortsIndexItem::BDEPS] : i18n("none");
+ a["available as"] = inditem->bin ? (inditem->port? i18n("binary package and source port") : i18n("binary package")) : i18n("source port");
+ }
+
+ a["description"] = value;
+
+ int pkg_state = pathInfo(a);
+ packageInfo *info = new packageInfo(a, this);
+ info->packageState = pkg_state;
+
+ info->fixup();
+ //pki->append(info);
+ info->pkgInsert(pki, typeID, true);
+
+ }
+ }
+}
+
+
+bsdPortsIndexItem::bsdPortsIndexItem(fbsdInterface *parent, char *desc, bool binaries, const QString &dname) : bin(binaries), port(!binaries), installed(false) {
+ fields = QStringList::split('|', desc, TRUE);
+ QString name = fields[NAME];
+
+ bsdPortsIndexItem *port = parent->ports[name];
+ if (port) {
+ port->bin = port->bin || bin;
+ port->port = port->port || port;
+ if (binaries) {
+ port->bin_filename = QString(name) + ".tbz";
+ port->bin_filename_base = dname + "/";
+ }
+ fields[NAME] = ""; // Acts as a 'not used' tag.
+ return;
+
+ }
+ if (binaries) {
+ bin_filename = QString(name) + ".tbz";
+ bin_filename_base = dname + "/";
+ }
+
+}
+
+void bsdPortsIndexItem::processFile(fbsdInterface *parent, const QString &fname, bool binaries, const QString &dname) {
+ // Read the file in to a buffer and null terminate it.
+
+ struct stat s;
+
+ if (stat(fname.ascii(), &s) == -1) {
+ // Error message?
+ return;
+ }
+
+ char *index = (char *) malloc(s.st_size);
+ int fd;
+
+ fd = open(fname.ascii(), O_RDONLY);
+ if (fd == -1) {
+ // Error message?
+ return;
+ }
+
+ int size = read(fd, index, s.st_size);
+ index[size] = 0;
+ close(fd);
+
+
+ // Go through each line and create a new bsdPortsIndexItem.
+ char *line = strtok(index, "\n");
+ while (line != 0) {
+ bsdPortsIndexItem *i = new bsdPortsIndexItem(parent, line, binaries, dname + "/All");
+ if (i->fields[NAME].isEmpty()) {
+ delete i;
+ } else {
+ parent->ports.insert(i->fields[NAME] , i);
+ }
+ line = strtok(0, "\n");
+ }
+}
+
+
+#include "fbsdInterface.moc"
diff --git a/kpackage/fbsdInterface.h b/kpackage/fbsdInterface.h
new file mode 100644
index 0000000..270b0c9
--- /dev/null
+++ b/kpackage/fbsdInterface.h
@@ -0,0 +1,158 @@
+/*
+** Copyright (C) 2000 by Alex Hayward
+**
+*/
+
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef FBSD_IFACE_H
+#define FBSD_IFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+//#ifdef HAVE_FBSD_PKGTOOLS
+
+#include <qptrlist.h>
+#include <qmap.h>
+
+#include "packageInfo.h"
+#include "pkgInterface.h"
+
+class KDir;
+class cacheObj;
+class bsdPortsIndexItem;
+
+class fbsdInterface : public pkgInterface
+{
+ Q_OBJECT
+
+public:
+ fbsdInterface();
+ ~fbsdInterface();
+
+ void init();
+
+ bool isType(char *buf, const QString &fname);
+
+ packageInfo *getPackageInfo(char mode, const QString &name, const QString &version);
+ QStringList getFileList(packageInfo *p);
+ QStringList getChangeLog(packageInfo *p);
+
+ bool filesTab(packageInfo *p);
+ // If files tab is to be enabled
+
+ bool changeTab(packageInfo *p);
+ // If change log tab is to be enabled
+
+ QString uninstall(int uninstallFlags, QPtrList<packageInfo> *p, bool &test);
+ QString uninstall(int uninstallFlags, packageInfo *p, bool &test);
+ QString doUninstall(int uninstallFlags, const QString &packs, bool &test);
+ QString doInstall(int installFlags, const QString &packs, bool &test);
+
+ QStringList FindFile(const QString &name, bool seachAll=false);
+ void collectDepends(packageInfo *p, const QString &name, int src);
+ bool parseName(const QString& name, QString *n, QString *v);
+
+ void listInstalledPackages(QPtrList<packageInfo> *pki);
+ void listPackages(QPtrList<packageInfo> *pki);
+
+ QDict <bsdPortsIndexItem> ports;
+public slots:
+ void setLocation();
+ void setAvail(LcacheObj *);
+
+private:
+ /**
+ * @short Add the name and version identifiers to a QMap<QString, QString>.
+ *
+ * name is parsed in to name and version and these are added to
+ * d. Errors are handled.
+ */
+ void addNV(QMap<QString, QString> &d, const QString &name);
+ int parseItem(QStringList::Iterator &it, QString &name, QString &value, QString separator, QStringList list );
+ int pathInfo(QMap<QString, QString> &a);
+
+};
+
+/**
+ * @short Ports description linked list item
+ *
+ * Each item in the list describes one port from the ports collection.
+ */
+class bsdPortsIndexItem {
+public:
+ /**
+ * desc is a line from the INDEX file (/usr/ports/INDEX under FreeBSD)
+ * which has a particular format:
+ *
+ * name|port path|inst prefix|1 line commect|DESCR file|maintainer|categories|build-deps|run-deps
+ *
+ * Multiple space separated categories may be specified.
+ *
+ * desc must remain allocated (ie, its not copied) will be modified.
+ *
+ * binaries should be true if this is a binary package.
+ *
+ * dname is the name of the base directory of this ports/packages tree.
+ */
+ bsdPortsIndexItem(fbsdInterface *parent, char *desc, bool binaries, const QString &dname);
+
+ /** @short true if this has a binary packages. */
+ bool bin;
+
+ /** @short true if this has a source port available. */
+ bool port;
+
+ /** @short true if this package is installed (set in listInstalledPackages) */
+ bool installed;
+
+ /** @short The next item in this linked list */
+ bsdPortsIndexItem *next;
+
+ QStringList fields;
+
+ enum {NAME=0, PATH, PREFIX, COMMENT, DESC_PATH, MAINT, CATS, BDEPS, RDEPS};
+
+ QString bin_filename;
+ QString bin_filename_base;
+ QString port_dirname;
+
+ /**
+ * @short Given the path to an INDEX file process each port in it.
+ *
+ * binaries should be true if the file is an index for packages, false for ports.
+ * dname is the base directory.
+ */
+ static void processFile(fbsdInterface *parent, const QString &fname, bool binaries, const QString &dname);
+
+private:
+ unsigned int name_hash;
+ static unsigned char calc_hash1(const char *name);
+ static unsigned int calc_hash4(const char *name);
+ static unsigned char hash1(unsigned int hash4);
+};
+
+#endif
+
diff --git a/kpackage/findf.cpp b/kpackage/findf.cpp
new file mode 100644
index 0000000..20e6a7c
--- /dev/null
+++ b/kpackage/findf.cpp
@@ -0,0 +1,228 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include <qlineedit.h>
+#include <qpainter.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kurldrag.h>
+#include <kiconloader.h>
+
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "findf.h"
+#include "options.h"
+#include "pkgInterface.h"
+
+extern pkgInterface *kpinterface[];
+extern Opts *opts;
+
+FindF::FindF(QWidget *parent)
+ : KDialogBase(parent, "find_file", false,
+ i18n("Find File"),
+ User1 | Close, User1, true,
+ KGuiItem(i18n("&Find"),"filefind"))
+{
+ tick = UserIcon("ptick");
+
+ QFrame *page = makeMainWidget();
+
+ setFocusPolicy(QWidget::StrongFocus);
+
+ QVBoxLayout* vtop = new QVBoxLayout( page, 10, 10, "vtop");
+ QFrame *frame1 = new QGroupBox(i18n("Find Package"), page, "frame1");
+ vtop->addWidget(frame1,1);
+
+ QGridLayout* gtop = new QGridLayout( frame1, 1, 1, 20 );
+ // gtop->setMargin( KDialog::marginHint() );
+ gtop->setSpacing( KDialog::spacingHint() );
+
+ value = new QLineEdit( frame1, "value" );
+ connect(value,SIGNAL(textChanged ( const QString & )),this,SLOT(textChanged ( const QString & )));
+ value->setFocus();
+
+ QLabel *valueLabel = new QLabel(value, i18n("Find:"), frame1);
+ valueLabel->setAlignment( AlignRight );
+
+ tab = new KListView(frame1, "tab");
+ connect(tab, SIGNAL(selectionChanged ( QListViewItem * )),
+ this, SLOT(search( QListViewItem * )));
+ tab->addColumn(i18n("Installed"),18);
+ tab->addColumn(i18n("Type"),110);
+ tab->addColumn("",0); // Hidden column for package type
+ tab->addColumn(i18n("Package"),180);
+ tab->addColumn(i18n("File Name"),330);
+ tab->setAllColumnsShowFocus(TRUE);
+ tab->setSorting(1);
+
+ if (kpackage->management->dirInstPackages->find("apt-file/deb")) {
+ searchAll = new QCheckBox(i18n("Also search uninstalled packages"), frame1, "searchAll");
+ } else {
+ searchAll = new QCheckBox(i18n("Also search uninstalled packages (apt-file needs to be installed)"), frame1, "searchAll");
+ }
+ searchAll->setChecked(FALSE);
+
+ gtop->addWidget(valueLabel, 0, 0);
+ gtop->addWidget(value, 0, 1);
+ gtop->addMultiCellWidget(tab, 1, 1, 0, 1);
+
+ gtop->addWidget(searchAll, 2, 0);
+
+ connect(this, SIGNAL(user1Clicked()), this, SLOT(ok_slot()));
+ connect(this, SIGNAL(closeClicked()), this, SLOT(done_slot()));
+ enableButton(User1 , false);
+ show();
+
+ setAcceptDrops(true);
+}
+
+FindF::~FindF()
+{
+}
+
+void FindF::checkSearchAll()
+{
+ // button not enabled if no package interface has search uninstalled
+ // packages for files ability
+ bool hasAll = FALSE;
+ for (int i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i] && opts->handlePackage[i]) {
+ if (kpinterface[i]->hasSearchAll)
+ hasAll = TRUE;
+ }
+ }
+
+ searchAll->setEnabled(hasAll);
+}
+
+void FindF::textChanged ( const QString & text)
+{
+ enableButton(User1 , !text.isEmpty());
+}
+
+void FindF::ok_slot()
+{
+ doFind(value->text());
+}
+
+void FindF::doFind(const QString &str)
+{
+ QString t;
+ int i, cnt = 0;
+
+ bool all = searchAll->isChecked();
+
+ QApplication::setOverrideCursor( waitCursor );
+
+ tab->clear();
+
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i] && opts->handlePackage[i]) {
+ QStringList filelist = kpinterface[i]->FindFile(str, all);
+
+ if (filelist.count() > 0) {
+ cnt++;
+
+ for ( QStringList::Iterator it = filelist.begin(); it != filelist.end(); ++it ) {
+ if ((*it).find("diversion by") >= 0) {
+ new QListViewItem(tab, "", *it);
+ }
+
+ int t1 = (*it).find('\t');
+ QString s1 = (*it).left(t1);
+ QString s2 = (*it).right((*it).length()-t1);
+ s2 = s2.stripWhiteSpace();
+
+ QListViewItem *ql = new QListViewItem(tab, "", kpinterface[i]->name, kpinterface[i]->head, s1, s2);
+
+ QString tx = s1 + kpinterface[i]->typeID;
+ if (kpackage->management->dirInstPackages->find(tx)) {
+ ql->setPixmap(0,tick);
+ }
+ }
+ }
+ }
+ }
+
+ if (!cnt) {
+ new QListViewItem(tab, "", i18n("--Nothing found--"));
+ }
+
+ QApplication::restoreOverrideCursor();
+}
+
+void FindF::done_slot()
+{
+ hide();
+}
+
+void FindF::resizeEvent(QResizeEvent *){
+}
+
+void FindF::search(QListViewItem *item)
+{
+ int p;
+
+ QString s = item->text(3);
+ s = s.stripWhiteSpace();
+ kdDebug() << "searchF=" << s << "\n";
+
+ p = s.find(',');
+ if (p > 0) {
+ s.truncate(p);
+ }
+
+ KpTreeListItem *k = kpackage->management->treeList->search(s ,item->text(2));
+ if (k)
+ kpackage->management->treeList->changePack(k);
+}
+
+void FindF::dragEnterEvent(QDragEnterEvent* e)
+{
+ e->accept(KURLDrag::canDecode(e));
+}
+
+void FindF::dropEvent(QDropEvent *de) // something has been dropped
+{
+ KURL::List list;
+ if (!KURLDrag::decode(de, list) || list.isEmpty())
+ return;
+
+ const KURL &url = list.first();
+
+ if (url.isLocalFile()) {
+ QString file = url.path(-1);
+ value->setText(file);
+ doFind(file);
+ } else {
+ KpMsgE(i18n("Incorrect URL type"),FALSE);
+ }
+}
+
+#include "findf.moc"
diff --git a/kpackage/findf.h b/kpackage/findf.h
new file mode 100644
index 0000000..5208c05
--- /dev/null
+++ b/kpackage/findf.h
@@ -0,0 +1,91 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#ifndef FINDF_H
+#define FINDF_H
+
+#include "../config.h"
+
+// Standard Headers
+#include <stdio.h>
+
+// Qt Headers
+#include <qdir.h>
+#include <qwidget.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qfiledialog.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+
+// KDE headers
+#include <kapplication.h>
+#include <kmenubar.h>
+#include <klistview.h>
+#include <kdialogbase.h>
+
+class FindF : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ FindF ( QWidget *parent = 0);
+ ~FindF();
+ void resizeEvent(QResizeEvent *);
+ void dropEvent(QDropEvent *);
+ void dragEnterEvent(QDragEnterEvent* e);
+ void checkSearchAll();
+
+
+private:
+ void doFind(const QString &str);
+ // Do the actual search
+
+ QLineEdit *value;
+ QListView *tab;
+ QVBoxLayout* vl;
+ QVBoxLayout* vtop, vf;
+
+ QHBoxLayout* hb;
+ QCheckBox *searchAll;
+ QPixmap tick;
+
+signals:
+ void findf_signal();
+ void findf_done_signal();
+
+public slots:
+ void done_slot();
+ void ok_slot();
+ void search(QListViewItem *);
+ void textChanged ( const QString & text);
+
+};
+
+#endif
diff --git a/kpackage/gentooInterface.cpp b/kpackage/gentooInterface.cpp
new file mode 100644
index 0000000..a8ef275
--- /dev/null
+++ b/kpackage/gentooInterface.cpp
@@ -0,0 +1,466 @@
+/*
+**
+** Copyright (C) 2004 Richard Lrkng <nouseforaname@home.se>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+#include "gentooInterface.h"
+#include "updateLoc.h"
+#include "kpackage.h"
+#include "cache.h"
+#include "kpTerm.h"
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kfilterdev.h>
+
+/* TODO
+
+ Make it possible to 'emerge sync'
+
+ Add possibilty for package manager plugins to have own compare version method,
+ and use it here for: (alpha|beta|pre|rc|p)
+
+ Slots, how to do that in a good way?
+
+ Should we care about the world-file?
+
+ Read masked packages from /usr/portage/profiles/package.mask
+
+ Use flags and CFLAGS?
+
+ Should read arch from make.conf along with directories etc
+ "~arch" implies "arch"
+
+ Do something about locateDialog, I don't want it here,
+ but I would like it to be possible to add own configuration,
+ and I don't like the crash when clicking locate ;-)
+*/
+
+Gentoo::Gentoo()
+ : pkgInterface()
+{
+ head = "Gentoo";
+ name = i18n("Gentoo");
+ icon = "gentoo";
+
+ pict = UserIcon(icon);
+ updated_pict = UserIcon("kupdated");
+ new_pict = UserIcon("knew");
+
+ packagePattern = "*.ebuild";
+ //typeID = "/kiss";
+
+ queryMsg = i18n("Querying Gentoo package list: ");
+
+ archesPossible << "~x86" << "x86";
+ portageDir="/usr/portage/";
+ QFile f(portageDir+"profiles/package.mask");
+ if (f.open(IO_ReadOnly))
+ {
+ QTextStream stream( &f );
+
+ QString line;
+ while (!stream.atEnd())
+ {
+ line = stream.readLine();
+ if (!line.startsWith("#") && !line.isEmpty())
+ {
+ // kdDebug() << "Adding: " << line << " to packageMask" << endl;
+ packageMask << line;
+ }
+ }
+ }
+
+ hasProgram = ifExe("emerge");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+Gentoo::~Gentoo()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool Gentoo::isType(char * /*buf*/, const QString &)
+{
+ return false;
+}
+
+bool Gentoo::parseName(const QString& name, QString *n, QString *v)
+{
+ // Taken from the portage code, should be correct
+ QRegExp r("([^/]+)-((\\d+(\\.\\d+)*[a-z]*)(_(alpha|beta|pre|rc|p)\\d*)?(-r(\\d+))?)$");
+
+ r.search(name);
+
+ *n = r.cap(1);
+ *v = r.cap(2);
+
+ if (n->isEmpty() || v->isEmpty())
+ return false;
+ else
+ return true;
+}
+
+void Gentoo::listInstalledPackages(QPtrList<packageInfo> *pki)
+{
+ QString vb;
+ packageInfo *p;
+
+ QString sline = i18n("Looking for Gentoo packages: ");
+
+ kpackage->setStatus(sline);
+ kpackage->setPercent(0);
+
+ QFile f(portageDir+"profiles/categories");
+ if (!f.open(IO_ReadOnly))
+ {
+ kdWarning() << "Couldn't open categories file" << endl;
+ return;
+ }
+
+ QTextStream stream( &f );
+ QStringList categories;
+ while (!stream.atEnd())
+ {
+ categories.append(stream.readLine());
+ }
+
+ int categoriesCount = categories.count();
+ int categoriesDone = 0;
+ for (QStringList::Iterator category = categories.begin(); category != categories.end(); ++category)
+ {
+ kpackage->setPercent(categoriesDone/categoriesCount);
+ categoriesDone += 100;
+
+ if (*category == "packages" || *category == "local" || *category == "virtual")
+ continue;
+
+ QDir d("/var/db/pkg/"+*category);
+ QStringList packages = d.entryList(QDir::Dirs);
+ for (QStringList::Iterator it = packages.begin(); it != packages.end(); ++it)
+ {
+ if (*it != "." && *it != "..")
+ {
+ p = collectInstalledInfo(*it, *category);
+ if (p)
+ {
+ if (!p->pkgInsert(pki, typeID, true))
+ {
+ delete p;
+ }
+ }
+ }
+ }
+ d.setPath("/var/cache/edb/dep/"+*category);
+ packages = d.entryList(QDir::Files);
+ for (QStringList::Iterator it = packages.begin(); it != packages.end(); ++it)
+ {
+ if (*it != "." && *it != "..")
+ {
+ bool isMasked = false;
+ QString version, name;
+ if (!parseName(*it, &name, &version))
+ {
+ kdDebug() << "Couldn't parse name: " << *it << endl;
+ continue;
+ }
+
+ for (QStringList::Iterator maskIt = packageMask.begin(); maskIt != packageMask.end(); ++maskIt)
+ {
+ // FIXME Should all be handled, just not implemented yet
+ if ((*maskIt).startsWith("<") || (*maskIt).startsWith("=") || (*maskIt).startsWith("~") || (*maskIt).startsWith(">"))
+ continue;
+ if (*category+"/"+name == *maskIt)
+ {
+ kdDebug() << "Package: " << name << "-" << version << " is masked" << endl;
+ isMasked = true;
+ break;
+ }
+ }
+
+ if (isMasked)
+ continue;
+
+ p = collectUninstalledInfo(name, *category, version);
+ if (p)
+ {
+ if (!p->pkgInsert(pki, typeID, false))
+ {
+ delete p;
+ }
+ }
+ }
+ }
+ }
+
+/*
+*/
+ kpackage->setPercent(100);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// mode: i = query installed u = query uninstalled
+packageInfo *Gentoo::getPackageInfo(char mode, const QString &name, const QString &version)
+{
+ packageInfo *pki = 0;
+ QString vb,search;
+
+ switch(mode)
+ {
+ ////////////////////////////////////////////////////////////////////////
+ // query an installed package!
+ case 'i':
+ pki = collectInstalledInfo(name, ""/*FIXME*/);
+ break;
+
+ ////////////////////////////////////////////////////////////////////
+ // query an uninstalled package
+ case 'u':
+ pki = collectUninstalledInfo(name, ""/*FIXME*/, version);
+ break;
+ }
+ return pki;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+packageInfo *Gentoo::collectInstalledInfo(const QString& name, const QString& category)
+{
+ QMap<QString, QString> a;
+
+ QIODevice* iod(KFilterDev::deviceForFile("/var/db/pkg/"+category+"/"+name+"/environment.bz2","application/x-bzip2", true));
+ QString line;
+ if (!iod->open(IO_ReadOnly))
+ return 0;
+ QTextStream stream( iod );
+ QString n, version, description;
+ while (!stream.atEnd())
+ {
+ line = stream.readLine();
+ if (line.startsWith("PN="))
+ {
+ n = line.mid(3);
+ a.insert("name", n);
+ }
+ else if (line.startsWith("PVR="))
+ {
+ version = line.mid(4);
+ a.insert("version", version);
+ }
+ else if (line.startsWith("DESCRIPTION="))
+ {
+ description = line.mid(12);
+ a.insert("summary", description);
+ }
+ if (a.count() >= 3)
+ break;
+ }
+ delete iod;
+ a.insert("group", category);
+// a.insert("file-size", "File-size");
+// a.insert("size", "Installed-size");
+
+ packageInfo *i = new packageInfo(a,this);
+ i->packageState = packageInfo::INSTALLED;
+ i->fixup();
+ return i;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+packageInfo *Gentoo::collectUninstalledInfo(const QString& name, const QString& category, const QString& version)
+{
+ QMap<QString, QString> a;
+
+ a.insert("name", name);
+ a.insert("group", category);
+ a.insert("version", version);
+ a.insert("base", portageDir+category+"/"+name);
+ a.insert("filename", name+"-"+version+".ebuild");
+
+ QFile f("/var/cache/edb/dep/"+category+"/"+name+"-"+version);
+ if (!f.open(IO_ReadOnly))
+ {
+ kdDebug() << "Couldn't read: " << name << "-" << version << endl;
+ return 0;
+ }
+
+ // Dep format:
+ // 1: DEPEND?
+ // 2: RDEPEND?
+ // 3: SLOT
+ // 4: SOURCE_URI
+ // 5: FEATURES
+ // 6: HOMEPAGE
+ // 7: LICENSE
+ // 8: DESCRIPTION
+ // 9: KEYWORDS (arch)
+ // 10: ECLASSES (inherited)
+ // 11: IUSE
+
+ // Skip first 7 lines for now
+ QTextStream stream( &f );
+ for (int i=0; i < 7 && !stream.atEnd(); i++)
+ stream.readLine();
+
+ if (!stream.atEnd())
+ a.insert("summary", stream.readLine());
+
+ QStringList keywords = QStringList::split(' ', stream.readLine());
+
+ bool works = false;
+ for (QStringList::Iterator it = keywords.begin(); it != keywords.end(); ++it)
+ {
+ for (QStringList::Iterator it2 = archesPossible.begin(); it2 != archesPossible.end(); ++it2)
+ {
+ if (*it == *it2)
+ {
+ works = true;
+ break;
+ }
+ }
+ if (works)
+ break;
+ }
+
+ if (!works)
+ {
+// kdDebug() << name << "-" << version << ": Doesn't contain working arch" << endl;
+ return 0;
+ }
+
+ packageInfo *i = new packageInfo(a,this);
+ i->packageState = packageInfo::AVAILABLE;
+ i->fixup();
+ return i;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList Gentoo::getChangeLog(packageInfo *p) {
+ QStringList clog;
+ QFile f(portageDir+p->getProperty("group")+"/"+p->getProperty("name")+"/ChangeLog");
+ if (!f.open(IO_ReadOnly))
+ return clog;
+ QTextStream stream(&f);
+ while (!stream.atEnd())
+ clog.append(stream.readLine());
+ return clog;
+}
+
+
+bool Gentoo::filesTab(packageInfo *p) {
+ return p->packageState == packageInfo::INSTALLED;
+}
+
+bool Gentoo::changeTab(packageInfo *) {
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QStringList Gentoo::getFileList(packageInfo *p)
+{
+ QStringList filelist;
+
+ QFile f("/var/db/pkg/"+p->getProperty("group")+"/"+p->getProperty("name")+"-"+p->getProperty("version")+"/CONTENTS");
+ if (!f.open(IO_ReadOnly))
+ return filelist;
+ QTextStream stream(&f);
+ QString line;
+ QRegExp removeEnd("(.*)( [a-f0-9]{32} [0-9]+| -> [^ ] [0-9]+| -> [^\\(]*\\([^\\)]*\\))$");
+ while (!stream.atEnd())
+ {
+ line = stream.readLine();
+
+ int pos=0;
+ while (line[pos] != ' ') pos++;
+
+ line = line.mid(pos+1);
+
+ removeEnd.search(line);
+ QString cap = removeEnd.cap(1);
+ if (!cap.isEmpty())
+ line = cap;
+
+ filelist.append(line);
+ }
+
+ return filelist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString Gentoo::uninstall(int , QPtrList<packageInfo> *plist, bool &test)
+{
+ QString cmd;
+ packageInfo *pk;
+
+ if (test)
+ cmd = "NOCOLOR=\"true\" emerge unmerge -p ";
+ else
+ cmd = "NOCOLOR=\"true\" emerge unmerge ";
+
+ for (pk = plist->first(); pk != 0; pk = plist->next()) {
+ cmd += "=" + pk->getProperty("group") + "/" + pk->getProperty("name") +
+ "-" + pk->getProperty("version") + " ";
+ }
+ return cmd;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString Gentoo::install(int, QPtrList<packageInfo> *plist, bool &test)
+{
+ QString cmd;
+ packageInfo *pk;
+
+ if (test)
+ cmd = "NOCOLOR=\"true\" emerge -p ";
+ else
+ cmd = "NOCOLOR=\"true\" emerge ";
+
+ for (pk = plist->first(); pk != 0; pk = plist->next()) {
+ cmd += "=" + pk->getProperty("group") + "/" + pk->getProperty("name") +
+ "-" + pk->getProperty("version") + " ";
+ }
+ return cmd;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+QStringList Gentoo::FindFile(const QString &, bool)
+{
+ return QStringList();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void Gentoo::setLocation()
+{
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void Gentoo::setAvail(LcacheObj *slist)
+{
+ Q_UNUSED(slist)
+}
+
+#include "gentooInterface.moc"
diff --git a/kpackage/gentooInterface.h b/kpackage/gentooInterface.h
new file mode 100644
index 0000000..12eaedb
--- /dev/null
+++ b/kpackage/gentooInterface.h
@@ -0,0 +1,68 @@
+/*
+**
+** Copyright (C) 2004 Richard Lrkng <nouseforaname@home.se>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+#ifndef GENTOOINTERFACE_H
+#define GENTOOINTERFACE_H
+
+#include "pkgInterface.h"
+
+class Gentoo : public pkgInterface
+{
+ Q_OBJECT
+
+public:
+ Gentoo();
+ ~Gentoo();
+
+ bool isType(char *buf, const QString &fname);
+ param *initinstallOptions();
+ param *inituninstallOptions();
+ packageInfo *getPackageInfo(char mode, const QString &name, const QString &version);
+ QStringList getFileList(packageInfo *p);
+ QStringList getChangeLog(packageInfo *p);
+
+ bool filesTab(packageInfo *p);
+ // If files tab is to be enabled
+
+ bool changeTab(packageInfo *p);
+ // If change log tab is to be enabled
+
+ QStringList FindFile(const QString &name, bool seachAll=false);
+ bool parseName(const QString& name, QString *n, QString *v);
+
+public slots:
+ void setLocation();
+ void setAvail(LcacheObj *);
+
+private:
+ packageInfo* collectInstalledInfo(const QString& name, const QString& category);
+ packageInfo* collectUninstalledInfo(const QString& name, const QString& category, const QString& version);
+ void listInstalledPackages(QPtrList<packageInfo> *pki);
+
+ QString install(int installFlags, QPtrList<packageInfo> *plist, bool &test);
+ QString uninstall(int uninstallFlags, QPtrList<packageInfo> *plist, bool &test);
+
+ QStringList archesPossible;
+ QString portageDir;
+ QStringList packageMask;
+};
+
+
+#endif // GENTOOINTERFACE_H
diff --git a/kpackage/icon/Makefile.am b/kpackage/icon/Makefile.am
new file mode 100644
index 0000000..7e0a8ef
--- /dev/null
+++ b/kpackage/icon/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON = kpackage
diff --git a/kpackage/icon/hi128-app-kpackage.png b/kpackage/icon/hi128-app-kpackage.png
new file mode 100644
index 0000000..8277291
--- /dev/null
+++ b/kpackage/icon/hi128-app-kpackage.png
Binary files differ
diff --git a/kpackage/icon/hi16-app-kpackage.png b/kpackage/icon/hi16-app-kpackage.png
new file mode 100644
index 0000000..fc716d0
--- /dev/null
+++ b/kpackage/icon/hi16-app-kpackage.png
Binary files differ
diff --git a/kpackage/icon/hi22-app-kpackage.png b/kpackage/icon/hi22-app-kpackage.png
new file mode 100644
index 0000000..b89a591
--- /dev/null
+++ b/kpackage/icon/hi22-app-kpackage.png
Binary files differ
diff --git a/kpackage/icon/hi32-app-kpackage.png b/kpackage/icon/hi32-app-kpackage.png
new file mode 100644
index 0000000..b938d97
--- /dev/null
+++ b/kpackage/icon/hi32-app-kpackage.png
Binary files differ
diff --git a/kpackage/icon/hi48-app-kpackage.png b/kpackage/icon/hi48-app-kpackage.png
new file mode 100644
index 0000000..4f629ea
--- /dev/null
+++ b/kpackage/icon/hi48-app-kpackage.png
Binary files differ
diff --git a/kpackage/icon/hi64-app-kpackage.png b/kpackage/icon/hi64-app-kpackage.png
new file mode 100644
index 0000000..2053a1e
--- /dev/null
+++ b/kpackage/icon/hi64-app-kpackage.png
Binary files differ
diff --git a/kpackage/kio.cpp b/kpackage/kio.cpp
new file mode 100644
index 0000000..1eb6f52
--- /dev/null
+++ b/kpackage/kio.cpp
@@ -0,0 +1,124 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include "kio.h"
+
+Kio::Kio()
+{
+}
+
+bool Kio::download(const KURL & from, const QString & to)
+{
+ KIO::Job *iojob = KIO::file_copy(from, to);
+ connect( iojob, SIGNAL( result(KIO::Job*) ),
+ SLOT( slotIOJobFinished( KIO::Job* )));
+ // missing modal widget hack here.
+ // I'd recommend using KIO::NetAccess instead (David).
+ kapp->enter_loop();
+ return worked;
+}
+
+void Kio::slotIOJobFinished( KIO::Job * job)
+{
+ worked = (job->error() == 0);
+ kapp->exit_loop();
+}
+
+Kiod::Kiod()
+{
+ file=0L;
+ fileT = 0L;
+}
+
+Kiod::~Kiod()
+{
+ delete file;
+ delete fileT;
+}
+
+bool Kiod::listDir(const QString &url, const QString &fname, bool subdirs)
+{
+ delete file;
+ file = new QFile(fname);
+ if (file->open(IO_WriteOnly)) {
+ delete fileT;
+ fileT = new QTextStream(file);
+ KIO::ListJob *job;
+ if (!subdirs)
+ job = KIO::listDir( url );
+ else
+ job = KIO::listRecursive( url, false);
+
+ kdDebug() << "started " << job << " " << subdirs << endl;
+
+ QObject::connect( job, SIGNAL( entries( KIO::Job*, const KIO::UDSEntryList& ) ),
+ SLOT( slotListEntries( KIO::Job*, const KIO::UDSEntryList& ) ) );
+ QObject::connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotFinished( KIO::Job* ) ) );
+
+ kapp->enter_loop();
+
+ file->close();
+ if (worked)
+ return TRUE;
+ else
+ return FALSE;
+ } else
+ return FALSE;
+}
+
+void Kiod::slotListEntries( KIO::Job *, const KIO::UDSEntryList& entries )
+{
+ long size = 0;
+ QString text;
+
+ KIO::UDSEntryList::ConstIterator entryIt = entries.begin();
+
+ for (; entryIt != entries.end(); ++entryIt) {
+ //kdDebug() << "listDir " << dynamic_cast<KIO::ListJob*>(job)->url() << endl;
+ for (KIO::UDSEntry::ConstIterator it = (*entryIt).begin();
+ it != (*entryIt).end(); it++ )
+ {
+ if ( (*it).m_uds == KIO::UDS_SIZE )
+ size = (*it).m_long;
+ else if ( (*it).m_uds == KIO::UDS_NAME )
+ text = (*it).m_str;
+ }
+ *fileT << text << "\n" << size << "\n";
+ kdDebug() << text << " " << size << "\n";
+ }
+}
+
+void Kiod::slotFinished( KIO::Job *job )
+{
+ //kdDebug() << "finished" << " " << job << " " << dynamic_cast<KIO::ListJob*>(job)->url() << endl;
+ worked = (job->error() == 0);
+ kapp->exit_loop();
+}
+
+#include "kio.moc"
diff --git a/kpackage/kio.h b/kpackage/kio.h
new file mode 100644
index 0000000..60614ea
--- /dev/null
+++ b/kpackage/kio.h
@@ -0,0 +1,75 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#ifndef KP_KIO_H
+#define KP_KIO_H
+
+
+#include <vector>
+
+#include <qobject.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include "../config.h"
+#include <kio/job.h>
+
+class Kio: public QObject
+{
+ Q_OBJECT
+
+public:
+ Kio();
+
+ bool download(const KURL & from, const QString & to);
+
+private:
+ bool worked;
+
+private slots:
+ void slotIOJobFinished( KIO::Job *job );
+};
+
+class Kiod: public QObject
+{
+ Q_OBJECT
+
+public:
+ Kiod();
+ ~Kiod();
+
+ bool listDir(const QString &url, const QString &fname, bool subdirs);
+
+private:
+ QFile *file;
+ QTextStream *fileT;
+ bool worked;
+
+private slots:
+ void slotListEntries( KIO::Job *, const KIO::UDSEntryList& );
+ void slotFinished( KIO::Job *);
+};
+#endif
diff --git a/kpackage/kissInterface.cpp b/kpackage/kissInterface.cpp
new file mode 100644
index 0000000..a568a18
--- /dev/null
+++ b/kpackage/kissInterface.cpp
@@ -0,0 +1,422 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include <setjmp.h>
+
+#include <qdir.h>
+#include <qfileinfo.h>
+
+#include <kurl.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+
+#include "packageInfo.h"
+#include "kissInterface.h"
+#include "updateLoc.h"
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "utils.h"
+#include "options.h"
+#include "cache.h"
+#include <klocale.h>
+
+
+extern KApplication *app;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+KISS::KISS():pkgInterface()
+{
+ head = "KISS";
+ name = i18n("KISS");
+ icon = "kiss";
+
+ pict = UserIcon(icon);
+ updated_pict = UserIcon("kupdated");
+ new_pict = UserIcon("knew");
+
+ packagePattern = "*.installer";
+ typeID = "/kiss";
+
+ locatedialog = new Locations(i18n("Location of KISS Packages"));
+ locatedialog->dLocations(2, 6, this, i18n("Folders", "F"),
+ "KISS", "*.installer",
+ i18n("Location of Folders Containing KISS Packages"));
+
+ connect(locatedialog,SIGNAL(returnVal(LcacheObj *)),
+ this,SLOT(setAvail(LcacheObj *)));
+ locatedialog->apply_slot();
+
+ queryMsg = i18n("Querying KISS package list: ");
+ procMsg = i18n("KPackage: Waiting on KISS");
+
+ param paramsInst[] = {
+ param(0,FALSE,FALSE,0)
+ };
+
+ param paramsUninst[] = {
+ param(0,FALSE,FALSE,0)
+ };
+ hasProgram = ifExe("kiss");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+KISS::~KISS()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// check if kiss file
+bool KISS::isType(char *buf, const QString &)
+{
+ if (hasProgram) {
+ QString tmp = buf;
+ if (tmp.find("perl",0,false) >= 0)
+ return true;
+ else
+ return false;
+ } else {
+ return false;
+ }
+}
+
+bool KISS::parseName(const QString& name, QString *n, QString *v)
+{
+ int d1, d2, s1;
+
+ s1 = name.findRev('.');
+ if (s1 > 0) {
+ d2 = name.findRev('-',s1-1);
+ if (d2 > 0) {
+ d1 = name.findRev('_',d2-1);
+ if (d1 < 0)
+ d1 = d2;
+ *n = name.left(d1);
+ *v = name.mid(d1+1,s1-d1-1);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void KISS::listInstalledPackages(QPtrList<packageInfo> *pki)
+{
+ QString vb;
+ packageInfo *p;
+
+ QString sline = i18n("Querying KISS package list: ");
+
+ reader.setup("kiss");
+ *reader.proc << "-qq";
+ if (!reader.start(0,FALSE))
+ return;
+
+ kpackage->setStatus(sline);
+ kpackage->setPercent(0);
+
+ vb = "" ;
+
+ int sc, sp = 0;
+ while ((sc = reader.buf.find("\n\n",sp)) >= 0) {
+ if (sc+1 == (signed int)reader.buf.length())
+ break;
+ p = collectInfo(reader.buf.mid(sp,sc-sp).ascii());
+ if (p) {
+ if (!p->pkgInsert(pki, typeID, TRUE)) {
+ delete p;
+ }
+ }
+ sp = sc + 2;
+ }
+
+ kpackage->setPercent(100);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// mode: i = query installed u = query uninstalled
+packageInfo *KISS::getPackageInfo(char mode, const QString &name, const QString &)
+{
+ packageInfo *pki = 0;
+ QString vb,search;
+
+ switch(mode)
+ {
+ ////////////////////////////////////////////////////////////////////////
+ // query an installed package!
+ case 'i':
+ reader.setup("kiss");
+ *reader.proc << "-q" << name;
+ if (reader.start(0,FALSE)) {
+ reader.buf += "package: " + name + "\n";
+ pki = collectInfo(reader.buf.ascii());
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////
+ // query an uninstalled package
+ case 'u':
+ reader.setup("perl");
+ *reader.proc << name << "-q";
+ if (reader.start(0,TRUE)) {
+ pki = collectInfo(reader.buf.ascii());
+
+ QFileInfo fi(name);
+ QString s;
+ s.setNum(fi.size());
+ pki->info.insert("file-size", s);
+ }
+ break;
+ }
+ return pki;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+packageInfo *KISS::collectInfo(const char *_inp)
+{
+ QMap<QString, QString> a;
+
+ char *str, *xstr;
+ QString qstr;
+
+ char *inp = qstrdup(_inp);
+ str = strtok(inp,"\n");
+ do {
+ xstr = strchr(str,':');
+ if (*str == ' ')
+ str++;
+ if (!strncmp("package",str,7))
+ break;
+ } while ((str = strtok(NULL,"\n")));
+
+ // parse 'name: text' elements
+
+ if (str) {
+ do {
+ if (str[0] == 0)
+ break;
+
+ xstr = strchr(str,':');
+ if (xstr) {
+ *xstr++ = 0;
+ xstr++;
+
+ for( int i = 0; str[ i ] != '\0'; ++i )
+ str[ i ] = tolower( str[ i ] );
+
+ if (*str == ' ')
+ str++;
+
+ if (!strcmp("package",str)) {
+ a.insert("name", xstr);
+ } else if (!strcmp("name",str)) {
+ a.insert("summary", xstr);
+ } else if (!strcmp("section",str)) {
+ a.insert("group", xstr);
+ } else if (!strcmp("size",str)) {
+ a.insert("file-size", xstr);
+ } else if (!strcmp("installed-size",str)) {
+ QString str = xstr;
+ a.insert("size", str + "000");
+ } else {
+ a.insert(str, xstr);
+ }
+ }
+ } while ((str = strtok(NULL,"\n")));
+ }
+
+ packageInfo *i = new packageInfo(a,this);
+ i->packageState = packageInfo::INSTALLED;
+ i->fixup();
+ delete [] inp;
+ return i;
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList KISS::getChangeLog(packageInfo *) {
+ return 0;
+}
+
+
+bool KISS::filesTab(packageInfo *) {
+ return TRUE;
+}
+
+bool KISS::changeTab(packageInfo *) {
+ return FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QStringList KISS::getFileList(packageInfo *p)
+{
+ QString vb, fn;
+ QString name;
+ char mode;
+
+ fn = p->getFilename();
+ if(!fn.isEmpty())
+ mode = 'u';
+ else
+ mode = 'i';
+
+ QStringList filelist;
+
+ switch(mode)
+ {
+ ////////////////////////////////////////////////////////////////////////
+ // query an installed package!
+ case 'i':
+ name = p->getProperty("name");
+
+ reader.setup("kiss");
+ *reader.proc << "-f" << name;
+ if (reader.start(0,FALSE)) {
+ char *buffer = qstrdup(reader.buf.ascii());
+ char *str = strtok(buffer,"\n");
+ if (str) {
+ do {
+ filelist.append(str);
+ } while ((str = strtok(NULL,"\n")));
+ }
+ delete [] buffer;
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////
+ // query an uninstalled package
+ case 'u':
+ reader.setup("perl");
+ *reader.proc << fn << "-f";
+ if (reader.start(0,TRUE)) {
+ char *buffer = qstrdup(reader.buf.ascii());
+ char *str = strtok(buffer,"\n");
+ if (str) {
+ do {
+ filelist.append(strdup(str));
+ } while ((str = strtok(NULL,"\n")));
+ }
+ delete [] buffer;
+ }
+ break;
+ }
+
+ return filelist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Call the script to install packages setting parameters
+// to kiss dependent on flags
+//////////////////////////////////////////////////////////////////////////////
+QString KISS::uninstall(int uninstallFlags, QPtrList<packageInfo> *plist, bool &test)
+{
+ QString packs;
+ packageInfo *pk;
+
+ for (pk = plist->first(); pk != 0; pk = plist->next()) {
+ packs = pk->getProperty("name");
+ doUninstall(uninstallFlags, packs, test);
+ }
+ return 0;
+}
+
+QString KISS::doUninstall(int, const QString &packs, bool &)
+{
+ return "kiss -d " + packs;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Call the script to install packages setting parameters
+// to kiss dependent on flags, returning whether everyting worked
+//////////////////////////////////////////////////////////////////////////////
+QString KISS::install(int installFlags, QPtrList<packageInfo> *plist, bool &test)
+{
+ packageInfo *pk;
+ int i = 0;
+ for (pk = plist->first(); pk != 0; pk = plist->next()) {
+ QString fname = pk->fetchFilename();
+ if (!fname.isEmpty()) {
+ doInstall(installFlags, fname, test);
+ i++;
+ }
+ }
+ return 0;
+}
+
+QString KISS::doInstall(int, const QString &packs, bool &)
+{
+ return "perl " + packs;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+QStringList KISS::FindFile(const QString &name, bool)
+{
+ QString s = "kiss -p ";
+ s += name;
+
+ QStringList filelist;
+ // filelist = kpty->run(s);
+
+ // for ( QStringList::Iterator it = filelist.begin(); it != filelist.end(); ++it ) {
+ // *it = *it + '\t' + name ;
+ // }
+
+ return filelist;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void KISS::setLocation()
+{
+ locatedialog->restore();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void KISS::setAvail(LcacheObj *slist)
+{
+ if (packageLoc)
+ delete packageLoc;
+ packageLoc = slist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+#include "kissInterface.moc"
diff --git a/kpackage/kissInterface.h b/kpackage/kissInterface.h
new file mode 100644
index 0000000..4a4484d
--- /dev/null
+++ b/kpackage/kissInterface.h
@@ -0,0 +1,87 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef KISS_IFACE_H
+#define KISS_IFACE_H
+
+#include "../config.h"
+
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <kprocess.h>
+
+#include "procbuf.h"
+#include "pkgInterface.h"
+
+class packageInfo;
+class updateLoc;
+class cacheObj;
+
+class KISS: public pkgInterface
+{
+ Q_OBJECT
+
+public:
+ KISS();
+ ~KISS();
+
+ bool isType(char *buf, const QString &fname);
+ param *initinstallOptions();
+ param *inituninstallOptions();
+ packageInfo *getPackageInfo(char mode, const QString &name, const QString &version);
+ QStringList getFileList(packageInfo *p);
+ QStringList getChangeLog(packageInfo *p);
+
+ bool filesTab(packageInfo *p);
+ // If files tab is to be enabled
+
+ bool changeTab(packageInfo *p);
+ // If change log tab is to be enabled
+
+ QStringList FindFile(const QString &name, bool seachAll=false);
+ bool parseName(const QString& name, QString *n, QString *v);
+
+public slots:
+ void setLocation();
+ void setAvail(LcacheObj *);
+
+private:
+ packageInfo* collectInfo(const char *inp);
+ void listInstalledPackages(QPtrList<packageInfo> *pki);
+
+ QString install(int installFlags, QPtrList<packageInfo> *plist, bool &test);
+ QString uninstall(int uninstallFlags, QPtrList<packageInfo> *plist, bool &test);
+
+ QString doUninstall(int installFlags, const QString &packs, bool &test);
+ QString doInstall(int installFlags, const QString &packs, bool &test);
+
+ procbuf reader;
+};
+
+#endif
+
+
+
diff --git a/kpackage/kpPty.cpp b/kpackage/kpPty.cpp
new file mode 100644
index 0000000..b395483
--- /dev/null
+++ b/kpackage/kpPty.cpp
@@ -0,0 +1,446 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#include "../config.h"
+
+#include <qtimer.h>
+#include <qregexp.h>
+
+#include <kprocctrl.h>
+#include <kpty.h>
+#include <kdebug.h>
+#include <kpassdlg.h>
+
+#include <kpPty.h>
+#include <kpackage.h>
+#include <kpTerm.h>
+#include <options.h>
+#include <utils.h>
+
+#define SHPROMPT "# "
+const int TIMEOUT = -3;
+const int PASSWORD = -2;
+const int PROMPT = -1;
+
+extern Opts *opts;
+//////////////////////////////////////////////////////////////////////////////
+
+kpKProcIO::kpKProcIO ( QTextCodec *_codec)
+ : KProcIO(_codec)
+{
+}
+
+kpKProcIO::~kpKProcIO()
+{
+}
+
+bool kpKProcIO::sstart (RunMode runmode)
+{
+
+ connect (this, SIGNAL (receivedStdout (KProcess *, char *, int)),
+ this, SLOT (received (KProcess *, char *, int)));
+
+
+ connect (this, SIGNAL (wroteStdin(KProcess *)),
+ this, SLOT (sent (KProcess *)));
+
+ return KProcess::start (runmode,( KProcess::Communication) ( KProcess::Stdin | KProcess::Stdout));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+kpPty::kpPty() : QObject()
+{
+ pty = new kpKProcIO();
+ pty->setUsePty(KProcess::All, false);
+
+ connect(pty, SIGNAL(readReady(KProcIO *)), this,
+ SLOT(readLines()));
+ connect(pty, SIGNAL(processExited(KProcess *)), this,
+ SLOT(done()));
+ pty->pty()->setWinSize(0,80);
+ tm = new QTimer(this);
+ connect(tm, SIGNAL(timeout()), this, SLOT(slotTimeout()));
+
+ eventLoop = FALSE;
+ inSession = FALSE;
+ pUnterm = FALSE;
+ loginSession = FALSE;
+
+ codec = QTextCodec::codecForLocale();
+ QMap<QString, QCString> passwords;
+}
+
+
+kpPty::~kpPty()
+{
+}
+
+void kpPty::startSu()
+{
+ kdDebug() << "startSu()\n";
+ pty->setEnvironment("PS1", SHPROMPT);
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ (*pty) << "su";
+#else
+ (*pty) << "su" << "-s" << "/bin/sh";
+#endif
+
+}
+
+void kpPty::startSudo()
+{
+ kdDebug() << "startSudo()\n";
+ pty->setEnvironment("PS1", SHPROMPT);
+ (*pty) << "sudo" << "-p" << "Password: " << "/bin/sh";
+}
+
+void kpPty::startSsh()
+{
+ kdDebug() << "startSsh()\n";
+ (*pty) << "/usr/bin/ssh" << "-t" << "-l" << "root";
+ if (hostName.isEmpty()) {
+ (*pty) << "-o" << "StrictHostKeyChecking=no" << "localhost";
+ } else {
+ (*pty) << hostName;
+ }
+ (*pty) << "env PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin PS1='" SHPROMPT "' sh";
+}
+
+bool kpPty::needSession(bool needRoot)
+{
+ return (!hostName.isEmpty() || needRoot);
+}
+
+bool kpPty::startSession(bool needRoot)
+{
+ bool interact = FALSE; // Have interacted with user, prevents loops
+ bool passwordTried = FALSE; // Have tried the current save password, so need to put up dialog
+ pUnterm = FALSE;
+ kdDebug() << "kpPty::startSession\n";
+ if (!inSession && needSession(needRoot)) {
+ // Assume !needRoot actions are simple executables
+ kdDebug() << "kpPty::startSession TRUE\n";
+ loginSession = TRUE;
+ int ret;
+ QString s = "echo START=$?\n";
+
+ FULL_RESTART:
+ interact = FALSE;
+ retList.clear();
+ pty->resetAll();
+
+ QString passMsg;
+ kdDebug() << "privCmd=" << opts->privCmd << "\n";
+ if (opts->privCmd == Opts::SSHcmd || !hostName.isEmpty()) {
+ passMsg = i18n("The action you requested uses ssh. Please enter the password or pass phrase.\n");
+ startSsh();
+ } else if (opts->privCmd == Opts::SUcmd) {
+ passMsg = i18n("The action you requested needs root privileges. Please enter root's password.\n");
+ startSu();
+ } else if (opts->privCmd == Opts::SUDOcmd) {
+ passMsg = i18n("The action you requested needs root privileges. Please enter your SUDO password.\n");
+ startSudo();
+ }
+ pty->sstart(KProcess::NotifyOnExit);
+
+ RESTART:
+ tm->start(6*1000, TRUE);
+ eventLoop = TRUE;
+ kdDebug() << "Loopst\n";
+ kapp->enter_loop();
+ kdDebug() << "Loopfn Result=" << Result << "\n";
+ tm->stop();
+ if (Result == TIMEOUT) { // timeout
+ interact = TRUE;
+ // kdDebug() << "Line=" << retList.last() << "\n";
+ kpstart->addText(retList);
+ kpstart->run("", i18n("Login Problem: Please login manually"));
+
+ ret = kpstart->exec();
+ kdDebug() << "Sret=" << ret << "\n";
+ if (ret) {
+ inSession = FALSE;
+ } else {
+ inSession = TRUE;
+ }
+ } else if (Result == PASSWORD) { // We got a password prompt
+ QCString pass;
+ int res;
+ interact = TRUE;
+ // kdDebug() << "H=" << hostName << " PH=" << passwords[hostName] << " PT=" << passwordTried <<"\n";
+ if (passwords[hostName] != 0 && !passwordTried) {
+ pass = passwords[hostName];
+ res = 1;
+ } else {
+ kdDebug() << "Passwd=" << retList.last() << "\n";
+ QString msg = passMsg;
+ // kdDebug() << "privCmd=" << opts->privCmd << " host=" << hostName.isEmpty() << "\n";
+ if (opts->privCmd == Opts::SSHcmd || !hostName.isEmpty()) {
+ msg += retList.last();
+ }
+ int keep = 1;
+ res = KPasswordDialog::getPassword(pass,msg,&keep);
+ // kdDebug() << "Pass=" << pass << " Keep=" << keep << " Res=" << res << "\n";
+ if (keep) {
+ passwords[hostName] = pass;
+ } else {
+ passwords.remove(hostName);
+ }
+ }
+ pty->writeStdin(pass.append("\n"), false);
+ passwordTried = TRUE;
+ if (res) {
+ retList.clear();
+ goto RESTART;
+ } else {
+ inSession = FALSE;
+ }
+ } else if (Result == PROMPT) { // Got Prompt
+ inSession = TRUE;
+ kdDebug() << "kpPty::startSession TRUE\n";
+ } else { // process return code
+ pty->writeStdin(QCString("\04"), false); // SU doesn't listen to ^C
+ if (interact) {
+ goto FULL_RESTART;
+ } else {
+ QString errMsg = retList.join(" ");
+ KpMsgE(errMsg, TRUE);
+ inSession = FALSE;
+ }
+ }
+ } else {
+ kdDebug() << "kpPty::startSession Not needed\n";
+ }
+
+ loginSession = FALSE;
+ if (!inSession)
+ close();
+
+ return inSession;
+}
+
+void kpPty::breakUpCmd(const QString &cmd)
+{
+ kdDebug() << " kpPty::run CMD=\""<< cmd <<"\" pty = " << pty << endl;
+
+ bool quote = FALSE;
+ QString s;
+ QStringList cl = QStringList::split(" ", cmd);
+
+ for ( QStringList::Iterator it = cl.begin(); it != cl.end(); ++it ) {
+ int lastPt = (*it).length() - 1;
+ if ((*it)[0] == '\'') { // Start of quoted string
+ s = *it;
+ if ((*it)[lastPt] == '\'') { // Also End of quoted string
+ s.replace("'","");
+ (*pty) << s;
+ quote = FALSE;
+ } else {
+ s += " ";
+ quote = TRUE;
+ }
+ } else if ((*it)[lastPt] == '\'') { // End of quoted string
+ s += *it;
+ s.replace("'","");
+ (*pty) << s;
+ quote = FALSE;
+ } else if (quote) {
+ s += *it;
+ s += " ";
+ } else {
+ (*pty) << (*it);
+ }
+ }
+}
+
+QStringList kpPty::run(const QString &cmd, bool inLoop, bool needRoot)
+{
+ Result = 0;
+
+ pUnterm = FALSE;
+
+ if (!inSession && !needSession(needRoot)) {
+ // Assume !needRoot actions are simple executables
+ pty->resetAll();
+ breakUpCmd(cmd);
+ pty->setEnvironment("TERM", "dumb");
+ if (!pty->sstart(KProcess::NotifyOnExit)) {
+ kdDebug() << " kpPty::run execute=0\n";
+ return 0;
+ }
+ } else {
+ if (startSession(needRoot)) {
+ kdDebug() << "CMDroot='"<< cmd <<"'\n";
+ QString s = cmd + ";echo RESULT=$?";
+ pty->writeStdin(s);
+ kdDebug() << " kpPty::run session\n";
+ } else {
+ kdDebug() << " kpPty::run other=0\n";
+ return 0;
+ }
+ }
+
+ retList.clear();
+
+ if (inLoop) {
+ eventLoop = TRUE;
+ kapp->enter_loop();
+
+ return retList;
+ } else {
+ return 0;
+ }
+}
+
+void kpPty::close() {
+ // kdDebug() << "kpPty::close\n";
+
+ pty->closeAll();
+ while(pty->isRunning()) {
+ KProcessController::theKProcessController->waitForProcessExit(1);
+ }
+ inSession = false;
+}
+
+void kpPty::finish(int ret)
+{
+ kdDebug() << "kpPty::finish " << ret << "\n";
+
+ QStringList::Iterator l;
+ Result = ret;
+
+ if (ret == PROMPT) { // Called program executed in session
+ if (!retList.empty()) {
+ l = retList.fromLast();
+ if ((*l).right(2) == SHPROMPT) {
+ retList.remove(l); // Remove prompt
+ }
+ }
+
+ if (!retList.empty()) {
+ int p;
+ l = retList.fromLast();
+ if ((p = (*l).find("RESULT=")) >= 0) {
+ ret = (*l).mid(p+7).toInt(0,10);
+ retList.remove(l); // Remove return code
+ } else {
+ ret = 666;
+ }
+ }
+
+ if (!retList.empty()) {
+ l = retList.begin();
+ if ( l != retList.end()) {
+ if ((*l).find("RESULT=") >= 0) {
+ retList.remove(l); // Remove command at start
+ }
+ }
+ }
+ }
+ emit result(retList,ret);
+
+
+ if (eventLoop) {
+ eventLoop = FALSE;
+ kapp->exit_loop();
+ }
+}
+
+void kpPty::readLines()
+{
+ bool unterm = FALSE;
+
+ QString stext;
+ while(pty->readln(stext, false, &unterm) >= 0)
+ {
+ stext = codec->toUnicode(stext.ascii(), stext.length());
+ emit textIn(stext, !unterm);
+// kdDebug() << "[" << pUnterm << "-" << unterm << "-" << stext << ">\n";
+ if (pUnterm) {
+ QStringList::Iterator lst = retList.fromLast();
+ if (lst != retList.end())
+ {
+ stext = *lst + stext;
+ retList.remove(lst);
+ }
+ }
+ int i;
+ if (!unterm)
+ {
+ while (stext.endsWith("\r")) {
+ stext.truncate(stext.length()-1);
+ }
+
+ i = stext.findRev('\r');
+ if (i > -1) {
+ stext = stext.mid(i+1);
+ }
+ }
+
+ pUnterm = unterm;
+
+ retList << stext;
+ // kdDebug() << "++" << stext << "\n";
+ if (stext.right(2) == SHPROMPT) { // Shell prompt
+ emit textIn("\r \n", false);
+ finish(PROMPT);
+ } else if (loginSession) {
+ QRegExp rx( "^[^:]+:[\\s]*$"); // Password prompt
+ if (rx.search(retList.last()) >= 0) {
+ kdDebug() << loginSession << " " <<retList.last()<< " Match password p\n";
+ finish(PASSWORD);
+ }
+ }
+ }
+ pty->ackRead();
+}
+
+void kpPty::keyOut(char ch)
+{
+ QCString s(2);
+ s[0] = ch;
+ s[1] = '\0';
+ pty->writeStdin(s, false);
+}
+
+void kpPty::done()
+{
+ int ret = pty->exitStatus();
+ QString stext;
+
+ //kdDebug() << "Done (" << ret << ")" << endl;
+
+ finish(ret);
+}
+
+void kpPty::slotTimeout()
+{
+ kdDebug() << "Timeout..............\n";
+ finish(TIMEOUT);
+}
+#include "kpPty.moc"
diff --git a/kpackage/kpPty.h b/kpackage/kpPty.h
new file mode 100644
index 0000000..f427ef8
--- /dev/null
+++ b/kpackage/kpPty.h
@@ -0,0 +1,106 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef KPPTY_H
+#define KPPTY_H
+
+#include <qmultilineedit.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+#include <qmap.h>
+
+#include <kprocio.h>
+
+//////////////////////////////////////////////////////////////////////////////
+
+class kpKProcIO: public KProcIO
+{
+ Q_OBJECT
+
+public:
+
+ kpKProcIO ( QTextCodec *_codec = 0);
+ ~kpKProcIO();
+
+ bool sstart (RunMode runmode);
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+class kpPty: public QObject
+{ Q_OBJECT
+public:
+ kpPty();
+ ~kpPty();
+
+ QStringList run(const QString &cmd, bool inLoop = TRUE,
+ bool needRoot= FALSE);
+ bool startSession(bool needRoot);
+ void close();
+
+ QString remote;
+ int Result;
+ // True if have started a session
+ bool inSession;
+
+private slots:
+ void readLines();
+ void done();
+ void slotTimeout();
+
+public slots:
+ void keyOut(char);
+
+signals:
+ void textIn(const QString &, bool);
+ void result(QStringList &, int);
+
+private:
+ void finish(int ret);
+
+ void startSsh();
+ void startSu();
+ void startSudo();
+ void breakUpCmd(const QString &);
+ bool needSession(bool needRoot);
+
+ kpKProcIO* pty;
+ QTimer *tm;
+ QStringList retList;
+ QRegExp terminator;
+ bool pUnterm;
+ QString uptext;
+ // True if in event loop
+ bool eventLoop;
+ // True if trying to login
+ bool loginSession;
+ QTextCodec *codec;
+ QMap<QString, QCString> passwords;
+};
+
+
+#endif
diff --git a/kpackage/kpTerm.cpp b/kpackage/kpTerm.cpp
new file mode 100644
index 0000000..0336da9
--- /dev/null
+++ b/kpackage/kpTerm.cpp
@@ -0,0 +1,234 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#include "../config.h"
+
+#include <qvbox.h>
+
+#include <kglobalsettings.h>
+#include <kdebug.h>
+
+#include <kpTerm.h>
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+kpTerm::kpTerm(kpPty *pt, QWidget * parent, const char * name ) :
+ QTextEdit(parent,name)
+{
+ pty = pt;
+ setFont(KGlobalSettings::fixedFont());
+ // setMinimumWidth(fontMetrics().maxWidth()*80 +
+ // minimumSizeHint().width());
+ setWordWrap(NoWrap);
+ setReadOnly(TRUE);
+}
+
+void kpTerm::doConnect()
+{
+ connect(pty, SIGNAL(textIn(const QString &, bool)), this,
+ SLOT(textIn(const QString &, bool)));
+ connect(pty,SIGNAL(result(QStringList &, int)),
+ this,SLOT(slotResult(QStringList &, int)));
+ connect(this, SIGNAL(keyOut(char)), pty,
+ SLOT(keyOut(char)));
+}
+
+void kpTerm::doUnconnect()
+{
+ disconnect(pty, SIGNAL(textIn(const QString &, bool)), this,
+ SLOT(textIn(const QString &, bool)));
+ disconnect(pty,SIGNAL(result(QStringList &, int)),
+ this,SLOT(slotResult(QStringList &, int)));
+ disconnect(this, SIGNAL(keyOut(char)), pty,
+ SLOT(keyOut(char)));
+}
+
+bool kpTerm::run(const QString &cmd, QStringList &r)
+{
+ setReadOnly(FALSE);
+ setFocus();
+ if (pty->startSession(TRUE)) {
+ doConnect();
+
+ r = pty->run(cmd,FALSE);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+void kpTerm::cancel() {
+ emit keyOut('\03');
+}
+
+void kpTerm::done()
+{
+ clear();
+ doUnconnect();
+ setReadOnly(TRUE);
+ clearFocus();
+}
+
+void kpTerm::keyPressEvent ( QKeyEvent * e )
+{
+ // kdDebug() << "K=" << e->ascii() << "," << e->ascii() << "\n";
+ if (e->ascii()) {
+ emit keyOut(e->ascii());
+ } else {
+ QTextEdit::keyPressEvent (e);
+ }
+ setCursorPosition(9999,9999);
+}
+
+void kpTerm::textIn(const QString &stext, bool bNewLine)
+{
+ QRegExp chrs("[\\010\\012\\015]");
+ QString del = "\010";
+ // kdDebug() << "Tin=[" << stext << "]\n";
+ if (stext.find(chrs) < 0) {
+ insert( stext );
+ } else {
+ int p;
+ int op = 0;
+
+ while ((p = stext.find(chrs,op)) >= 0) {
+ if (p != op) {
+ insert( stext.mid(op, p-op));
+ }
+ if (stext[p] == '\b') {
+ doKeyboardAction(ActionBackspace);
+ } else if (stext[p] == '\r') {
+ moveCursor(MoveLineStart, false);
+ } else if (stext[p] == '\n') {
+ moveCursor(MoveEnd, false);
+ doKeyboardAction(ActionReturn);
+ }
+ op = p + 1;
+ }
+ if ((signed int)stext.length() > op)
+ insert( stext.right(stext.length()-op));
+ }
+ if (bNewLine) {
+ moveCursor(MoveEnd, false);
+ doKeyboardAction(ActionReturn);
+ }
+ moveCursor(MoveEnd, false);
+}
+
+void kpTerm::insert ( const QString & str, bool) {
+ int x,y;
+ getCursorPosition(&y,&x);
+
+ if (str.length() > 0) {
+ // kdDebug() << "ins:" << y << "," << x << str <<":" << str.length() << "\n";
+ if (x == 0 && str != "\n") {
+ doKeyboardAction(ActionKill);
+ getCursorPosition(&y,&x);
+ // kdDebug() << "k=" << y << "," << x <<"\n";
+ }
+ QTextEdit::insert(str,(bool)FALSE);
+ }
+}
+
+void kpTerm::slotResult(QStringList &rlist, int ret)
+{
+ emit result(rlist, ret);
+ doUnconnect();
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Dialog window for password prompt
+//
+//////////////////////////////////////////////////////////////////////////////
+kpRun::kpRun( QWidget *parent)
+ : KDialogBase(parent, "kpRun", true, QString::null,
+ Cancel, Cancel, true )
+{
+ QVBox *page = makeVBoxMainWidget();
+ title = new QLabel("", page);
+ QFont f( KGlobalSettings::generalFont());
+ f.setBold(true);
+ f.setPointSize(f.pointSize()+4);
+ title->setFont(f);
+
+ term = new kpTerm(kpty,page);
+ resize(600, 300);
+ connect(term,SIGNAL(result(QStringList &, int)),
+ this,SLOT(slotResult(QStringList &, int)));
+
+ hide();
+}
+
+bool kpRun::run(QString cmd, QString msg)
+{
+ QStringList r;
+
+ title->setText(msg);
+ if (!cmd.isEmpty()) {
+ return term->run(cmd, r);
+ } else {
+ term->doConnect();
+ term->setReadOnly(FALSE);
+ term->setFocus();
+ return true;
+ }
+}
+
+void kpRun::addText(const QStringList &ret)
+{
+ int last = ret.count()-1;
+ int i = 0;
+ for ( QStringList::ConstIterator it = ret.begin(); it != ret.end(); ++it, ++i ) {
+ // kdDebug() << "ks=" << *it << "\n";
+ term->textIn(*it, (i != last));
+ }
+}
+
+void kpRun::slotResult(QStringList &, int ret)
+{
+ if (ret == 0 || ret == 666) {
+ term->clear();
+ if (ret == 0)
+ accept();
+ else
+ reject();
+ }
+}
+
+void kpRun::slotCancel()
+{
+ term->clear();
+ term->cancel();
+ accept();
+}
+
+#include "kpTerm.moc"
diff --git a/kpackage/kpTerm.h b/kpackage/kpTerm.h
new file mode 100644
index 0000000..7767565
--- /dev/null
+++ b/kpackage/kpTerm.h
@@ -0,0 +1,90 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#ifndef KPTERMD_H
+#define KPTERMD_H
+
+#include "../config.h"
+
+#include <qtextedit.h>
+#include <qstringlist.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kdialogbase.h>
+#include <kpackage.h>
+#include <kpPty.h>
+
+//////////////////////////////////////////////////////////////////////////////
+class kpTerm: public QTextEdit
+{
+ Q_OBJECT
+
+public:
+ kpTerm(kpPty *pt, QWidget * parent=0, const char * name=0);
+ void keyPressEvent ( QKeyEvent * e );
+ bool run(const QString &cmd, QStringList &r);
+ void doConnect();
+ void doUnconnect();
+ void insert ( const QString & str, bool mark=FALSE );
+ kpPty *pty;
+ void cancel();
+ void done();
+
+public slots:
+ void textIn(const QString &, bool);
+ void slotResult(QStringList &, int);
+
+signals:
+ void keyOut(char);
+ void result(QStringList &, int);
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class kpRun: public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ kpRun(QWidget *parent = 0);
+ bool run(QString cmd, QString title);
+ void addText(const QStringList &ret);
+
+public slots:
+ void slotResult(QStringList &, int);
+ void slotCancel();
+
+private:
+ kpTerm *term;
+ QLabel *title;
+};
+//////////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/kpackage/kpackage.cpp b/kpackage/kpackage.cpp
new file mode 100644
index 0000000..5c328e1
--- /dev/null
+++ b/kpackage/kpackage.cpp
@@ -0,0 +1,759 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+// Toivo Pedaste
+//
+// See kpackage.h for more information.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#include "../config.h"
+
+#include <qdir.h>
+#include <qlabel.h>
+#include <qframe.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <kprogress.h>
+#include <kurl.h>
+#include <kapplication.h>
+#include <kaccel.h>
+#include <kaction.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kstdaction.h>
+#include <kedittoolbar.h>
+#include <kmimemagic.h>
+#include <kurldrag.h>
+
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "pkgOptions.h"
+#include "kio.h"
+#include "findf.h"
+#include "search.h"
+#include "options.h"
+#include "cache.h"
+
+extern Opts *opts;
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+KPKG::KPKG(KConfig *_config)
+ : KMainWindow(0)
+{
+ kpackage = new KPACKAGE(_config, this);
+ setCentralWidget(kpackage);
+
+ config = kapp->config();
+ config->setGroup("Kpackage");
+
+ kpackage->management->readPSeparator();
+
+ // Get a nice default size
+ resize(760,540);
+
+ setupMenu();
+ disableNext();
+ disablePrevious();
+
+ optiondialog = new Options(this);
+
+ prop_restart = false;
+ setAutoSaveSettings();
+}
+
+// Set up the menu
+
+void KPKG::setupMenu()
+{
+
+ pack_open = KStdAction::open(kpackage, SLOT(fileOpen()),
+ actionCollection());
+
+ recent = KStdAction::openRecent(this, SLOT(openRecent(const KURL&)),
+ actionCollection());
+ recent->loadEntries( config );
+
+ pack_find = new KAction( i18n("Find &Package..."), "find",
+ KStdAccel::shortcut(KStdAccel::Find), kpackage,
+ SLOT(find()), actionCollection(), "pack_find");
+
+ pack_findf = new KAction( i18n("Find &File..."), "filefind",
+ 0, kpackage,
+ SLOT(findf()), actionCollection(), "pack_findf");
+
+ kpack_reload = new KAction( i18n("&Reload"), "reload",
+ KStdAccel::shortcut(KStdAccel::Reload), kpackage,
+ SLOT(reload()), actionCollection(), "kpack_reload");
+
+ (void) KStdAction::quit(kpackage, SLOT(fileQuit()),
+ actionCollection());
+
+ pack_prev = KStdAction::back(kpackage->management->treeList, SLOT(previous()),
+ actionCollection(),"pack_prev");
+
+ pack_next = KStdAction::forward(kpackage->management->treeList, SLOT(next()),
+ actionCollection(),"pack_next");
+
+ (void) (new KAction( i18n("&Expand Tree"), "ftout",
+ 0, kpackage,
+ SLOT(expandTree()), actionCollection(), "kpack_expand"));
+
+ (void) (new KAction( i18n("&Collapse Tree"), "ftin",
+ 0, kpackage,
+ SLOT(collapseTree()), actionCollection(), "kpack_collapse"));
+
+ (void) (new KAction( i18n("Clear &Marked"), QString::null,
+ 0, kpackage,
+ SLOT(clearMarked()), actionCollection(), "kpack_clear"));
+
+ (void) (new KAction( i18n("Mark &All"), QString::null,
+ 0, kpackage,
+ SLOT(markAll()), actionCollection(), "kpack_markall"));
+
+ pack_install = new KAction( i18n("&Install"), QString::null,
+ 0, kpackage->management,
+ SLOT(installSingleClicked()), actionCollection(), "install_single");
+
+ pack_install->setEnabled(false);
+ kpackage->management->setInstallAction(pack_install);
+
+
+ pack_uninstall = new KAction( i18n("&Uninstall"), QString::null,
+ 0, kpackage->management,
+ SLOT(uninstallSingleClicked()), actionCollection(), "uninstall_single");
+
+ pack_uninstall->setEnabled(false);
+ kpackage->management->setUninstallAction(pack_uninstall);
+
+
+ (void) (new KAction( i18n("&Install Marked"), QString::null,
+ 0, kpackage->management,
+ SLOT(installMultClicked()), actionCollection(), "install_marked"));
+
+ (void) (new KAction( i18n("&Uninstall Marked"), QString::null,
+ 0, kpackage->management,
+ SLOT(uninstallMultClicked()), actionCollection(), "uninstall_marked"));
+
+ setStandardToolBarMenuEnabled(true);
+
+ KStdAction::configureToolbars( this, SLOT(configureToolBars()),
+ actionCollection());
+
+ KStdAction::saveOptions( this, SLOT(saveSettings()), actionCollection());
+
+ KStdAction::keyBindings( guiFactory(), SLOT(configureShortcuts()), actionCollection());
+
+ (void) (new KAction( i18n("Configure &KPackage..."), "configure",
+ 0, this,
+ SLOT(setOptions()), actionCollection(), "kpack_options"));
+
+ (void) (new KAction( i18n("Clear Package &Folder Cache"), QString::null,
+ 0, this,
+ SLOT(clearDCache()), actionCollection(), "clear_dcache"));
+
+ (void) (new KAction( i18n("Clear &Package Cache"), QString::null,
+ 0, this,
+ SLOT(clearPCache()), actionCollection(), "clear_pcache"));
+
+ int i;
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ kpinterface[i]->makeMenu(actionCollection());
+ }
+ }
+
+ // urlList.setAutoDelete(TRUE);
+ createGUI();
+}
+
+void KPKG::disableMenu()
+{
+ pack_open->setEnabled(false);
+ pack_find->setEnabled(false);
+ pack_findf->setEnabled(false);
+ kpack_reload->setEnabled(false);
+ recent->setEnabled(false);
+}
+
+void KPKG::enableMenu()
+{
+ pack_open->setEnabled(true);
+ pack_find->setEnabled(true);
+ pack_findf->setEnabled(true);
+ kpack_reload->setEnabled(true);
+ recent->setEnabled(true);
+}
+
+void KPKG::disableNext() {
+ pack_next->setEnabled(false);
+}
+
+void KPKG::enableNext() {
+ pack_next->setEnabled(true);
+}
+
+void KPKG::disablePrevious() {
+ pack_prev->setEnabled(false);
+}
+
+void KPKG::enablePrevious() {
+ pack_prev->setEnabled(true);
+}
+void KPKG::openRecent(const KURL& url){
+ kpackage->openNetFile( url );
+}
+
+void KPKG::add_recent_file(const QString &newfile){
+
+ KURL url = KURL(newfile);
+
+ recent->addURL( url );
+}
+
+void KPKG::configureToolBars() {
+ KEditToolbar dlg(actionCollection());
+ connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(slotNewToolbarConfig()));
+ dlg.exec();
+}
+
+void KPKG::slotNewToolbarConfig() {
+ createGUI();
+}
+
+void KPKG::writeSettings(){
+
+ kpackage->management->writePSeparator();
+
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+
+ recent->saveEntries( config );
+
+ kpackage->management->treeList->writeTreeConfig();
+ kpackage->management->treeList->writeTreeType();
+
+ config->sync();
+}
+
+void KPKG::setOptions(){
+ optiondialog->restore();
+}
+
+void KPKG::saveSettings(){
+ writeSettings();
+}
+
+void KPKG::clearPCache(){
+ cacheObj::clearPCache();
+}
+
+void KPKG::clearDCache(){
+ cacheObj::clearDCache();
+}
+
+void KPKG::saveProperties(KConfig *config )
+{
+ config->writePathEntry("Name", kpackage->save_url.url());
+}
+
+
+void KPKG::readProperties(KConfig *config)
+{
+ QString entry = config->readPathEntry("Name"); // no default
+ if (entry.isNull())
+ return;
+ kpackage->openNetFiles(entry);
+ prop_restart = true;
+}
+
+bool KPKG::queryClose() {
+ kpackage->cleanUp();
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+KPACKAGE::KPACKAGE(KConfig *_config, QWidget *parent)
+ : QWidget(parent)
+{
+
+ // Save copy of config
+ config = _config;
+
+ setAcceptDrops(true);
+ setupModeWidgets();
+
+ setupStatusBar();
+
+ file_dialog = NULL;
+ findialog = NULL;
+ srchdialog = NULL;
+
+}
+
+// Destructor
+KPACKAGE::~KPACKAGE()
+{
+ // destroyModeWidgets();
+ // delete status;
+ // delete processProgress;
+}
+
+// resize event -- arrange the widgets
+void KPACKAGE::resizeEvent(QResizeEvent *re)
+{
+ re = re; // prevent warning
+ arrangeWidgets();
+}
+
+// Set up the mode widgets
+void KPACKAGE::setupModeWidgets()
+{
+ management = new managementWidget(this);
+
+ for (int i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ kpinterface[i]->uninstallation = new pkgOptionsU(kpinterface[i]);
+ kpinterface[i]->installation = new pkgOptionsI(kpinterface[i]);
+ }
+ }
+}
+
+// destroy the mode widgets
+void KPACKAGE::destroyModeWidgets()
+{
+ // delete management;
+ // for (int i = 0; i < kpinterfaceN; i++) {
+ // if (kpinterface[i]) {
+ // delete kpinterface[i]->installation;
+ // delete kpinterface[i]->uninstallation;
+ // }
+ // }
+}
+
+
+// Set up the status bar
+void KPACKAGE::setupStatusBar()
+{
+ statusbar = new QFrame(this);
+ statusbar->setFrameStyle(QFrame::Raised | QFrame::Panel);
+ processProgress = new KProgress(100,statusbar);
+ processProgress->setTextEnabled(FALSE);
+
+ status = new QLabel(i18n("Management Mode"), statusbar);
+}
+
+// Arrange the widgets nicely
+void KPACKAGE::arrangeWidgets()
+{
+ int i;
+
+ statusbar->resize(width(),20);
+ statusbar->move(0,height()-20);
+ status->resize((statusbar->width() / 4) * 3, 16);
+ status->move(2,2);
+ processProgress->resize(statusbar->width() / 4 - 4, 16);
+ processProgress->move((statusbar->width() / 4) * 3 + 3, 2);
+
+ management->resize(width(),height() - 20);
+
+ for (i = 0; i < kpinterfaceN; i++)
+ if (kpinterface[i]) {
+ kpinterface[i]->installation->resize(width(),height() - 20);
+ }
+}
+
+void KPACKAGE::setup()
+{
+ management->collectData(1);
+}
+
+void KPACKAGE::fileQuit() // file->quit selected from menu
+{
+ cleanUp();
+
+ KApplication::exit(0); // exit the application
+}
+
+void KPACKAGE::cleanUp() // file->quit selected from menu
+{
+ kpkg->writeSettings();
+ if (opts->DCache >= Opts::SESSION) {
+ cacheObj::clearDCache(); // clear dir caches if needed
+ }
+ if (opts->PCache >= Opts::SESSION) {
+ cacheObj::clearPCache(); // clear package caches if needed
+ }
+}
+
+void KPACKAGE::reload()
+{
+ kpackage->management->collectData(TRUE);
+}
+
+void KPACKAGE::fileOpen() // file->quit selected from menu
+{
+ KFileDialog *box;
+
+ box = getFileDialog(i18n("Select Package"));
+
+ if( box->exec())
+ {
+ if(!box->selectedURL().isEmpty())
+ {
+ openNetFile( box->selectedURL() );
+ }
+ }
+}
+
+void KPACKAGE::clearMarked()
+{
+ management->treeList->clearMarked(management->treeList->firstChild());
+}
+
+void KPACKAGE::markAll()
+{
+ management->treeList->markAll(management->treeList->firstChild());
+}
+
+void KPACKAGE::expandTree()
+{
+ management->treeList->expandTree(management->treeList);
+}
+
+void KPACKAGE::collapseTree()
+{
+ management->treeList->collapseTree(management->treeList);
+}
+
+pkgInterface *KPACKAGE::pkType(const QString &fname)
+{
+ // Get the package information for this package
+ char buf[51];
+ int i;
+
+ FILE *file= fopen(QFile::encodeName(fname),"r");
+ if (file) {
+ fgets(buf,sizeof(buf)-1,file);
+ buf[50] = 0;
+
+ // check enabled package handlers
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ if (opts->handlePackage[i] && kpinterface[i]->isType(buf, fname)) {
+ fclose(file);
+ return kpinterface[i];
+ }
+ }
+ }
+ // check unenabled package handlers
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ if (!opts->handlePackage[i] && kpinterface[i]->isType(buf, fname)) {
+ fclose(file);
+ return kpinterface[i];
+ }
+ }
+ }
+ fclose(file);
+ KpMsgE(i18n("Unknown package type: %1").arg(fname),TRUE);
+ } else {
+ KpMsgE(i18n("File not found: %1").arg(fname),TRUE);
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////
+int KPACKAGE::typeIndex(pkgInterface *type) {
+ int i;
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (type == kpinterface[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void KPACKAGE::openNetFiles (const QStringList &urls, bool install )
+{
+ QStringList files;
+ int i;
+ int index;
+ QPtrList<packageInfo> **lst = new QPtrList<packageInfo>*[kpinterfaceN];
+ packageInfo *pk = 0;
+
+ kdDebug() << "openNetFiles\n";
+
+ for (QStringList::ConstIterator it = urls.begin(); it != urls.end(); ++it) {
+ files.append(fetchNetFile(*it));
+ kpkg->add_recent_file(*it);
+ }
+
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ lst[i] = new QPtrList<packageInfo>;
+ }
+ }
+
+ for (QStringList::Iterator t = files.begin(); t != files.end(); ++t) {
+ pkgInterface *type = pkType(*t);
+ index = typeIndex(type);
+ if (index >= 0) {
+ pk = type->getPackageInfo('u', *t, 0);
+ if (pk) {
+ pk->pkgFileIns(*t);
+ lst[index]->insert(0,pk);
+ }
+ }
+ }
+
+ if (install)
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ if ( lst[i]->count() > 0) {
+ kpinterface[i]->installation->setup(lst[i],kpinterface[i]->head);
+ if (kpinterface[i]->installation->exec()) {
+ for (packageInfo *inf = lst[i]->first(); inf != 0; inf = lst[i]->next()) {
+ kpackage->management->updatePackage(inf,TRUE);
+ }
+ }
+ }
+ }
+ } else {
+ if (pk) {
+ KpTreeListItem *pt = pk->item;
+ // NOT the best place for this CODE
+ kpackage->management->tabChanged(Opts::ALL);
+ if (pt)
+ kpackage->management->packageHighlighted(pt);
+ }
+ }
+
+ // Dealloc memory
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ delete lst[i];
+ }
+ }
+ delete [] lst;
+}
+
+void KPACKAGE::openNetFile(const KURL &url, bool install )
+{
+ openNetFiles(url.url(), install);
+}
+
+// KMimeMagic *magic = KMimeMagic::self();
+// KMimeMagicResult *r = magic->findFileType(s);
+ // printf("r=%s\n",(r->mimeType()).data());
+
+
+
+QString KPACKAGE::getFileName(const KURL & url, QString &cacheName )
+{
+ QString none = "";
+ QString fname = "";
+
+ if ( !url.isValid() ) {
+ KpMsgE(i18n("Malformed URL: %1").arg(url.url()),TRUE);
+ } else {
+
+ // Just a usual file ?
+ if ( url.isLocalFile() ) {
+ cacheName = url.path();
+ fname = url.path();
+ } else {
+
+ QString tmpd = cacheObj::PDir();
+ if (!tmpd.isEmpty()) {
+
+ QString cacheFile = tmpd + url.fileName();
+
+ cacheName = cacheFile;
+ QFileInfo f(cacheFile);
+ if (f.exists() && (opts->DCache != Opts::NEVER)) {
+ fname = cacheFile;
+ }
+ }
+ }
+ }
+ return fname;
+}
+
+bool KPACKAGE::isFileLocal( const KURL & url )
+{
+ QString cf;
+
+ QString f = getFileName(url, cf);
+
+ if (cf.isEmpty()) {
+ return false;
+ } else {
+ if (!f.isEmpty()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
+QString KPACKAGE::fetchNetFile( const KURL & url )
+{
+
+ QString cf;
+
+ QString f = getFileName(url, cf);
+
+ if (cf.isEmpty()) {
+ return "";
+ } else {
+
+ if (!f.isEmpty()) {
+ return f;
+ } else {
+ save_url = url;
+
+ setStatus(i18n("Starting KIO"));
+
+ Kio kio;
+
+ if (kio.download(url, cf)) {
+ setStatus(i18n("KIO finished"));
+ QFileInfo fi(cf);
+ if (!(fi.exists() && fi.size() > 0)) {
+ unlink(QFile::encodeName(cf));
+ return "";
+ } else {
+ CacheList cl(fi.dirPath());
+ cl.append(fi.fileName());
+ cl.write();
+ return cf;
+ }
+ } else {
+ setStatus(i18n("KIO failed"));
+ return "";
+ }
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////
+void KPACKAGE::fileOpenUrl(){
+
+ bool ok;
+
+ QString url = KInputDialog::getText( QString::null,
+ i18n( "Open location:" ), save_url.prettyURL(), &ok, this );
+
+ if ( ok )
+ {
+ kpkg->add_recent_file( url );
+ openNetFile( url );
+ }
+}
+
+void KPACKAGE::find(){
+ if (srchdialog)
+ srchdialog->show();
+ else
+ srchdialog = new Search(this, "find package");
+}
+
+void KPACKAGE::findf(){
+ if (findialog)
+ findialog->show();
+ else
+ findialog = new FindF(this);
+}
+
+KFileDialog* KPACKAGE::getFileDialog(const QString &captiontext)
+{
+
+ if(!file_dialog) {
+ file_dialog = new KFileDialog(QDir::currentDirPath(), "",
+ this,"file_dialog",TRUE);
+ }
+
+ QString pat;
+ for (int i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i] && opts->handlePackage[i]) {
+ pat += kpinterface[i]->packagePattern;
+ pat += " ";
+ }
+ }
+ file_dialog->setFilter(pat);
+ file_dialog->setCaption(captiontext);
+ // file_dialog->rereadDir();
+
+ return file_dialog;
+}
+
+void KPACKAGE::dragEnterEvent(QDragEnterEvent* e)
+{
+ e->accept(KURLDrag::canDecode(e));
+}
+
+void KPACKAGE::dropEvent(QDropEvent *de) // something has been dropped
+{
+ KURL::List list;
+ if (!KURLDrag::decode(de, list) || list.isEmpty())
+ return;
+
+ openNetFiles(list.toStringList());
+}
+
+void KPACKAGE::setStatus(const QString &s) // set the text in the status bar
+{
+ status->setText(s);
+ kapp->processEvents(); // refresh the screen
+}
+
+QString KPACKAGE::getStatus() // get the text in the status bar
+{
+ if(status)
+ return status->text();
+ else
+ return "";
+}
+
+void KPACKAGE::setPercent(int x) // set the progress in the status bar
+{
+ processProgress->setValue(x);
+ kapp->processEvents(); // refresh it
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+#include "kpackage.moc"
diff --git a/kpackage/kpackage.desktop b/kpackage/kpackage.desktop
new file mode 100644
index 0000000..6974aa9
--- /dev/null
+++ b/kpackage/kpackage.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Name=KPackage
+Name[af]=Kpackage
+Name[ar]=برنامج KPackage
+Name[bn]=কে-প্যাকেজ
+Name[eo]=Pakaĵadministrilo
+Name[fo]=KPakka
+Name[hi]=के-पैकेज
+Name[lv]=KPakotne
+Name[mn]=КДЕ Багц
+Name[ne]=केडीई प्याकेज
+Name[pa]=ਕੇ-ਪੈਕੇਜ
+Name[pl]=Pakiety
+Name[sv]=Kpackage
+Name[ta]=கே தொகுப்பு
+Name[th]=จัดการแพ็คเกจ - K
+Name[ven]=Tshiputo tsha K
+Name[xh]=UdibanisolweK
+Name[zu]=kphakethe
+GenericName=Package Manager
+GenericName[af]=Paket Bestuurder
+GenericName[ar]=مسيير الحزمات
+GenericName[az]=Paket İdarəçisi
+GenericName[bg]=Мениджър на пакети
+GenericName[bn]=প্যাকেজ ম্যানেজার
+GenericName[br]=Merour ar pakadoù
+GenericName[bs]=Upravitelj paketima
+GenericName[ca]=Gestor de paquets
+GenericName[cs]=Správce balíčků
+GenericName[cy]=Rheolydd Pecynnau
+GenericName[da]=Pakkehåndtering
+GenericName[de]=Paketmanager
+GenericName[el]=Διαχειριστής πακέτων
+GenericName[eo]=Administrilo por programpakaĵoj
+GenericName[es]=Administrador de paquetes
+GenericName[et]=Pakettide haldamine
+GenericName[eu]=Pakete kudeatzailea
+GenericName[fa]=مدیر بسته
+GenericName[fi]=Ohjelmapakettien hallinta
+GenericName[fo]=Pakkahandfarari
+GenericName[fr]=Gestionnaire de paquetages
+GenericName[ga]=Bainisteoir Pacáistí
+GenericName[gl]=Xestor de Pacotes
+GenericName[he]=מנהל חבילות
+GenericName[hi]=पैकेज प्रबंधक
+GenericName[hr]=Alat za upravljanje paketima
+GenericName[hu]=Telepítő
+GenericName[is]=Pakkastjóri
+GenericName[it]=Gestione pacchetti
+GenericName[ja]=パッケージマネージャ
+GenericName[ka]=პაკეტების მმართველი
+GenericName[kk]=Дестелер менеджері
+GenericName[km]=កម្មវិធី​គ្រប់គ្រង​កញ្ចប់
+GenericName[ko]=꾸러미 관리자
+GenericName[lt]=Paketų tvarkyklė
+GenericName[lv]=Pakotņu Menedžers
+GenericName[mk]=Менаџер на пакети
+GenericName[mn]=Багц Зохицуулагч
+GenericName[ms]=Pengurus Pakej
+GenericName[mt]=Manager ta' pakketti
+GenericName[nb]=Pakkebehandler
+GenericName[nds]=Paket-Pleger
+GenericName[ne]=प्याकेज प्रबन्धक
+GenericName[nl]=Pakketbeheerder
+GenericName[nn]=Pakkehandsamar
+GenericName[pa]=ਪੈਕੇਜ ਪਰਬੰਧਕ
+GenericName[pl]=Menedżer pakietów
+GenericName[pt]=Gestor de Pacotes
+GenericName[pt_BR]=Gerenciador de Pacotes
+GenericName[ro]=Manager de pachete
+GenericName[ru]=Менеджер пакетов
+GenericName[se]=Páhkkagieđahalli
+GenericName[sk]=Správca balíkov
+GenericName[sl]=Upravljalnik paketov
+GenericName[sr]=Менаџер пакета
+GenericName[sr@Latn]=Menadžer paketa
+GenericName[sv]=Pakethanterare
+GenericName[ta]=தொகுப்பு மேலாளர்
+GenericName[tg]=Роҳбари Package
+GenericName[th]=เครื่องมือจัดการแพ็คเกจ
+GenericName[tr]=Paket Yöneticisi
+GenericName[uk]=Менеджер пакунків
+GenericName[ven]=Phakhedzhi ya Murangaphanda
+GenericName[vi]=Bộ quản lý gói
+GenericName[wa]=Manaedjeu di pacaedjes
+GenericName[xh]=Umphathi Wokudityaniswe kunye
+GenericName[zh_CN]=软件包管理器
+GenericName[zh_HK]=套件管理程式
+GenericName[zh_TW]=套件管理程式
+GenericName[zu]=Umphathi Wokusongwayo
+MimeType=application/x-rpm;application/x-deb;
+Exec=kpackage -caption "%c" %i %m %u
+Icon=kpackage
+Type=Application
+DocPath=kpackage/index.html
+Terminal=false
+Path=
+InitialPreference=5
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;System;
diff --git a/kpackage/kpackage.h b/kpackage/kpackage.h
new file mode 100644
index 0000000..07d22da
--- /dev/null
+++ b/kpackage/kpackage.h
@@ -0,0 +1,336 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+** This is the main widget for kpackage
+** The whole widget is a DND drop zone where users can drop packages to
+** be installed.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+
+#ifndef KPACKAGE_H
+#define KPACKAGE_H
+
+#include "../config.h"
+
+// KDE headers
+#include <kurl.h>
+#include <kmainwindow.h>
+#include <kpPty.h>
+
+class KFileDialog;
+class KProgress;
+class QFrame;
+class KConfig;
+class QLabel;
+class Search;
+class FindF;
+class Options;
+class pkgInterface;
+class managementWidget;
+class KAccel;
+class QDropEevnt;
+class KRecentFilesAction;
+class KAction;
+class kpRun;
+
+#define kpinterfaceN 7
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class KPACKAGE : public QWidget
+{
+ Q_OBJECT
+
+ ///////////// METHODS ------------------------------------------------------
+public:
+ KPACKAGE(KConfig *_config, QWidget *parent);
+ // Constructor
+
+ ~KPACKAGE();
+ // Destructor
+
+ enum { OPEN_READWRITE = 1,
+ OPEN_READONLY = 2,
+ OPEN_INSERT = 4 };
+
+ void setStatus(const QString &s);
+ // this sets the status bar's string to s
+
+ void setPercent(int x);
+ // this set the status bar's progress to x
+
+ QString getStatus();
+ // this gets the current status string on the status bar
+
+ // void setMode(int newmode, pkgInterface *type, int refresh);
+ // This sets the mode to newmode and updates the display accordingly.
+
+ void setup();
+
+ pkgInterface *pkType(const QString &fname);
+ // find type of package
+
+ int typeIndex(pkgInterface *);
+ // convert interface pointer to index
+
+ void openNetFiles(const QStringList &urls, bool install=TRUE);
+ void openNetFile(const KURL & url, bool install=TRUE);
+ // open a file given a URL
+
+ QString fetchNetFile(const KURL & url);
+ // fetch a file given a URL
+
+ static QString getFileName(const KURL & url, QString &cacheName);
+ // return file name, if not local file cachename is name for cache entry
+
+ static bool isFileLocal( const KURL & url );
+ // true if URL refers to local or cached file
+
+protected:
+ void resizeEvent(QResizeEvent *re);
+ // This is called when the widget is resized
+
+ void dropEvent(QDropEvent *);
+ // This is called when a URL has been dropped in the drop zone
+
+ void dragEnterEvent(QDragEnterEvent* e);
+
+private:
+
+ void setupModeWidgets();
+ // This sets up the mode widgets (ie management/installation widgets)
+
+ void destroyModeWidgets();
+ // This deletes the mode widgets (ie management/installation widgets)
+
+ void setupStatusBar();
+ // This sets up the status bar
+
+ void arrangeWidgets();
+ // This arranges the widgets in the window (should be called after a
+ // resize event)
+
+ KFileDialog* getFileDialog(const QString &captiontext);
+
+ ///////////// SLOTS --------------------------------------------------------
+public slots:
+
+// void modeFinished(int mode, pkgInterface *interface, int refresh);
+ // This is called when the mode `mode' has finished. KPACKAGE should
+ // then change modes appropriately
+
+ void fileOpen();
+ // This is called when File->Open is selected from the menu
+
+ void clearMarked();
+ // clear package Marks
+
+ void markAll();
+ // mark all packages in the selected view
+
+ void expandTree();
+ void collapseTree();
+ // expand and collapse file tree
+
+ void fileOpenUrl();
+ // menu item FIle->OpenUrl
+
+ void find();
+ // search for package
+
+ void findf();
+ // search for file in package
+
+ void fileQuit();
+ // This is called when File->Quit is selected from the menu
+
+ void cleanUp();
+ // Cleanup for Exit
+
+ void reload();
+ // reload file package infomation
+
+ ///////////// SIGNALS ------------------------------------------------------
+
+ ///////////// DATA ---------------------------------------------------------
+public:
+
+ enum { Management, Installation } ;
+ // Widget modes
+
+ KConfig *config;
+ // pointer to kconfig object
+
+ managementWidget *management;
+ // management widget
+
+ KURL save_url;
+ // save the URL entered
+
+ FindF *findialog;
+ // find file dialog
+
+private:
+ int mode;
+ // Widget mode
+
+ // Menu item identifiers
+
+ QFrame *statusbar;
+ // the status bar
+
+ KProgress *processProgress;
+ // Progress bar for showing progress
+
+ QLabel *status;
+ // The actual status
+
+ KFileDialog *file_dialog;
+ /// If we load a file from the net this is the corresponding URL
+
+ Search *srchdialog;
+ // find package dialog
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class KPKG : public KMainWindow
+{
+ Q_OBJECT
+
+ enum { Tback = 1,
+ Tforward = 2,
+ Tfileopen = 3,
+ Tftout = 4,
+ Tftin = 5,
+ Tfind = 6,
+ Tfindf = 7,
+ Treload = 8
+ };
+
+public:
+
+ KPKG(KConfig *_config);
+ // Constructor
+
+ void add_recent_file(const QString &newfile);
+ // keep list of files accessed
+
+ void writeSettings();
+ // write config settings
+
+ void saveProperties(KConfig *config);
+ void readProperties(KConfig *config);
+ // save and read restart sstate
+
+ void disableMenu();
+ void enableMenu();
+ // enable/deisable menu elements
+
+ bool prop_restart;
+ // indicates a restart from saved state
+
+ Options *optiondialog;
+ // Options dialog
+
+ KConfig *config ;
+ // Saved config information
+
+ void disableNext();
+ void enableNext();
+ void disablePrevious();
+ void enablePrevious();
+ // Control next and previous commands
+
+
+private:
+
+ void setupMenu();
+ // This sets up the menubar
+
+ QStrList recent_files;
+
+ KAction *pack_open;
+ KAction *pack_find;
+ KAction *pack_findf;
+ KAction *kpack_reload;
+ KAction *pack_prev;
+ KAction *pack_next;
+ KAction *pack_install;
+ KAction *pack_uninstall;
+
+ int toolID, selectID;
+ // refrences to toolbar and menu items
+
+ bool hide_toolbar;
+ // don't display toolbar
+
+ KRecentFilesAction *recent;
+
+public slots:
+
+ void openRecent(const KURL& url);
+ // opens file from list of recently opened ones
+
+ void setOptions();
+ // set options
+
+ void saveSettings();
+ // save config
+
+ void configureToolBars();
+
+ void clearPCache();
+ // Clear package cache
+
+ void clearDCache();
+ // Clear directory cache
+
+private slots:
+ void slotNewToolbarConfig();
+
+protected:
+ bool queryClose ();
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern KPKG *kpkg;
+extern KPACKAGE *kpackage;
+extern kpPty *kpty;
+extern kpRun *kprun;
+extern kpRun *kpstart;
+
+extern QString hostName;
+
+extern pkgInterface *kpinterface[];
+
+void KpMsg(const QString &lab, const QString &msg, bool stop);
+void KpMsgE(const QString &msg, bool stop = FALSE);
+#endif
+
diff --git a/kpackage/kpackageui.rc b/kpackage/kpackageui.rc
new file mode 100644
index 0000000..b3229b9
--- /dev/null
+++ b/kpackage/kpackageui.rc
@@ -0,0 +1,60 @@
+<!DOCTYPE kpartgui >
+<kpartgui name="kpackage" version="4">
+ <MenuBar>
+ <Menu name="file" >
+ <text>&amp;File</text>
+ <Action name="pack_find" />
+ <Action name="pack_findf" />
+ <Separator/>
+ <Action name="kpack_reload" />
+</Menu>
+
+<Menu name="packages" >
+ <text>&amp;Packages</text>
+ <Action name="pack_prev" />
+ <Action name="pack_next" />
+ <Separator/>
+ <Action name="kpack_expand" />
+ <Action name="kpack_collapse" />
+ <Separator/>
+ <Action name="kpack_clear" />
+ <Action name="kpack_markall" />
+ <Separator/>
+ <Action name="install_single" />
+ <Action name="install_marked" />
+ <Action name="uninstall_single" />
+ <Action name="uninstall_marked" />
+</Menu>
+
+<Menu name="cache" >
+ <text>&amp;Cache</text>
+ <Action name="clear_dcache" />
+ <Action name="clear_pcache" />
+</Menu>
+
+<Menu name="special" >
+ <text>Spe&amp;cial</text>
+ <Menu name="debapt" >
+ <text>&amp;APT: Debian</text>
+ <Action name="debapt_update" />
+ <Action name="debapt_upgrade" />
+ <Action name="debapt_fixup" />
+ <Action name="debapt_file" />
+ </Menu>
+</Menu>
+
+<Menu name="settings" >
+ <text>&amp;Settings</text>
+ <Action name="kpack_options" append="configure_merge"/>
+</Menu>
+</MenuBar>
+ <ToolBar position="Left" name="mainToolBar" >
+ <Action name="pack_prev" />
+ <Action name="pack_next" />
+ <Action name="kpack_expand" />
+ <Action name="kpack_collapse" />
+ <Action name="pack_find" />
+ <Action name="pack_findf" />
+ <Action name="kpack_reload" />
+ </ToolBar>
+</kpartgui>
diff --git a/kpackage/kplview.cpp b/kpackage/kplview.cpp
new file mode 100644
index 0000000..1889150
--- /dev/null
+++ b/kpackage/kplview.cpp
@@ -0,0 +1,667 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+#include <qpixmap.h>
+#include <qptrstack.h>
+#include <qheader.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+// kpackage.headers
+#include "kpackage.h"
+#include "pkgInterface.h"
+#include "packageInfo.h"
+#include "managementWidget.h"
+#include "packageDisplay.h"
+#include "kplview.h"
+#include "options.h"
+
+#define MPOS 1
+
+KpTreeList::KpTreeList( QWidget *parent ) :
+KListView (parent)
+{
+ markPkg = 0;
+ setShowSortIndicator(true);
+
+ QPtrStack<QString> stack();
+ readTreeType();
+
+ setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ setLineWidth(2);
+ setItemMargin(2);
+ addColumn(i18n("Package"));
+ setColumnWidthMode(0,QListView::Manual);
+ addColumn(i18n("Mark"));
+ setColumnWidthMode(1,QListView::Manual);
+ addColumn(i18n("Summary"));
+ setColumnWidthMode(2,QListView::Manual);
+ addColumn(i18n("Size"));
+ setColumnWidthMode(3,QListView::Manual);
+ addColumn(i18n("Version"));
+ setColumnWidthMode(4,QListView::Manual);
+ addColumn(i18n("Old Version"));
+ setColumnWidthMode(5,QListView::Manual);
+
+ // setAllColumnsShowFocus(TRUE);
+ setRootIsDecorated(TRUE);
+ readTreeConfig();
+ update();
+ show();
+
+}
+
+void KpTreeList::clear()
+{
+ markPkg = 0;
+ emit cleared();
+ KListView::clear();
+}
+
+KpTreeListItem *KpTreeList::firstChild()
+{
+ return (KpTreeListItem *)KListView::firstChild();
+}
+
+KpTreeListItem *KpTreeList::currentItem()
+{
+ return (KpTreeListItem *)KListView::currentItem();
+}
+
+void KpTreeList::contentsMousePressEvent ( QMouseEvent * e )
+{
+ bool markUpdate = false;
+
+ if (e->button() == LeftButton) {
+ if (inMark(e->x())) {
+ QPoint vp = contentsToViewport(e->pos());
+ KpTreeListItem *i = ( KpTreeListItem *)itemAt( vp );
+ if (i && i->childCount() == 0) {
+ if (e->state() == ShiftButton) {
+ if (i->childCount() == 0) {
+ i->setMark(true);
+ markUpdate = true;
+ }
+ KpTreeListItem *item = i;
+ while ((item = (KpTreeListItem *)item->itemAbove()) && !item->marked) {;}
+ if (item) {
+ item = i;
+ while ((item = (KpTreeListItem *)item->itemAbove()) && !item->marked) {
+ if (item->childCount() == 0) {
+ item->setMark(true);
+ markUpdate = true;
+ }
+ }
+ } else {
+ item = i;
+ while ((item = (KpTreeListItem *)item->itemBelow()) && !item->marked) {;}
+ if (item) {
+ item = i;
+ while ((item = (KpTreeListItem *)item->itemBelow()) && !item->marked) {
+ if (item->childCount() == 0) {
+ item->setMark(true);
+ markUpdate = true;
+ }
+ }
+ }
+ }
+ } else {
+ i->toggleMark();
+ markUpdate = true;
+ }
+ setCurrentItem(i);
+ } else
+ KListView::contentsMousePressEvent (e);
+ } else
+ KListView::contentsMousePressEvent (e);
+ }
+
+ if (markUpdate)
+ emit updateMarked();
+
+}
+
+bool KpTreeList::inMark(int x) {
+ int st = 0;
+ int i;
+
+
+ QHeader* const thisHeader = header();
+ int mpos = thisHeader->mapToIndex(MPOS);
+
+ for (i = 0; i < mpos; i++)
+ st += columnWidth(i);
+
+ return (x >= st && x <= st + columnWidth(mpos));
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+void KpTreeList::expand()
+{
+ KpTreeListItem *item = firstChild();
+
+ if (!item)
+ return;
+
+ do {
+ expandChild(item->firstChild());
+ } while ((item = item->nextSibling()));
+}
+
+void KpTreeList::expandChild(KpTreeListItem *it)
+{
+ do {
+ if (it->childCount() > 0) {
+ expandChild(it->firstChild());
+ it->setVisible(true);
+ }
+
+ } while ((it = it->nextSibling()));
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void KpTreeList::sweep(bool init)
+{
+ KpTreeListItem *item = firstChild();
+
+ if (!item)
+ return;
+
+ if (init) {
+ expand();
+ }
+
+ do {
+ sweepChild(item->firstChild());
+ } while ((item = item->nextSibling()));
+}
+
+int KpTreeList::sweepChild(KpTreeListItem *it)
+{
+ int ret, shown = 0;
+
+ do {
+ if (it->childCount() > 0) {
+ ret = sweepChild(it->firstChild());
+ // kdDebug()<<"VV="<<it->text(0)<<" "<<it->isVisible()<<" " << ret << "\n";
+ if (!ret) {
+ it->setVisible(false);
+ } else {
+ if (it->isVisible())
+ shown += ret;
+ }
+ } else {
+ // kdDebug()<<"VV="<<it->text(0)<<" "<<it->isVisible()<<"\n";
+ if (!it->info->display(treeType)) {
+ it->setVisible(false);
+ } else {
+ if (it->isVisible())
+ shown++;
+ }
+ }
+ } while ((it = it->nextSibling()));
+ return shown;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+void KpTreeList::clearMarked(KpTreeListItem *item)
+{
+ while (item) {
+ if (item->childCount() > 0) {
+ clearMarked(item->firstChild());
+ }
+ item->setMark(false);
+ item = item->nextSibling();
+ }
+}
+
+void KpTreeList::markAll(KpTreeListItem *item)
+{
+ while (item) {
+ if (item->childCount() > 0) {
+ markAll(item->firstChild());
+ }
+ else {
+ if (item->info->display(treeType)) {
+ item->setMark(true);
+ }
+ }
+ item = item->nextSibling();
+ }
+}
+
+void KpTreeList::findMarked(KpTreeListItem *item, QPtrList<KpTreeListItem> &selList)
+{
+ while (item) {
+ if (item->childCount() > 0) {
+ findMarked(item->firstChild(), selList);
+ }
+ if (item->marked) {
+ selList.insert(0,item);
+ }
+ item = item->nextSibling();
+ }
+}
+
+void KpTreeList::countMarked(KpTreeListItem *item, int &cntInstall, int &cntUnInstall)
+{
+ while (item) {
+ if (item->childCount() > 0) {
+ countMarked(item->firstChild(), cntInstall, cntUnInstall);
+ }
+ if (item->marked) {
+ if (item->info->isInstallable())
+ cntInstall++;
+ else
+ cntUnInstall++;
+ }
+ item = item->nextSibling();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+void KpTreeList::expandTree(KpTreeList *list)
+{
+ KpTreeListItem *item = list->firstChild();
+
+ while (item) {
+ if (item->childCount() > 0) {
+ item->setOpen(TRUE);
+ expandTree(item);
+ }
+ item = item->nextSibling();
+ }
+}
+
+
+void KpTreeList::expandTree(KpTreeListItem *pitem)
+{
+ KpTreeListItem *item = pitem->firstChild();
+
+ while (item) {
+ if (item->childCount() > 0) {
+ item->setOpen(TRUE);
+ expandTree(item);
+ }
+ item = item->nextSibling();
+ }
+}
+
+void KpTreeList::collapseTree(KpTreeList *list)
+{
+ KpTreeListItem *item = list->firstChild();
+
+ while (item) {
+ if (item->childCount() > 0) {
+ collapseTree(item);
+ }
+ item = item->nextSibling();
+ }
+}
+
+void KpTreeList::collapseTree(KpTreeListItem *pitem)
+{
+ int n = 0;
+ KpTreeListItem *item = pitem->firstChild();
+
+ while (item) {
+ if (item->childCount() > 0) {
+ n++;
+ collapseTree(item);
+ }
+ item = item->nextSibling();
+ };
+ if (n)
+ pitem->setOpen(TRUE);
+ else
+ pitem->setOpen(FALSE);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// A package has been highlighted in the list tree
+void KpTreeList::packageHighlighted(QListViewItem *item, packageDisplayWidget *packageDisplay)
+{
+ KpTreeListItem *sel = (KpTreeListItem *)item;
+
+ if (!sel || sel->childCount()) {
+ packageDisplay->changePackage(0);
+ } else if (sel) {
+ if (!notPress) {
+ int n = stack.at();
+ int num = stack.count();
+ for (int i = num - 1; i >= n; i--) {
+ stack.remove(i);
+ }
+ kpkg->disableNext();
+ }
+
+ // Disable the tree list while we do this
+ setEnabled(FALSE);
+
+ // Tell everything that is interested to change packages
+ packageDisplay->changePackage(sel->info);
+
+ // Re-enable the treeList and uninstall button
+ setEnabled(TRUE);
+ setFocus();
+
+ if (!notPress) {
+ stack.append(sel);
+ }
+ }
+
+ notPress = false;
+}
+
+KpTreeListItem *KpTreeList::search(const QString &str, const QString &head,
+ KpTreeListItem *start)
+{
+ KpTreeListItem *item = firstChild();
+
+ searchCitem = start;
+ searchSkip = FALSE;
+ searchSubstr = FALSE;
+ searchStr = str;
+ searchResult = 0;
+
+ do {
+ if (item->text(0) == head) {
+ searchChild(item->firstChild());
+ if (searchResult != 0)
+ return searchResult;
+ }
+ } while ((item = item->nextSibling()));
+ return 0;
+}
+
+KpTreeListItem *KpTreeList::search(const QString &str, bool subStr, bool wrap,
+ bool start=FALSE)
+{
+ if (!firstChild())
+ return 0;
+
+ if (start)
+ searchCitem = 0;
+ else
+ searchCitem = currentItem();
+ searchSkip = !wrap;
+ searchSubstr = subStr;
+ searchStr = str;
+ searchResult = 0;
+
+ searchChild(firstChild());
+
+ return changePack(searchResult);
+}
+
+bool KpTreeList::searchChild(KpTreeListItem *it)
+{
+ do {
+ if (!searchSkip) {
+ QString s = it->text(0);
+ // kdDebug() << "s='" << s << "'='" << searchStr << "\n";
+ if ((it->childCount() == 0) && (it->info->display(treeType)) &&
+ (searchSubstr ? s.contains(searchStr,FALSE) : s == searchStr)) {
+ searchResult = it;
+ return TRUE;
+ }
+ }
+
+ if (searchCitem == it) {
+ if (searchSkip) {
+ searchSkip = FALSE;
+ } else {
+ return TRUE;
+ }
+ }
+
+ if (it->childCount() > 0) {
+ if (searchChild(it->firstChild()))
+ return TRUE;
+ }
+ } while ((it = it->nextSibling()));
+ return FALSE;
+}
+
+KpTreeListItem *KpTreeList::changePack(KpTreeListItem *searchResult, bool push)
+{
+ if (searchResult) {
+ QListViewItem *i;
+
+ i = searchResult;
+ while ((i = i->parent())) {
+ i->setOpen(TRUE);
+ }
+ if (push) {
+ stack.append(searchResult);
+ kpkg->enablePrevious();
+ }
+
+ notPress = true;
+ setSelected(searchResult,TRUE);
+ setCurrentItem(searchResult);
+ ensureItemVisible(searchResult);
+ return searchResult;
+ } else {
+ return 0;
+ }
+}
+
+void KpTreeList::next()
+{
+ int n = stack.at();
+ KpTreeListItem *s = stack.at(n + 1);
+ if (s) {
+ changePack(s, false);
+ }
+ if (n >= int(stack.count() - 2)) {
+ kpkg->disableNext();
+ }
+ if (n >= 0) {
+ kpkg->enablePrevious();
+ }
+}
+
+void KpTreeList::previous()
+{
+ int n = stack.at();
+ KpTreeListItem *s = stack.at(n-1);
+
+ if (s) {
+ changePack(s, false);
+ kpkg->enableNext();
+ }
+ if (n <= 1) {
+ kpkg->disablePrevious();
+ }
+ if (n < int(stack.count() - 2)) {
+ kpkg->enableNext();
+ }
+}
+
+void KpTreeList::stackRemove(KpTreeListItem *pack)
+{
+ int n = stack.find(pack);
+ if (n >= 0) {
+ if (n == 0) {
+ kpkg->disablePrevious();
+ }
+ if (n >= int(stack.count() - 1)) {
+ kpkg->disableNext();
+ }
+ stack.remove(pack);
+ }
+}
+
+////////////////////////////////////////////////////////////////
+void KpTreeList::writeTreeType()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+
+ config->writeEntry("Package_Display",treeType);
+}
+
+void KpTreeList::readTreeType()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+
+ treeType = config->readNumEntry("Package_Display",3);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void KpTreeList::writeTreeConfig()
+{
+ saveLayout( kapp->config(), "Tree");
+}
+
+void KpTreeList::readTreeConfig()
+{
+ KConfig *config = kapp->config();
+
+ restoreLayout(config, "Tree");
+
+ config->setGroup("Tree");
+ if (!config->hasKey("ColumnWidths")) {
+ int i,n;
+ int num[] = {185,37,180,54,95,95};
+
+ QString colpos;
+ for (i = 0; i < 6; i++) {
+ colpos.setNum(i);
+ n = config->readNumEntry(colpos,num[i]);
+ setColumnWidth(i,n);
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+KpTreeListItem::KpTreeListItem( QListViewItem *parent, packageInfo* pinfo,
+ const QPixmap& thePixmap,
+ QString label1, QString label2 ,
+ QString label3 , QString label4 ,
+ QString label5 , QString label6 ,
+ QString label7 , QString label8
+
+) : QListViewItem(parent, label1, label2, label3, label4, label5,
+ label6, label7, label8)
+{
+ info = pinfo;
+ marked = false;
+ setPixmap(0, thePixmap);
+ if (!label2.isNull())
+ setPixmap(1,info->interface->markUnInst);
+}
+
+KpTreeListItem::KpTreeListItem( KListView *parent, packageInfo* pinfo,
+ const QPixmap& thePixmap,
+ QString label1, QString label2 ,
+ QString label3 , QString label4 ,
+ QString label5 , QString label6 ,
+ QString label7 , QString label8
+) : QListViewItem(parent, label1, label2, label3, label4, label5,
+ label6, label7, label8)
+{
+ info = pinfo;
+ marked = false;
+ setPixmap(0, thePixmap);
+ if (!label2.isNull())
+ setPixmap(1,info->interface->markUnInst);
+}
+
+KpTreeListItem *KpTreeListItem::firstChild()
+{
+ return (KpTreeListItem *)QListViewItem::firstChild();
+}
+
+KpTreeListItem *KpTreeListItem::nextSibling()
+{
+ return (KpTreeListItem *)QListViewItem::nextSibling();
+}
+
+void KpTreeListItem::toggleMark()
+{
+ marked = ! marked;
+ if (marked)
+ setPixmap(1,info->interface->markInst);
+ else
+ setPixmap(1,info->interface->markUnInst);
+}
+
+void KpTreeListItem::setMark(bool mark)
+{
+ marked = mark;
+ if (mark)
+ setPixmap(1,info->interface->markInst);
+ else {
+ if (info)
+ setPixmap(1,info->interface->markUnInst);
+ }
+}
+
+void KpTreeListItem::hide()
+{
+ setHeight(0);
+}
+
+void KpTreeListItem::show()
+{
+ setup();
+}
+
+int KpTreeListItem::compare( QListViewItem *i, int col, bool ascending ) const
+{ // Make sorting more certain
+ if (col == 3) { // size column
+ QString k, j;
+
+ j = key( col, ascending );
+ j = j.replace(' ','0');
+ j = j.rightJustify(6,'0');
+
+ k = i->key( col, ascending );
+ k = k.replace(' ','0');
+ k = k.rightJustify(6,'0');
+
+ // kdDebug() << k <<"=" << j << "\n";
+ return j.compare(k);
+ } else {
+ return QListViewItem::compare(i, col, ascending);
+ }
+}
+
+#include "kplview.moc"
diff --git a/kpackage/kplview.h b/kpackage/kplview.h
new file mode 100644
index 0000000..7931c99
--- /dev/null
+++ b/kpackage/kplview.h
@@ -0,0 +1,191 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#ifndef KPLVITEM_H
+#define KPLVITEM_H
+
+#include "../config.h"
+// Standard Headers
+
+// Qt Headers
+#include <qframe.h>
+#include <qpushbutton.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qlayout.h>
+
+// KDE headers
+#include "klistview.h"
+
+// ksetup headers
+#include "packageInfo.h"
+
+class packageDisplayWidget;
+
+////////////////////////////////////////////////////////////////////////
+class KpTreeList: public KListView
+{
+ Q_OBJECT
+
+public:
+ KpTreeList ( QWidget * parent = 0);
+
+ void contentsMousePressEvent ( QMouseEvent * e );
+
+ bool inMark(int x);
+
+ KpTreeListItem *firstChild();
+ KpTreeListItem *currentItem();
+ void clear();
+
+ KpTreeListItem *markPkg;
+
+ QPtrList<KpTreeListItem> stack;
+ // Stack of jumped to packages
+
+ void sweep(bool init);
+ // sweep tree adjusting visibility
+ void expand();
+ // sweep tree expanding everything
+
+ void findMarked(KpTreeListItem *item, QPtrList<KpTreeListItem> &selList);
+ // generate list of marked tree items
+ void clearMarked(KpTreeListItem *item);
+ // unmark marked tree items
+
+ // mark all packages in the selected view
+ void markAll(KpTreeListItem *item) ;
+
+ void expandTree(KpTreeList *list);
+ // expand package tree
+
+ void expandTree(KpTreeListItem *item);
+ // expand package sub-tree
+
+ void collapseTree(KpTreeList *list);
+ // semi-collapse package tree
+
+ void collapseTree(KpTreeListItem *item);
+ // semi-collapse package sub-tree
+
+ void countMarked(KpTreeListItem *, int &cntInstall, int &cntUnInstall);
+ // Count marked packages that can be installed/uninstalled
+
+ void packageHighlighted(QListViewItem *item, packageDisplayWidget *packageDisplay);
+ // A package has been highlighted in the list tree
+
+ KpTreeListItem *search(const QString &str, const QString &head,
+ KpTreeListItem *start = 0);
+ KpTreeListItem *search(const QString &str, bool subStr, bool wrap, bool start);
+ // search for a package in tree
+ KpTreeListItem *changePack(KpTreeListItem *searchResult, bool push = true);
+ // Change to other package
+
+ void stackRemove(KpTreeListItem *pack);
+ // Remove entry from package stack
+
+ void readTreeType();
+ void writeTreeType();
+ // config: Tree display type
+
+ void writeTreeConfig();
+ void readTreeConfig();
+ // save and restore column positions
+
+ int treeType;
+
+public slots:
+ void next();
+ // Package stack forward
+
+ void previous();
+ // Package stack back
+
+private:
+ int sweepChild(KpTreeListItem *it);
+ void expandChild(KpTreeListItem *it);
+
+ bool searchChild(KpTreeListItem *it);
+ // recurse thru the display tree looking for 'str'
+
+ bool notPress;
+ // flag to packageHighlighted
+
+ KpTreeListItem *searchCitem;
+ bool searchSkip, searchSubstr;
+ QString searchStr;
+ KpTreeListItem *searchResult;
+ // globals used by searchChild for start from current position,
+ // skip to current item before search flag, substring search flag,
+ // search string, result item (if found)
+
+ // flag skipping in searchChild
+
+
+signals:
+ void updateMarked();
+ void cleared();
+};
+
+////////////////////////////////////////////////////////////////////////
+class KpTreeListItem : public QListViewItem
+{
+public:
+ KpTreeListItem( QListViewItem *parent, packageInfo* pinfo,
+ const QPixmap& thePixmap,
+ QString label1 = 0, QString label2 = 0,
+ QString label3 = 0, QString label4 = 0,
+ QString label5 = 0, QString label6 = 0,
+ QString label7 = 0, QString label8 = 0);
+
+
+ KpTreeListItem( KListView *parent, packageInfo* pinfo,
+ const QPixmap& thePixmap,
+ QString label1 = 0, QString label2 = 0,
+ QString label3 = 0, QString label4 = 0,
+ QString label5 = 0, QString label6 = 0,
+ QString label7 = 0, QString label8 = 0);
+
+
+ KpTreeListItem *firstChild();
+ KpTreeListItem *nextSibling();
+
+ void toggleMark();
+ void setMark(bool mark);
+ // flag for install/uninstall
+
+ void hide();
+ void show();
+
+ virtual int compare( QListViewItem *i, int col, bool ascending ) const;
+
+ packageInfo *info;
+ bool marked;
+};
+
+
+#endif
diff --git a/kpackage/main.cpp b/kpackage/main.cpp
new file mode 100644
index 0000000..781d741
--- /dev/null
+++ b/kpackage/main.cpp
@@ -0,0 +1,159 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+// Author: Toivo Pedaste
+//
+// This is the entry point to the program
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include <stdlib.h>
+
+#include "../config.h"
+#include "kpackage.h"
+
+#include <qfile.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <options.h>
+
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include <kpTerm.h>
+#include "debInterface.h"
+#include "debAptInterface.h"
+#include "debDpkgInterface.h"
+#include "kissInterface.h"
+#include "slackInterface.h"
+#include "fbsdInterface.h"
+#include "rpmInterface.h"
+#include "gentooInterface.h"
+
+
+static const char description[] =
+ I18N_NOOP("KDE Package installer");
+
+static KCmdLineOptions options[] =
+{
+ { "remote ", I18N_NOOP("Remote host for Debian APT, via SSH"), 0 },
+ { "r ", 0, 0},
+ { "+[Package]", I18N_NOOP("Package to install"), 0 },
+ KCmdLineLastOption
+};
+
+// Globals
+KPKG *kpkg;
+KPACKAGE *kpackage;
+kpPty *kpty;
+kpRun *kprun;
+kpRun *kpstart;
+Opts *opts;
+
+QString hostName;
+
+pkgInterface *kpinterface[kpinterfaceN];
+
+int main(int argc, char **argv)
+{
+ KAboutData aboutData( "kpackage", I18N_NOOP("KPackage"),
+ VERSION, description, KAboutData::License_GPL,
+ // VERSION, description, 0,
+ "(c) 1999-2001, Toivo Pedaste");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ aboutData.addAuthor( "Toivo Pedaste",0, "toivo@ucs.uwa.edu.au");
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+ KApplication app;
+
+ kpkg = 0;
+ int j = 0;
+
+// Make sure PATH has the right directories in it
+ QCString path = getenv("PATH");
+ path = "PATH=" + path + ":/sbin:/usr/sbin:/usr/local/bin";
+ putenv(strdup(path.data()));
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ QString remoteHost = args->getOption("remote");
+
+ if (remoteHost.isEmpty() || remoteHost == "localhost") {
+ hostName = "";
+ } else {
+ hostName = remoteHost;
+ }
+
+ kpty = new kpPty();
+ kprun = new kpRun();
+ kpstart = new kpRun();
+
+ for (int i = 0; i < kpinterfaceN; i++) {
+ kpinterface[i] = 0;
+ }
+
+ kdDebug() << "Hostname=" << hostName << "\n";
+ opts = new Opts(hostName);
+
+ kpinterface[j++] = new DEBDPKG();
+ kpinterface[j++] = new DEBAPT();
+ kpinterface[j++] = new KISS();
+ kpinterface[j++] = new RPM();
+ kpinterface[j++] = new fbsdInterface();
+ kpinterface[j++] = new SLACK(); // Also catched BSD packages...
+ kpinterface[j++] = new Gentoo();
+
+ opts->readLaterSettings();
+
+ if ( app.isRestored() ) {
+ if (KPKG::canBeRestored(1)) {
+ kpkg = new KPKG(app.config());
+ kpkg->restore(1);
+ }
+ } else {
+ // Create the main widget and show it
+ kpkg = new KPKG(app.config());
+ kpkg->show();
+ }
+ kpkg->setCaption(hostName);
+
+ if (args->count()) { // an argument has been given
+ QStringList files;
+ for(int i = 0; i < args->count(); i++) {
+ files.append(args->url(i).url());
+ }
+ kpackage->openNetFiles(files, FALSE);
+ } else {
+ if (!kpkg->prop_restart)
+ kpackage->setup();
+ }
+
+ args->clear();
+
+ int r = app.exec(); // execute the application
+
+ return r; // return the result
+}
+
diff --git a/kpackage/managementWidget.cpp b/kpackage/managementWidget.cpp
new file mode 100644
index 0000000..50cda53
--- /dev/null
+++ b/kpackage/managementWidget.cpp
@@ -0,0 +1,699 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+// Author: Toivo Pedaste
+//
+// See managementWidget.h for more information
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#include <qsplitter.h>
+#include <qtoolbutton.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <klistviewsearchline.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <ktoolbar.h>
+#include <kiconloader.h>
+
+// kpackage.headers
+#include "kpackage.h"
+#include "kplview.h"
+#include "managementWidget.h"
+#include "pkgInterface.h"
+#include "pkgOptions.h"
+#include "packageDisplay.h"
+#include "packageProperties.h"
+#include "options.h"
+
+extern Opts *opts;
+
+KpListViewSearchLine::KpListViewSearchLine(QWidget *parent, KpTreeList *listView)
+ :KListViewSearchLine(parent, listView)
+{
+ list = listView;
+}
+
+KpListViewSearchLine::~KpListViewSearchLine()
+{
+}
+
+void KpListViewSearchLine::updateSearch(const QString &s)
+{
+ list->expand();
+ KListViewSearchLine::updateSearch(s);
+ KListViewSearchLine::updateSearch(s); // Yes both are needed
+ list->sweep(false);
+}
+
+
+// constructor -- initialise variables
+managementWidget::managementWidget(QWidget *parent)
+ : QFrame(parent)
+{
+ install_action = 0;
+ uninstall_action = 0;
+
+ allPackages = new QPtrList<packageInfo>;
+
+ tType[0] = i18n("Installed");
+ tType[1] = i18n("Updated");
+ tType[2] = i18n("New");
+ tType[3] = i18n("All");
+
+ dirInstPackages = new QDict<packageInfo>(7717);
+ dirUninstPackages = new QDict<packageInfo>(7717);
+ dirInfoPackages = new QDict<packageInfo>(7717);
+
+ setupWidgets();
+
+ connect(treeList,SIGNAL(updateMarked()),
+ this, SLOT( checkMarked()));
+}
+
+managementWidget::~managementWidget()
+{
+ // if(allPackages)
+ // delete allPackages;
+ // delete dirInstPackages;
+ // delete dirUninstPackages;
+}
+
+void managementWidget::resizeEvent(QResizeEvent *)
+{
+ arrangeWidgets();
+}
+
+
+void managementWidget::setupWidgets()
+{
+ QTab t;
+
+ top = new QBoxLayout(this,QBoxLayout::TopToBottom);
+ vPan = new QSplitter(QSplitter::Horizontal, this);
+ top->addWidget(vPan);
+
+ // the left panel
+ leftpanel = new QFrame(vPan);
+ leftbox = new QBoxLayout(leftpanel,QBoxLayout::TopToBottom);
+
+ QTabBar *ltab = new QTabBar(leftpanel);
+
+ treeList = new KpTreeList(leftpanel);
+
+
+ for (int i = 0; i < 4; i++) {
+ QTab *t = new QTab();
+ t->setText( tType[i] );
+ ltab->addTab(t);
+ }
+ // Quick Search Bar
+ searchToolBar = new KToolBar( leftpanel, "search toolbar");
+
+ QToolButton *clearSearch = new QToolButton(searchToolBar);
+ clearSearch->setTextLabel(i18n("Clear Search"), true);
+ clearSearch->setIconSet(SmallIconSet(QApplication::reverseLayout() ? "clear_left"
+ : "locationbar_erase"));
+ (void) new QLabel(i18n("Search: "),searchToolBar);
+
+ searchLine = new KpListViewSearchLine(searchToolBar, treeList);
+ // searchLine->setKeepParentsVisible(false);
+ connect( clearSearch, SIGNAL( pressed() ), searchLine, SLOT( clear() ));
+
+ QValueList<int> clist; clist.append(0); clist.append(2);
+ searchLine->setSearchColumns(clist);
+
+ searchToolBar->setStretchableWidget( searchLine );
+ connect( treeList, SIGNAL( cleared() ), searchLine, SLOT( clear() ));
+
+ connect(ltab,SIGNAL(selected (int)),SLOT(tabChanged(int)));
+ ltab->setCurrentTab(treeList->treeType);
+
+ leftbox->addWidget(ltab,10);
+ leftbox->addWidget(searchToolBar,10);
+ leftbox->addWidget(treeList,10);
+
+ leftbox->addStretch();
+
+ lbuttons = new QBoxLayout(QBoxLayout::LeftToRight);
+
+ luinstButton = new QPushButton(i18n("Uninstall Marked"),leftpanel);
+ luinstButton->setEnabled(FALSE);
+ connect(luinstButton,SIGNAL(clicked()),
+ SLOT(uninstallMultClicked()));
+ linstButton = new QPushButton(i18n("Install Marked"),leftpanel);
+ linstButton->setEnabled(FALSE);
+ connect(linstButton,SIGNAL(clicked()),
+ SLOT(installMultClicked()));
+
+ leftbox->addLayout(lbuttons,0); // top level layout as child
+
+ // Setup the `buttons' layout
+ lbuttons->addWidget(linstButton,1,AlignBottom);
+ lbuttons->addWidget(luinstButton,1,AlignBottom);
+ lbuttons->addStretch(1);
+
+ connect(treeList, SIGNAL(selectionChanged(QListViewItem *)),
+ SLOT(packageHighlighted(QListViewItem *)));
+
+ // the right panel
+ rightpanel = new QFrame(vPan);
+ rightbox = new QBoxLayout(rightpanel,QBoxLayout::TopToBottom);
+
+ packageDisplay = new packageDisplayWidget(rightpanel);
+ // connect(this, SIGNAL(changePackage(packageInfo *)),
+ // packageDisplay, SLOT(changePackage(packageInfo *)));
+
+ rbuttons = new QBoxLayout(QBoxLayout::LeftToRight);
+
+ uinstButton = new QPushButton(i18n("Uninstall"),rightpanel);
+ uinstButton->setEnabled(FALSE);
+ connect(uinstButton,SIGNAL(clicked()),
+ SLOT(uninstallSingleClicked()));
+ instButton = new QPushButton(i18n("Install"),rightpanel);
+ instButton->setEnabled(FALSE);
+ connect(instButton,SIGNAL(clicked()),
+ SLOT(installSingleClicked()));
+
+
+ // Setup the `right panel' layout
+ rightbox->addWidget(packageDisplay,10);
+ rightbox->addLayout(rbuttons,0); // top level layout as child
+
+ // Setup the `buttons' layout
+ rbuttons->addWidget(instButton,1);
+ rbuttons->addWidget(uinstButton,1);
+ rbuttons->addStretch(1);
+
+}
+
+////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////
+void managementWidget::writePSeparator()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+
+ config->writeEntry("panel1Width",vPan->sizes().first());
+ config->writeEntry("panel2Width",vPan->sizes().last());
+}
+
+void managementWidget::readPSeparator()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+
+ int w1 = config->readNumEntry("panel1Width",200);
+ int w2 = config->readNumEntry("panel2Width",200);
+
+ QValueList<int> size;
+ size << w1 << w2;
+ vPan->setSizes(size);
+}
+
+///////////////////////////////////////////////////////////////////
+void managementWidget::setupMultButton(int &cntInstall, int &cntUnInstall)
+{
+ if (cntInstall)
+ linstButton->setEnabled(true);
+ else
+ linstButton->setEnabled(false);
+
+ if (cntUnInstall)
+ luinstButton->setEnabled(true);
+ else
+ luinstButton->setEnabled(false);
+}
+
+void managementWidget::setupInstButton()
+{
+ bool u,i;
+
+ packageInfo *package = packageDisplay->package;
+
+ if (!package) {
+ i = false;
+ u = false;
+ } else {
+ if (package->isFetchable() ) {
+ instButton->setText(i18n("Install"));
+ } else {
+ instButton->setText(i18n("Fetch"));
+ }
+ if (package->isInstallable() ) {
+
+ i = true;
+ u = false;
+ } else {
+ i = false;
+ u = true;
+ }
+ }
+ instButton->setEnabled(i);
+ if (install_action)
+ install_action->setEnabled(i);
+
+ uinstButton->setEnabled(u);
+ if (uninstall_action)
+ uninstall_action->setEnabled(u);
+}
+
+void managementWidget::arrangeWidgets()
+{
+ // this is done automatically by the layout managers
+}
+
+void managementWidget::tabChanged(int tab)
+{
+ treeList->treeType = tab;
+ searchLine->updateSearch();
+}
+
+
+// Collect data from package.
+void managementWidget::collectData(bool refresh)
+{
+ int i;
+
+ if (!refresh && allPackages) {
+ treeList->sweep(true);
+ return; // if refresh not required already initialised
+ }
+
+ QApplication::setOverrideCursor( waitCursor );
+
+// stop clear() sending selectionChanged signal
+ disconnect(treeList, SIGNAL(selectionChanged(QListViewItem *)),
+ this, SLOT(packageHighlighted(QListViewItem *)));
+ treeList->hide(); // hide list tree
+ treeList->clear(); // empty it
+ connect(treeList, SIGNAL(selectionChanged(QListViewItem *)),
+ SLOT(packageHighlighted(QListViewItem *)));
+
+ packageDisplay->changePackage(0);
+
+ // Delete old list if necessary
+ if(allPackages) {
+ delete allPackages;
+ }
+
+ allPackages = new QPtrList<packageInfo>;
+ allPackages->setAutoDelete(TRUE);
+
+ dirInstPackages->clear();
+ dirUninstPackages->clear();
+ // List installed packages
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i] && kpinterface[i]->hasProgram && opts->handlePackage[i]) {
+ if (hostName.isEmpty() || (kpinterface[i]->hasRemote)) {
+ kpinterface[i]->listPackages(allPackages);
+ }
+ }
+ }
+
+ // Rebuild the list tree
+ rebuildListTree();
+
+ QApplication::restoreOverrideCursor();
+}
+
+// Rebuild the list tree
+void managementWidget::rebuildListTree()
+{
+ packageInfo *i;
+ int n = 0;
+
+ kpackage->setStatus(i18n("Building package tree"));
+ kpackage->setPercent(0);
+
+ treeList->setSorting(-1);
+
+ // place all the packages found
+ int count = allPackages->count();
+ int incr = count/50;
+ if (incr == 0)
+ incr = 1;
+
+ for(i=allPackages->first(); i!=0; i=allPackages->next())
+ {
+ i->place(treeList,TRUE);
+
+ if (!(n % incr)) {
+ kpackage->setPercent(int (n*100/count));
+ }
+ n++;
+ }
+ treeList->sweep(true);
+ treeList->show(); // show the list tree
+
+ treeList->setSorting(0);
+
+ kpackage->setPercent(100); // set the progress
+ kpackage->setStatus("");
+
+ checkMarked();
+}
+
+// A package has been highlighted in the list tree
+void managementWidget::packageHighlighted(QListViewItem *item)
+{
+
+ treeList->packageHighlighted(item, packageDisplay);
+ setupInstButton();
+
+ kpackage->setPercent(100);
+}
+
+/////////////////////////////////////////////////////////////////////////
+// install has been clicked
+
+void managementWidget::installSingleClicked()
+{
+ int result;
+ QPtrList<packageInfo> plist;
+
+ packageInfo *package = packageDisplay->package;
+
+ if (package) {
+ QString filename = package->getFilename();
+ kdDebug() << "File=" << filename <<"\n";
+ pkgInterface *interface = package->interface;
+ if (interface->noFetch || !filename.isEmpty()) {
+ plist.append(package);
+ if (!interface->installation->setup(&plist, interface->head)) {
+ return;
+ }
+ result = interface->installation->exec();
+
+ if (interface->installation->result() == QDialog::Accepted ||
+ interface->installation->modified) {
+ // it was accepted, so the package has been installed
+ packageInfo *inf;
+ for (inf = plist.first(); inf != 0; inf = plist.next()) {
+ updatePackage(inf,TRUE);
+ }
+
+ if (treeList->currentItem()) {
+ KpTreeListItem *p = treeList->currentItem();
+ packageDisplay->changePackage(p->info);
+ } else {
+ packageDisplay->changePackage(0); // change package to no package
+ }
+ setupInstButton();
+ }
+
+ // kdDebug() << "Result=" << result <<"\n";
+ } else {
+ QString url = package->getUrl();
+ if (!url.isEmpty()) {
+ QString s = kpackage->fetchNetFile(url);
+ if (!s.isEmpty()) {
+ packageDisplay->changePackage(package);
+ setupInstButton();
+ }
+ } else {
+ KpMsgE(i18n("Filename not available\n"),TRUE);
+ }
+ }
+ }
+ kpackage->setPercent(100);
+
+ searchLine->updateSearch();
+ checkMarked();
+}
+
+// install has been clicked
+void managementWidget::installMultClicked()
+{
+ int i;
+ KpTreeListItem *it;
+ packageInfo *inf;
+ QPtrList<packageInfo> **lst = new QPtrList<packageInfo>*[kpinterfaceN];
+
+ selList.clear();
+ treeList->findMarked(treeList->firstChild(), selList);
+
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ lst[i] = new QPtrList<packageInfo>;
+ for (it = selList.first(); it != 0; it = selList.next()) {
+ if (it->info->interface == kpinterface[i] &&
+ it->childCount() == 0 &&
+ (it->info->packageState == packageInfo::UPDATED ||
+ it->info->packageState == packageInfo::NEW)
+ ) {
+ lst[i]->insert(0,it->info);
+ }
+ }
+ }
+ }
+ selList.clear();
+
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ if (lst[i]->count() > 0) {
+ if (kpinterface[i]->installation->setup(lst[i],kpinterface[i]->head)) {
+ if (kpinterface[i]->installation->exec() ||
+ kpinterface[i]->installation->modified) {
+ for (inf = lst[i]->first(); inf != 0; inf = lst[i]->next()) {
+ updatePackage(inf,TRUE);
+ }
+ }
+ }
+ delete lst[i];
+ }
+ }
+ }
+ delete [] lst;
+
+ searchLine->updateSearch();
+ checkMarked();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Uninstall has been clicked
+
+void managementWidget::uninstallSingleClicked()
+{
+ int result;
+ QPtrList<packageInfo> plist;
+
+ packageInfo *package = packageDisplay->package;
+
+ if (package) { // check that there is a package to uninstall
+ pkgInterface *interface = package->interface;
+ plist.append(package);
+ if (!interface->uninstallation->setup(&plist, interface->head)) {
+ return;
+ }
+ result = interface->uninstallation->exec();
+
+ if(result == QDialog::Accepted ||
+ interface->installation->modified) {
+ packageInfo *inf;
+ for (inf = plist.first(); inf != 0; inf = plist.next()) {
+ updatePackage(inf,FALSE);
+ }
+
+ if (treeList->currentItem()) {
+ KpTreeListItem *p = treeList->currentItem();
+ packageDisplay->changePackage(p->info);
+ } else {
+ packageDisplay->changePackage(0); // change package to no package
+ }
+ setupInstButton();
+ }
+ // kdDebug() << "Result=" << result <<"\n";
+ }
+ kpackage->setPercent(100);
+
+ searchLine->updateSearch();
+ checkMarked();
+}
+
+void managementWidget::uninstallMultClicked()
+{
+ int i;
+ KpTreeListItem *it;
+ packageInfo *inf;
+ QPtrList<packageInfo> **lst = new QPtrList<packageInfo>*[kpinterfaceN];
+
+ selList.clear();
+ treeList->findMarked(treeList->firstChild(), selList);
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ lst[i] = new QPtrList<packageInfo>;
+ for (it = selList.first(); it != 0; it = selList.next()) {
+ if (it->info->interface == kpinterface[i] &&
+ it->childCount() == 0 &&
+ (it->info->packageState == packageInfo::INSTALLED ||
+ it->info->packageState == packageInfo::BAD_INSTALL)
+ ) {
+ lst[i]->insert(0,it->info);
+ }
+ }
+ }
+ }
+ selList.clear();
+
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ if (lst[i]->count() > 0) {
+ if (kpinterface[i]->uninstallation->setup(lst[i],kpinterface[i]->head)) {
+ if (kpinterface[i]->uninstallation->exec()||
+ kpinterface[i]->installation->modified ) {
+ for (inf = lst[i]->first(); inf != 0; inf = lst[i]->next()) {
+ updatePackage(inf,FALSE);
+ }
+ }
+ }
+ delete lst[i];
+ }
+ }
+ }
+ delete [] lst;
+
+ searchLine->updateSearch();
+ checkMarked();
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+void managementWidget::doChangePackage(packageInfo *p)
+{
+ packageDisplay->changePackage(p);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+KpTreeListItem *managementWidget::search(QString str, bool subStr, bool wrap,
+ bool start)
+{
+ return treeList->search(str, subStr, wrap, start);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+KpTreeListItem *managementWidget::updatePackage(packageInfo *pki, bool install)
+{
+ QString version;
+ KpTreeListItem *q;
+
+ if (allPackages) {
+ QString name(pki->getProperty("name"));
+ if (pki->hasProperty("version"))
+ version = pki->getProperty("version");
+ else
+ version = "";
+ pkgInterface *interface = pki->interface;
+ packageInfo *pnew = interface->getPackageInfo('i', name, version);
+ packageInfo *ptree;
+ QString pkgId = name + interface->typeID;
+
+ if (install) {
+ if (pnew) {
+ if (pnew->packageState != packageInfo::BAD_INSTALL) {
+ ptree = dirInstPackages->find(pkgId); // remove installed entry
+ dirInstPackages->remove(pkgId);
+ if (ptree) {
+ if (ptree->getItem()) {
+ delete ptree->getItem();
+ ptree->item = 0;
+ }
+ }
+
+ ptree = dirUninstPackages->find(pkgId); // remove uninstalled entry
+ if (ptree) {
+ ptree->packageState = packageInfo::HIDDEN;
+ if (ptree->getItem()) {
+ delete ptree->getItem();
+ ptree->item = 0;
+ }
+ }
+ }
+
+ dirInstPackages->insert(pkgId,pnew);
+
+ q = pnew->place(treeList,TRUE);
+ allPackages->insert(0,pnew);
+ if (!q) {
+ printf("NOTP=%s \n",pnew->getProperty("name").ascii());
+ } else {
+ return q;
+ }
+ }
+ } else { // uninstalling
+ if (!pnew) {
+ dirInstPackages->remove(pkgId);
+ KpTreeListItem *qt = pki->getItem();
+ if (qt) {
+ treeList->stackRemove(qt);
+ treeList->setSelected(qt,false);
+ if (treeList->markPkg == qt)
+ treeList->markPkg = 0;
+ delete qt;
+ } else {
+ kdDebug() << "DEL=" << name << endl;
+ }
+ packageInfo *pb = dirUninstPackages->find(pkgId);
+ if (pb) { // available package matching the one just uninstalled
+ pb->packageState = packageInfo::NEW;
+ q = pb->place(treeList,TRUE);
+ if (!q) {
+ printf("NOTP=%s \n",pb->getProperty("name").ascii());
+ } else {
+ return q;
+ }
+ }
+
+ } else {
+ delete pnew;
+ }
+ }
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////
+void managementWidget::checkMarked()
+{
+int cntInstall = 0;
+int cntUnInstall = 0;
+
+ treeList->countMarked(treeList->firstChild(), cntInstall, cntUnInstall);
+ setupMultButton(cntInstall, cntUnInstall);
+}
+
+
+#include "managementWidget.moc"
diff --git a/kpackage/managementWidget.h b/kpackage/managementWidget.h
new file mode 100644
index 0000000..bf1c6d1
--- /dev/null
+++ b/kpackage/managementWidget.h
@@ -0,0 +1,227 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+//
+// This widget is used to provide the management mode of ksetup.
+// There are two subwidgets; firstly a tree list showing all the
+// currently installed packages and secondly a display of the currently
+// selected package's properties.
+//
+// There are also some control buttons which allow the currently
+// selected package to be uninstalled or verified.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+
+#ifndef MANAGEMENTWIDGET_H
+#define MANAGEMENTWIDGET_H
+
+#include "../config.h"
+// Standard Headers
+
+// Qt Headers
+#include <qframe.h>
+#include <qpushbutton.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qlayout.h>
+#include <qtabwidget.h>
+#include <qlabel.h>
+#include <qhbox.h>
+
+// KDE headers
+#include <kaction.h>
+#include <klistview.h>
+#include <klistviewsearchline.h>
+
+// ksetup headers
+#include "packageInfo.h"
+#include "kplview.h"
+
+class packageDisplayWidget;
+class packageInfo;
+class QSplitter;
+class KActionCollection;
+class KToolBar;
+class managementWidget;
+
+class KpListViewSearchLine : public KListViewSearchLine
+{
+ Q_OBJECT
+
+public:
+
+ KpListViewSearchLine(QWidget *parent, KpTreeList *listView);
+
+ ~KpListViewSearchLine();
+
+
+ void updateSearch(const QString &s = QString::null);
+
+private:
+ KpTreeList *list;
+};
+
+
+class managementWidget : public QFrame
+{
+ Q_OBJECT
+
+ ///////////// METHODS ------------------------------------------------------
+public:
+ managementWidget(QWidget *parent);
+ // Constructor
+
+ ~managementWidget();
+ // Destructor
+
+ KpTreeListItem *updatePackage(packageInfo *pki, bool install);
+ // update package in treelist
+
+ void readPSeparator();
+ void writePSeparator();
+ // config: position of panel seperator
+
+ void doChangePackage(packageInfo *p);
+ // emit change package
+
+ KpTreeListItem *search(QString str, bool subStr, bool wrap,
+ bool start=FALSE);
+protected:
+ void resizeEvent(QResizeEvent *re);
+ // This is called when the widget is resized
+
+private:
+ void setupWidgets();
+ // This sets up the sub-widgets
+
+ void setupInstButton();
+ // Set button for inst or uninst
+
+ void arrangeWidgets();
+ // This arranges the widgets in the window (should be called after a
+ // resize event)
+
+ void setupMultButton(int &cntInstall, int &cntUnInstall);
+ // Setup mult install/uninstall button appropriately
+
+
+ ///////////// SLOTS ------------------------------------------------------
+ public slots:
+ void collectData(bool refresh);
+ // This collects data about all the packages installed.
+ // The list tree is filled with this data. Whenever something happens
+ // that requires data to be (re)collected a signal connected to this slot
+ // should be emitted. This function can also be called directly.
+
+ void rebuildListTree();
+ // This rebuilds the list tree. This would normally be called if the
+ // data contained about the packages has been changed (e.g. a verification
+ // failed / succeeded).
+
+ void uninstallMultClicked();
+ // This is called when uninstalling multiple packages
+
+ void uninstallSingleClicked();
+ // This is called when uninstalling a single package
+
+ void installSingleClicked();
+ // This is called when the install button has been clicked with single package
+
+ void installMultClicked();
+ // This is called when the install button has been clicked with multiple packages
+
+ void setInstallAction(KAction *a) { install_action = a; }
+ void setUninstallAction(KAction *a) { uninstall_action = a; }
+
+ void packageHighlighted(QListViewItem *);
+ // This is called when a package has been highlighted in the list tree
+
+ void tabChanged(int);
+ // treelist display tab changed
+
+ void checkMarked();
+ // Count marked packages that can be installed/uninstalled
+
+ ///////////// SIGNALS ------------------------------------------------------
+
+
+ ///////////// DATA ---------------------------------------------------------
+private:
+
+ QPushButton *linstButton,*luinstButton,*instButton,*uinstButton;
+ // This button is used to (un)install the selected package
+
+ packageDisplayWidget *packageDisplay;
+ // This widget displays the package info / file-list
+
+ QBoxLayout *top, *leftbox, *rightbox, *lbuttons, *rbuttons;
+ // These are the geometry managers
+
+ QFrame *leftpanel, *rightpanel;
+ // frame to put QBox in
+
+ QTabWidget *ltab;
+ // tab between various treelist displays
+
+ QSplitter *vPan;
+ // veritcal panner between panels
+
+ KToolBar *searchToolBar;
+
+ QPtrList<KpTreeListItem> selList;
+ // list for selected packages
+
+ QString tType[4];
+ // identifiers for tree display
+
+public:
+ QPtrList<packageInfo> *allPackages;
+ // The list of packages
+
+ QDict<packageInfo> *dirInstPackages;
+ // maps installed package name to package
+
+ QDict<packageInfo> *dirUninstPackages;
+ // maps uninstalled package name to package
+
+ QDict<packageInfo> *dirInfoPackages;
+ // maps Info package name to package
+
+ KpTreeList *treeList;
+ // This is the tree list where all the packages / groups are displayed
+
+ KpListViewSearchLine *searchLine;
+ // Widget for search treeList
+
+ KAction *install_action;
+ KAction *uninstall_action;
+};
+
+#endif
+
+
+
diff --git a/kpackage/mini-icon/cr16-mime-debfile.png b/kpackage/mini-icon/cr16-mime-debfile.png
new file mode 100644
index 0000000..35c3b4e
--- /dev/null
+++ b/kpackage/mini-icon/cr16-mime-debfile.png
Binary files differ
diff --git a/kpackage/mini-icon/cr16-mime-rpmfile.png b/kpackage/mini-icon/cr16-mime-rpmfile.png
new file mode 100644
index 0000000..27fa032
--- /dev/null
+++ b/kpackage/mini-icon/cr16-mime-rpmfile.png
Binary files differ
diff --git a/kpackage/options.cpp b/kpackage/options.cpp
new file mode 100644
index 0000000..758e68d
--- /dev/null
+++ b/kpackage/options.cpp
@@ -0,0 +1,469 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "pkgInterface.h"
+#include "options.h"
+#include "cache.h"
+
+#include <qvbox.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kurlrequester.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qgroupbox.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qtabdialog.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+
+#include <findf.h>
+
+extern Opts *opts;
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+Options::Options(QWidget *parent)
+ : KDialogBase(Tabbed, i18n("Options"), Ok | Cancel, Ok, parent, 0, false){
+
+ fRemote = false;
+
+ DCache = dc = opts->DCache;
+ PCache = pc = opts->PCache;
+ privCmd = prc = opts->privCmd;
+
+ if (DCache >= Opts::SESSION) {
+ cacheObj::clearDCache(); // clear dir caches if needed
+ }
+ if (PCache >= Opts::SESSION) {
+ cacheObj::clearPCache(); // clear package caches if needed
+ }
+
+ {
+ QVBox *page = addVBoxPage(i18n("&Types"));
+
+ framet = new QGroupBox(1,Qt::Horizontal,i18n("Handle Package Type"), page);
+
+ hh = new QGroupBox(1,Qt::Horizontal,i18n("Remote Host"),framet);
+ huse = new QCheckBox(i18n("Use remote host (Debian APT only):"),hh);
+ connect(huse, SIGNAL(clicked()), this, SLOT(useRemote()));
+ hosts = new KComboBox( true, hh, "combo" );
+ KCompletion *comp = hosts->completionObject();
+ connect(hosts,SIGNAL(returnPressed(const QString&)),comp,SLOT(addItem(const QString&)));
+ connect(hosts,SIGNAL(returnPressed()),this,SLOT(insHosts()));
+ hosts->setMaxCount(20);
+ hosts->setDuplicatesEnabled(false);
+ hosts->setInsertionPolicy(QComboBox::AtTop);
+ // hosts->setInsertionPolicy(QComboBox::NoInsertion);
+ hosts->setTrapReturnKey(true);
+
+ int i;
+ QString msgStr;
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ if (kpinterface[i]->hasProgram) {
+ msgStr = kpinterface[i]->name;
+ } else {
+ msgStr = kpinterface[i]->name;
+ msgStr = i18n("%1: %2 not found")
+ .arg(kpinterface[i]->name)
+ .arg(kpinterface[i]->errExe);
+ }
+ packageBox[i] = new QGroupBox(2,Qt::Horizontal,msgStr, framet, "box");
+ packageHandle[i] = new QCheckBox(i18n("Enable"), packageBox[i]);
+ connect(packageHandle[i], SIGNAL(clicked()), this, SLOT(scanLocates()));
+ locate[i] = new QPushButton(i18n("Location of Packages"),packageBox[i]);
+ connect(locate[i], SIGNAL(clicked()), kpinterface[i], SLOT(setLocation()));
+ } else {
+ packageHandle[i] = 0;
+ }
+ }
+ }
+
+ {
+ QVBox *page = addVBoxPage(i18n("Cac&he"));
+
+ bc = new QButtonGroup(page);
+ bc->setTitle(i18n("Cache Remote Package Folders"));
+ connect( bc, SIGNAL(clicked(int)), SLOT(PDCache(int)) );
+
+ QVBoxLayout* vc = new QVBoxLayout( bc, 15, 10, "vc");
+ vc->addSpacing( bc->fontMetrics().height() );
+
+ dcache[0] = new QRadioButton(i18n("Always"),bc);
+ vc->addWidget(dcache[0]);
+
+ dcache[1] = new QRadioButton(i18n("During a session"),bc);
+ vc->addWidget(dcache[1]);
+
+ dcache[2] = new QRadioButton(i18n("Never"),bc);
+ vc->addWidget(dcache[2]);
+
+ bp = new QButtonGroup(page);
+ bp->setTitle(i18n("Cache Remote Package Files"));
+ connect( bp, SIGNAL(clicked(int)), SLOT(PPCache(int)) );
+
+ QVBoxLayout* vp = new QVBoxLayout( bp, 15, 10, "vp");
+ vp->addSpacing( bp->fontMetrics().height() );
+
+ pcache[0] = new QRadioButton(i18n("Always"),bp);
+ vp->addWidget(pcache[0]);
+
+ pcache[1] = new QRadioButton(i18n("During a session"),bp);
+ vp->addWidget(pcache[1]);
+
+ pcache[2] = new QRadioButton(i18n("Never"),bp);
+ vp->addWidget(pcache[2]);
+
+ QGroupBox* cd = new QGroupBox (1, Qt::Horizontal, i18n("Cache Folder"), page) ;
+ cd->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed) ;
+
+ cachedir = new KURLRequester("", cd, "cachedir");
+ }
+
+ {
+ QWidget *page = addVBoxPage(i18n("&Misc"));
+ QVBoxLayout *vf = new QVBoxLayout(page);
+
+ // vf->setSpacing(KDialog::spacingHint());
+ vf->setMargin(0);
+
+ bs = new QButtonGroup(page);
+ bs->setTitle(i18n("Execute Privileged Commands Using"));
+ connect( bs, SIGNAL(clicked(int)), SLOT(PPrivs(int)) );
+
+ QVBoxLayout* vs = new QVBoxLayout( bs, 15, 10, "bs");
+ vs->addSpacing( bs->fontMetrics().height() );
+
+ privs[0] = new QRadioButton(i18n("su command"),bs);
+ vs->addWidget(privs[0]);
+
+ privs[1] = new QRadioButton(i18n("sudo command"),bs);
+ vs->addWidget(privs[1]);
+
+ privs[2] = new QRadioButton(i18n("ssh command"),bs);
+ vs->addWidget(privs[2]);
+
+ valid = new QCheckBox(i18n("Verify file list"), page, "valid");
+ vf->addWidget(valid,0,AlignLeft);
+
+ pkgRead = new QCheckBox(i18n("Read information from all local package files"), page, "pkgr");
+ vf->addWidget(pkgRead,0,AlignLeft);
+
+ vf->addSpacing(100);
+ }
+
+ connect( this, SIGNAL(okClicked()), SLOT(apply_slot()) );
+ connect( this, SIGNAL(closeClicked()), SLOT(cancel_slot()) );
+ connect( this, SIGNAL(cancelClicked()), SLOT(cancel_slot()) );
+
+ setValues();
+
+}
+
+
+void Options::insHosts() {
+ // kdDebug() << "insHosts " << "\n";
+ bool found = false;
+ QString s = hosts->currentText();
+
+ int i;
+ for (i = 0; i < hosts->count(); i++) {
+ if (s == hosts->text(i))
+ found = true;
+ }
+
+ if (!found)
+ hosts->insertItem(hosts->currentText(), 0);
+}
+
+void Options::setValues() {
+ // kdDebug() << "setValues:\n";
+ DCache = dc = opts->DCache;
+ PCache = pc = opts->PCache;
+ privCmd = prc = opts->privCmd;
+ CacheDir = opts->CacheDir;
+
+ hosts->clear();
+ hosts->completionObject()->clear();
+
+ hosts->insertStringList(opts->hostList);
+ if (hosts->completionObject()) {
+ hosts->completionObject()->setItems(opts->hostList);
+ }
+
+ if (!hostName.isEmpty()) {
+ huse->setChecked(TRUE);
+ }
+ // kdDebug() << "C=" <<opts->hostList.count() << "\n";
+
+ int i;
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ packageHandle[i]->setChecked(opts->handlePackage[i]);
+ }
+ }
+ scanLocates();
+
+ dcache[DCache]->setChecked(TRUE);
+ pcache[PCache]->setChecked(TRUE);
+ privs[privCmd]->setChecked(TRUE);
+ cachedir->lineEdit()->setText(CacheDir);
+
+ valid->setChecked(opts->VerifyFL);
+ pkgRead->setChecked(opts->PkgRead);
+}
+
+Options::~Options()
+{
+}
+
+void Options::scanLocates() {
+ int i;
+
+ bool remote = huse->isChecked();
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i]) {
+ // kdDebug() << i << " " << hostName << " " << kpinterface[i]->hasRemote << "\n";
+ if (kpinterface[i]->hasProgram) {
+ packageBox[i]->setEnabled(true);
+ if (remote) {
+ if (kpinterface[i]->hasRemote) {
+ packageHandle[i]->setEnabled(true);
+ locate[i]->setEnabled(true);
+ } else {
+ packageHandle[i]->setEnabled(false);
+ locate[i]->setEnabled(false);
+ }
+ } else {
+ packageHandle[i]->setEnabled(true);
+ if ( packageHandle[i]->isChecked()) {
+ locate[i]->setEnabled(true);
+ } else {
+ locate[i]->setEnabled(false);
+ }
+ }
+ } else {
+ packageBox[i]->setEnabled(false);
+ }
+ }
+ }
+}
+
+void Options::useRemote()
+{
+ scanLocates();
+}
+
+void Options::restore()
+{
+ show();
+ fRemote = huse->isChecked();
+}
+
+void Options::cancel_slot()
+{
+ // kdDebug() << "Cancel\n";
+ opts->readSettings();
+ setValues();
+}
+
+void Options::apply_slot()
+{
+ bool doReload = false;
+ bool newHost = false;
+
+ opts->VerifyFL = valid->isChecked();
+ opts->PkgRead = pkgRead->isChecked();
+
+ insHosts();
+ opts->hostList.clear();
+ int i;
+ QString prev;
+ for (i = 0; i < hosts->count(); i++) {
+ // kdDebug() << "=" << prev << "=" << hosts->text(i) << "=\n";
+ if (prev != hosts->text(i))
+ opts->hostList.append(hosts->text(i));
+ prev = hosts->text(i);
+ }
+
+ QString remoteHost = hosts->currentText();
+
+ if ((fRemote != huse->isChecked()) || huse->isChecked() && (remoteHost != hostName)) {
+ newHost = true;
+ doReload = true;
+ }
+ if (huse->isChecked()) {
+ hostName = remoteHost;
+ } else {
+ hostName = "";
+ }
+ kpkg->setCaption(hostName);
+
+ opts->DCache = dc;
+ opts->PCache = pc;
+ opts->privCmd = prc;
+ cachedir->lineEdit()->setText (QDir(cachedir->lineEdit()->text()).path().append("/")) ; // make sure that cache directory ends with "/"
+ opts->CacheDir = cachedir->lineEdit()->text() ;
+
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (packageHandle[i]) {
+ if ( opts->handlePackage[i] != packageHandle[i]->isChecked()) {
+ doReload = true;
+ }
+ opts->handlePackage[i] = packageHandle[i]->isChecked();
+ }
+ }
+
+ if (kpackage->findialog)
+ kpackage->findialog->checkSearchAll();
+ scanLocates();
+ opts->writeSettings();
+
+ if (doReload) {
+ if (newHost) {
+ kpty->close();
+ }
+ kpackage->reload();
+ }
+}
+
+void Options::PDCache(int r)
+{
+ dc = r;
+}
+
+void Options::PPCache(int r)
+{
+ pc = r;
+}
+
+void Options::PPrivs(int r)
+{
+ kdDebug() << "Privs=" << r << "\n";
+ prc = r;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+Opts::Opts(const QString &initHost)
+{
+ readSettings(initHost);
+}
+
+Opts::~Opts()
+{
+}
+
+void Opts::readSettings(const QString &initHost)
+{
+
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+
+ // kdDebug() << "readSettings: " << initHost << "\n";
+ hostList = config->readListEntry("Host_list");
+ if (!initHost.isEmpty() && !hostList.contains(initHost)) {
+ hostList.prepend(initHost);
+ config->writeEntry("Host_list", hostList);
+ }
+ hostList.sort();
+
+ DCache = config->readNumEntry("Dir_Cache",1);
+ if (DCache >2) {
+ DCache = 1;
+ }
+ PCache = config->readNumEntry("Package_Cache",0);
+ if (PCache >2) {
+ PCache = 0;
+ }
+ CacheDir = config->readPathEntry("Cache_Directory", QDir::homeDirPath() + "/.kpackage/");
+
+ // Backward compatability
+ bool useSSH = config->readNumEntry("Use_SSH",0);
+ privCmd = config->readNumEntry("Priv_Command", -1);
+
+ if (privCmd == -1) {
+ if (useSSH) {
+ privCmd = SSHcmd;
+ } else {
+ privCmd = SUcmd;
+ }
+ }
+ VerifyFL = config->readNumEntry("Verify_File_List",1);
+ PkgRead = config->readNumEntry("Read_Package_files",0);
+}
+
+void Opts::readLaterSettings()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("Kpackage");
+
+ int i;
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i])
+ handlePackage[i] = config->readBoolEntry(kpinterface[i]->head,
+ kpinterface[i]->defaultHandle);
+ }
+}
+
+void Opts::writeSettings()
+{
+
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+
+ config->writeEntry("Host_list", hostList);
+
+ config->writeEntry("Dir_Cache", DCache);
+ config->writeEntry("Package_Cache", PCache);
+ config->writePathEntry("Cache_Directory", CacheDir);
+
+ config->writeEntry("Priv_Command",privCmd );
+
+ config->writeEntry("Verify_File_List",VerifyFL );
+ config->writeEntry("Read_Package_files", PkgRead);
+
+ int i;
+ for (i = 0; i < kpinterfaceN; i++) {
+ if (kpinterface[i])
+ config->writeEntry(kpinterface[i]->head, handlePackage[i]);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+#include "options.moc"
diff --git a/kpackage/options.h b/kpackage/options.h
new file mode 100644
index 0000000..4f8b1e7
--- /dev/null
+++ b/kpackage/options.h
@@ -0,0 +1,181 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+#include "../config.h"
+
+// Standard Headers
+#include <stdio.h>
+
+// Qt Headers
+#include <qdir.h>
+#include <qwidget.h>
+#include <qfiledialog.h>
+#include <qgroupbox.h>
+
+// KDE headers
+#include <kapplication.h>
+#include <kfiledialog.h>
+
+#include <kpackage.h>
+
+class KURLRequester;
+
+
+class QVBoxLayout;
+class QGroupBox;
+class QCheckBox;
+class QPushButton;
+class KComboBox;
+class QButtonGroup;
+class QRadioButton;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class Options : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ Options ( QWidget *parent = 0);
+ ~Options();
+
+ void restore();
+ // show window, setting the buttons
+
+ void setValues();
+ // set the dialog to match options values
+
+private:
+
+ bool verifyFL;
+ bool PkgRead;
+ bool fRemote;
+ int DCache, dc, PCache, pc, privCmd, prc;
+ QString CacheDir;
+
+ QVBoxLayout* vl;
+
+ QVBoxLayout* vt;
+ QGroupBox *framet;
+ QGroupBox *packageBox[kpinterfaceN];
+ QCheckBox *packageHandle[kpinterfaceN];
+ QPushButton *locate[kpinterfaceN];
+
+ QGroupBox *hh;
+ QCheckBox *huse;
+ KComboBox *hosts;
+
+ QVBoxLayout* vb;
+ QButtonGroup *bg;
+ QRadioButton *disp[4];
+
+ QVBoxLayout* vc;
+ QButtonGroup *bc;
+ QRadioButton *dcache[3];
+
+ QVBoxLayout* vp;
+ QButtonGroup *bp;
+ QRadioButton *pcache[3];
+
+ QVBoxLayout* vs;
+ QButtonGroup *bs;
+ QRadioButton *privs[3];
+
+ KURLRequester *cachedir;
+
+ QVBoxLayout* vr;
+ QGroupBox *framer;
+ QCheckBox *pkgRead;
+
+ QVBoxLayout* vf;
+ QGroupBox *framem;
+ QCheckBox *valid;
+
+
+public slots:
+ void scanLocates();
+ void apply_slot();
+ void cancel_slot();
+ void PDCache(int);
+ void PPCache(int);
+ void PPrivs(int);
+
+private slots:
+ void insHosts();
+ void useRemote();
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class Opts
+{
+public:
+ void readSettings(const QString &initHost = "");
+ void writeSettings();
+
+ void readLaterSettings();
+ // options to be setup after package interfaces setup
+
+ QStringList hostList;
+ // list of hosts to choose from
+
+ bool VerifyFL;
+ // config: verify the file list
+
+ bool PkgRead;
+ // read information about uninstalled packages from each RPM file itself
+
+ bool handlePackage[kpinterfaceN];
+
+ enum {INSTALLED, UPDATED, NEW, ALL};
+ enum {ALWAYS, SESSION, NEVER};
+
+ int DCache;
+ // how much to cache uninstall package directories
+
+ int PCache;
+ // how much to cache uninstall packages
+
+ int privCmd;
+ // which command to use to execute priveliged commands
+ enum {SUcmd=0, SUDOcmd=1, SSHcmd=2};
+
+ QString CacheDir;
+ // cache directory
+
+ Opts(const QString &initHost);
+ ~Opts();
+};
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/kpackage/packageDisplay.cpp b/kpackage/packageDisplay.cpp
new file mode 100644
index 0000000..67b0754
--- /dev/null
+++ b/kpackage/packageDisplay.cpp
@@ -0,0 +1,439 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+// Author: Toivo Pedaste
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#include "../config.h"
+// Standard headers
+#include <stdio.h>
+
+// Qt headers
+
+#include <qapplication.h>
+#include <qfileinfo.h>
+#include <qtextedit.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kglobal.h>
+#include <krun.h>
+#include <kopenwith.h>
+
+// kpackage.headers
+#include "kpackage.h"
+#include "packageDisplay.h"
+#include "packageProperties.h"
+#include "pkgInterface.h"
+#include "utils.h"
+#include "options.h"
+#include <klocale.h>
+
+extern Opts *opts;
+
+// constructor
+packageDisplayWidget::packageDisplayWidget(QWidget *parent)
+ : QTabWidget(parent)
+{
+ // Initially we're not dealing with any package
+ package=NULL;
+
+ // Set up the widgets
+ setupWidgets();
+
+ // Load the pixmaps
+ tick = UserIcon("ptick");
+ cross = UserIcon("cross");
+ question = UserIcon("question");
+ blank = new QPixmap();
+
+}
+
+packageDisplayWidget::~packageDisplayWidget()
+{
+ delete blank;
+}
+
+void packageDisplayWidget::setupWidgets()
+{
+ proptab = new QVBox( this);
+ curTab = proptab;
+ fltab = new QVBox( this);
+ cltab = new QVBox( this);
+
+ packageProperties = new packagePropertiesWidget(proptab);
+
+ fileList = new kpFileList(fltab, this);
+ connect(fileList, SIGNAL(executed(QListViewItem *)),
+ this, SLOT( openBinding(QListViewItem *)) );
+ connect(fileList, SIGNAL(returnPressed(QListViewItem *)),
+ this, SLOT( openBinding(QListViewItem *)) );
+
+ changeLog = new QTextEdit(cltab);
+
+ addTab(proptab, i18n("Properties"));
+ addTab(fltab, i18n("File List"));
+ addTab(cltab, i18n("Change Log"));
+
+ if (isTabEnabled(cltab))
+ setTabEnabled(cltab,false);
+ if (isTabEnabled(fltab))
+ setTabEnabled(fltab,false);
+ if (isTabEnabled(proptab))
+ setTabEnabled(proptab,false);
+
+ connect(this,SIGNAL(currentChanged(QWidget *)), this, SLOT(tabSelected(QWidget *)));
+}
+
+void packageDisplayWidget::tabSelected(QWidget *tab)
+{
+ curTab = tab;
+ tabSet(tab);
+}
+
+void packageDisplayWidget::tabSet(QWidget *tab)
+{
+ disconnect(this,SIGNAL(currentChanged(QWidget *)), this, SLOT(tabSelected(QWidget *)));
+ if(tab == proptab) {
+ packageProperties->show();
+ fileList->hide();
+ changeLog->hide();
+ setCurrentPage(0);
+ } else if (tab == fltab) {
+ packageProperties->hide();
+ changeLog->hide();
+ if (isTabEnabled(fltab)) {
+ if (!initList) {
+ updateFileList();
+ initList = 1;
+ }
+ fileList->show();
+ } else {
+ fileList->hide();
+ }
+ setCurrentPage(1);
+ } else {
+ fileList->hide();
+ packageProperties->hide();
+ if (isTabEnabled(cltab)) {
+ updateChangeLog();
+ changeLog->show();
+ } else {
+ changeLog->hide();
+ }
+ setCurrentPage(2);
+ }
+ connect(this,SIGNAL(currentChanged(QWidget *)), this, SLOT(tabSelected(QWidget *)));
+}
+
+void packageDisplayWidget::noPackage()
+{
+ disconnect(this,SIGNAL(currentChanged(QWidget *)), this, SLOT(tabSelected(QWidget *)));
+
+ if (isTabEnabled(fltab)) {
+ fileList->setColumnText(0,"");
+ setTabEnabled(fltab,false);
+ }
+ if (isTabEnabled(proptab))
+ setTabEnabled(proptab,false);
+ if (isTabEnabled(cltab))
+ setTabEnabled(cltab,false);
+
+ packageProperties->changePackage(NULL);
+
+ packageProperties->setText("");
+ fileList->clear();
+ changeLog->setText("");
+
+ connect(this,SIGNAL(currentChanged(QWidget *)), this, SLOT(tabSelected(QWidget *)));
+}
+
+// Change packages
+void packageDisplayWidget::changePackage(packageInfo *p)
+{
+
+// This is to stop selectionChanged firing off here
+
+ disconnect(fileList, SIGNAL(executed(QListViewItem *)),
+ this, SLOT( openBinding(QListViewItem *)) );
+ disconnect(fileList, SIGNAL(returnPressed(QListViewItem *)),
+ this, SLOT( openBinding(QListViewItem *)) );
+ disconnect(fileList, SIGNAL(contextMenu(KListView *, QListViewItem *, const QPoint &)),
+ fileList, SLOT( openContext(KListView *, QListViewItem *, const QPoint &)) );
+
+
+ if (package && package != p) {
+ if (!package->getItem() && !kpackage->management->allPackages->find(package)) {
+ delete package;
+ package = 0;
+ }
+ }
+
+ package = p;
+ if (!p) { // change to no package
+ noPackage();
+ } else {
+ QString u = package->getFilename();
+ if (!package->updated && !u.isEmpty()) {
+ packageInfo *np = package->interface->getPackageInfo('u', u, 0);
+
+ if (np) {
+ QMap<QString, QString>::Iterator it; // update info entries in p
+ for ( it = np->info.begin(); it != np->info.end(); ++it ) {
+ package->info.replace(it.key(),it.data());
+ }
+ package->interface = np->interface;
+ delete np;
+ package->updated = TRUE;
+ }
+ }
+
+ initList = 0;
+ packageProperties->changePackage(package);
+
+ if (package->interface->changeTab(package))
+ setTabEnabled(cltab,true);
+ else
+ setTabEnabled(cltab,false);
+
+ if (package->interface->filesTab(package))
+ setTabEnabled(fltab,true);
+ else
+ setTabEnabled(fltab,false);
+
+ setTabEnabled(proptab,true);
+
+ tabSet(curTab);
+
+
+ }
+ connect(fileList, SIGNAL(executed(QListViewItem *)),
+ this, SLOT( openBinding(QListViewItem *)) );
+ connect(fileList, SIGNAL(returnPressed(QListViewItem *)),
+ this, SLOT( openBinding(QListViewItem *)) );
+ connect(fileList, SIGNAL(contextMenu(KListView *, QListViewItem *, const QPoint &)),
+ fileList, SLOT( openContext(KListView *, QListViewItem *, const QPoint &)) );
+
+ }
+
+void packageDisplayWidget::updateChangeLog()
+{
+ if (!package)
+ return;
+
+ QStringList lines;
+ QString stmp;
+ lines = package->interface->getChangeLog(package);
+
+
+ changeLog->setTextFormat(Qt::LogText);
+ changeLog->hide();
+ if (lines.count() > 1) {
+ changeLog->setText("");
+ for (QStringList::ConstIterator it = lines.begin();
+ (it != lines.end());
+ it++) {
+ if (! (*it).isEmpty())
+ changeLog->append(*it);
+ else
+ changeLog->append(" ");
+ }
+ } else {
+ changeLog->setText(i18n(" - No change log -"));
+ }
+
+ changeLog->show();
+ changeLog->setContentsPos(0,0);
+
+}
+
+void packageDisplayWidget::updateFileList()
+{
+ if (!package)
+ return;
+
+ // Get a list of files in the package
+ QStringList files;
+ QStringList errorfiles;
+
+ // set the status
+ kpackage->setStatus(i18n("Updating File List"));
+
+ // clear the file list
+ fileList->clear();
+
+ // Check if the package is installed
+ int installed;
+ if(package->getFilename().isEmpty()) {
+ if(package->packageState == packageInfo::UPDATED) {
+ fileList->setColumnText(0, "");
+ return;
+ } else
+ installed=1;
+ } else
+ installed=0;
+
+ files = package->interface->getFileList(package);
+
+ if (files.count() == 0)
+ return;
+
+ // Get a list of files that failed verification
+ if(installed && opts->VerifyFL) {
+ errorfiles = package->interface->verify(package, files);
+ }
+
+ kpackage->setStatus(i18n("Updating File List"));
+
+ uint c=0, p=0;
+ uint step = (files.count() / 100) + 1;
+
+ QString ftmp;
+ ftmp.setNum(files.count());
+ ftmp += i18n(" Files");
+
+ fileList->setColumnText(0, ftmp);
+ fileList->hide();
+ fileList->setSorting(-1);
+
+ QListViewItem *q;
+
+ // Go through all the files
+ for (QStringList::ConstIterator it = files.begin(); (it != files.end()); ) {
+ // Update the status progress
+ c++;
+ if(c > step) {
+ c=0;
+ p++;
+ kpackage->setPercent(p);
+ }
+
+ int error=0;
+
+ QString cur = *it;
+ it++;
+ QPixmap pixmap;
+
+ if (installed) { // see if file failed verification,
+
+ if ( errorfiles.count() > 0) {
+ for( QStringList::ConstIterator itError = errorfiles.begin();
+ (itError != errorfiles.end());
+ (itError++) ) {
+ if (cur == *itError) {
+ error = 1;
+ }
+ }
+ }
+ if(error) pixmap=cross;
+ else
+ pixmap=tick;
+
+ } else
+ pixmap=question;
+
+ q = fileList->insert(cur, pixmap);
+ }
+
+ fileList->setSorting(0);
+ fileList->show();
+ kpackage->setPercent(100);
+}
+
+ kpFileList::kpFileList(QWidget* parent, packageDisplayWidget* parent2) : KListView(parent)
+ {
+ hide();
+ addColumn("name");
+ setRootIsDecorated(TRUE);
+ connect(this, SIGNAL(contextMenu(KListView *, QListViewItem *, const QPoint &)),
+ this, SLOT( openContext(KListView *, QListViewItem *, const QPoint &)) );
+
+ FileListMenu = new KPopupMenu();
+ openwith = FileListMenu->insertItem(i18n("&Open With..."),parent2,SLOT(__openBindingWith()));
+
+ pkDisplay = parent2;
+ }
+
+
+ void packageDisplayWidget::__openBindingWith()
+ {
+ openBindingWith(fileList->selectedItem());
+ }
+
+ void packageDisplayWidget::openBindingWith(QListViewItem *index)
+ {
+ if ( !index ) return;
+ KURL url;
+ if (package && package->packageState == packageInfo::INSTALLED) {
+ url.setPath( fileList->item2Path(index) ); // from local file to URL
+ KRun::displayOpenWithDialog(KURL::List::List(url) );
+ }
+ }
+
+
+ void kpFileList::openContext(KListView *, QListViewItem *, const QPoint &p)
+ {
+ FileListMenu->setItemEnabled(openwith,
+ (selectedItem() && pkDisplay->package && pkDisplay->package->getFilename().isEmpty()) ? TRUE : FALSE);
+ FileListMenu->exec(p);
+
+ }
+
+ void kpFileList::clear()
+ {
+ KListView::clear();
+ }
+
+ QString kpFileList::item2Path(QListViewItem *it)
+ {
+ QString res;
+ res = it ? it->text(0) : NULL;
+ return res;
+ }
+
+
+ QListViewItem* kpFileList::insert(const QString &cur, const QPixmap &pixmap)
+ {
+ QListViewItem* q;
+
+ q = new QListViewItem(this, cur);
+ if (q)
+ q->setPixmap(0,pixmap);
+ return q;
+ }
+
+ void packageDisplayWidget::openBinding(QListViewItem *index)
+ {
+ if ( !index ) return;
+ KURL url;
+ if (package && package->packageState == packageInfo::INSTALLED) {
+ url.setPath( fileList->item2Path(index) ); // from local file to URL
+ (void) new KRun ( url ); // run the URL
+ }
+ }
+
+
+#include "packageDisplay.moc"
diff --git a/kpackage/packageDisplay.h b/kpackage/packageDisplay.h
new file mode 100644
index 0000000..5631925
--- /dev/null
+++ b/kpackage/packageDisplay.h
@@ -0,0 +1,164 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// This widget is used to display information and the file list of a
+// package.
+//
+// Package information will be displayed using (another) sub-widget
+// that is inherited from a QTableView.
+//
+// The file list will be displayed using a tree list.
+//
+// The widget is mainly a QTabDialog with two tabs: Info and FileList.
+// The Info tab is the default one.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+
+#ifndef PACKAGEDISPLAY_H
+#define PACKAGEDISPLAY_H
+#include "../config.h"
+
+// Qt Headers
+#include <qframe.h>
+#include <qtabbar.h>
+#include <qtabwidget.h>
+#include <qvbox.h>
+#include <kpopupmenu.h>
+#include <klistview.h>
+
+class packagePropertiesWidget;
+class packageInfo;
+class QListViewItem;
+class QTextEdit;
+class packageDisplayWidget;
+class kpFileList : public KListView
+{
+ Q_OBJECT
+
+public:
+
+ kpFileList(QWidget* parent, packageDisplayWidget* parent2);
+
+ QString item2Path(QListViewItem *it);
+
+
+public slots:
+
+ void openContext(KListView *, QListViewItem *, const QPoint &);
+
+ virtual void clear();
+
+ QListViewItem* insert(const QString &cur, const QPixmap &pixmap);
+
+
+ private:
+ KPopupMenu *FileListMenu;
+ packageDisplayWidget* pkDisplay;
+
+ int openwith;
+
+};
+
+class packageDisplayWidget : public QTabWidget
+{
+ Q_OBJECT
+
+ friend class kpFileList;
+ ///////////// METHODS ------------------------------------------------------
+public:
+ packageDisplayWidget(QWidget *parent=0);
+ // Constructor
+
+ ~packageDisplayWidget();
+ // Destructor
+
+ void noPackage();
+ // clear package display in right panel
+
+ void changePackage(packageInfo *p);
+ // Set currently selected package
+
+private:
+ void setupWidgets();
+ // This sets up the sub-widgets
+
+ void updateFileList();
+ // This updates the file list to match that found with the currently
+ // selected package
+
+ void updateChangeLog();
+ // This updates the change log to match that found with the currently
+ // selected package
+
+ void tabSet(QWidget *);
+ // Set display for corresponding tab
+
+ ///////////// SLOTS --------------------------------------------------------
+public slots:
+
+ void tabSelected(QWidget *);
+
+ void openBinding(QListViewItem *);
+
+ void openBindingWith(QListViewItem *);
+
+void __openBindingWith();
+
+
+ ///////////// SIGNALS ------------------------------------------------------
+
+ ///////////// DATA ---------------------------------------------------------
+public:
+ packageInfo *package;
+ // the currently selected package
+
+private:
+
+ QTabWidget *tabbar;
+ // The tab bar
+
+ QVBox *proptab, *fltab, *cltab;
+
+ QWidget *curTab;
+ // current active tab
+
+ kpFileList *fileList;
+ // This holds the file list (and is used as a page on the tab dialog)
+
+ QTextEdit *changeLog;
+ // Holds changelog
+
+ QPixmap tick, cross, question, *blank;
+ // The pixmaps for the filelist
+
+ packagePropertiesWidget *packageProperties;
+ // This displays the package properties (and is used as a page on the
+ // tab dialog)
+
+ bool initList;
+ // True is file list has been initialised
+};
+#endif
diff --git a/kpackage/packageInfo.cpp b/kpackage/packageInfo.cpp
new file mode 100644
index 0000000..1e19afc
--- /dev/null
+++ b/kpackage/packageInfo.cpp
@@ -0,0 +1,635 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+// Author: Toivo Pedaste
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// Standard headers
+#include <stdlib.h>
+
+#include <qregexp.h>
+#include <qdir.h>
+#include <ctype.h>
+
+// KDE headers
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+// kpackage headers
+#include "kpackage.h"
+#include "kplview.h"
+#include "packageInfo.h"
+#include "pkgInterface.h"
+#include "managementWidget.h"
+#include "utils.h"
+#include "options.h"
+
+// Global pixmap for
+QPixmap *pict = NULL;
+
+//////////////////////////////////////////////////////////////////////////////
+// Constructor -- get the pixmap
+packageInfo::packageInfo(QMap<QString, QString> _info, pkgInterface *type)
+{
+ interface = type;
+ info = _info;
+
+ item = NULL;
+ packageState = UNSET;
+ updated = FALSE;
+ url = QString::null;
+}
+
+// Another constructor, for a packge with a url
+packageInfo::packageInfo(QMap<QString, QString> _info, const QString &_url)
+{
+ info = _info;
+ url = _url;
+ item = NULL;
+}
+
+packageInfo::~packageInfo()
+{
+}
+
+// Return a property
+QString packageInfo::getProperty(const QString &property)
+{
+ QString result = info[property];
+ if (result.isEmpty()) {
+ return QString::null;
+ }
+ return result;
+}
+
+// Check for existance of a property
+bool packageInfo::hasProperty(const QString &property)
+{
+ QString s = info[property];
+ if (s.isEmpty())
+ return false;
+ else
+ return true;
+}
+
+// Initialize fields if missing
+void packageInfo::fixup()
+{
+ if (info["name"].isEmpty()) {
+ QString q;
+ q.setNum((long)this);
+ info.insert("name", q);
+ }
+
+ if (info["group"].isEmpty()) {
+ info.insert("group", i18n("OTHER"));
+ kdDebug() << "Package " << info["name"] << " has no group set." << endl;
+ }
+
+ if (!info["version"]) {
+ info.insert("version", "");
+ }
+}
+
+// Set the file name
+void packageInfo::setFilename(const QString &f)
+{
+ url = f;
+}
+
+// Get the url
+QString packageInfo::getUrl()
+{
+ if (url.isEmpty()) {
+ if (hasProperty("base") && hasProperty("filename")) {
+ url = getProperty("base") + "/" + getProperty("filename");
+ }
+ }
+ return url;
+}
+
+QString packageInfo::fetchFilename()
+{
+ QString f = getFilename();
+
+ if (!f.isEmpty()) {
+ return f;
+ } else {
+ QString aurl = getUrl();
+ if (!aurl.isEmpty()) {
+ return kpackage->fetchNetFile(aurl);
+ } else {
+ return getProperty("name");
+ }
+ }
+}
+
+bool packageInfo::isFileLocal()
+{
+ QString aurl = getUrl();
+ if (!aurl.isEmpty()) {
+ return KPACKAGE::isFileLocal(aurl);
+ }
+ return false;
+}
+
+bool packageInfo::isInstallable()
+{
+ if (packageState != packageInfo::INSTALLED &&
+ !getProperty("filename").isNull() )
+ return true;
+ else
+ return false;
+}
+
+bool packageInfo::isFetchable()
+{
+ if (interface->noFetch || !getFilename().isEmpty() )
+ return true;
+ else
+ return false;
+}
+
+QString packageInfo::getFilename()
+{
+ QString cn = "";
+ QString aurl = getUrl();
+ if (!aurl.isEmpty()) {
+ return KPACKAGE::getFileName(aurl,cn);
+ } else {
+ return "";
+ }
+}
+
+int packageInfo::getDigElement(const QString &str, int *pos)
+ // Extract the next element from the string
+ // All digits
+{
+ QString s = str;
+
+ if (*pos < 0)
+ return -1;
+
+ s = s.mid(*pos);
+ if (s.isEmpty())
+ return -1;
+
+ QRegExp ndig("[^0-9]");
+
+ int nf = 0;
+ int val = 0;
+
+ if ((s[0] >= '0') && (s[0] <= '9')) {
+ nf = s.find(ndig);
+ if (nf >= 0) {
+ val = s.left(nf).toInt();
+ } else {
+ val = s.toInt();
+ nf = s.length();
+ }
+ }
+
+ // printf("n=%s %d %d\n",s.mid(nf,999).data(),nf,val);
+ *pos += nf;
+ return val;
+}
+
+QString packageInfo::getNdigElement(const QString &string, int *pos)
+ // Extract the next element from the string
+ // All all non-digits
+{
+ QString s(string);
+
+ if (*pos < 0)
+ return QString::null;
+
+ s = s.mid(*pos);
+ if (s.isEmpty())
+ return QString::null;
+
+ QString str;
+ int nf = 0;
+
+ QRegExp idig("[0-9]");
+
+ if ((s[0] < '0') || (s[0] > '9') ) {
+ nf = s.find(idig);
+ if (nf < 0)
+ nf = s.length();
+ str = s.left(nf);
+ for (unsigned int i = 0; i < str.length() ; i++) {
+ // Strange Debian package sorting magic
+ if (!str[i].isLetter()) {
+ char t = str[i].latin1();
+ t += 128;
+ str[i] = t;
+ }
+ }
+ }
+ *pos += nf;
+ return str;
+}
+
+
+int packageInfo::pnewer(const QString &s, const QString &sp)
+{
+ int ns = 0, nsp = 0, vs, vsp;
+
+ // kdDebug() << "S=" << s << " SP=" << sp << "\n";
+ while (TRUE) {
+ vs = getDigElement(s,&ns);
+ vsp = getDigElement(sp,&nsp);
+ // kdDebug() << "s=" << ns << " " << vs << " sp=" << nsp << " " << vsp << "\n";
+ if (vs < 0 && vsp < 0)
+ return 0;
+ if (vs < 0 && vsp < 0)
+ return 1;
+ if (vs < 0 && vsp < 0)
+ return -1;
+ if (vsp > vs)
+ return 1;
+ else if (vs > vsp)
+ return -1;
+
+ QString svs = getNdigElement(s,&ns);
+ QString svsp = getNdigElement(sp,&nsp);
+ // kdDebug() << "vs=" << ns << " " << svs << " sp=" << nsp << " " << svsp << "\n";
+ if (svs.isEmpty() && svsp.isEmpty())
+ return 0;
+ if (svs.isEmpty() && !svsp.isEmpty())
+ return 1;
+ if (!svs.isEmpty() && svsp.isEmpty())
+ return -1;
+
+ if (svsp.isNull()) { // Allow for QT strangeness comparing null string
+ svsp = "";
+ }
+ if (svs.isNull()) {
+ svs = "";
+ }
+ int n = svsp.compare(svs);
+ // kdDebug() << "svsp=" << svsp << "=" << svsp.length() << " svs=" << svs << "=" <<svs.length() << " n=" << n << "\n";
+ if (n != 0)
+ return n;
+ }
+}
+
+static bool split(QString orig, char seperator, QString &first, QString &second)
+{
+ int pos = orig.find(seperator);
+ if (pos > 0) {
+ first = orig.mid(0,pos);
+ second = orig.mid(pos+1);
+ return true;
+ }
+ return false;
+}
+
+int packageInfo::newer(packageInfo *p)
+{
+ QString mySerial; // Serial number of this package
+ QString myVersion; // Version of this package
+ QString myRelease; // Release of this package
+
+// Version of this package
+ QString s = getProperty("version");
+
+ (void) split(s, ':', mySerial, s);
+ if (!split(s, '-', myVersion, myRelease))
+ {
+ myVersion = s;
+ }
+
+// Version of other package
+ QString hisSerial; // Serial number of the other package
+ QString hisVersion; // Version of the other package
+ QString hisRelease; // Release of the other package
+
+ s = p->getProperty("version");
+ if (p->hasProperty("release")) {
+ s = s + "-" + p->getProperty("release");
+ }
+ if (p->hasProperty("serial")) {
+ s = p->getProperty("serial") + ":" + s;
+ }
+
+ (void) split(s, ':', hisSerial, s);
+ if (!split(s, '-', hisVersion, hisRelease))
+ {
+ hisVersion = s;
+ }
+
+ // kdDebug() << "mySerial=" << mySerial << " hisSerial=" << hisSerial <<"\n";
+ // kdDebug() << "myVersion=" << myVersion << " hisVersion=" << hisVersion <<"\n";
+ // kdDebug() << "myRelease=" << myRelease << " hisRelease=" << hisRelease <<"\n";
+
+ int n = pnewer(mySerial,hisSerial);
+ if (n)
+ return n;
+ else {
+ n = pnewer(myVersion,hisVersion);
+ if (n)
+ return n;
+ else
+ return pnewer(myRelease,hisRelease);
+ }
+}
+
+bool packageInfo::display(int treeType)
+{
+ switch (treeType) {
+ case Opts::INSTALLED:
+ if (packageState == INSTALLED || packageState == BAD_INSTALL)
+ return TRUE;
+ break;
+ case Opts::UPDATED:
+ if (packageState == UPDATED)
+ return TRUE;
+ break;
+ case Opts::NEW:
+ if ((packageState == UPDATED) || (packageState == NEW))
+ return TRUE;
+ break;
+ case Opts::ALL:
+ return TRUE;
+ break;
+ };
+ return FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Place the package in a QListView
+
+KpTreeListItem *packageInfo::place(KpTreeList *tree, bool insertI)
+{
+ KpTreeListItem *search = tree->firstChild(), *parent=NULL, *child=NULL;
+ QString qtmp, tmp;
+ bool doit = FALSE;
+
+ doit = TRUE;
+ if (packageState == NOLIST || packageState == HIDDEN)
+ doit = FALSE;
+
+ if (doit) {
+ qtmp = interface->head;
+ qtmp += "/";
+ qtmp += getProperty("group");
+ int cnt = 0;
+
+ QStringList list = QStringList::split("/",qtmp);
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ KpTreeListItem *group;
+
+ if( search && (group=findGroup(*it, search)) ) {
+ parent = group;
+ parent->setOpen(TRUE);
+ search = group->firstChild();
+ } else {
+ if (parent) {
+ group = new KpTreeListItem(parent, 0, interface->folder, *it);
+ } else {
+ group = new KpTreeListItem(tree, 0, interface->folder, *it);
+ }
+ parent = group;
+ parent->setOpen(TRUE);
+ search = NULL;
+ }
+ cnt++;
+ }
+
+ tmp = *info.find("name");
+
+ if(item)
+ delete item;
+
+ QString sz = "";
+ if (!info["size"].isEmpty()) {
+ sz = info["size"].stripWhiteSpace();
+ if (sz.length() > 3)
+ sz.truncate(sz.length() - 3);
+ else
+ sz = "0";
+ sz += "K";
+ } else if (!info["file-size"].isEmpty()) {
+ sz = info["file-size"].stripWhiteSpace();
+ if (sz.length() > 3)
+ sz.truncate(sz.length() - 3);
+ else
+ sz = "0";
+ sz += "k";
+ }
+ sz = sz.rightJustify(6,' ');
+
+ QString ver = "";
+ if (!info["version"].isEmpty()) {
+ ver = info["version"];
+ }
+
+ QString over = "";
+ if (!info["old-version"].isEmpty()) {
+ over = info["old-version"];
+ }
+ QString summary = "";
+ if (!info["summary"].isEmpty()) {
+ summary = info["summary"];
+ }
+
+
+ QPixmap pic;
+ if (packageState == BAD_INSTALL) {
+ pic = interface->bad_pict;
+ } else if (packageState == UPDATED) {
+ pic = interface->updated_pict;
+ } else if (packageState == NEW) {
+ pic = interface->new_pict;
+ } else if (packageState == INSTALLED) {
+ pic = interface->pict;
+ } else {
+ pic = interface->pict;
+ }
+
+ if (child) {
+ item = new KpTreeListItem(child, this, pic, tmp, "", summary, sz, ver, over);
+ } else {
+ item = new KpTreeListItem(parent, this, pic, tmp, "", summary, sz, ver, over);
+ }
+
+ if (insertI) {
+ parent->setOpen(TRUE);
+ } else {
+ parent->setOpen(FALSE);
+ }
+
+ return item;
+ } else {
+ return 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+
+// Get the QListViewItem
+KpTreeListItem *packageInfo::getItem()
+{
+ return item;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool packageInfo::smerge( const QString &exp) {
+
+ QDict<packageInfo> *dirInfoPackages = kpackage->management->dirInfoPackages;
+ QString pname = getProperty("name") + exp;
+
+ packageInfo *pi = dirInfoPackages->find(pname);
+ if (pi) {
+ QMap<QString,QString>::Iterator it;
+
+ for ( it = pi->info.begin(); it != pi->info.end(); ++it ) {
+ if (!(it.key() == "size" && !info["size"].isEmpty()) ||
+ !(it.key() == "file-size" && !info["file-size"].isEmpty())) {
+ info.insert(it.key(), it.data());
+ }
+ ++it;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void packageInfo::pkgFileIns(const QString &fileName)
+{
+ info.insert("filename", fileName);
+ info.insert("base", "/");
+
+ if (pkgInsert(kpackage->management->allPackages, interface->typeID, FALSE)) {
+ packageState = packageInfo::NEW;
+ place(kpackage->management->treeList,TRUE);
+
+ QString pname = getProperty("name") + interface->typeID;
+ kpackage->management->dirUninstPackages->insert(pname,this);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+bool packageInfo::pkgInsert(QPtrList<packageInfo> *pki, const QString &exp,
+ bool installed, bool infoPackage)
+{
+ QDict<packageInfo> *dirInstPackages = kpackage->management->dirInstPackages;
+ QDict<packageInfo> *dirUninstPackages = kpackage->management->dirUninstPackages;
+ QDict<packageInfo> *dirInfoPackages = kpackage->management->dirInfoPackages;
+
+ QString pname = getProperty("name") + exp;
+ // printf("U1=%s\n",pname.data());
+
+ bool shouldUpdate = TRUE;
+ bool hidden = FALSE;
+
+ packageInfo *pi = dirInstPackages->find(pname);
+ if (pi) { // installed version exists
+ if ((pi->packageState != BAD_INSTALL)
+ && (pi->packageState != NOLIST)) {
+ if (newer(pi) >= 0) {
+ hidden = TRUE;
+ }
+ }
+ }
+
+ packageInfo *pu = dirUninstPackages->find(pname);
+ if (pu) { // available version exists
+ if ((pu->packageState != BAD_INSTALL)
+ && (pu->packageState != NOLIST)) {
+ if (newer(pu) >= 0) {
+ shouldUpdate = FALSE;
+ } else if (!installed) { // If older available package exists, remove it
+ dirUninstPackages->remove(*(pu->info.find("name")));
+ pki->remove(pu);
+ }
+ }
+ }
+
+ if (getProperty("version").isEmpty()) {
+ shouldUpdate = TRUE;
+ }
+
+ if (shouldUpdate) {
+ if (packageState != BAD_INSTALL) {
+ if (installed)
+ packageState = INSTALLED;
+ else if (pi) { // installed version exists
+ if (hidden) {
+ packageState = HIDDEN;
+ } else {
+ QString version = pi->getProperty("version");
+ if (version.isEmpty()) {
+ if (pi->packageState == NOLIST)
+ packageState = NEW;
+ else
+ packageState = UPDATED;
+ } else {
+ packageState = UPDATED;
+ if (pi->hasProperty("old-version")) {
+ info.insert("old-version",
+ pi->getProperty("old-version"));
+ } else {
+ info.insert("old-version",version);
+ }
+ QString group = getProperty("group");
+ if (group == "NEW") {
+ if (pi->hasProperty("group")) {
+ info.replace("group",
+ pi->getProperty("group") );
+ }
+ }
+ }
+ }
+ } else
+ packageState = NEW;
+ }
+
+ pki->insert(0,this);
+ if (installed) {
+ if (infoPackage)
+ dirInfoPackages->insert(pname,this);
+ else
+ dirInstPackages->insert(pname,this);
+ } else
+ dirUninstPackages->insert(pname,this);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
diff --git a/kpackage/packageInfo.h b/kpackage/packageInfo.h
new file mode 100644
index 0000000..be0dbb3
--- /dev/null
+++ b/kpackage/packageInfo.h
@@ -0,0 +1,165 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+//
+// This file contains the definition of the class packageInfo
+//
+// packageInfo is used to store information regarding an package.
+// This information is normally gained by querying the database or
+// by querying an package.
+//
+// The package information consists of a set of properties. These
+// properties are stored in a dictionary that is passed to the
+// constructor. The properties can be accessed using the function
+// `getProperty'.
+//
+// In addition, packageInfo objects can place themselves inside
+// a tree list with the function `place'. Doing this creates
+// a tree list item object that can be accessed with the function
+// `item'.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef PACKAGEINFO_H
+#define PACKAGEINFO_H
+#include "../config.h"
+
+#include <qmap.h>
+#include <qdict.h>
+#include <qstring.h>
+#include <qpixmap.h>
+#include <qptrlist.h>
+#include <qlistview.h>
+
+class pkgInterface;
+class KpTreeListItem;
+class KpTreeList;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class packageInfo
+{
+public:
+ packageInfo(QMap<QString, QString> _info, pkgInterface *type);
+ // Constructor: create a packageInfo object using the property
+ // dictionary from _info
+
+ packageInfo(QMap<QString, QString> _info, const QString &_filename);
+ // Constructor: same as above, but also sets filename to _filename.
+ // This is used in the case that the package info was obtained from
+ // an uninstalled package.
+
+ ~packageInfo();
+ // Distructor
+
+ /**
+ * Look ups the property `property' from the dictionary
+ */
+ QString getProperty(const QString &property);
+
+ /**
+ * Checks whether the property `property' is defined in the dictionary
+ */
+ bool hasProperty(const QString &property);
+
+ void fixup();
+ // Initialize fields if missing
+
+ KpTreeListItem *place(KpTreeList *tree, bool InsertI=FALSE);
+ // places the object in the treelist `tree' and initialises
+ // `item'. If necessary, new groups will be added to `tree'.
+
+ KpTreeListItem *getItem();
+ // returns the treelist item object for this package or
+ // NULL if the object hasn't been placed
+
+ void setFilename(const QString &f);
+
+ QString getUrl();
+ // return URL of package file
+
+ bool isFileLocal();
+ // True if package file is local or cached file
+
+ bool isInstallable();
+ // True if package can be installed
+
+ bool isFetchable();
+ // True if package needs to be fetched
+
+ QString getFilename();
+
+ QString fetchFilename();
+ // gets the filename, fetching package if necessary
+
+ int newer(packageInfo *p);
+ // if package p is newer
+
+ void pkgFileIns(const QString &fileName);
+ // Insert a package from a file into package tree
+
+ bool pkgInsert(QPtrList<packageInfo> *pki, const QString &exp, bool installed,
+ bool infoPackage = FALSE);
+ // insert packgeInfo either installed or not installed
+
+ QMap<QString, QString> info;
+ // This stores the property dictionary of the package
+
+ KpTreeListItem *item;
+ // This stores the tree list item for this package (or NULL if
+ // the package hasn't been placed in a tree list)
+
+ pkgInterface *interface;
+ // interface points to the class of the package (deb, rpm etc)
+
+ bool smerge( const QString &exp);
+ // merge with already existing NOLIST package info
+
+ bool display(int treeType);
+ // if this package is to be should in the tree list
+
+ enum {UNSET, AVAILABLE, INSTALLED, BAD_INSTALL, UPDATED,
+ NEW, NOLIST, HIDDEN};
+ int packageState;
+
+ bool updated;
+
+private:
+ int getDigElement(const QString &s, int *pos);
+ QString getNdigElement(const QString &s, int *pos);
+ // break up version string
+
+ int pnewer(const QString &s, const QString &sp);
+ // compare parts of a version string
+
+ QString url;
+ // This stores the filename of the package the info was obtained from.
+ // If it is empty then the info was obtained from an installed package.
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+#endif
+
diff --git a/kpackage/packageProperties.cpp b/kpackage/packageProperties.cpp
new file mode 100644
index 0000000..b05a00c
--- /dev/null
+++ b/kpackage/packageProperties.cpp
@@ -0,0 +1,278 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#include "../config.h"
+#include <stdio.h>
+#include <kdebug.h>
+
+#include <kapplication.h>
+
+#include "kpackage.h"
+#include "packageProperties.h"
+#include "pkgInterface.h"
+#include "managementWidget.h"
+
+packagePropertiesWidget::packagePropertiesWidget
+ (QWidget *parent)
+ : KTextBrowser(parent)
+{
+ QDict<QString> trl(53);
+ QStringList pList();
+ QStringList cList();
+
+ // hide();
+ package=NULL;
+ QColorGroup cg = colorGroup();
+ setBackgroundColor(cg.base());
+ initTranslate();
+}
+
+packagePropertiesWidget::~packagePropertiesWidget()
+{
+}
+
+void packagePropertiesWidget::iList(const QString &txt, const QString &itxt)
+{
+ trl.insert(txt, new QString(itxt));
+ pList.append(txt);
+}
+
+
+void packagePropertiesWidget::initTranslate()
+{
+
+ iList("name", i18n("name"));
+ iList("summary", i18n("summary"));
+ iList("version", i18n("version"));
+ iList("old-version", i18n("old-version"));
+ iList("status", i18n("status"));
+ iList("group", i18n("group"));
+ iList("size", i18n("size"));
+ iList("file-size", i18n("file-size"));
+ iList("description", i18n("description"));
+ iList("url", i18n("url"));
+ iList("architecture", i18n("architecture"));
+
+ iList("unsatisfied dependencies", i18n("unsatisfied dependencies"));
+ iList("pre-depends", i18n("pre-depends"));
+ iList("dependencies", i18n("dependencies"));
+ iList("depends", i18n("depends"));
+ iList("conflicts", i18n("conflicts"));
+ iList("provides", i18n("provides"));
+ iList("recommends", i18n("recommends"));
+ iList("replaces", i18n("replaces"));
+ iList("suggests", i18n("suggests"));
+ iList("priority", i18n("priority"));
+
+ iList("essential", i18n("essential"));
+ iList("install time", i18n("install time"));
+ iList("config-version", i18n("config-version"));
+ iList("distribution", i18n("distribution"));
+ iList("vendor", i18n("vendor"));
+ iList("maintainer", i18n("maintainer"));
+ iList("packager", i18n("packager"));
+ iList("source", i18n("source"));
+ iList("build-time", i18n("build-time"));
+ iList("build-host", i18n("build-host"));
+ iList("base", i18n("base"));
+ iList("filename", i18n("filename"));
+ iList("serial", i18n("serial"));
+
+ iList("also in", i18n("also in"));
+ iList("run depends", i18n("run depends"));
+ iList("build depends", i18n("build depends"));
+ iList("available as", i18n("available as"));
+}
+
+void packagePropertiesWidget::changePackage(packageInfo *p)
+{
+
+ package = p;
+ cList.clear();
+ if (p) {
+ // append properties in ordered list to current list
+ for ( QStringList::Iterator s = pList.begin();
+ s != pList.end();
+ ++s) {
+
+ if (!p->getProperty(*s).isEmpty()) {
+ cList.append(*s);
+ }
+ }
+ // append other properties to end
+ QMap<QString, QString>::Iterator it;
+ for ( it = p->info.begin(); it != p->info.end(); ++it ) {
+ if (!trl.find(it.key())) {
+ if (!it.data().isEmpty())
+ cList.append(it.key());
+ }
+ }
+
+ stmp = "";
+ stmp += "<html><head></head><body>";
+ stmp += "<h1 style='font-family: serif;'>";
+ stmp += p->getProperty("name");
+ stmp += "</h1><hr/>";
+ stmp += "<table style='width: 100%; border: none; border-spacing: 4px;>";
+ for ( QStringList::Iterator s = cList.begin();
+ s != cList.end();
+ ++s) {
+ QString *pr = trl[*s];
+ QString propName;
+ if(pr) {
+ propName = *pr;
+ } else {
+ propName = *s;
+ }
+ stmp += "<tr>";
+ stmp += "<td style='vertical-align: top; font-weight: bold'>";
+ stmp += propName;
+ stmp += "</td><td>";
+ QString f = p->getProperty(*s);
+ if (*s == "maintainer" || *s == "packager") {
+ f.replace(QRegExp("<"),"&lt;");
+ f.replace(QRegExp(">"),"&gt;");
+ }
+ if (*s == "filename") {
+ int p = f.findRev("/");
+ if (p >= 0) {
+ f.insert(p+1,"\n");
+ };
+ stmp += f;
+ } else if (*s == "depends" || *s == "conflicts" ||
+ *s == "replaces" ||
+ *s == "suggests" || *s == "recommends" ||
+ *s == "pre-depends" || *s == "unsatisfied dependencies") {
+ depends(f);
+ } else if (*s == "url") {
+ if (f.right(1) == " ") f.remove(f.length()-1, 1);
+ if (f.startsWith("http:") || f.startsWith("ftp:")) /*if (!(f == "(none)")) */
+ stmp += "<a href=\"" + f +"\">" + f + "</a>";
+ else stmp += i18n("none");
+ } else {
+ stmp += f;
+ }
+ stmp += "</td>";
+ stmp += "</tr>";
+ }
+ stmp += "</table>";
+ stmp += "</body></html>";
+ setText(stmp);
+ }
+ update();
+}
+
+void packagePropertiesWidget::depends(const QString &f) {
+ // printf("d=%s\n",f.data());
+
+ int i = 0;
+ QStringList list = QStringList::split(',',f);
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ if (i++ > 0)
+ stmp += ",";
+ dor((*it));
+ }
+}
+
+void packagePropertiesWidget::dor(const QString &f) {
+ // printf("o=%s\n",f.data());
+
+ int i = 0;
+ QStringList list = QStringList::split('|',f);
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ if (i++ > 0)
+ stmp += "|";
+ delement((*it));
+ }
+}
+
+void packagePropertiesWidget::delement(const QString &f) {
+ int n = f.find("(");
+ if (n < 0) {
+ n = f.length();
+ }
+
+ QString u = f.left(n);
+ QString uf = package->interface->provMap(u.stripWhiteSpace());
+
+ QString us = uf + package->interface->typeID;
+
+ bool inst = false, uninst = false;
+ if (kpackage->management->dirInstPackages->find(us)) {
+ inst = true;
+ } else if (kpackage->management->dirUninstPackages->find(us)) {
+ uninst = true;
+ }
+
+ if (uninst)
+ stmp += "<i>";
+ if (inst||uninst) {
+ stmp += "<a href=\"";
+ stmp += uf;
+ stmp += "\">";
+ stmp += u;
+ stmp += "</a>";
+ } else {
+ stmp += u;
+ }
+ if (uninst)
+ stmp += "</i>";
+ if (n < (signed)f.length())
+ stmp += f.mid(n).replace(QRegExp("<"),"&lt;");
+}
+
+void packagePropertiesWidget::setSource(const QString &name) {
+ QString s = name;
+
+ if (s.startsWith("http:") || s.startsWith("ftp:"))
+ {
+ KApplication::kApplication()->invokeBrowser( s );
+ return;
+ }
+
+ if (s.startsWith("file:")) {
+ s = s.mid(5);
+ }
+ else if (s.at(1) == '/') {
+ s = s.mid(1);
+ }
+
+ QString ind = s + package->interface->typeID;
+ packageInfo *p = kpackage->management->dirInstPackages->find(ind);
+ if (p) {
+ kpackage->management->treeList->changePack(p->getItem(), package->getItem() != 0);
+ } else {
+ kdDebug() << "nfound=" << ind << endl;
+ p = kpackage->management->dirUninstPackages->find(ind);
+ if (p) {
+ kpackage->management->treeList->changePack(p->getItem(), package->getItem() != 0);
+ } else {
+ kdDebug() << "Nfound=" << ind << endl;
+ }
+ }
+}
+#include "packageProperties.moc"
diff --git a/kpackage/packageProperties.h b/kpackage/packageProperties.h
new file mode 100644
index 0000000..0b7e035
--- /dev/null
+++ b/kpackage/packageProperties.h
@@ -0,0 +1,103 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// Author: Damyan Pepper
+//
+// This widget is used to provide a list of all the properties that are
+// found in the package's property dictionary
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#ifndef PACKAGEPROPERTIES_H
+#define PACKAGEPROPERTIES_H
+#include "../config.h"
+
+// Standard Headers
+
+// Qt Headers
+#include <qpainter.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+
+// KDE Headers
+#include <klocale.h>
+#include <ktextbrowser.h>
+
+// kpackage Headers
+#include "packageInfo.h"
+
+class packageInfo;
+
+class packagePropertiesWidget : public KTextBrowser
+{
+ Q_OBJECT
+ ///////////// METHODS ------------------------------------------------------
+public:
+
+ packagePropertiesWidget(QWidget *parent=0);
+ // constructor
+
+ ~packagePropertiesWidget();
+ // destructor
+
+ void changePackage(packageInfo *p);
+
+ void setSource( const QString & name );
+ // url selected
+
+protected:
+
+
+
+ ///////////// DATA ---------------------------------------------------------
+private:
+ packageInfo *package;
+
+ void initTranslate();
+ void iList(const QString &txt, const QString &itxt);
+
+ QDict<QString> trl ;
+ // allow for translation of labels
+
+ QStringList pList;
+ // list specifying order of property distplay
+
+ QStringList cList;
+ // list giving order of currently displayed properties
+
+ QString stmp;
+ // text accumulation buffer
+
+ void depends(const QString &f);
+ // translate depends string
+
+ void dor(const QString &f);
+ // translate depends string
+
+ void delement(const QString &f);
+ // translate depends element
+};
+
+
+#endif
diff --git a/kpackage/pics/Makefile.am b/kpackage/pics/Makefile.am
new file mode 100644
index 0000000..4e55083
--- /dev/null
+++ b/kpackage/pics/Makefile.am
@@ -0,0 +1,6 @@
+pics_DATA = cross.png dbad.png deb.png dnew.png dupdated.png \
+ ptick.png question.png rnew.png rpm.png rupdated.png \
+ kiss.png knew.png kupdated.png slack.png snew.png \
+ supdated.png bsd.png bnew.png bupdated.png tick.png noball.png
+
+picsdir = $(kde_datadir)/kpackage/pics
diff --git a/kpackage/pics/bnew.png b/kpackage/pics/bnew.png
new file mode 100644
index 0000000..0a70e91
--- /dev/null
+++ b/kpackage/pics/bnew.png
Binary files differ
diff --git a/kpackage/pics/bsd.png b/kpackage/pics/bsd.png
new file mode 100644
index 0000000..92b0b88
--- /dev/null
+++ b/kpackage/pics/bsd.png
Binary files differ
diff --git a/kpackage/pics/bupdated.png b/kpackage/pics/bupdated.png
new file mode 100644
index 0000000..2d733d6
--- /dev/null
+++ b/kpackage/pics/bupdated.png
Binary files differ
diff --git a/kpackage/pics/cross.png b/kpackage/pics/cross.png
new file mode 100644
index 0000000..748afec
--- /dev/null
+++ b/kpackage/pics/cross.png
Binary files differ
diff --git a/kpackage/pics/dbad.png b/kpackage/pics/dbad.png
new file mode 100644
index 0000000..89b70c4
--- /dev/null
+++ b/kpackage/pics/dbad.png
Binary files differ
diff --git a/kpackage/pics/deb.png b/kpackage/pics/deb.png
new file mode 100644
index 0000000..7c5ac7f
--- /dev/null
+++ b/kpackage/pics/deb.png
Binary files differ
diff --git a/kpackage/pics/dnew.png b/kpackage/pics/dnew.png
new file mode 100644
index 0000000..85cb602
--- /dev/null
+++ b/kpackage/pics/dnew.png
Binary files differ
diff --git a/kpackage/pics/dupdated.png b/kpackage/pics/dupdated.png
new file mode 100644
index 0000000..f807221
--- /dev/null
+++ b/kpackage/pics/dupdated.png
Binary files differ
diff --git a/kpackage/pics/kiss.png b/kpackage/pics/kiss.png
new file mode 100644
index 0000000..40956ae
--- /dev/null
+++ b/kpackage/pics/kiss.png
Binary files differ
diff --git a/kpackage/pics/knew.png b/kpackage/pics/knew.png
new file mode 100644
index 0000000..1b49daa
--- /dev/null
+++ b/kpackage/pics/knew.png
Binary files differ
diff --git a/kpackage/pics/kupdated.png b/kpackage/pics/kupdated.png
new file mode 100644
index 0000000..bc1b90b
--- /dev/null
+++ b/kpackage/pics/kupdated.png
Binary files differ
diff --git a/kpackage/pics/noball.png b/kpackage/pics/noball.png
new file mode 100644
index 0000000..0e9fbe4
--- /dev/null
+++ b/kpackage/pics/noball.png
Binary files differ
diff --git a/kpackage/pics/ptick.png b/kpackage/pics/ptick.png
new file mode 100644
index 0000000..7f8c315
--- /dev/null
+++ b/kpackage/pics/ptick.png
Binary files differ
diff --git a/kpackage/pics/question.png b/kpackage/pics/question.png
new file mode 100644
index 0000000..e6c809d
--- /dev/null
+++ b/kpackage/pics/question.png
Binary files differ
diff --git a/kpackage/pics/rnew.png b/kpackage/pics/rnew.png
new file mode 100644
index 0000000..2b44ca3
--- /dev/null
+++ b/kpackage/pics/rnew.png
Binary files differ
diff --git a/kpackage/pics/rpm.png b/kpackage/pics/rpm.png
new file mode 100644
index 0000000..8437a8f
--- /dev/null
+++ b/kpackage/pics/rpm.png
Binary files differ
diff --git a/kpackage/pics/rupdated.png b/kpackage/pics/rupdated.png
new file mode 100644
index 0000000..b570636
--- /dev/null
+++ b/kpackage/pics/rupdated.png
Binary files differ
diff --git a/kpackage/pics/slack.png b/kpackage/pics/slack.png
new file mode 100644
index 0000000..f46fb11
--- /dev/null
+++ b/kpackage/pics/slack.png
Binary files differ
diff --git a/kpackage/pics/snew.png b/kpackage/pics/snew.png
new file mode 100644
index 0000000..0043371
--- /dev/null
+++ b/kpackage/pics/snew.png
Binary files differ
diff --git a/kpackage/pics/supdated.png b/kpackage/pics/supdated.png
new file mode 100644
index 0000000..c608b55
--- /dev/null
+++ b/kpackage/pics/supdated.png
Binary files differ
diff --git a/kpackage/pics/tick.png b/kpackage/pics/tick.png
new file mode 100644
index 0000000..7f8c315
--- /dev/null
+++ b/kpackage/pics/tick.png
Binary files differ
diff --git a/kpackage/pkgInterface.cpp b/kpackage/pkgInterface.cpp
new file mode 100644
index 0000000..eeb6f74
--- /dev/null
+++ b/kpackage/pkgInterface.cpp
@@ -0,0 +1,435 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+
+#include "kpackage.h"
+#include "pkgInterface.h"
+#include "options.h"
+#include "cache.h"
+#include "updateLoc.h"
+#include "kio.h"
+
+extern Opts *opts;
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+param::param(const QString &nameP, bool initP, bool invertP, const QString &flagP)
+{
+ name = nameP;
+ init = initP;
+ invert = invertP;
+ flag = flagP;
+ flagA = "";
+}
+
+param::param(const QString &nameP, bool initP, bool invertP, const QString &flagP, const QString &flagAP )
+{
+ name = nameP;
+ init = initP;
+ invert = invertP;
+ flag = flagP;
+ flagA = flagAP;
+
+}
+
+param::~param()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+pkgInterface::pkgInterface( ) : QObject(), new_pict(), updated_pict()
+{
+ packageLoc = 0;
+
+ DELMSG = i18n("'Delete this window to continue'");
+
+ folder = SmallIcon("folder");
+ markInst = UserIcon("tick");
+ markUnInst = UserIcon("noball");
+ bad_pict = UserIcon("dbad");
+
+ hasRemote = FALSE;
+ defaultHandle = 1;
+ noFetch = FALSE;
+ hasSearchAll = FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+pkgInterface::~pkgInterface()
+{
+ // if (locatedialog)
+ // delete locatedialog;
+ // if (packageLoc)
+ // delete packageLoc;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void pkgInterface::makeMenu(KActionCollection *)
+{
+}
+
+void pkgInterface::setMenu(KActionCollection*, bool )
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QStringList pkgInterface::depends(const QString &, int ) {return 0;}
+
+QString pkgInterface::doUninstall(int, const QString &, bool &) {return 0;}
+QString pkgInterface::doInstall(int, const QString &, bool &) {return 0;}
+
+////////////////////////////////////////////////////////////////////////////
+
+bool pkgInterface::ifExe(QString exe) {
+ if (!KGlobal::dirs()->findExe( exe ).isNull()) {
+ return TRUE;
+ } else {
+ kdDebug() << "Program not found: " << exe << "\n";
+ errExe = exe;
+ return FALSE;
+ }
+}
+
+
+void pkgInterface::listPackages(QPtrList<packageInfo> *pki)
+{
+ listInstalledPackages(pki);
+ if (packageLoc) {
+ for (cacheObj *cp = packageLoc->first(); cp != 0; cp = packageLoc->next()) {
+ QString s = getDir(cp);
+ if (!s.isEmpty())
+ listDir(pki, s, cp->location, cp->subdirs);
+ }
+ }
+}
+
+void pkgInterface::smerge(packageInfo *)
+{ }
+
+void pkgInterface::listDir(QPtrList<packageInfo> *pki, const QString &fname, const QString &dir, bool subdirs)
+{
+ // fname - path to directory or cached remote infromation file
+ // dir - url of directory
+
+ QString name, size, rfile;
+ packageInfo *p;
+
+ QString sline( queryMsg + fname );
+ kpackage->setStatus(sline);
+
+ kdDebug() << "listDir fn=" << fname << " dir=" << dir << endl;
+
+ QDir d(fname,packagePattern);
+
+ if (subdirs)
+ d.setMatchAllDirs( TRUE ); // list contains subdirs
+ else
+ d.setMatchAllDirs( FALSE ); // list contains no subdirs
+
+ if (d.exists()) {
+ if ( d.isReadable() ) {
+ QString pn;
+ const QFileInfoList *list = d.entryInfoList();
+ QFileInfoListIterator it( *list ); // create list iterator
+ QFileInfo *fi; // pointer for traversing
+
+ while ( (fi=it.current()) ) { // for each entry...
+ if ( fi->isDir() ) {
+ // entry is a subdir
+ if ( fi->fileName() != QString::fromLatin1(".") &&
+ fi->fileName() != QString::fromLatin1("..") )
+ {
+ // not current dir and not parent dir
+ // -> recursive call:
+ listDir( pki, dir + "/" + fi->fileName(), dir + "/" + fi->fileName(), subdirs );
+ } else {
+ // current dir or parent dir
+ // -> notihng to do
+ ;
+ }
+ } else {
+ // entry is a file
+ if (opts->PkgRead) {
+ rfile = fname + "/";
+ rfile += fi->fileName();
+ p = getPackageInfo('u',rfile, 0);
+ if (p) {
+ p->info.insert("filename", fi->fileName());
+ p->info.insert("base", dir);
+ }
+ } else {
+ p = collectDir(fi->fileName(),pn.setNum(fi->size()),dir);
+ }
+ if (p) {
+ smerge(p);
+ if (!p->pkgInsert(pki, typeID, FALSE))
+ delete p;
+ }
+ }
+ ++it; // goto next list element
+ }
+ } else {
+ // directory is not readable
+ kdDebug() << QString("WARNING: directory '%1' not readable (will be ignored) !\n").arg(d.absPath() ) << endl;
+ }
+ } else {
+ QFile f(fname);
+ if ( f.open(IO_ReadOnly) ) {
+ QTextStream t( &f );
+ QString name;
+ while ( !t.eof() ) {
+ name = t.readLine();
+ if (!t.eof() ) {
+ size = t.readLine();
+ } else
+ size = "";
+ packageInfo *p = collectDir(name,size,dir);
+ if (p) {
+ smerge(p);
+ if (!p->pkgInsert(pki, typeID, FALSE))
+ delete p;
+ }
+ }
+ f.close();
+ }
+ }
+ }
+
+packageInfo *pkgInterface::collectDir(const QString &name, const QString &size, const QString &dir)
+{
+ kdDebug() << "collectDir " << name << " " << size << " " << dir << endl;
+ QString n,v;
+
+ if (parseName(name, &n, &v)) {
+ QMap<QString, QString> a;
+
+ a.insert("group", "NEW");
+ a.insert("name", n);
+ a.insert("version", v);
+ a.insert("file-size", size);
+ a.insert("filename", name);
+ a.insert("base", dir);
+
+ packageInfo *i = new packageInfo(a,this);
+ i->packageState = packageInfo::AVAILABLE;
+ // i->packageState = packageInfo::NEW;
+ return i;
+ }
+ return 0;
+}
+
+QString pkgInterface::getPackList(cacheObj *cp)
+{
+ QString tmpf;
+ int res;
+ QString url = cp->location;
+ kdDebug() << "pkgInterface::getPackList " << url << " " << cp->cacheFile << "\n";
+ if ((res = cacheObj::newDCache(url, cp->cacheFile, tmpf))) {
+ if (res < 0)
+ return 0;
+
+ unlink(QFile::encodeName(tmpf));
+ if (kpkg)
+ kpackage->setStatus(i18n("Starting Kio"));
+
+ Kio kio;
+ if (kio.download(url, tmpf)) {
+ if (kpkg)
+ kpackage->setStatus(i18n("Kio finished"));
+ QFileInfo f(tmpf);
+ if (!(f.exists() && f.size() > 0)) {
+ unlink(QFile::encodeName(tmpf));
+ return "";
+ } else {
+ return tmpf;
+ }
+ } else {
+ if (kpkg)
+ kpackage->setStatus(i18n("Kio failed"));
+ return "";
+ }
+ } else {
+ return tmpf;
+ }
+}
+
+QString pkgInterface::getDir(cacheObj *cp) {
+ int res;
+ QString tmpDir;
+ QString url = cp->location;
+
+ if ((res = cacheObj::newDCache(url, cp->cacheFile, tmpDir))) {
+ if (res < 0)
+ return QString::null;
+
+ Kiod kiod;
+ if (kiod.listDir(url,tmpDir, cp->subdirs)) {
+ QFileInfo fi (tmpDir);
+ CacheList cl (fi.dirPath());
+ cl.append (fi.fileName());
+ cl.write();
+ return tmpDir;
+ } else {
+ KpMsgE(i18n("Cannot read folder %1").arg(url),FALSE);
+ unlink(tmpDir.ascii());
+ return QString::null;
+ }
+ } else {
+ return tmpDir;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+QString pkgInterface::provMap(const QString &p)
+{
+ // kdDebug() << "provMap=>" << p << endl;
+ return p;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QStringList pkgInterface::verify(packageInfo *, const QStringList &files)
+{
+ int p = 0;
+ uint c = 0;
+ QStringList errorlist;
+ QDir d;
+
+ if (hostName.isEmpty()) {
+
+ uint step = (files.count() / 100) + 1;
+
+ kpackage->setStatus(i18n("Verifying"));
+ kpackage->setPercent(0);
+
+ for( QStringList::ConstIterator it = files.begin();
+ it != files.end();
+ it++)
+ {
+ // Update the status progress
+ c++;
+ if(c > step) {
+ c=0; p++;
+ kpackage->setPercent(p);
+ }
+
+ if (!d.exists(*it)) {
+ errorlist.append(*it);
+ }
+ }
+
+ kpackage->setPercent(100);
+ }
+ return errorlist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString pkgInterface::uninstall(int uninstallFlags, packageInfo *p, bool &test)
+{
+ QString packs( p->getProperty("name"));
+
+ return doUninstall(uninstallFlags, packs, test);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString pkgInterface::uninstall(int uninstallFlags, QPtrList<packageInfo> *p, bool &test)
+{
+ QString packs;
+ packageInfo *i;
+
+ for (i = p->first(); i!= 0; i = p->next()) {
+ packs += i->getProperty("name");
+ packs += " ";
+ }
+ return doUninstall( uninstallFlags, packs, test);
+}
+//////////////////////////////////////////////////////////////////////////////
+
+QString pkgInterface::install(int installFlags, packageInfo *p, bool &test)
+{
+ QString fname = p->fetchFilename();
+
+ return doInstall(installFlags, fname, test);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString pkgInterface::install(int installFlags, QPtrList<packageInfo> *p, bool &test)
+{
+ QString packs = "";
+ packageInfo *i;
+
+ for (i = p->first(); i!= 0; i = p->next()) {
+ QString fname = i->fetchFilename();
+ if (!fname.isEmpty()) {
+ packs += fname;
+ packs += " ";
+ }
+ }
+ return doInstall(installFlags, packs, test);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QStringList pkgInterface::listInstalls(const QStringList &packs, bool , bool &cancel)
+{
+ cancel = FALSE;
+ return packs;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QString pkgInterface::setOptions(int flags, QPtrList<param> &params)
+{
+ int i;
+ QString s;
+
+ param *p;
+ i = 0;
+ for ( p=params.first(); p != 0; p=params.next(), i++ ) {
+ if ((flags>>i & 1) ^ p->invert) {
+ s += p->flag + " ";
+ } else {
+ if (!p->flagA.isEmpty())
+ s += p->flagA + " ";
+ }
+ }
+ return s;
+}
+
+ QStringList pkgInterface::readApt()
+{
+ return 0;
+}
+
+ void pkgInterface::writeApt(const QStringList &)
+{
+}
+
+#include "pkgInterface.moc"
diff --git a/kpackage/pkgInterface.h b/kpackage/pkgInterface.h
new file mode 100644
index 0000000..3094af8
--- /dev/null
+++ b/kpackage/pkgInterface.h
@@ -0,0 +1,220 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#ifndef PKG_IFACE_H
+#define PKG_IFACE_H
+
+#include "../config.h"
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#include "packageInfo.h"
+#include "managementWidget.h"
+
+class packageInfo;
+class pkgOptions;
+class Locations;
+class LcacheObj;
+class cacheObj;
+class KAccel;
+class KActionCollection;
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// flags to install and uninstall
+class param
+{
+public:
+ param(const QString &nameP, bool initP, bool invertP, const QString &flagP);
+ param(const QString &nameP, bool initP, bool invertP, const QString &flagP, const QString &flagAP);
+ ~param();
+
+ QString name; // Name of flag
+ bool init; // Initial value
+ bool invert; // Whether it needs to be inverted
+ QString flag; // text flag on command
+ QString flagA; // text flag on command
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class pkgInterface: public QObject
+{
+ Q_OBJECT
+
+public:
+ pkgInterface();
+ virtual ~pkgInterface();
+
+ virtual bool isType(char *buf, const QString &fname) = 0;
+ // looks at start of file to check that package is correct type
+
+ virtual void makeMenu(KActionCollection* act);
+ virtual void setMenu(KActionCollection* act, bool enable);
+
+ bool ifExe(QString exe);
+ // Check if this executable exists
+
+ virtual packageInfo *getPackageInfo(char mode, const QString &name,
+ const QString &version) = 0;
+ // get info on installed or uninstalled package. version is only set if
+ // mode is 'i' (ie, if the package is already installed).
+
+ virtual QStringList getFileList(packageInfo *p) = 0;
+ // get list of files in the package
+
+ virtual QStringList depends(const QString &name, int src);
+ // check dependencies for package
+
+ virtual QStringList verify(packageInfo *p, const QStringList &files);
+ // check the installed files in a package
+
+ virtual QStringList FindFile(const QString &name, bool seachAll=false) = 0;
+ // search for packages containg a file
+
+ virtual QStringList getChangeLog(packageInfo *p) = 0;
+ // Get change log
+
+ virtual bool filesTab(packageInfo *p) = 0;
+ // If files tab is to be enabled
+
+ virtual bool changeTab(packageInfo *p) = 0;
+ // If change log tab is to be enabled
+
+ virtual bool parseName(const QString &name, QString *n, QString *v) = 0;
+ // breakup file name into package name and version
+
+ virtual void listPackages(QPtrList<packageInfo> *pki);
+ // scan various locations for list of packages
+
+ virtual void listInstalledPackages(QPtrList<packageInfo> *pki) = 0;
+ // produce list of currently installed packages
+
+ virtual QStringList listInstalls(const QStringList &packs, bool install, bool &cancel);
+ // Convert list of packages requested to install to list of all packages to install
+
+ virtual void smerge(packageInfo *p);
+ // merge in package info entry
+
+ QString getDir(cacheObj *cp);
+ // list directory local or remote
+
+ void listDir(QPtrList<packageInfo> *pki, const QString &fname, const QString &dir, bool subdirs = FALSE);
+ // list the packages in a directory
+
+ packageInfo *collectDir(const QString &name, const QString &size, const QString &dir);
+ // build packageInfo object from directory entry
+
+ QString getPackList(cacheObj *cp);
+ // get packages information file
+
+ virtual QString provMap(const QString &p);
+ // convert from package depends to package
+
+ QString setOptions(int flags, QPtrList<param> &params);
+ // convert un/install flags to text
+
+ virtual QString doUninstall(int uninstallFlags, const QString &packs, bool &test);
+ virtual QString doInstall(int installFlags, const QString &packs, bool &test);
+ virtual QString uninstall(int uninstallFlags, QPtrList<packageInfo> *p,
+ bool &test);
+ virtual QString uninstall(int uninstallFlags, packageInfo *p,
+ bool &test);
+ virtual QString install(int installFlags, QPtrList<packageInfo> *p,
+ bool &test);
+ virtual QString install(int installFlags, packageInfo *p,
+ bool &test);
+
+ virtual QStringList readApt();
+ virtual void writeApt(const QStringList &list);
+
+ ///////////// DATA ///////////////////////
+ pkgOptions *uninstallation, *installation;
+
+ QString icon;
+ // name icon file
+ QString head;
+ // capitalized name of package type
+ QString name;
+ // More descriptive name
+ QPixmap pict, bad_pict, new_pict, updated_pict;
+ // icons for package states
+ QPixmap folder;
+ // icon for package group
+ QPixmap markInst;
+ QPixmap markUnInst;
+ // icon indicating mark for install/uninstall
+
+ Locations *locatedialog;
+ // dialog for setting the locations of uninstalled packages
+ LcacheObj *packageLoc;
+ // List of locations of uninstalled pacckages
+
+ bool dirOK;
+ // variables related to reading packages from directories
+
+ QString packagePattern;
+ QString queryMsg;
+ QString typeID;
+ // Parameters for reading packages from directories
+
+ QPtrList<param> paramsInst;
+ QPtrList<param> paramsUninst;
+
+ bool noFetch;
+ // kpackage doesn't fetch this type of package itself
+
+ bool defaultHandle;
+ // This package type defaults to on
+
+ QString errExe;
+ // The name of an executable that wasn't found
+
+ QString procMsg;
+ // for running processes
+
+ QString DELMSG;
+
+ bool hasRemote;
+ // can access on remote host
+
+ bool hasSearchAll;
+ // can search uninstalled packages for files
+
+ bool hasProgram;
+ // the program needed to handle this package type is available
+
+public slots:
+ virtual void setLocation() = 0;
+ virtual void setAvail(LcacheObj *) = 0;
+};
+
+#endif
diff --git a/kpackage/pkgOptions.cpp b/kpackage/pkgOptions.cpp
new file mode 100644
index 0000000..19a3c5e
--- /dev/null
+++ b/kpackage/pkgOptions.cpp
@@ -0,0 +1,372 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#include "../config.h"
+// qt headers
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klistview.h>
+#include <kseparator.h>
+#include <kdebug.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "pkgOptions.h"
+#include "managementWidget.h"
+#include "debInterface.h"
+#include "kpackage.h"
+#include "options.h"
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+pkgOptions::pkgOptions(pkgInterface *pki, QWidget *parent, const QString &caption)
+ : KDialog(parent,0,TRUE)
+{
+ // setFrameStyle(QFrame::Raised | QFrame::Panel);
+
+ pkgInt = pki;
+
+ hide();
+
+ setCaption(caption);
+}
+
+// Destructor
+pkgOptions::~pkgOptions()
+{
+ // int i;
+ // for (i = 0; i < bnumber; i++) {
+ // delete(Boxs[i]);
+ // }
+}
+
+// Set up the sub-widgets
+void pkgOptions::setupWidgets(QPtrList<param> &pars)
+{
+ int i;
+
+ // Create widgets
+ title = new QLabel("", this);
+ QFont f( KGlobalSettings::generalFont());
+ f.setBold(true);
+ f.setPointSize(f.pointSize()+6);
+ title->setFont(f);
+ // title->setAutoResize(TRUE);
+ // title->update();
+
+ installButton = new QPushButton(insType,this);
+ cancelButton = new KPushButton(KStdGuiItem::cancel(),this);
+ // count number of buttons
+ bnumber = pars.count();
+
+ Boxs = new QCheckBox *[bnumber];
+ param *p;
+ i = 0;
+ for ( p=pars.first(); p != 0; p=pars.next(), i++ ) {
+ Boxs[i] = new QCheckBox(p->name, this);
+ Boxs[i]->setChecked(p->init);
+ }
+
+ Keep = new QCheckBox(i18n("Keep this window"), this);
+
+ // Connections
+ connect(installButton,SIGNAL(clicked()),SLOT(pkginstallButtonClicked()));
+ connect(cancelButton,SIGNAL(clicked()),SLOT(cancelButtonClicked()));
+ connect(Keep, SIGNAL(toggled(bool)), SLOT(keepToggle(bool)));
+
+ // Do the layout
+ vlayout = new QBoxLayout(this, QBoxLayout::TopToBottom, marginHint(), spacingHint());
+ vlayout->addWidget(title,0);
+
+ {
+ hlayout = new QBoxLayout(vlayout,QBoxLayout::LeftToRight, spacingHint());
+
+ {
+ layout = new QBoxLayout(hlayout,QBoxLayout::TopToBottom, spacingHint());
+
+ packages = new KListView(this);
+ layout->addWidget(packages,20);
+ packages->addColumn(i18n("PACKAGES"),200);
+
+ connect(packages, SIGNAL(selectionChanged ( QListViewItem * )),
+ this, SLOT(slotSearch( QListViewItem * )));
+
+ layout->addStretch(1);
+ for (i = 0; i < bnumber; i++) {
+ layout->addWidget(Boxs[i],1);
+ }
+ layout->addWidget(new KSeparator(KSeparator::HLine, this), 2);
+
+ QBoxLayout *slayout = new QBoxLayout(layout, QBoxLayout::LeftToRight);
+ slayout->addStretch(1);
+ slayout->addWidget(Keep, 1);
+ slayout->addStretch(1);
+
+ layout->addWidget(new KSeparator(KSeparator::HLine, this), 2);
+
+ QBoxLayout *buttons = new QBoxLayout(QBoxLayout::LeftToRight);
+ layout->addLayout(buttons);
+
+ buttons->addWidget(installButton,2);
+ buttons->addStretch(1);
+ buttons->addWidget(cancelButton,2);
+ }
+ {
+ term = new kpTerm(kpty,this);
+ hlayout->addWidget(term, 1000);
+ }
+ }
+ resize(800, 400);
+}
+
+void pkgOptions::setup(packageInfo *p, const QString &type) {
+ QPtrList<packageInfo> *pl = new QPtrList<packageInfo>;
+ pl->append(p);
+ setup(pl,type);
+}
+
+bool pkgOptions::setup(QPtrList<packageInfo> *pl, const QString &)
+{
+ QString s;
+ modified = FALSE;
+
+ packList = pl;
+
+ packages->clear();
+ packageInfo *p;
+
+ QStringList plist, rlist, clist;
+ QDict<QString> dict;
+ QString mark("x");
+ for ( p = pl->first(); p != 0; p = pl->next() ) {
+ QString file = p->getFilename();
+ plist += p->getProperty("name");
+ if (file.isEmpty()) {
+ clist += p->getProperty("name");
+ }
+ dict.insert(p->getProperty("name"), &mark);
+ }
+
+ packageInfo *pk;
+ bool cancel;
+ if (clist.count() > 0) {
+ rlist = pkgInt->listInstalls(clist, installer, cancel);
+ if (cancel) {
+ reject();
+ return false;
+ }
+ for ( QStringList::Iterator it = rlist.begin(); it != rlist.end(); ++it ) {
+ if (!dict[*it]) {
+ plist.append(*it);
+ QString dirIndex = *it + pkgInt->typeID;
+ if (installer) {
+ pk = kpackage->management->dirUninstPackages->find(dirIndex);
+ } else {
+ pk = kpackage->management->dirInstPackages->find(dirIndex);
+ }
+ if (pk) {
+ // kdDebug() << "FF=" << dirIndex << "\n";
+ pl->append(pk);
+ } else {
+ // kdDebug() << "uF=" << dirIndex << "\n";
+ }
+ }
+ }
+ }
+
+ s = i18n("%1: 1 %2 Package","%1: %n %2 Packages",plist.count()).arg(insType,pkgInt->name);
+ title->setText(s);
+
+ for (QStringList::Iterator pit = plist.begin(); pit != plist.end(); ++pit ) {
+ // kdDebug() << "P=" << *pit << "\n";
+ new QListViewItem(packages, *pit);
+ }
+ cancelButton->setGuiItem(KStdGuiItem::cancel());
+ return TRUE;
+}
+
+// install button has been clicked....so install the package
+void pkgOptions::pkginstallButtonClicked()
+{
+ int i;
+ QStringList r;
+ modified = TRUE;
+
+ // Collect data from check boxes
+ int installFlags = 0;
+
+ for (i = 0; i < bnumber; i++) {
+ installFlags |= (Boxs[i]->isChecked()) << i;
+ }
+
+ test = FALSE;
+ QString s = doPackages(installFlags, packList, test);
+ // A "0=" or "1=" indicates it was actually (un)installed by the doPackages
+ // routine instead of just returning a command to execute
+
+ kdDebug() << "S=" << s << "\n";
+ if (s == "0=") {
+ cancelButtonClicked();
+ } else if (s.left(2) == "1=") {
+ term->textIn(s.mid(2), true);
+ } else {
+ connect(term,SIGNAL(result(QStringList &, int)),
+ this,SLOT(slotResult(QStringList &, int)));
+
+ installButton->setEnabled(FALSE);
+
+ if (term->run(s, r)) {
+ running = TRUE;
+ cancelButton->setGuiItem(KStdGuiItem::cancel());
+ } else {
+ reset();
+ }
+ }
+}
+
+void pkgOptions::slotSearch(QListViewItem *item)
+{
+ QString s = item->text(0);
+ kdDebug() << "searchI=" << s << "h=" << pkgInt->head <<"\n";
+
+ packageInfo *p;
+ for ( p = packList->first(); p != 0; p = packList->next() ) {
+ if (s == p->getProperty("name")) {
+ kpackage->management->doChangePackage(p);
+ break;
+ }
+ }
+}
+
+void pkgOptions::reset() {
+ installButton->setEnabled(TRUE);
+ cancelButton->setGuiItem(KGuiItem(i18n("Done"))); //clear icon
+ disconnect(term,SIGNAL(result(QStringList &, int)),
+ this,SLOT(slotResult(QStringList &, int)));
+ running = FALSE;
+}
+
+void pkgOptions::slotResult(QStringList &, int ret)
+{
+ reset();
+ if (ret == 0 && !test && !keep) {
+ term->done();
+ accept();
+ }
+}
+
+void pkgOptions::terminate() {
+ if (running) {
+ term->cancel();
+ reset();
+ }
+}
+
+void pkgOptions::cancelButtonClicked()
+{
+ terminate();
+ term->done();
+
+ if (!modified || test)
+ reject();
+ else
+ accept();
+}
+
+void pkgOptions::closeEvent ( QCloseEvent * e ) {
+ kdDebug() << "pkgOptions::QCloseEvent\n";
+ terminate();
+
+ QWidget::closeEvent (e);
+}
+
+void pkgOptions::showEvent ( QShowEvent *e ) {
+ // kdDebug() << "pkgOptions::showEvent\n";
+ getKeep();
+
+ modified = FALSE;
+ running = FALSE;
+
+ QWidget::showEvent(e);
+}
+
+void pkgOptions::keepToggle(bool kp)
+{
+ // kdDebug() << "KEEP " << kp << "\n";
+
+ KConfig *config = kapp->config();
+
+ config->setGroup("Kpackage");
+ config->writeEntry("keepIWin", kp);
+
+ keep = kp;
+}
+
+void pkgOptions::getKeep()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("Kpackage");
+ keep = config->readBoolEntry("keepIWin", true);
+ kdDebug() << "getKEEP " << keep << "\n";
+ Keep->setChecked(keep);
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+pkgOptionsI::pkgOptionsI(pkgInterface *pkg, QWidget *parent):
+ pkgOptions(pkg, parent, i18n("Install"))
+{
+ insType = i18n("Install");
+ installer = TRUE;
+ setupWidgets(pkg->paramsInst);
+}
+
+QString pkgOptionsI::doPackages(int installFlags, QPtrList<packageInfo> *p, bool &test)
+{
+ return pkgInt->install(installFlags, p, test);
+}
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+pkgOptionsU::pkgOptionsU(pkgInterface *pkg, QWidget *parent):
+ pkgOptions(pkg, parent, i18n("Uninstall"))
+{
+ insType = i18n("Uninstall");
+ installer = FALSE;
+ setupWidgets(pkg->paramsUninst);
+}
+
+QString pkgOptionsU::doPackages(int installFlags, QPtrList<packageInfo> *p, bool &test)
+{
+ return pkgInt->uninstall(installFlags, p, test);
+}
+#include "pkgOptions.moc"
diff --git a/kpackage/pkgOptions.h b/kpackage/pkgOptions.h
new file mode 100644
index 0000000..707c340
--- /dev/null
+++ b/kpackage/pkgOptions.h
@@ -0,0 +1,151 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+// This provides the installation options, plus the install and cancel
+// buttons. When the install button is clicked, the current package
+// is installed.
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+#ifndef PKGINSTALL_OPTIONS
+#define PKGINSTALL_OPTIONS
+
+#include "../config.h"
+// Qt headers
+#include <qframe.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+
+#include <kdialog.h>
+
+// kpackage headers
+#include "packageInfo.h"
+#include "pkgInterface.h"
+#include "kpTerm.h"
+
+class KListView;
+class KPushButton;
+
+class pkgOptions : public KDialog
+{
+ Q_OBJECT
+public:
+ pkgOptions( pkgInterface *pki, QWidget *parent=0, const QString &caption=QString::null);
+ ~pkgOptions();
+
+ bool setup(QPtrList<packageInfo> *pl, const QString &type);
+ void setup(packageInfo *p, const QString &type);
+ void reset();
+
+ virtual QString doPackages(int installFlags, QPtrList<packageInfo> *p,
+ bool &test) = 0;
+
+ QCheckBox **Boxs;
+ // options buttons
+
+ QCheckBox *Keep;
+ // keep window
+
+ KListView *packages;
+
+ int bnumber;
+ // number of option buttons
+
+ QLabel *title;
+ // Widget title
+
+ kpTerm *term;
+
+ pkgInterface *pkgInt;
+
+ bool modified;
+ bool test;
+ bool running;
+
+protected:
+ // This sets up the sub-widgets
+ void setupWidgets(QPtrList<param> &pars);
+
+private slots:
+ virtual void pkginstallButtonClicked();
+ virtual void cancelButtonClicked();
+ void slotSearch(QListViewItem *item);
+ void keepToggle(bool);
+
+public slots:
+ void slotResult(QStringList &rlist, int ret);
+
+signals:
+ // This signal indicates that the widget has finished.
+ void finished(int refresh);
+
+protected:
+ // The layout managers
+ QBoxLayout *layout, *hlayout, *vlayout;
+
+ // Sub widgets
+ QPushButton *installButton;
+ KPushButton *cancelButton;
+
+ QString insType;
+ bool installer;
+ // install or uninstall
+
+ bool keep;
+ // keep the window
+
+ QPtrList<packageInfo> *packList;
+
+ void getKeep();
+
+ void showEvent (QShowEvent *);
+ void closeEvent (QCloseEvent * e );
+
+ void terminate();
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+class pkgOptionsI: public pkgOptions
+{
+ Q_OBJECT
+public:
+ pkgOptionsI(pkgInterface *pkg, QWidget *parent = 0);
+ QString doPackages(int installFlags, QPtrList<packageInfo> *p, bool &test);
+};
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+class pkgOptionsU: public pkgOptions
+{
+ Q_OBJECT
+public:
+ pkgOptionsU(pkgInterface *pkg, QWidget *parent = 0);
+ QString doPackages(int installFlags, QPtrList<packageInfo> *p, bool &test);
+};
+
+#endif
diff --git a/kpackage/procbuf.cpp b/kpackage/procbuf.cpp
new file mode 100644
index 0000000..c994d70
--- /dev/null
+++ b/kpackage/procbuf.cpp
@@ -0,0 +1,165 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+#include "procbuf.h"
+#include <kprocess.h>
+#include "kpackage.h"
+#include <klocale.h>
+#include <qlabel.h>
+#include <kdebug.h>
+
+Modal::Modal(QString msg, QWidget *parent, const char * name )
+ : KDialog( parent, name, TRUE )
+{
+ QLabel *line1 = new QLabel(msg,this);
+ line1->setAlignment(AlignCenter);
+ line1->setAutoResize(true);
+
+ }
+
+void Modal::terminate()
+{
+ done(0);
+}
+
+procbuf::procbuf()
+{
+ m = NULL;
+ tm = new QTimer(this);
+ connect(tm, SIGNAL(timeout()), this, SLOT(slotTimeout()));
+}
+
+procbuf::~procbuf()
+{
+}
+
+void procbuf::setup(QString cmd)
+{
+ buf.truncate(0);
+ proc = new KProcess();
+ connect(proc, SIGNAL( receivedStdout(KProcess *, char *, int)),
+ this, SLOT(slotReadInfo(KProcess *, char *, int)));
+ connect(proc, SIGNAL( receivedStderr(KProcess *, char *, int)),
+ this, SLOT(slotReadInfo(KProcess *, char *, int)));
+ connect(proc, SIGNAL( processExited(KProcess *)),
+ this, SLOT(slotExited(KProcess *)));
+ proc->clearArguments();
+ *proc << cmd;
+ command = cmd;
+}
+
+void procbuf::slotReadInfo(KProcess *, char *buffer, int buflen)
+{
+ char last;
+
+ last = buffer[buflen - 1];
+ buffer[buflen - 1] = 0;
+
+ buf += buffer;
+ buf += last;
+
+ if (timed) {
+ timed = FALSE;
+ tm->stop();
+ }
+}
+
+void procbuf::slotExited(KProcess *)
+{
+ if (m) {
+ m->terminate();
+ }
+ if (timed) {
+ timed = FALSE;
+ tm->stop();
+ }
+}
+
+void procbuf::slotTimeout()
+{
+ if (m) {
+ m->terminate();
+ }
+ // kdDebug() << "TTT\n";
+}
+
+int procbuf::start (QString msg, bool errorDlg,
+ int timeout, QString timeMsg )
+{
+ if (timeout) {
+ tm->start(timeout*1000, TRUE);
+ timed = true;
+ }
+
+ if (!proc->start(!msg.isNull() ? KProcess::NotifyOnExit : KProcess::Block,
+ KProcess::All)) {
+ if (errorDlg) {
+ KpMsgE(i18n("Kprocess Failure"),TRUE);
+ }
+ return 0;
+ };
+
+ if (!msg.isEmpty()) {
+ m = new Modal(msg,kpkg, "wait");
+ m->exec();
+ delete m;
+ m = 0;
+ }
+
+ kdDebug() << command
+ << " dialog=" << errorDlg
+ << " normal=" << proc->normalExit()
+ << " exit=" << proc->exitStatus() << endl;
+ if (timed) {
+ kdDebug() << "timeout..................\n";
+ KpMsg("Error",i18n("Timeout: %1").arg(timeMsg), TRUE);
+ delete proc; proc = 0;
+ return 0;
+ } else {
+ if (!proc->normalExit() || proc->exitStatus()) {
+ if (errorDlg) {
+ KpMsg("Error",i18n("Kprocess error:%1").arg(buf), TRUE);
+ }
+ delete proc; proc = 0;
+ return 0;
+ }
+ }
+ delete proc; proc = 0;
+ return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+#include "procbuf.moc"
diff --git a/kpackage/procbuf.h b/kpackage/procbuf.h
new file mode 100644
index 0000000..8463810
--- /dev/null
+++ b/kpackage/procbuf.h
@@ -0,0 +1,68 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#include "../config.h"
+#include <kprocess.h>
+#include <kdialog.h>
+#include <qobject.h>
+#include <qtimer.h>
+
+#ifndef PROCBUF
+#define PROCBUF
+
+class Modal : public KDialog {
+ Q_OBJECT
+public:
+ Modal(QString msg, QWidget *parent, const char * name );
+ void terminate();
+};
+
+class procbuf: public QObject
+{
+ Q_OBJECT
+
+public:
+ procbuf();
+ ~procbuf();
+ void setup(QString);
+ int start(QString msg, bool errorDlg = TRUE,
+ int timeout=0, QString timeMsg = "");
+
+ QString buf;
+ KProcess *proc;
+ Modal *m;
+ QString command;
+ bool timed;
+ QTimer *tm;
+
+public slots:
+ void slotReadInfo(KProcess *, char *, int);
+ void slotExited(KProcess *);
+ void slotTimeout();
+};
+#endif
diff --git a/kpackage/rpmInterface.cpp b/kpackage/rpmInterface.cpp
new file mode 100644
index 0000000..655e6b8
--- /dev/null
+++ b/kpackage/rpmInterface.cpp
@@ -0,0 +1,631 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+//////////////////////////////////////////////////////////////////////////////
+///
+/// RPM Program version
+///
+//////////////////////////////////////////////////////////////////////////////
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+
+#include "kpPty.h"
+#include "kpackage.h"
+#include "rpmInterface.h"
+#include "updateLoc.h"
+#include "cache.h"
+
+RPM::RPM():pkgInterface()
+{
+ head = "RPM";
+ name = i18n("RPM");
+ icon = "rpm";
+
+ pict = UserIcon(icon);
+ updated_pict = UserIcon("rupdated");
+ new_pict = UserIcon("rnew");
+
+ packagePattern = "*.rpm";
+ typeID = "/rpm";
+
+ locatedialog = new Locations(i18n("Location of RPM Package Archives"));
+ locatedialog->dLocations(7,6, this, i18n("Folder","F"),
+ "Rpm","*.rpm", i18n("Location of Folders Containing RPM Packages"));
+
+ connect(locatedialog,SIGNAL(returnVal(LcacheObj *)),
+ this,SLOT(setAvail(LcacheObj *)));
+ locatedialog->apply_slot();
+
+ paramsInst.append(new param(i18n("Upgrade"),TRUE,FALSE,"-U","-i"));
+ paramsInst.append(new param(i18n("Replace Files"),FALSE,FALSE,"--replacefiles"));
+ paramsInst.append(new param(i18n("Replace Packages"),TRUE,FALSE,"--replacepkgs"));
+ paramsInst.append(new param(i18n("Check Dependencies"),TRUE,TRUE,"--nodeps"));
+ paramsInst.append(new param(i18n("Test (do not install)"),FALSE,FALSE,"--test"));
+
+ paramsUninst.append(new param(i18n("Remove all versions"),FALSE,FALSE,"--allmatches"));
+ paramsUninst.append(new param(i18n("Use Scripts"),TRUE,TRUE,"--noscripts"));
+ paramsUninst.append(new param(i18n("Check Dependencies"),TRUE,TRUE,"--nodeps"));
+ paramsUninst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE,"--test"));
+
+
+ queryMsg = i18n("Querying RPM package list: ");
+
+ QDict<QString> provides(1433,false);
+
+ infoList.append("name/%{NAME}");
+ infoList.append("version/%{VERSION}");
+ infoList.append("release/%{RELEASE}");
+ infoList.append("summary/%{SUMMARY}");
+ infoList.append("url/%{URL}");
+ infoList.append("architecture/%{ARCH}");
+ infoList.append("group/%{GROUP}");
+ infoList.append("distribution/%{DISTRIBUTION}");
+ infoList.append("vendor/%{VENDOR}");
+ infoList.append("packager/%{PACKAGER}");
+ infoList.append("installtime/%{INSTALLTIME:date}");
+ infoList.append("buildtime/%{BUILDTIME:date}");
+ infoList.append("size/%{SIZE}");
+ infoList.append("provides/[%{PROVIDES}, ]");
+ infoList.append("requires/[%{REQUIRENAME} (%{REQUIREFLAGS:depflags} %{REQUIREVERSION}), ]");
+ infoList.append("description/[%{DESCRIPTION}]");
+
+ hasProgram = ifExe("rpm");
+}
+
+ RPM::~RPM(){}
+
+bool RPM::isType(char *buf, const QString & /* fname */)
+{
+ if (hasProgram) {
+ if ((unsigned char)buf[0] == 0355 && (unsigned char)buf[1] == 0253 &&
+ (unsigned char)buf[2] == 0356 && (unsigned char)buf[3] == 0333 ) {
+ return true;
+ } else
+ return false;
+ } else {
+ return false;
+ }
+}
+
+bool RPM::parseName(const QString &name, QString *n, QString *v)
+{
+ int d1, d2, s1, s2;
+
+ s2 = name.findRev('.');
+ if (s2 > 0) {
+ s1 = name.findRev('.',s2-1);
+ if (s1 > 0) {
+ d2 = name.findRev('-',s1-1);
+ if (d2 > 0) {
+ d1 = name.findRev('-',d2-1);
+ if (d1 < 0)
+ d1 = d2;
+ *n = name.left(d1);
+ *v = name.mid(d1+1,s1-d1-1);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+QString RPM::packageQuery() {
+ QString cmd = " --queryformat '";
+ for ( QStringList::Iterator it = infoList.begin(); it != infoList.end(); ++it ) {
+ QStringList s = QStringList::split("/",*it);
+ cmd += "==";
+ cmd += s[0];
+ cmd += "\\n";
+ cmd += s[1];
+ cmd += "\\n";
+ }
+ cmd += "==\\n'";
+ return cmd;
+}
+
+void RPM::listInstalledPackages(QPtrList<packageInfo> *pki)
+{
+ int NLINES = 70000;
+
+ packageInfo *p;
+ QStringList plist;
+
+ QString cmd = "rpm -q -a";
+ cmd += packageQuery();
+
+ kpackage->setStatus(i18n("Querying RPM package list"));
+ kpackage->setPercent(0);
+
+ QStringList list = kpty->run(cmd);
+ kpackage->setStatus(i18n("Processing RPM package list"));
+ // kdDebug() << "P=" << list.count() <<"\n";
+ kpackage->setPercent(50);
+
+
+ if (list.count() > 0) {
+
+ QString s;
+
+ kpackage->setPercent(0 );
+ int cnt = 0;
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ cnt++;
+ if (cnt % (NLINES/20) == 0) {
+ kpackage->setPercent((cnt * 100)/ NLINES );
+ }
+ if (*it != "==") {
+ s = *it;
+ // kdDebug() << s.length() << "<" << s << ">\n";
+ plist << s;
+ } else {
+ p = collectInfo(plist);
+ if (p) {
+ if (!p->pkgInsert(pki, typeID, TRUE)) {
+ delete p;
+ }
+ }
+ plist.clear();
+ }
+ }
+ }
+
+ list.clear();
+ kpackage->setStatus(i18n("DEB APT"));
+ kpackage->setPercent(100);
+}
+
+packageInfo* RPM::collectInfo(QStringList &ln) {
+
+ bool haveName = FALSE;
+ QMap<QString, QString> a;
+
+ QString name, value;
+
+ for ( QStringList::Iterator it = ln.begin(); it != ln.end(); ++it ) {
+ if ((*it).left(2) == "==" && (*it).length() >= 2) {
+ name = (*it).right((*it).length() - 2);
+ }
+ value = "";
+ it++;
+ while (it != ln.end() && (*it).left(2) != "==") {
+ value += *it;
+ value += " ";
+ it++;
+ }
+ it--;
+
+ // kdDebug() << "name=" << name << " value='" << value << "'\n";
+ if (name == "installtime") {
+ a.insert("install time", value);
+ } else if (name == "name") {
+ if (!value.isEmpty())
+ haveName = TRUE;
+ a.insert("name", value.stripWhiteSpace());
+ } else if (name == "buildtime") {
+ a.insert("build-time", value);
+ } else if (name == "requires") {
+ value = value.replace(QRegExp("\\(\\)"),"");
+ value = value.replace(QRegExp("\\( \\)"),"");
+ value = value.stripWhiteSpace();
+ if (value.endsWith(",")) {
+ value.truncate(value.length()-1);
+ }
+ a.insert("depends", value);
+ } else if (name == "provides") {
+ int s = 0, n;
+ QString t;
+
+ if (!(*a.find("name")).isEmpty()) {
+ while ((n = value.find(",",s)) > 0) {
+ t = value.mid(s,n-s);
+ t = t.stripWhiteSpace();
+ if (!t.isEmpty())
+ provides.insert(t,new QString(*a.find("name")));
+ s = n+1;
+ }
+ t = value.mid(s);
+ t = t.stripWhiteSpace();
+ if (!t.isEmpty())
+ provides.insert(t,new QString(*a.find("name")));
+
+ value = value.stripWhiteSpace();
+ if (value.endsWith(",")) {
+ value.truncate(value.length()-1);
+ }
+ a.insert("provides", value);
+ }
+ } else {
+ if (!name.isEmpty())
+ a.insert(name, value.stripWhiteSpace());
+ }
+
+ }
+
+ QString vers = a["version"];
+ QString rel = a["release"];
+ if (!vers.isEmpty() && !rel.isEmpty()) {
+ vers += "-";
+ vers += rel;
+ a["version"] = vers;
+ a.remove("release");
+ }
+
+ if (haveName) {
+ packageInfo *i = new packageInfo(a,this);
+ i->packageState = packageInfo::INSTALLED;
+ i->fixup();
+ return i;
+ } else {
+ return 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList RPM::getChangeLog(packageInfo *p)
+{
+ QStringList clog;
+ QString fn( p->getFilename());
+
+ if(!fn.isEmpty())
+ return getUChangeLog(fn);
+ else
+ return getIChangeLog(p);
+
+ return clog;
+}
+
+
+// query an installed package
+QStringList RPM::getIChangeLog(packageInfo *p)
+{
+ QString name = p->getProperty("name");
+
+ QString cmd = "rpm -q --changelog ";
+ cmd += name;
+
+ QStringList filelist = kpty->run(cmd);
+
+ return filelist;
+}
+
+
+// query an uninstalled package
+QStringList RPM::getUChangeLog(const QString &fn)
+{
+ QString cmd = "rpm -q --changelog -p ";
+ cmd += quotePath(fn);
+
+ QStringList filelist = kpty->run(cmd);
+
+ return filelist;
+}
+
+
+bool RPM::filesTab(packageInfo *p) {
+ if (p->packageState == packageInfo::INSTALLED) {
+ return true;
+ } else if (p->isFileLocal()) {
+ return true;
+ }
+ return false;
+}
+
+bool RPM::changeTab(packageInfo *p) {
+ if (p->packageState == packageInfo::INSTALLED) {
+ return true;
+ } else if (p->isFileLocal()) {
+ return true;
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+QStringList RPM::getFileList(packageInfo *p)
+{
+ QStringList filelist;
+ QString fn( p->getFilename());
+
+ if(!fn.isEmpty())
+ return getUFileList(fn);
+ else
+ return getIFileList(p);
+
+ return filelist;
+}
+
+
+
+// query an installed package
+QStringList RPM::getIFileList(packageInfo *p)
+{
+ QString name = p->getProperty("name");
+
+ QString cmd = "rpm -q -l ";
+ cmd += name;
+
+ QStringList filelist = kpty->run(cmd);
+
+ return filelist;
+}
+
+
+// query an uninstalled package
+QStringList RPM::getUFileList(const QString &fn)
+{
+ QString cmd = "rpm -q -l -p ";
+ cmd += quotePath(fn);
+
+ QStringList filelist = kpty->run(cmd);
+
+ return filelist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+packageInfo *RPM::getPackageInfo(char mode, const QString &name, const QString &)
+{
+ if (mode == 'i') {
+ return getIPackageInfo(name);
+ } else
+ return getUPackageInfo(name);
+}
+
+packageInfo *RPM::getIPackageInfo( const QString &name )
+{
+ // query an installed package!
+ QString cmd = "rpm -q";
+ cmd += packageQuery();
+ cmd += " ";
+ cmd += name;
+
+ QStringList infoList = kpty->run(cmd);
+ packageInfo *pki = collectInfo(infoList);
+ if (pki) {
+ pki->packageState = packageInfo::INSTALLED;
+ collectDepends(pki,name,0);
+ }
+ return pki;
+}
+
+packageInfo *RPM::getUPackageInfo( const QString &name )
+{
+ // query an uninstalled package
+ QString cmd = "rpm -q";
+ cmd += packageQuery();
+ cmd += " -p ";
+ cmd += quotePath(name);
+
+ QStringList infoList = kpty->run(cmd);
+ packageInfo *pki = collectInfo(infoList);
+ if (pki) {
+ pki->updated = TRUE;
+ pki->packageState = packageInfo::AVAILABLE;
+ if (pki->hasProperty("install time"))
+ pki->info.remove("install time");
+ collectDepends(pki,name,1);
+ }
+
+ return pki;
+}
+
+QString RPM::provMap( const QString &p )
+{
+ QString *r = provides[p];
+ if (r) {
+ QString s = *r;
+ // printf("%s=>%s\n",p.data(),s.data());
+ return s;
+ } else {
+ return p;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+void RPM::collectDepends(packageInfo *p, const QString &name, int src)
+{
+ QString cmd = "rpm -V --nofiles ";
+ if (src) {
+ cmd += "-p ";
+ }
+ cmd += quotePath(name);
+
+ // cmd = "cat /home/toivo/rpm.deps";
+ QStringList list = kpty->run(cmd);
+
+ if (list.count() > 0) {
+ QStringList::Iterator it = list.begin();
+ int pt = (*it).find(":");
+ if (pt > 0) {
+ QString s = (*it).mid(pt+1);
+ if (!s.isEmpty()) {
+ // kdDebug() << "S=" << s << "\n";
+ p->info.insert("unsatisfied dependencies", s);
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void RPM::setLocation()
+{
+ locatedialog->restore();
+}
+
+void RPM::setAvail(LcacheObj *slist)
+{
+ if (packageLoc)
+ delete packageLoc;
+ packageLoc = slist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+QString RPM::uninstall(int uninstallFlags, QPtrList<packageInfo> *plist, bool &test)
+{
+ QStringList files;
+
+ packageInfo *pk;
+ for (pk = plist->first(); pk != 0; pk = plist->next()) {
+ files.append( pk->getProperty("name") );
+ }
+
+ if (getuid() == 0) {
+ return doUninst(uninstallFlags,files, test);
+ } else {
+ return doUninstP(uninstallFlags,files, test);
+ }
+}
+
+QString RPM::uninstall(int uninstallFlags, packageInfo *p, bool &test)
+{
+ QStringList files;
+ files.append( p->getProperty("name") );
+
+ if (getuid() == 0) {
+ return doUninstP(uninstallFlags,files, test);
+ } else {
+ return doUninstP(uninstallFlags,files, test);
+ }
+}
+
+QString RPM::doUninstP(int uninstallFlags, const QStringList &files, bool &test)
+{
+ QString s = "rpm -e ";
+ s += setOptions(uninstallFlags, paramsUninst);
+
+ for (QStringList::ConstIterator it = files.begin(); it != files.end(); ++it ) {
+ s += " ";
+ s += *it;
+ }
+
+ if (uninstallFlags>>3 & 1)
+ test = TRUE;
+
+ kdDebug() << "uCMD=" << s << " test=" << test << "\n";
+
+ return s;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+QString RPM::install(int installFlags, QPtrList<packageInfo> *plist, bool &test)
+{
+ QStringList files;
+
+ for (packageInfo *pk = plist->first(); pk != 0; pk = plist->next()) {
+ QString fname( pk->fetchFilename() );
+ if (!fname.isEmpty()) {
+ files.append(quotePath(fname));
+ }
+ }
+
+ if (getuid() == 0) {
+ return doinstP(installFlags,files,test);
+ } else {
+ return doinstP(installFlags,files,test);
+ }
+}
+
+QString RPM::install(int installFlags, packageInfo *p, bool &test)
+{
+ QStringList files;
+ files.append(quotePath(p->fetchFilename()));
+ if (getuid() == 0) {
+ return doinstP(installFlags,files,test);
+ } else {
+ return doinstP(installFlags,files,test);
+ }
+}
+
+
+QString RPM::doinstP(int installFlags, const QStringList &files, bool &test)
+{
+ QString s = "rpm ";
+ s += setOptions(installFlags, paramsInst);
+
+ for (QStringList::ConstIterator it = files.begin(); it != files.end(); ++it ) {
+ s += " ";
+ s += *it;
+ }
+
+ if (installFlags>>4 & 1)
+ test = TRUE;
+
+ kdDebug() << "iCMD=" << s << " test=" << test << "\n";
+
+ return s;
+}
+
+ QStringList RPM::verify(packageInfo *p, const QStringList &files){
+ return pkgInterface::verify(p,files);}
+
+//////////////////////////////////////////////////////////////////////////////
+QStringList RPM::FindFile(const QString &name, bool) {
+ QString cmd = "rpm -q -a --filesbypkg";
+
+ QStringList list = kpty->run(cmd);
+ QStringList retlist;
+ if (kpty->Result > 0) {
+ list.clear();
+ } else {
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ int p = (*it).find(" ");
+ int nm = (*it).find(name,p);
+ if (nm >= 0) {
+ (*it).replace(p, 1, "\t");
+ retlist.append(*it);
+ }
+ }
+ }
+
+ return retlist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+QString RPM::quotePath( const QString &path) {
+ QString s = path;
+ s = s.replace(" ","\\ ");
+ return ( "'" + s + "'" );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+ QStringList RPM::depends(const QString &, int){return 0;}
+
+ QString RPM::doUninst(int, const QStringList &, bool &){return "0=";}
+ QString RPM::doinst(int, const QStringList &, bool &){return "0=";}
+
+
+#include "rpmInterface.moc"
diff --git a/kpackage/rpmInterface.h b/kpackage/rpmInterface.h
new file mode 100644
index 0000000..a1357ef
--- /dev/null
+++ b/kpackage/rpmInterface.h
@@ -0,0 +1,111 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef RPM_IFACE_H
+#define RPM_IFACE_H
+
+#include "../config.h"
+
+
+#include <qptrlist.h>
+
+#include "packageInfo.h"
+#include "pkgInterface.h"
+
+class KDir;
+class cacheObj;
+
+class RPM : public pkgInterface
+{
+ Q_OBJECT
+
+public:
+ RPM();
+ ~RPM();
+
+ bool isType(char *buf, const QString &fname);
+
+ packageInfo *getPackageInfo(char mode, const QString &name, const QString &version);
+ QStringList getFileList(packageInfo *p);
+ QStringList getChangeLog(packageInfo *p);
+
+ bool filesTab(packageInfo *p);
+ // If files tab is to be enabled
+
+ bool changeTab(packageInfo *p);
+ // If change log tab is to be enabled
+
+ QStringList depends(const QString &name, int src);
+ QStringList verify(packageInfo *p, const QStringList &files);
+
+ QString uninstall(int uninstallFlags, QPtrList<packageInfo> *p, bool &test);
+ QString uninstall(int uninstallFlags, packageInfo *p, bool &test);
+ QString doUninst(int uninstallFlags, const QStringList &files, bool &test);
+ QString doUninstP(int uninstallFlags, const QStringList &files, bool &test);
+
+ QString install(int installFlags, QPtrList<packageInfo> *p, bool &test);
+ QString install(int installFlags, packageInfo *p, bool &test);
+ QString doinst(int installFlags, const QStringList &files, bool &test);
+ QString doinstP(int installFlags, const QStringList &files, bool &test);
+
+ QStringList FindFile(const QString &name, bool seachAll=false);
+ void collectDepends(packageInfo *p, const QString &name, int src);
+ bool parseName(const QString &name, QString *n, QString *v);
+
+ QString provMap(const QString &p);
+
+public slots:
+ void setLocation();
+ void setAvail(LcacheObj *);
+
+private:
+ packageInfo* collectInfo(QStringList &ln);
+
+ void listInstalledPackages(QPtrList<packageInfo> *pki);
+
+ QDict<QString> provides;
+ bool rpmSetup;
+ QStringList infoList;
+
+ QString packageQuery();
+
+ QStringList getIFileList( packageInfo *p );
+ QStringList getUFileList( const QString &fn );
+
+ QStringList getIChangeLog( packageInfo *p );
+ QStringList getUChangeLog( const QString &fn );
+
+ packageInfo *getIPackageInfo( const QString &name);
+ packageInfo *getUPackageInfo( const QString &name);
+
+ QString quotePath( const QString &path);
+
+ };
+
+#endif
+
+
+
diff --git a/kpackage/search.cpp b/kpackage/search.cpp
new file mode 100644
index 0000000..e4254f4
--- /dev/null
+++ b/kpackage/search.cpp
@@ -0,0 +1,115 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "search.h"
+#include <klocale.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qframe.h>
+#include <qgroupbox.h>
+
+Search::Search(QWidget *parent, const char * name)
+ : KDialogBase(parent, name, false,
+ i18n("Find Package"),
+ User1 | Close, User1, true,
+ KGuiItem( i18n("&Find"), "find"))
+{
+ QFrame *page = makeMainWidget();
+
+ setFocusPolicy(QWidget::StrongFocus);
+
+ QVBoxLayout* vtop = new QVBoxLayout( page, 10, 10, "vtop");
+
+ QFrame *frame1 = new QGroupBox(i18n("Find Package"), page, "frame1");
+ vtop->addWidget(frame1,1);
+ QVBoxLayout* vf = new QVBoxLayout( frame1, 20, 10, "vf");
+
+ value = new QLineEdit( frame1, "v");
+ vf->addWidget(value,0);
+ value->setFocus();
+ value->setFixedHeight(value->sizeHint().height());
+ value->setMinimumWidth(250);
+ connect(value, SIGNAL(textChanged(const QString &)),this, SLOT(textChanged(const QString &)));
+
+ QHBoxLayout* hc = new QHBoxLayout( );
+ vf->addLayout(hc,0);
+
+ substr = new QCheckBox(i18n("Sub string"), frame1, "substr");
+ substr->setChecked(TRUE);
+ hc->addWidget(substr,1,AlignLeft);
+ substr->setFixedSize(substr->sizeHint());
+ hc->addStretch(1);
+
+ wrap = new QCheckBox(i18n("Wrap search"), frame1, "wrap");
+ wrap->setChecked(TRUE);
+ hc->addWidget(wrap,1,AlignRight);
+ wrap->setFixedSize(wrap->sizeHint());
+
+ enableButton( User1, false );
+
+ connect(this, SIGNAL(user1Clicked()), this, SLOT(ok_slot()));
+ connect(this, SIGNAL(closeClicked()), this, SLOT(done_slot()));
+
+ show();
+}
+
+Search::~Search()
+{
+}
+
+void Search::textChanged(const QString &text)
+{
+ enableButton( User1, !text.isEmpty() );
+}
+
+void Search::ok_slot()
+{
+ QListViewItem *pkg;
+
+ QString to_find = value->text();
+ to_find = to_find.stripWhiteSpace();
+
+ pkg = kpackage->management->search(to_find,
+ substr->isChecked(),FALSE,FALSE);
+ if (pkg == 0 && wrap->isChecked()) {
+ pkg = kpackage->management->search(to_find,
+ substr->isChecked(),TRUE,FALSE);
+ }
+ if (pkg == 0)
+ KpMsg(i18n("Note"),
+ i18n("%1 was not found.").arg(to_find),TRUE);
+}
+
+void Search::done_slot()
+{
+ hide();
+}
+
+#include "search.moc"
diff --git a/kpackage/search.h b/kpackage/search.h
new file mode 100644
index 0000000..e5ae2cd
--- /dev/null
+++ b/kpackage/search.h
@@ -0,0 +1,69 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#ifndef SEARCH_H
+#define SEARCH_H
+
+#include "../config.h"
+
+// Standard Headers
+#include <stdio.h>
+
+
+class QLineEdit;
+class QCheckBox;
+
+// KDE headers
+#include <kapplication.h>
+#include <kmenubar.h>
+#include <kdialogbase.h>
+
+class Search : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ Search ( QWidget *parent = 0, const char * name=0);
+ ~Search();
+
+private:
+ QCheckBox *substr;
+ QCheckBox *wrap;
+ QLineEdit *value;
+
+signals:
+ void search_signal();
+ void search_done_signal();
+
+public slots:
+ void done_slot();
+ void ok_slot();
+ void textChanged(const QString &);
+};
+#endif
diff --git a/kpackage/slackInterface.cpp b/kpackage/slackInterface.cpp
new file mode 100644
index 0000000..8b80f2d
--- /dev/null
+++ b/kpackage/slackInterface.cpp
@@ -0,0 +1,691 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include <setjmp.h>
+
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+#include <kurl.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include "packageInfo.h"
+#include "slackInterface.h"
+#include "updateLoc.h"
+#include "kpackage.h"
+#include "managementWidget.h"
+#include "utils.h"
+#include "procbuf.h"
+#include "options.h"
+#include "cache.h"
+#include <klocale.h>
+
+
+#define DIR "/var/log/packages/"
+#define FILELIST "FILE LIST:\n"
+
+enum {INITIAL, INSTALLED, UNINSTALLED};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+SLACK::SLACK():pkgInterface()
+{
+ head = "SLACK";
+ name = i18n("Slackware");
+ icon = "slack";
+
+ pict = UserIcon(icon);
+ updated_pict = UserIcon("supdated");
+ new_pict = UserIcon("snew");
+
+ packagePattern = "*.tgz *.tar.gz";
+ typeID = "/slack";
+
+ locatedialog = 0;
+
+ queryMsg = i18n("Querying SLACK package list: ");
+ procMsg = i18n("KPackage: Waiting on SLACK");
+
+ locatedialog = new Locations(i18n("Location of Slackware Package Archives"));
+ locatedialog->pLocations(1, 1, this, i18n("Install location", "I"),
+ "Slackware", "*.TXT *.txt *.tgz *.tar.gz",
+ i18n("Location of a 'PACKAGES.TXT' File for Extended Information"));
+ locatedialog->pLocations(4, 1, this, i18n("Packages file", "P"),
+ "Slackware", "*.tgz *.tar.gz",
+ i18n("Location of 'PACKAGES.TXT' File for Slackware Distribution"),
+ i18n("Location of Base Folder of Slackware Distribution"));
+ locatedialog->dLocations(2, 6, this, i18n("Folders", "F"),
+ "Slackware", "*.tgz *.tar.gz",
+ i18n("Location of Folders Containing Slackware Packages"));
+
+ connect(locatedialog,SIGNAL(returnVal(LcacheObj *)),
+ this,SLOT(setAvail(LcacheObj *)));
+ locatedialog->apply_slot();
+
+ paramsInst.append(new param(i18n("Test (do not install)"),FALSE,FALSE,"-warn"));
+
+ paramsUninst.append(new param(i18n("Test (do not uninstall)"),FALSE,FALSE,"-warn"));
+
+ hasProgram = ifExe("installpkg");
+
+ initTranslate();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+SLACK::~SLACK()
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void SLACK::initTranslate()
+{
+ trl = new QDict<QString>(53);
+
+ trl->insert("a",new QString(i18n("Base System")));
+ trl->insert("ap",new QString(i18n("Linux Applications")));
+ trl->insert("d",new QString(i18n("Program Development")));
+ trl->insert("e",new QString(i18n("GNU EMacs")));
+ trl->insert("f",new QString(i18n("FAQs")));
+ trl->insert("k",new QString(i18n("Kernel Source")));
+ trl->insert("n",new QString(i18n("Networking")));
+ trl->insert("t",new QString(i18n("TeX Distribution")));
+ trl->insert("tcl",new QString(i18n("TCL Script Language")));
+ trl->insert("x",new QString(i18n("X Window System")));
+ trl->insert("xap",new QString(i18n("X Applications")));
+ trl->insert("xd",new QString(i18n("X Development Tools")));
+ trl->insert("xv",new QString(i18n("XView and OpenLook")));
+ trl->insert("y",new QString(i18n("Games")));
+}
+
+// check if slack file
+bool SLACK::isType(char *buf, const QString &)
+{
+ if (hasProgram) {
+ if ((unsigned char)buf[0] == 037 && (unsigned char)buf[1] == 0213 ) {
+ return true;
+ } else
+ return false;
+ } else {
+ return false;
+ }
+}
+
+bool SLACK::parseName(const QString &name, QString *n, QString *v)
+{
+ int s1;
+ s1 = name.findRev('.');
+ if (s1 > 0) {
+ *n = name.left(s1);
+ v = new QString("");
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void SLACK::listPackages(QPtrList<packageInfo> *pki)
+{
+ QString s;
+ cacheObj *cp;
+
+ if (packageLoc) {
+ for (cp = packageLoc->first(); cp != 0; cp = packageLoc->next()) {
+ // first entry is special
+ if (cp->cacheFile == "SLACK_0_0") {
+ s = getPackList(cp);
+ if (!s.isEmpty()) {
+ listPackList(pki, s, cp, INITIAL);
+ }
+ }
+ }
+ }
+
+ listInstalledPackages(pki);
+
+ if (packageLoc) {
+ for (cp = packageLoc->first(); cp != 0; cp = packageLoc->next()) {
+ if (cp->cacheFile == "SLACK_0_0") {
+ // already done
+ } else if ( !cp->base.isEmpty() ) {
+ s = getPackList(cp);
+ if (!s.isEmpty()) {
+ listPackList(pki, s, cp, UNINSTALLED);
+ }
+ } else {
+ s = getDir(cp);
+ if (!s.isEmpty()) {
+ listDir(pki,s,cp->location);
+ }
+ }
+ }
+ }
+}
+
+void SLACK::listInstalledPackages(QPtrList<packageInfo> *pki)
+{
+ FILE *file;
+ char linebuf[1024];
+ QString vb;
+ packageInfo *p;
+ QString fn, dr = DIR;
+
+ QDir d(DIR);
+ if (d.exists()) {
+ QString sline = i18n("Querying SLACK package list: ");
+ kpackage->setStatus(sline);
+
+ const QFileInfoList *list = d.entryInfoList();
+ int count = list->count();
+ QFileInfoListIterator it( *list ); // create list iterator
+ QFileInfo *fi; // pointer for traversing
+
+ kpackage->setPercent(0);
+ int cnt = 0;
+ while ( (fi=it.current()) ) { // for each file...
+ int n = (cnt*100)/count;
+ if (!(n % 5))
+ kpackage->setPercent(n);
+
+ if (!fi->isDir() && fi->isReadable()) {
+ fn = dr + fi->fileName();
+ file = fopen(QFile::encodeName(fn),"r");
+ if (file) {
+ vb = QString::null;
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ if (strcmp(linebuf,FILELIST)) {
+ vb += linebuf;
+ } else {
+ break;
+ }
+ }
+ fclose(file);
+ p = collectInfo(vb.ascii(), INSTALLED);
+ if (p) {
+ smerge(p);
+ if (!p->pkgInsert(pki, typeID, TRUE))
+ delete p;
+ }
+ }
+ }
+ cnt++;
+ ++it; // goto next list element
+ }
+ kpackage->setPercent(100);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+void SLACK::listPackList(QPtrList<packageInfo> *pki, const QString &s, cacheObj *cp, int insState)
+{
+ int np;
+ QString vb;
+ char linebuf[1024];
+ FILE *file;
+ packageInfo *p;
+
+ QString sline = i18n("Querying SLACK package list: ");
+ sline += cp->location;
+
+ kpackage->setStatus(sline);
+ kpackage->setPercent(0);
+
+ np = 0;
+ file= fopen(QFile::encodeName(s), "r");
+ vb = "";
+
+ if (file) {
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ int len = strlen(linebuf);
+ if (len > 1) {
+ if (linebuf[len - 2] == '\r') {
+ linebuf[len - 2] = '\n';
+ linebuf[len - 1] = 0;
+ }
+ }
+ if (strcmp(linebuf,"\n")) {
+ vb += linebuf;
+ } else if ( !vb.isEmpty() ) {
+ p = collectInfo(vb.ascii(), insState);
+ if (p) {
+ if (!p->pkgInsert(pki, typeID, insState == INITIAL, insState == INITIAL)) {
+ delete p;
+ } else if (cp && insState != INITIAL) {
+ p->info.insert("base", cp->base);
+ }
+ if (p && insState == INITIAL) {
+ p->packageState = packageInfo::NOLIST;
+ p->info.remove("summary");
+ }
+ }
+ vb.truncate(0);
+ }
+ }
+ fclose(file);
+ }
+ kpackage->setPercent(100);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// mode: i = query installed u = query uninstalled
+packageInfo *SLACK::getPackageInfo(char mode, const QString &name, const QString &)
+{
+ char linebuf[1024];
+ packageInfo *pki = 0;
+ QString vb, search, fn;
+ QString n,v;
+ FILE *file;
+
+ switch(mode) {
+ ////////////////////////////////////////////////////////////////////////
+ // query an installed package!
+ case 'i':
+ fn = DIR + name;
+ file = fopen(QFile::encodeName(fn),"r");
+ if (file) {
+ vb = QString::null;
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ if (strcmp(linebuf,FILELIST)) {
+ vb += linebuf;
+ } else {
+ break;
+ }
+ }
+ fclose(file);
+ pki = collectInfo(vb.ascii(), INSTALLED);
+ if (pki) {
+ smerge(pki);
+ }
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////
+ // query an uninstalled package
+ case 'u':
+ QFile f(name);
+ if (f.exists()) {
+ QMap<QString, QString> a;
+
+ a.insert("group", i18n("OTHER"));
+ a.insert("filename", name);
+
+ QFileInfo f(name);
+ a.insert("name", f.baseName());
+
+ QString st;
+ st.setNum(f.size());
+ a.insert("file-size", st);
+
+ pki = new packageInfo(a,this);
+ if (pki) {
+ smerge(pki);
+ pki->updated = TRUE;
+ }
+ }
+ break;
+ }
+ return pki;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+packageInfo *SLACK::collectInfo(const char *_inp, int insState)
+{
+ QString stmp, fn = "";
+ QMap<QString, QString> a;
+
+ char *str, *xstr;
+ QString qstr;
+
+ char *inp = qstrdup(_inp);
+ str = strtok(inp,"\n");
+
+ if (str) {
+ do {
+ if (str[0] == 0)
+ break;
+
+ xstr = strchr(str,':');
+ if (xstr) {
+ *xstr++ = 0;
+ xstr++;
+ while (*xstr == ' ') {
+ xstr++;
+ }
+
+ for( int i = 0; str[ i ] != '\0'; ++i )
+ str[ i ] = tolower( str[ i ] );
+
+ if (*str == ' ')
+ str++;
+
+ if (!strcmp("package name",str)) {
+ fn = xstr;
+ QString st = xstr;
+ if (st.right(4) == ".tgz")
+ a.insert("name", st.left(st.length() - 4));
+ else
+ a.insert("name", st);
+ } else if (!strcmp("package description",str)) {
+ int i = 0;
+ QString qstr = "";
+
+ while ((str = strtok(NULL,"\n"))) {
+ xstr = strchr(str,':');
+ if (xstr) {
+ *xstr++ = 0;
+ if (*(xstr) != 0)
+ xstr++;
+ while (*xstr == ' ') {
+ xstr++;
+ }
+ if (i == 0) {
+ a.insert("summary", xstr);
+ } else {
+ if (!strcmp(xstr,"") && (i != 1)) {
+ qstr += "\n";
+ } else {
+ qstr += xstr;
+ qstr += " ";
+ }
+ }
+ }
+ i++;
+ }
+ a.insert("description", qstr);
+ } else if (!strcmp("package location",str)) {
+ QString sl = xstr;
+ if (insState != INSTALLED) {
+ int sls = sl.findRev("/");
+ if (sls >= 0) {
+ QRegExp num("[0-9][0-9]*");
+ int slf = sl.find(num,sls);
+ if (slf >= 0) {
+ sls++;
+ QString gt = sl.mid(sls,slf-sls);
+ if (trl->find(gt)) {
+ gt = *trl->find(gt);
+ }
+ a.insert("group",gt);
+ }
+ }
+ sl = sl.right(sl.length() - 2);
+ sl += "/";
+ sl += fn;
+ }
+ if (insState == UNINSTALLED) {
+ a.insert("filename", sl);
+ }
+ } else if (!strcmp("section",str)) {
+ a.insert("group", xstr);
+ } else if (!strcmp("compressed package size",str) ||
+ !strcmp("package size (compressed)",str)) {
+ QString stmp = xstr;
+ stmp.truncate(stmp.length() - 2);
+ stmp += "000";
+ a.insert("file-size", stmp);
+ } else if (!strcmp("uncompressed package size",str) ||
+ !strcmp("package size (uncompressed)",str)) {
+ QString stmp = xstr;
+ stmp.truncate(stmp.length() - 2);
+ stmp += "000";
+ a.insert("size", stmp);
+ } else {
+ a.insert(str, xstr);
+ }
+ }
+ } while ((str = strtok(NULL,"\n")));
+ }
+
+ delete [] inp;
+
+ if (a["name"].isEmpty()) {
+ return 0;
+ } else {
+ packageInfo *i = new packageInfo(a,this);
+ i->packageState = packageInfo::INSTALLED;
+ i->fixup();
+ return i;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList SLACK::getChangeLog(packageInfo *) {
+ return 0;
+}
+
+bool SLACK::filesTab(packageInfo *) {
+ return TRUE;
+}
+
+bool SLACK::changeTab(packageInfo *) {
+ return FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+QStringList SLACK::getFileList(packageInfo *p)
+{
+ char linebuf[1024];
+ QString st, fn;
+ FILE *file;
+ QString name;
+ char mode;
+
+ fn = p->getFilename();
+ if(!fn.isEmpty())
+ mode = 'u';
+ else
+ mode = 'i';
+
+ QStringList filelist;
+
+ switch(mode) {
+ ////////////////////////////////////////////////////////////////////////
+ // query an installed package!
+ case 'i':
+ name = p->getProperty("name");
+
+ fn = DIR + name;
+ file = fopen(QFile::encodeName(fn),"r");
+ if (file) {
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ if (!strcmp(linebuf,FILELIST)) {
+ break;
+ }
+ }
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ st = "/";
+ st += linebuf;
+ st.truncate(st.length() -1);
+ if (st.left(8) != "/install") {
+ filelist.append(st);
+ }
+ }
+ fclose(file);
+ }
+ break;
+
+ ////////////////////////////////////////////////////////////////////
+ // query an uninstalled package
+ case 'u':
+ name = fn;
+
+ QString s = "sh -c 'cat ";
+ s += fn;
+ s += "|gunzip |tar -t -f -'";
+
+ filelist = kpty->run(s);
+ break;
+ }
+
+ return filelist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Call the script to uninstall packages setting parameters
+// to slack dependent on flags, returning whether everyting worked
+//////////////////////////////////////////////////////////////////////////////
+QString SLACK::doUninstall(int uninstallFlags, const QString &packs, bool &)
+{
+ QString s = "removepkg ";
+ s += setOptions(uninstallFlags, paramsUninst);
+ s += packs;
+
+ kdDebug() << "uCMD=" << s << "\n";
+
+ return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Call the script to install packages setting parameters
+// to slack dependent on flags, returning whether everyting worked
+//////////////////////////////////////////////////////////////////////////////
+QString SLACK::install(int installFlags, QPtrList<packageInfo> *plist, bool &test)
+{
+ packageInfo *pk;
+ int i = 0;
+ QString packs = "";
+ for (pk = plist->first(); pk != 0; pk = plist->next()) {
+ QString fname = pk->fetchFilename();
+ if ( !fname.isEmpty() ) {
+ packs += fname + " ";
+ i++;
+ }
+ }
+ return doInstall(installFlags, packs, test);
+}
+
+QString SLACK::doInstall(int installFlags, const QString &packs, bool &)
+{
+
+ QString s = "installpkg ";
+ s += setOptions(installFlags, paramsInst);
+ s += packs;
+
+ kdDebug() << "iCMD=" << s << "\n";
+
+ return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+QStringList SLACK::FindFile(const QString &name, bool)
+{
+ FILE *file;
+ char linebuf[1024];
+ QString buf, st;
+ QString fn, dr = DIR;
+ QStringList filelist;
+
+ QDir d(DIR);
+ if (d.exists()) {
+ QString sline = i18n("Querying SLACK package list: ");
+ kpackage->setStatus(sline);
+
+ const QFileInfoList *list = d.entryInfoList();
+ int count = list->count();
+ QFileInfoListIterator it( *list ); // create list iterator
+ QFileInfo *fi; // pointer for traversing
+
+ kpackage->setPercent(0);
+ int cnt = 0;
+ while ( (fi=it.current()) ) { // for each file...
+ int n = (cnt*100)/count;
+ if (!(n % 5))
+ kpackage->setPercent(n);
+
+ if (!fi->isDir() && fi->isReadable()) {
+ fn = dr + fi->fileName();
+ file = fopen(QFile::encodeName(fn),"r");
+ if (file) {
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ if (!strcmp(linebuf,FILELIST)) {
+ break;
+ }
+ }
+ while (fgets(linebuf,sizeof(linebuf),file)) {
+ if (QString::fromLocal8Bit(linebuf).find(name) != -1) {
+ st = "/";
+ st += linebuf;
+ st.truncate(st.length() -1);
+ if (st.left(8) != "/install") {
+ QString s = fi->fileName();
+ s += "\t";
+ s += st;
+ filelist.append(s);
+ }
+ }
+ }
+ fclose(file);
+ }
+ }
+ cnt++;
+ ++it; // goto next list element
+ }
+ }
+ return filelist;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void SLACK::setLocation()
+{
+ locatedialog->restore();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+void SLACK::setAvail(LcacheObj *slist)
+{
+ delete packageLoc;
+ packageLoc = slist;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+void SLACK::smerge(packageInfo *p)
+{
+ p->smerge(typeID);
+}
+#include "slackInterface.moc"
diff --git a/kpackage/slackInterface.h b/kpackage/slackInterface.h
new file mode 100644
index 0000000..c11a7c2
--- /dev/null
+++ b/kpackage/slackInterface.h
@@ -0,0 +1,92 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef SLACK_IFACE_H
+#define SLACK_IFACE_H
+
+#include "../config.h"
+
+#include <qptrlist.h>
+#include <kprocess.h>
+
+#include "pkgInterface.h"
+
+class packageInfo;
+class updateLoc;
+class cacheObj;
+
+class SLACK: public pkgInterface
+{
+ Q_OBJECT
+
+public:
+ SLACK();
+ ~SLACK();
+
+ bool isType(char *buf, const QString &fname);
+
+ packageInfo *getPackageInfo(char mode, const QString &name,
+ const QString &version);
+ QStringList getFileList(packageInfo *p);
+ QStringList getChangeLog(packageInfo *p);
+
+ bool filesTab(packageInfo *p);
+ // If files tab is to be enabled
+
+ bool changeTab(packageInfo *p);
+ // If change log tab is to be enabled
+
+ QStringList FindFile(const QString &name, bool seachAll=false);
+ bool parseName(const QString& name, QString *n, QString *v);
+
+ QString install(int installFlags, QPtrList<packageInfo> *plist, bool &test);
+
+public slots:
+ void setLocation();
+ void setAvail(LcacheObj *);
+
+private:
+ packageInfo* collectInfo(const char *inp, int insState);
+ void listInstalledPackages(QPtrList<packageInfo> *pki);
+
+ QString doUninstall(int installFlags, const QString &packs, bool &test);
+ QString doInstall(int installFlags, const QString &packs, bool &test);
+
+ void listPackages(QPtrList<packageInfo> *pki);
+ void listPackList(QPtrList<packageInfo> *pki, const QString &s,
+ cacheObj *cp, int insState);
+
+ void initTranslate();
+
+ void smerge(packageInfo *p);
+
+ QDict<QString> *trl;
+};
+
+#endif
+
+
+
diff --git a/kpackage/toolbar/Makefile.am b/kpackage/toolbar/Makefile.am
new file mode 100644
index 0000000..c19c175
--- /dev/null
+++ b/kpackage/toolbar/Makefile.am
@@ -0,0 +1,2 @@
+pics_DATA = ftin.xpm ftout.xpm
+picsdir = $(kde_datadir)/kpackage/pics
diff --git a/kpackage/toolbar/ftin.xpm b/kpackage/toolbar/ftin.xpm
new file mode 100644
index 0000000..e70d56d
--- /dev/null
+++ b/kpackage/toolbar/ftin.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char * kmfolderin_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"15 13 5 1",
+/* colors */
+" c None",
+". c red3",
+"X c white",
+"o c #c0c0c0",
+"O c #808080",
+/* pixels */
+" . . ",
+" ... ",
+" ...XXXXXXXX",
+" ...ooooooXX",
+" .......XXXXXO",
+" .....oooXXOX",
+" XX...XXXXXOXO",
+" Xooo.oooXXOXOX",
+"XXXXXXXXXXOXOX ",
+"OOOOOOOOOOXOX ",
+"XXXXXXXXXXOX ",
+"OOOOOOOOOOX ",
+"XXXXXXXXXX "};
diff --git a/kpackage/toolbar/ftout.xpm b/kpackage/toolbar/ftout.xpm
new file mode 100644
index 0000000..db28a8e
--- /dev/null
+++ b/kpackage/toolbar/ftout.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char * kmfolderout_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"15 13 5 1",
+/* colors */
+" c None",
+". c blue4",
+"X c white",
+"o c #c0c0c0",
+"O c #808080",
+/* pixels */
+" . ",
+" ... ",
+" .....XXXXXXX",
+" .......ooooXX",
+" ...XXXXXXXO",
+" X...ooooXXOX",
+" XX...XXXXXOXO",
+" Xoo.X.ooXXOXOX",
+"XXXXXXXXXXOXOX ",
+"OOOOOOOOOOXOX ",
+"XXXXXXXXXXOX ",
+"OOOOOOOOOOX ",
+"XXXXXXXXXX "};
diff --git a/kpackage/updateLoc.cpp b/kpackage/updateLoc.cpp
new file mode 100644
index 0000000..cf4e582
--- /dev/null
+++ b/kpackage/updateLoc.cpp
@@ -0,0 +1,761 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+
+#include "kpackage.h"
+#include "updateLoc.h"
+#include "pkgInterface.h"
+#include "options.h"
+#include "cache.h"
+
+#include <qvbox.h>
+#include <qscrollview.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kcombobox.h>
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+apanel::apanel( QWidget *parent,
+ const char * name )
+ : QWidget( parent, name )
+{
+ puse = 0;
+
+ pack = new QHBoxLayout(this);
+ {
+ puse = new QCheckBox(i18n("Use"),this);
+ pack->addWidget(puse,0);
+
+ pent = new QLineEdit(this);
+ pent->setMinimumWidth(600);
+ pack->addWidget(pent,0);
+
+ }
+}
+
+apanel::~apanel()
+{
+}
+
+QString apanel::getText() const
+{
+ QString s = pent->text();
+ return s;
+}
+
+void apanel::setText(const QString &s)
+{
+ pent->setText(s);
+}
+
+bool apanel::getUse()
+{
+ if (puse)
+ return puse->isChecked();
+ else
+ return FALSE;
+}
+
+void apanel::setUse(int n)
+{
+ if (puse) {
+ if (n)
+ puse->setChecked(TRUE);
+ else
+ puse->setChecked(FALSE);
+ }
+}
+
+void apanel::clear()
+{
+ puse->setChecked(FALSE);
+ pent->clear();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+dpanel::dpanel( QWidget *parent, const char * name )
+ : QWidget( parent, name )
+{
+ puse = 0;
+ psubdirs = 0;
+
+ pack = new QHBoxLayout(this);
+ {
+ pent = new QLineEdit(this);
+ pent->setMinimumWidth(280);
+ pack->addWidget(pent,0);
+
+ pbut = new QPushButton("...",this);
+ pack->addWidget(pbut,0);
+
+ connect(pbut, SIGNAL(clicked()), this, SLOT(dirOpen()));
+
+ }
+}
+
+dpanel::dpanel(dpanel *basep, const QString &Pfilter, bool bsubdirs,
+ QWidget *parent, const char * name )
+ : QWidget( parent, name )
+{
+ filter = Pfilter;
+ puse = 0;
+ psubdirs = 0;
+
+ base = basep;
+
+ pack = new QHBoxLayout(this);
+ {
+ puse = new QCheckBox(i18n("Use"),this);
+ pack->addWidget(puse,0);
+
+ pent = new QLineEdit(this);
+ pent->setMinimumWidth(280);
+ pack->addWidget(pent,0);
+
+ if (bsubdirs) {
+ psubdirs = new QCheckBox(i18n("Subfolders"),this);
+ psubdirs->setFixedSize(psubdirs->sizeHint());
+ pack->addWidget(psubdirs,0);
+ }
+
+ pbut = new QPushButton("...",this);
+ pack->addWidget(pbut,0);
+
+ if (base)
+ connect(pbut, SIGNAL(clicked()), this, SLOT(fileOpen()));
+ else
+ connect(pbut, SIGNAL(clicked()), this, SLOT(dirOpen()));
+
+ }
+}
+
+dpanel::~dpanel()
+{
+}
+
+QString dpanel::getText() const
+{
+ QString s = pent->text();
+ return s;
+}
+
+void dpanel::setText(const QString &s)
+{
+ pent->setText(s);
+}
+
+bool dpanel::getUse() const
+{
+ if (puse)
+ return puse->isChecked();
+ else
+ return FALSE;
+}
+
+void dpanel::setUse(int n)
+{
+ if (puse) {
+ if (n)
+ puse->setChecked(TRUE);
+ else
+ puse->setChecked(FALSE);
+ }
+}
+
+bool dpanel::getSubdirs() const
+{
+ if (psubdirs)
+ return psubdirs->isChecked();
+ else
+ return FALSE;
+}
+
+void dpanel::setSubdirs(int n)
+{
+ if (psubdirs)
+ {
+ if (n)
+ psubdirs->setChecked(TRUE);
+ else
+ psubdirs->setChecked(FALSE);
+ }
+}
+
+void dpanel::fileOpen()
+{
+ QString st;
+
+ if (base && getText().isEmpty()) {
+ st = base->getText();
+ } else {
+ st = getText();
+ }
+ if (st.right(8) == "Packages") {
+ st.truncate(st.length() - 8);
+ }
+
+ KURL url = KFileDialog::getOpenURL
+ (st, filter, 0, i18n("Package File"));
+
+ if( url.isEmpty() )
+ return;
+
+ pent->setText( url.url() );
+}
+
+void dpanel::dirOpen()
+{
+ QString st;
+
+ if (base && getText().isEmpty()) {
+ st = base->getText();
+ } else {
+ st = getText();
+ }
+
+ KURL url = KFileDialog::getExistingURL
+ (st, 0, i18n("Package Archive"));
+
+
+ if( url.isEmpty() )
+ return;
+
+ pent->setText( url.url() );
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+updateLoc::updateLoc(QWidget *p, int panelNumber, pkgInterface *inter, const QString &iname)
+ : QWidget(p,"updateLoc",FALSE)
+{
+ interName = iname;
+ interface = inter;
+ panNumber = panelNumber;
+
+ vf = new QVBoxLayout( this, 15, 10, "vf");
+}
+
+updateLoc::~updateLoc()
+{
+}
+
+void updateLoc::doBase(const QString & bmsg)
+{
+ base = 0;
+ if (haveBase) {
+ fbase = new QGroupBox(bmsg, this);
+ fbase->setColumnLayout(0, Qt::Vertical );
+ fbase->layout()->setSpacing( KDialog::spacingHint() );
+ fbase->layout()->setMargin( KDialog::marginHint() );
+ vbase = new QVBoxLayout(fbase->layout());
+ vf->addWidget(fbase,1);
+ base = new dpanel(fbase);
+ vbase->addWidget(base,0);
+ vbase->activate();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+aUpdateLoc::aUpdateLoc(QWidget *p, int panelNumber, pkgInterface *inter, const QString &iname,
+ int numberLines, const QString &label)
+ : updateLoc(p, panelNumber, inter, iname)
+{
+
+ if (numberLines > PNUM)
+ numLines = PNUM;
+ else
+ numLines = numberLines;
+
+ ap[0] = 0;
+
+ QGroupBox *floc = new QGroupBox(1,Qt::Vertical, label, this);
+ vf->addWidget(floc,1);
+ QScrollView* sv = new QScrollView(floc);
+ sv->setHScrollBarMode(QScrollView::AlwaysOff);
+ sv->setResizePolicy(QScrollView::AutoOneFit);
+
+ QFrame *f = new QFrame(sv->viewport());
+ sv->addChild(f);
+
+ QVBoxLayout *vloc = new QVBoxLayout(f, 0, 3, "vloc");
+
+ for (int i = 0; i < numLines; i++) {
+ ap[i] = new apanel( f);
+ vloc->addWidget(ap[i],0);
+ }
+
+}
+
+
+aUpdateLoc::~aUpdateLoc()
+{
+}
+
+void aUpdateLoc::readSettings()
+{
+ int i = 0;
+ QString a,b;
+
+ for (int i = 0; i < numLines; i++) {
+ ap[i]->clear();
+ }
+
+ QStringList list = interface->readApt();
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ if (!(*it).isEmpty()) {
+ if ((*it).left(1) == "#") {
+ ap[i]->setText(((*it).mid(1)).stripWhiteSpace());
+ ap[i]->setUse(0);
+ } else {
+ ap[i]->setText((*it));
+ ap[i]->setUse(1);
+ }
+ i++;
+ if (i >= numLines) {
+ ap[numLines - 1]->setText(i18n("File truncated..."));
+ break;
+ }
+ }
+ }
+}
+
+void aUpdateLoc::writeSettings() {
+ QStringList list;
+ QString s;
+
+ QString ln;
+ for (int i = 0; i < numLines; i++) {
+ if (!ap[i])
+ break;
+
+ ln = ap[i]->getText();
+ if (!ln.isEmpty()) {
+ if (ap[i]->getUse()) {
+ s = "";
+ } else {
+ s = "# ";
+ }
+ s += ln;
+ list.append(s);
+ }
+ }
+ interface->writeApt(list);
+}
+
+void aUpdateLoc::applyS(LcacheObj *) {
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+pdUpdateLoc::pdUpdateLoc(QWidget *p, int panelNumber, pkgInterface *inter, const QString &iname,
+ int numberLines, const QString &filter,
+ const QString &lmsg, QString bmsg,
+ bool subdirs )
+ : updateLoc(p, panelNumber, inter, iname)
+{
+
+ if (numberLines > PNUM)
+ numLines = PNUM;
+ else
+ numLines = numberLines;
+
+ haveBase = !bmsg.isNull();
+
+ dp[0] = 0;
+
+ QString pn;
+ pn.setNum(panNumber);
+ pn += "_";
+
+ packL = "Package_L_";
+ packL += pn;
+ packU = "Package_U_";
+ packU += pn;
+ packS = "Package_S_";
+ packS += pn;
+ availB = "Available_Base";
+ availB += pn;
+
+ doBase(bmsg);
+
+ QGroupBox *floc = new QGroupBox(lmsg, this);
+ floc->setColumnLayout(0, Qt::Vertical );
+ floc->layout()->setSpacing( KDialog::spacingHint() );
+ floc->layout()->setMargin( KDialog::marginHint() );
+ vf->addWidget(floc,1);
+ QVBoxLayout *vloc = new QVBoxLayout(floc->layout());
+
+ for (int i = 0; i < numLines; i++) {
+ dp[i] = new dpanel(base, filter, subdirs, floc);
+ vloc->addWidget(dp[i],0);
+ }
+
+ readSettings();
+}
+
+
+pdUpdateLoc::~pdUpdateLoc()
+{
+}
+
+void pdUpdateLoc::applyS(LcacheObj *slist)
+{
+ QString t,pn,cn,pv,prev,opts;
+ cacheObj *CObj;
+ KConfig *config = kapp->config();
+ config->setGroup(interName);
+
+ cn = interface->head;
+ cn += "_";
+ cn += pn.setNum(panNumber);
+ cn += "_";
+
+
+ for (int i = 0; i < numLines; i++) {
+ // delete chached dir if text changed
+ pv = packL + pn.setNum(i);
+ prev = config->readEntry(pv);
+ if (prev != dp[i]->getText())
+ cacheObj::rmDCache(QString(cn + pn.setNum(i)));
+
+ // create cache object corresponding to this entry
+ if (dp[i]->getUse()) {
+ t = dp[i]->getText();
+ if (!t.isEmpty()) {
+ CObj = new cacheObj(haveBase ? base->getText() : QString::null,
+ t, cn + pn.setNum(i), "", dp[i]->getSubdirs());
+ slist->append(CObj);
+ // printf("T=%s\n",t.data());
+ }
+ }
+ }
+ // writeSettings();
+}
+
+void pdUpdateLoc::readSettings()
+{
+ QString pv, pn;
+
+ KConfig *config = kapp->config();
+
+ config->setGroup(interName);
+
+ if (haveBase)
+ base->setText(config->readEntry(availB));
+
+ for (int i = 0; i < numLines; i++) {
+ if (!dp[i])
+ break;
+ pv = packL + pn.setNum(i);
+ dp[i]->setText(config->readEntry(pv));
+ pv = packU + pn.setNum(i);
+ dp[i]->setUse(config->readNumEntry(pv));
+ pv = packS + pn.setNum(i);
+ dp[i]->setSubdirs(config->readNumEntry(pv));
+ }
+}
+
+void pdUpdateLoc::writeSettings()
+{
+ QString pv, pn;
+
+ KConfig *config = kapp->config();
+
+ config->setGroup(interName);
+ if (haveBase) {
+ if (!base->getText().isEmpty())
+ config->writeEntry(availB,base->getText());
+ }
+
+ for (int i = 0; i < numLines; i++) {
+ if (!dp[i])
+ break;
+ pv = packL + pn.setNum(i);
+ config->writeEntry(pv,dp[i]->getText());
+ pv = packU + pn.setNum(i);
+ config->writeEntry(pv,(int)dp[i]->getUse());
+ pv = packS + pn.setNum(i);
+ config->writeEntry(pv,(int)dp[i]->getSubdirs());
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+cUpdateLoc::cUpdateLoc(QWidget *p, int panelNumber, pkgInterface *inter, const QString &iname,
+ int numberLines, const QString &baseMsg,
+ const QString &boxLabels, const QString &boxValues)
+ : updateLoc(p, panelNumber, inter, iname)
+{
+ if (numberLines > PNUM)
+ numLines = PNUM;
+ else
+ numLines = numberLines;
+
+ haveBase = !baseMsg.isNull();
+
+ combo[0] = 0;
+
+ QString pn;
+ pn.setNum(panNumber);
+ pn += "_";
+
+ packC = "Package_C_";
+ packC += pn;
+ availB = "Available_Base";
+ availB += pn;
+
+ QStringList kc = QStringList::split('\n', boxLabels);
+ QStringList::Iterator kcIt = kc.begin();
+
+ QStringList oc = QStringList::split('\n', boxValues);
+ QStringList::Iterator ocIt = oc.begin();
+
+
+ doBase(baseMsg);
+
+ for (int i = 0; i < numLines; i++) {
+ QGroupBox *floc = new QGroupBox(*kcIt, this);
+ floc->setColumnLayout(0, Qt::Vertical );
+ floc->layout()->setSpacing( KDialog::spacingHint() );
+ floc->layout()->setMargin( KDialog::marginHint() );
+ vf->addWidget(floc,1);
+ QVBoxLayout *vloc = new QVBoxLayout(floc->layout());
+
+ combo[i] = new KComboBox( true, floc);
+ KCompletion *comp = combo[i]->completionObject();
+ connect(combo[i],SIGNAL(returnPressed(const QString&))
+ ,comp,SLOT(addItem(const QString&)));
+ combo[i]->insertStringList(QStringList::split(' ',*ocIt));
+ vloc->addWidget(combo[i]);
+ if (kcIt != kc.end()) {
+ ++kcIt;
+ }
+ if (ocIt != oc.end()) {
+ ++ocIt;
+ }
+ }
+
+ readSettings();
+}
+
+cUpdateLoc::~cUpdateLoc()
+{
+}
+
+ void cUpdateLoc::applyS(LcacheObj *slist)
+{
+ QString t,pn,cn,pv,prev,opts;
+ cacheObj *CObj;
+ KConfig *config = kapp->config();
+ config->setGroup(interName);
+
+ cn = interface->head;
+ cn += "_";
+ cn += pn.setNum(panNumber);
+ cn += "_";
+
+ if (!base->getText().isEmpty()) {
+ for (int i = 0; i < numLines; i++) {
+ opts += combo[i]->currentText();
+ opts += "\n";
+ }
+ CObj = new cacheObj(base->getText(),
+ "", cn + ":", opts);
+ slist->append(CObj);
+ }
+ // writeSettings();
+}
+
+void cUpdateLoc::readSettings()
+{
+ QString pv, pn;
+
+ KConfig *config = kapp->config();
+
+ config->setGroup(interName);
+
+ if (haveBase)
+ base->setText(config->readEntry(availB));
+
+ for (int i = 0; i < numLines; i++) {
+ if (!combo[i])
+ break;
+ pv = packC + pn.setNum(i);
+ if (!config->readEntry(pv).isEmpty()) {
+ combo[i]->insertItem(config->readEntry(pv), 0);
+ }
+ }
+
+}
+
+void cUpdateLoc::writeSettings()
+{
+ QString pv, pn;
+
+ KConfig *config = kapp->config();
+
+ config->setGroup(interName);
+
+ if (haveBase) {
+ config->writeEntry(availB,base->getText());
+ }
+
+ for (int i = 0; i < numLines; i++) {
+ if (!combo[i])
+ break;
+ pv = packC + pn.setNum(i);
+ config->writeEntry(pv,combo[i]->currentText());
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+Locations::Locations(const QString &msg)
+ : KDialogBase(Tabbed, msg, Ok | Cancel, Ok, 0, "Locations", false)
+{
+ numPanels = 0;
+
+ connect( this, SIGNAL(okClicked()), SLOT(write_slot()) );
+}
+
+void Locations::dLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname,
+ const QString &label, const QString &filter, const QString &dirMsg,
+ bool subdirs)
+{
+ QString nm;
+
+ for (int i = numPanels ; (i < numPanels + numberDirs) && (i < PANNUM); i++) {
+
+ QString mp = iname;
+ nm.setNum(i+1);
+ mp += nm;
+ QVBox *page = addVBoxPage(mp);
+ pn[i] = new pdUpdateLoc(page, i, inter,
+ label, numberLines,
+ filter, dirMsg, NULL, subdirs);
+ }
+ numPanels += numberDirs;
+}
+
+void Locations::pLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname, const QString &label,
+ const QString &filter,
+ const QString &packMsg, QString baseMsg, bool subdirs)
+{
+ QString nm;
+
+ for (int i = numPanels; (i < numPanels + numberDirs) && (i < PANNUM); i++) {
+ QString mp = iname;
+ nm.setNum(i+1);
+ mp += nm;
+ QVBox *page = addVBoxPage(mp);
+ pn[i] = new pdUpdateLoc(page, i, inter, label,
+ numberLines,
+ filter, packMsg, baseMsg, subdirs);
+ }
+ numPanels += numberDirs;
+}
+
+void Locations::cLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname, const QString &label,
+ const QString &boxLables, const QString &baseMsg, const QString &boxValues)
+{
+ QString nm;
+
+ for (int i = numPanels; (i < numPanels + numberDirs) && (i < PANNUM); i++) {
+ QString mp = iname;
+ nm.setNum(i+1);
+ mp += nm;
+ QVBox *page = addVBoxPage(mp);
+ pn[i] = new cUpdateLoc(page, i, inter, label,
+ numberLines, baseMsg,
+ boxLables, boxValues);
+ }
+ numPanels += numberDirs;
+}
+
+void Locations::aLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname, const QString &label)
+{
+ QString nm;
+
+ for (int i = numPanels; (i < numPanels + numberDirs) && (i < PANNUM); i++) {
+ QString mp = iname;
+ nm.setNum(i+1);
+ mp += nm;
+ QVBox *page = addVBoxPage(mp);
+ pn[i] = new aUpdateLoc(page, i, inter, iname,
+ numberLines, label);
+ }
+ numPanels += numberDirs;
+}
+
+Locations::~Locations() {
+ // for (int i = 0; (i < numPanels) && (i < PANNUM) && pn[i]; i++) {
+ // delete pn[i];
+ // }
+}
+
+void Locations::restore()
+{
+ for (int i = 0; (i < numPanels) && (i < PANNUM); i++) {
+ pn[i]->readSettings();
+ }
+ show();
+}
+
+void Locations::apply_slot()
+{
+ LcacheObj *slist = new LcacheObj();
+
+ for (int i = 0; (i < numPanels) && (i < PANNUM); i++) {
+ pn[i]->applyS(slist);
+ }
+ emit returnVal(slist);
+}
+
+void Locations::write_slot()
+{
+ apply_slot();
+
+ for (int i = 0; (i < numPanels) && (i < PANNUM); i++) {
+ pn[i]->writeSettings();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+#include "updateLoc.moc"
diff --git a/kpackage/updateLoc.h b/kpackage/updateLoc.h
new file mode 100644
index 0000000..269bf74
--- /dev/null
+++ b/kpackage/updateLoc.h
@@ -0,0 +1,326 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+
+
+#ifndef DEBLOCATE_H
+#define DEBLOCATE_H
+
+#include "../config.h"
+
+// Standard Headers
+#include <stdio.h>
+
+// Qt Headers
+#include <qdir.h>
+#include <qwidget.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qfiledialog.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+
+// KDE headers
+#include <kbuttonbox.h>
+#include <kdialogbase.h>
+
+class pkgInterface;
+class updateLoc;
+class cacheObj;
+class LcacheObj;
+class KComboBox;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class dpanel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ dpanel(QWidget *parent, const char * name = 0);
+ dpanel(dpanel *basep, const QString &Pfilter, bool bsubdirs,
+ QWidget *parent, const char * name = 0);
+ ~dpanel();
+
+
+ QString getText() const;
+ void setText(const QString &s);
+ bool getUse() const;
+ void setUse(int n);
+ bool getSubdirs() const;
+ void setSubdirs(int n);
+
+private:
+
+ QCheckBox *psubdirs;
+ QCheckBox *puse;
+ QHBoxLayout* pack;
+ QLineEdit *pent;
+ QPushButton *pbut;
+
+ dpanel *base;
+ QString filter;
+
+ public slots:
+ void fileOpen();
+ void dirOpen();
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class apanel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ apanel( QWidget *parent, const char * name = 0 );
+ ~apanel();
+
+
+ QString getText() const;
+ void setText(const QString &s);
+ bool getUse();
+ void setUse(int n);
+ void clear();
+
+private:
+
+ QCheckBox *puse;
+ QHBoxLayout* pack;
+ QLineEdit *pent;
+
+
+
+ public slots:
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class updateLoc : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ updateLoc (QWidget *p, int panelNumber, pkgInterface *inter, const QString &iname);
+ ~updateLoc();
+
+ virtual void readSettings() = 0;
+ virtual void writeSettings() = 0;
+
+ virtual void applyS(LcacheObj *slist) = 0;
+
+ void doBase(const QString &bmsg);
+
+ QString interName;
+ int panNumber;
+
+ bool haveBase;
+
+ pkgInterface *interface;
+
+ QVBoxLayout *vf;
+ dpanel *base;
+
+ QGroupBox *fbase;
+ QVBoxLayout* vbase;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class aUpdateLoc : public updateLoc
+{
+ Q_OBJECT
+
+public:
+
+ aUpdateLoc (QWidget *p, int panelNumber, pkgInterface *inter, const QString &iname,
+ int numberLines, const QString &label);
+ ~aUpdateLoc();
+
+
+ void readSettings();
+ void writeSettings();
+
+ void applyS(LcacheObj *slist);
+
+private:
+
+ QString packL, packU, packS, availB;
+
+ int wdth;
+
+ QPushButton *butloc;
+
+ QHBoxLayout* hloc;
+
+ int numLines;
+ enum { PNUM = 100 };
+ apanel *ap[PNUM];
+
+ QVBoxLayout* vl;
+ QVBoxLayout* vtop;
+ QGroupBox *frame1;
+ KButtonBox* hb;
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class pdUpdateLoc : public updateLoc
+{
+ Q_OBJECT
+
+public:
+
+ pdUpdateLoc (QWidget *p, int panelNumber, pkgInterface *inter,
+ const QString &iname, int numberLines, const QString &filter,
+ const QString &lmsg, QString bmsg = 0,
+ bool subdirs = FALSE);
+ ~pdUpdateLoc();
+
+
+ void readSettings();
+ void writeSettings();
+
+ void applyS(LcacheObj *slist);
+
+private:
+
+ QString packL, packU, packS, availB;
+
+ int wdth;
+
+ QPushButton *butloc;
+
+ QHBoxLayout* hloc;
+
+ int numLines;
+ enum { PNUM = 40 };
+ dpanel *dp[PNUM];
+
+ QVBoxLayout* vl;
+ QVBoxLayout* vtop;
+ QGroupBox *frame1;
+ KButtonBox* hb;
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+class cUpdateLoc : public updateLoc
+{
+ Q_OBJECT
+
+public:
+
+ cUpdateLoc (QWidget *p, int panelNumber, pkgInterface *inter,
+ const QString &iname, int numberLines, const QString &baseMsg,
+ const QString &boxLabels, const QString &boxValues);
+ ~cUpdateLoc();
+
+
+ void readSettings();
+ void writeSettings();
+
+ void applyS(LcacheObj *slist);
+
+private:
+
+ QString packC, availB;
+
+ QPushButton *butloc;
+
+ QHBoxLayout* hloc;
+
+ int numLines;
+ enum { PNUM = 40 };
+ KComboBox *combo[PNUM];
+
+ QVBoxLayout* vl;
+ QVBoxLayout* vtop;
+ QGroupBox *frame1;
+ KButtonBox* hb;
+
+
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class Locations : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ Locations( const QString &msg);
+ ~Locations();
+
+ void dLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname,
+ const QString &label, const QString &filter, const QString &dirMsg,
+ bool subdirs=TRUE );
+
+ void pLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname,
+ const QString &label, const QString &filter,
+ const QString &packMsg, QString baseMsg = 0,
+ bool subdirs=FALSE);
+
+ void cLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname, const QString &label,
+ const QString &boxLabels, const QString &baseMsg, const QString &boxValues);
+
+ void aLocations(int numberDirs, int numberLines,
+ pkgInterface *inter, const QString &iname, const QString &label);
+
+
+
+ // bmsg indicates the panel has a base entry
+ void restore();
+
+ int numPanels;
+ enum { PANNUM = 10 };
+ updateLoc *pn[PANNUM];
+
+public slots:
+ void apply_slot();
+ void write_slot();
+
+signals:
+ void returnVal(LcacheObj *);
+
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/kpackage/utils.cpp b/kpackage/utils.cpp
new file mode 100644
index 0000000..4f0ef44
--- /dev/null
+++ b/kpackage/utils.cpp
@@ -0,0 +1,63 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "../config.h"
+#include <kpackage.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include "utils.h"
+#include "kplview.h"
+
+void KpMsgE( const QString &msg, bool stop)
+{
+ KpMsg( "Error", msg, stop);
+}
+
+void KpMsg(const QString &lab, const QString &msg, bool stop)
+{
+ if (stop)
+ KMessageBox::sorry(kpkg, msg, lab);
+ else
+ KMessageBox::information(kpkg, msg, lab);
+}
+
+KpTreeListItem *findGroup(const QString &name, KpTreeListItem *search)
+{
+ if(!search)
+ return NULL;
+
+ do {
+ if (name == search->text(0)) {
+ return search;
+ }
+ } while( (search=search->nextSibling()) != NULL);
+
+ return NULL;
+}
+
+
+
diff --git a/kpackage/utils.h b/kpackage/utils.h
new file mode 100644
index 0000000..5cf30d9
--- /dev/null
+++ b/kpackage/utils.h
@@ -0,0 +1,39 @@
+/*
+** Copyright (C) 1999,2000 Toivo Pedaste <toivo@ucs.uwa.edu.au>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include "../config.h"
+#include <string.h>
+#include <klistview.h>
+
+class KpTreeListItem;
+
+KpTreeListItem *findGroup(const QString &name, KpTreeListItem *search);
+
+#endif
+
diff --git a/ksysv/AUTHORS b/ksysv/AUTHORS
new file mode 100644
index 0000000..a2a59a9
--- /dev/null
+++ b/ksysv/AUTHORS
@@ -0,0 +1,17 @@
+Current Code
+============
+
+Main developer:
+Peter Putzer <putzer@kde.org>
+
+leveldb.{h,c} (from chkconfig):
+Red Hat Software http://www.redhat.com
+
+Previous Versions
+=================
+
+IPC (stuff taken from kdehelp):
+Martin Jones
+
+Printing (stuff taken from kedit):
+Bernd Johannes Wuebben
diff --git a/ksysv/ActionList.cpp b/ksysv/ActionList.cpp
new file mode 100644
index 0000000..a2e2de8
--- /dev/null
+++ b/ksysv/ActionList.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#include <qapplication.h>
+#include "ksvdraglist.h"
+#include "ActionList.h"
+
+//////////////////////////////////
+// Action //
+//////////////////////////////////
+
+KSVAction::KSVAction()
+{
+}
+
+KSVAction::~KSVAction()
+{
+ // default - shouldnt be used normally (pure virtual declaration)
+}
+
+SimpleAction::SimpleAction (KSVDragList* s, const KSVData* i)
+ : KSVAction(),
+ mSource (s),
+ mItem (new KSVData (*i))
+{
+}
+
+SimpleAction::~SimpleAction()
+{
+ delete mItem;
+}
+
+ChangeAction::ChangeAction (KSVDragList* s, const KSVData* oldS, const KSVData* newS)
+ : SimpleAction (s, oldS),
+ mNew (new KSVData (*newS))
+{
+ source()->addToRMList (*oldState());
+}
+
+ChangeAction::~ChangeAction()
+{
+ delete mNew;
+}
+
+void ChangeAction::redo ()
+{
+ source()->addToRMList(*oldState());
+ source()->match (*oldState())->copy (*newState());
+ source()->sort();
+}
+
+void ChangeAction::undo()
+{
+ source()->removeFromRMList(*oldState());
+ source()->match(*newState())->copy (*oldState());
+ source()->sort();
+}
+
+AddAction::AddAction (KSVDragList* s, const KSVData* i)
+ : SimpleAction(s, i)
+{
+}
+
+AddAction::~AddAction()
+{
+}
+
+void AddAction::redo ()
+{
+ new KSVItem (source(), *item());
+}
+
+void AddAction::undo()
+{
+ delete source()->match(*item());
+}
+
+RemoveAction::RemoveAction (KSVDragList* s, const KSVData* i)
+ : SimpleAction(s, i)
+{
+ source()->addToRMList (*item());
+}
+
+RemoveAction::~RemoveAction()
+{
+}
+
+void RemoveAction::redo()
+{
+ source()->addToRMList(*item());
+
+ delete source()->match (*item());
+}
+
+void RemoveAction::undo()
+{
+ source()->removeFromRMList(*item());
+
+ new KSVItem (source(), *item());
+}
+
+CompoundAction::CompoundAction (KSVAction** a, int nr)
+ : mActions (new KSVAction* [nr]),
+ mCount (nr)
+{
+ memcpy (mActions, a, sizeof(KSVAction*) * nr);
+}
+
+CompoundAction::~CompoundAction()
+{
+ for (int i=0; i < mCount; ++i)
+ {
+ delete mActions[i];
+ }
+
+ delete[] mActions;
+}
+
+void CompoundAction::redo ()
+{
+ for (int i=0; i < mCount; ++i)
+ {
+ mActions[i]->redo();
+ }
+}
+
+void CompoundAction::undo()
+{
+ for (int i=0; i < mCount; ++i)
+ {
+ mActions[i]->undo();
+ }
+}
+
+//////////////////////////////////
+// ActionList //
+//////////////////////////////////
+
+ActionList::ActionList (QObject* parent, const char* name)
+ : QObject(parent, name)
+{
+ setAutoDelete(false);
+}
+
+ActionList::~ActionList()
+{
+}
+
+void ActionList::undoLast()
+{
+ if (!count())
+ return;
+
+ KSVAction* a = QPtrStack<KSVAction>::pop();
+ a->undo();
+
+ emit undone();
+
+ if (!count())
+ emit empty();
+}
+
+void ActionList::undoAll()
+{
+ while (count())
+ undoLast();
+}
+
+void ActionList::redoLast()
+{
+ if (!count())
+ return;
+
+ KSVAction* a = QPtrStack<KSVAction>::pop();
+ a->redo();
+
+ emit undone();
+
+ if (!count())
+ emit empty();
+}
+
+void ActionList::redoAll()
+{
+ while (count())
+ redoLast();
+}
+
+void ActionList::push (KSVAction* a)
+{
+ QPtrStack<KSVAction>::push(a);
+
+ if (count() == 1)
+ emit filled();
+}
+
+void ActionList::clear()
+{
+ setAutoDelete (true);
+ QPtrStack<KSVAction>::clear();
+ setAutoDelete (false);
+
+ emit empty();
+}
+
+#include "ActionList.moc"
diff --git a/ksysv/ActionList.h b/ksysv/ActionList.h
new file mode 100644
index 0000000..f420b48
--- /dev/null
+++ b/ksysv/ActionList.h
@@ -0,0 +1,131 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_ACTIONLIST_H
+#define KSV_ACTIONLIST_H
+
+#include <qptrstack.h>
+#include <qobject.h>
+
+class KSVData;
+class KSVDragList;
+
+class KSVAction
+{
+public:
+ KSVAction ();
+ virtual ~KSVAction () = 0;
+
+ virtual void undo () = 0;
+ virtual void redo() = 0;
+
+private:
+ const KSVAction& operator= (const KSVAction&); // undefined
+ KSVAction (const KSVAction&); // undefined
+};
+
+class SimpleAction : public KSVAction
+{
+public:
+ SimpleAction (KSVDragList* source, const KSVData* item);
+ virtual ~SimpleAction();
+
+ inline KSVDragList* source() { return mSource; }
+ inline KSVData* item() { return mItem; }
+
+ virtual void undo() = 0;
+ virtual void redo() = 0;
+
+private:
+ KSVDragList* mSource;
+ KSVData* mItem;
+};
+
+class RemoveAction : public SimpleAction
+{
+public:
+ RemoveAction (KSVDragList* s, const KSVData* i);
+ virtual ~RemoveAction();
+
+ virtual void undo();
+ virtual void redo();
+};
+
+class AddAction : public SimpleAction
+{
+public:
+ AddAction (KSVDragList* s, const KSVData* i);
+ virtual ~AddAction();
+
+ virtual void undo();
+ virtual void redo();
+};
+
+class ChangeAction : public SimpleAction
+{
+public:
+ ChangeAction (KSVDragList* s, const KSVData* oldState, const KSVData* newState);
+ virtual ~ChangeAction();
+
+ virtual void undo();
+ virtual void redo();
+
+ inline KSVData* newState() { return mNew; }
+ inline KSVData* oldState() { return item(); }
+private:
+ KSVData* mNew;
+};
+
+class CompoundAction : public KSVAction
+{
+public:
+ CompoundAction (KSVAction*[], int nr);
+ virtual ~CompoundAction();
+
+ virtual void undo();
+ virtual void redo();
+
+private:
+ KSVAction** mActions;
+ int mCount;
+};
+
+
+
+class ActionList : public QObject, private QPtrStack<KSVAction>
+{
+ Q_OBJECT
+
+public:
+ ActionList (QObject* parent, const char* name);
+ virtual ~ActionList ();
+
+ KSVAction* top () const { return QPtrStack<KSVAction>::top(); }
+
+public slots:
+ void undoLast ();
+ void undoAll ();
+ void redoLast ();
+ void redoAll ();
+ void push (KSVAction*);
+ void clear ();
+
+signals:
+ void undone ();
+ void empty ();
+ void filled ();
+};
+
+#endif
+
diff --git a/ksysv/Data.cpp b/ksysv/Data.cpp
new file mode 100644
index 0000000..caa4a1b
--- /dev/null
+++ b/ksysv/Data.cpp
@@ -0,0 +1,190 @@
+// (c) 2000 Peter Putzer
+
+#include <qdatastream.h>
+#include <kdatastream.h>
+
+#include "Data.h"
+
+KSVData::KSVData ()
+{
+ mNrChanged = mLabelChanged = mFilenameChanged = mOtherChanged = mNewEntry = false;
+ mNr = mOldNr = 0;
+}
+
+KSVData::KSVData (const QString& file, const QString& path,
+ const QString& label, Q_INT8 nr)
+ : mPath (path),
+ mLabel (label), mFilename (file)
+{
+ mNrChanged = mLabelChanged = mFilenameChanged = mOtherChanged = mNewEntry = false;
+ mNr = mOldNr = 0;
+ setNumber (nr);
+ mNrChanged = false;
+}
+
+KSVData::KSVData (const KSVData& rhs)
+ : mPath (rhs.mPath),
+ mLabel (rhs.mLabel),
+ mFilename (rhs.mFilename),
+ mRunlevel (rhs.mRunlevel),
+ mNr (rhs.mNr),
+ mOldLabel (rhs.mOldLabel),
+ mOldFilename (rhs.mOldFilename),
+ mOriginalRunlevel (rhs.mOriginalRunlevel),
+ mOldNr (rhs.mOldNr),
+ mNrChanged (rhs.mNrChanged),
+ mLabelChanged (rhs.mLabelChanged),
+ mOtherChanged (rhs.mOtherChanged),
+ mFilenameChanged (rhs.mFilenameChanged),
+ mNewEntry (rhs.mNewEntry), mNumberString (rhs.mNumberString)
+{
+}
+
+const KSVData& KSVData::operator= (const KSVData& rhs)
+{
+ if (this ==&rhs)
+ return *this;
+
+ mPath = rhs.mPath;
+ mLabel = rhs.mLabel;
+ mFilename = rhs.mFilename;
+ mRunlevel = rhs.mRunlevel;
+ mNr = rhs.mNr;
+
+ mOldLabel = rhs.mOldLabel;
+ mOldFilename = rhs.mOldFilename;
+ mOriginalRunlevel = rhs.mOriginalRunlevel;
+ mOldNr = rhs.mOldNr;
+
+ mNrChanged = rhs.mNrChanged;
+ mLabelChanged = rhs.mLabelChanged;
+ mOtherChanged = rhs.mOtherChanged;
+ mFilenameChanged = rhs.mFilenameChanged;
+ mNewEntry = rhs.mNewEntry;
+
+ mNumberString = rhs.mNumberString;
+
+ return *this;
+}
+
+bool KSVData::operator== (const KSVData& rhs) const
+{
+ return mLabel == rhs.mLabel &&
+ mPath == rhs.mPath && mFilename == rhs.mFilename;
+ // return mPath == rhs.mPath &&
+ // mLabel == rhs.mLabel &&
+ // mFilename == rhs.mFilename &&
+ // mRunlevel == rhs.mRunlevel &&
+ // mNr == rhs.mNr &&
+
+ // mOldLabel == rhs.mOldLabel &&
+ // mOldFilename == rhs.mOldFilename &&
+ // mOriginalRunlevel == rhs.mOriginalRunlevel &&
+ // mOldNr == rhs.mOldNr &&
+
+ // mNrChanged == rhs.mNrChanged &&
+ // mLabelChanged == rhs.mLabelChanged &&
+ // mOtherChanged == rhs.mOtherChanged &&
+ // mFilenameChanged == rhs.mFilenameChanged &&
+ // mNewEntry == rhs.mNewEntry;
+}
+
+bool KSVData::operator< (const KSVData& rhs) const
+{
+ return mNr< rhs.mNr;
+}
+
+void KSVData::setPath (const QString& s)
+{
+ if (mPath != s)
+ mOtherChanged = true;
+
+ mPath = s;
+}
+
+void KSVData::setLabel (const QString& s)
+{
+ if (!mLabelChanged && mLabel != s)
+ {
+ mOldLabel = mLabel;
+ mLabelChanged = true;
+ }
+
+ mLabel = s;
+}
+
+void KSVData::setFilename (const QString& s)
+{
+ if (!mFilenameChanged && mFilename != s)
+ {
+ mOldFilename = mFilename;
+ mFilenameChanged = true;
+ }
+
+ mFilename = s;
+}
+
+void KSVData::setRunlevel (const QString& s)
+{
+ mRunlevel = s;
+}
+
+void KSVData::setNumber (Q_INT8 nr)
+{
+ if (!mNrChanged && mNr != nr)
+ {
+ mOldNr = mNr;
+ mNrChanged = true;
+ }
+
+ mNr = nr;
+ mNumberString.sprintf ("%.2i", nr);
+}
+
+void KSVData::setChanged (bool val)
+{
+ mNrChanged = mLabelChanged = mOtherChanged = mFilenameChanged = val;
+}
+
+void KSVData::setOriginalRunlevel (const QString& rl)
+{
+ mOriginalRunlevel = rl;
+}
+
+QDataStream& operator<< (QDataStream& stream, const KSVData& data)
+{
+ return stream << data.mPath
+ << data.mFilename
+ << data.mNr
+ << data.mRunlevel
+ << data.mLabel
+ << data.mOldFilename
+ << data.mOldNr
+ << data.mOldLabel
+ << data.mNrChanged
+ << data.mLabelChanged
+ << data.mFilenameChanged
+ << data.mOtherChanged << data.mOriginalRunlevel << data.mNewEntry;
+
+}
+
+QDataStream& operator>> (QDataStream& stream, KSVData& data)
+{
+ stream >> data.mPath
+ >> data.mFilename
+ >> data.mNr
+ >> data.mRunlevel
+ >> data.mLabel
+ >> data.mOldFilename
+ >> data.mOldNr
+ >> data.mOldLabel
+ >> data.mNrChanged
+ >> data.mLabelChanged
+ >> data.mFilenameChanged
+ >> data.mOtherChanged >> data.mOriginalRunlevel >> data.mNewEntry;
+
+
+ data.mNumberString.sprintf ("%.2i", data.mNr);
+
+ return stream;
+}
diff --git a/ksysv/Data.h b/ksysv/Data.h
new file mode 100644
index 0000000..e282346
--- /dev/null
+++ b/ksysv/Data.h
@@ -0,0 +1,79 @@
+// (c) 2000 Peter Putzer
+
+#ifndef KSV_DATA_H
+#define KSV_DATA_H
+
+class QDataStream;
+
+class KSVData
+{
+public:
+ KSVData ();
+ KSVData (const QString& file, const QString& path, const QString& label, Q_INT8 nr);
+ KSVData (const KSVData& rhs);
+ inline ~KSVData () {}
+
+ const KSVData& operator= (const KSVData& rhs);
+ bool operator== (const KSVData& rhs) const;
+ bool operator< (const KSVData& rhs) const;
+
+ inline QString filenameAndPath () const { return mPath + "/" + mFilename; }
+
+ inline const QString& path () const { return mPath; }
+ inline const QString& label () const { return mLabel; }
+ inline const QString& filename () const { return mFilename; }
+ inline const QString& runlevel () const { return mRunlevel; }
+ inline Q_INT8 number () const { return mNr; }
+
+ inline const QString& numberString () const { return mNumberString; }
+
+ inline const QString& oldLabel () const { return mOldLabel; }
+ inline const QString& oldFilename () const { return mOldFilename; }
+ inline const QString& originalRunlevel () const { return mOldFilename; }
+ inline Q_INT8 oldNumber () const { return mOldNr; }
+
+ inline bool numberChanged () const { return mNrChanged; }
+ inline bool labelChanged () const { return mLabelChanged; }
+ inline bool otherChanged () const { return mOtherChanged; }
+ inline bool filenameChanged () const { return mFilenameChanged; }
+ inline bool newEntry () const { return mNewEntry; }
+
+ inline bool changed () const { return mNrChanged || mLabelChanged || mFilenameChanged; }
+
+ inline void setNumberChanged (bool val) { mNrChanged = val; }
+ inline void setNewEntry (bool val) { mNewEntry = val; }
+ void setPath (const QString&);
+ void setLabel (const QString&);
+ void setFilename (const QString&);
+ void setRunlevel (const QString&);
+ void setOriginalRunlevel (const QString&);
+ void setNumber (Q_INT8 nr);
+ void setChanged (bool);
+
+private:
+ friend QDataStream& operator<< (QDataStream&, const KSVData&);
+ friend QDataStream& operator>> (QDataStream&, KSVData&);
+
+ QString mPath;
+ QString mLabel;
+ QString mFilename;
+ QString mRunlevel;
+ Q_INT8 mNr;
+ QString mOldLabel;
+ QString mOldFilename;
+ QString mOriginalRunlevel;
+ Q_INT8 mOldNr;
+
+ bool mNrChanged;
+ bool mLabelChanged;
+ bool mOtherChanged;
+ bool mFilenameChanged;
+ bool mNewEntry;
+
+ QString mNumberString;
+};
+
+QDataStream& operator<< (QDataStream& stream, const KSVData& data);
+QDataStream& operator>> (QDataStream& stream, KSVData& data);
+
+#endif // KSV_DATA_H
diff --git a/ksysv/IOCore.cpp b/ksysv/IOCore.cpp
new file mode 100644
index 0000000..c61dec6
--- /dev/null
+++ b/ksysv/IOCore.cpp
@@ -0,0 +1,291 @@
+/***************************************************************************
+ ksv::IO.cpp - description
+ -------------------
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-2000 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <qfileinfo.h>
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmimemagic.h>
+#include <kservice.h>
+#include <kuserprofile.h>
+
+#include "Data.h"
+#include "IOCore.h"
+#include "ksvdraglist.h"
+#include "ksv_core.h"
+#include "ksv_conf.h"
+
+QString ksv::IO::relToAbs (const QString& dir, const QString& rel)
+{
+ if (rel.left(1) != "/")
+ return QDir::cleanDirPath (dir + "/" + rel);
+ else
+ return QDir::cleanDirPath (rel);
+}
+
+void ksv::IO::removeFile (const QFileInfo& info, QDir& dir, QString& rich, QString& plain)
+{
+ if (!dir.remove(info.fileName(), FALSE))
+ {
+ rich = (i18n ("<error>FAILED</error> to remove <cmd>%1</cmd> from <cmd>%2</cmd>: \"%3\"<br/>")
+ .arg(info.fileName())
+ .arg(dir.path())
+ .arg(strerror(errno)));
+ plain = (i18n ("FAILED to remove %1 from %2: \"%3\"\n")
+ .arg(info.fileName())
+ .arg(dir.path())
+ .arg(strerror(errno)));
+ }
+ else
+ {
+ rich = i18n("removed <cmd>%1</cmd> from <cmd>%2</cmd><br/>")
+ .arg(info.fileName())
+ .arg(dir.path());
+
+ plain = i18n("removed %1 from %2\n")
+ .arg(info.fileName())
+ .arg(dir.path());
+ }
+}
+
+void ksv::IO::dissectFilename (const QString& file, QString& base, int& nr)
+{
+ QString tmp = file.mid(1, file.length());
+
+ nr = tmp.left(2).toInt();
+ base = tmp.mid(2, tmp.length());
+}
+
+void ksv::IO::makeSymlink (const KSVData& data, int runlevel, bool start,
+ QString& rich, QString& plain)
+{
+ const QString symName = QString("%1%2%3").arg(start ? "S" : "K").arg(data.numberString()).arg(data.label());
+ const QString symPath = QString("%1/rc%2.d/").arg(KSVConfig::self()->runlevelPath()).arg(runlevel);
+
+ const QString symbol = symPath + symName;
+ QString target = data.filename();
+
+ if (QDir::isRelativePath(target))
+ target = ksv::IO::makeRelativePath(QDir::cleanDirPath(symPath),
+ QDir::cleanDirPath(data.path())) + data.filename();
+
+ if (symlink(target.local8Bit(), symbol.local8Bit()) == 0)
+ {
+ rich = i18n("created <cmd>%1</cmd> in <cmd>%2</cmd><br/>").arg(symName).arg(symPath);
+ plain = i18n("created %1 in %2\n").arg(symName).arg(symPath);
+ }
+ else
+ {
+ rich = i18n("<error>FAILED</error> to create <cmd>%1</cmd> in <cmd>%2</cmd>: \"%3\"<br/>")
+ .arg(symName)
+ .arg(symPath)
+ .arg(strerror(errno));
+
+ plain = i18n("FAILED to create %1 in %2: \"%3\"\n")
+ .arg(symName)
+ .arg(symPath)
+ .arg(strerror(errno));
+ }
+}
+
+QString ksv::IO::makeRelativePath (const QString& from, const QString& to)
+{
+ if (QDir::isRelativePath(from) || QDir::isRelativePath(to))
+ return QString::null;
+
+ int pos = 0;
+ const int f_length = from.length();
+
+ QStringList from_list;
+ while (pos > -1)
+ {
+ const int old = pos + 1;
+ const int res = from.find('/', old);
+
+ int length = 0;
+
+ if (res > -1)
+ length = res - old + 1;
+ else
+ length = f_length - old;
+
+ from_list.append (from.mid(old, length));
+
+ pos = res;
+ }
+
+ const int t_length = to.length();
+
+ QStringList to_list;
+ pos = 0;
+
+ while (pos > -1)
+ {
+ const int old = pos + 1;
+ const int res = to.find('/', old);
+
+ int length = 0;
+
+ if (res > -1)
+ length = res - old + 1;
+ else
+ length = t_length - old;
+
+ to_list.append (to.mid(old, length));
+
+ pos = res;
+ }
+
+ int lcp = 0; // longest common prefix
+ const int f_c = from_list.count();
+ const int t_c = to_list.count();
+
+ while (lcp < f_c && lcp < t_c
+ && *from_list.at(lcp) == *to_list.at(lcp))
+ lcp++;
+
+ QString result;
+ for (int i = f_c - lcp; i > 0; --i)
+ result += "../";
+
+ for (int i = lcp; i < t_c; ++i)
+ result += *to_list.at(i) + "/";
+
+ return result;
+}
+
+bool ksv::IO::loadSavedConfiguration (QDataStream& s,
+ QValueList<KSVData>* start,
+ QValueList<KSVData>* stop)
+{
+ QCString magic;
+ s >> magic;
+ if (magic != "KSysV")
+ return false;
+
+ Q_INT32 version = 0;
+ s >> version;
+
+ if (version != 3)
+ return false; // too old
+
+ QDateTime saveTime;
+ s >> saveTime;
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ QString rlMagic;
+ QString section;
+
+ s >> rlMagic;
+ s >> section;
+
+ if (rlMagic != QString::fromLatin1("RUNLEVEL %1").arg(i))
+ return false;
+
+ if (section != "START")
+ return false;
+
+ Q_INT32 numberOfItems;
+ s >> numberOfItems;
+
+ KSVData data;
+ for (int j = 0; j < numberOfItems; ++j)
+ {
+ s >> data;
+ start[i].append (data);
+ }
+
+ s >> section;
+ if (section != "STOP")
+ return false;
+
+ s >> numberOfItems;
+ for (int j = 0; j < numberOfItems; ++j)
+ {
+ s >> data;
+ stop[i].append(data);
+ }
+ }
+
+ return true;
+}
+
+bool ksv::IO::saveConfiguration (QDataStream& s,
+ KSVDragList** start,
+ KSVDragList** stop)
+{
+ Q_INT32 version = 3;
+
+ s << QCString("KSysV")
+ << version
+ << QDateTime::currentDateTime(); // save date
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ Q_INT32 numberOfItems = start[i]->childCount();
+
+ s << QString::fromLatin1 ("RUNLEVEL %1").arg (i)
+ << QString::fromLatin1 ("START")
+ << numberOfItems;
+
+ for (QListViewItemIterator it (start[i]);
+ it.current();
+ ++it)
+ {
+ s << *static_cast<KSVItem*> (it.current())->data();
+ }
+
+ numberOfItems = stop[i]->childCount();
+
+ s << QString::fromLatin1 ("STOP")
+ << numberOfItems;
+
+ for (QListViewItemIterator it (stop[i]);
+ it.current();
+ ++it)
+ {
+ s << *static_cast<KSVItem*> (it.current())->data();
+ }
+ }
+
+ return true;
+}
+
+KTrader::OfferList ksv::IO::servicesForFile (const QString& filename)
+{
+ static KTrader* trader = KTrader::self();
+ static KMimeMagic* magic = KMimeMagic::self();
+ const QString mimetype = magic->findFileType(filename)->mimeType();
+
+ return trader->query (mimetype, "Type == 'Application'");
+}
+
+KService::Ptr ksv::IO::preferredServiceForFile (const QString& filename)
+{
+ static KMimeMagic* magic = KMimeMagic::self();
+ const QString mimetype = magic->findFileType(filename)->mimeType();
+
+ return KServiceTypeProfile::preferredService (mimetype, "Application");
+}
diff --git a/ksysv/IOCore.h b/ksysv/IOCore.h
new file mode 100644
index 0000000..37ac4e5
--- /dev/null
+++ b/ksysv/IOCore.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ ksv::IO.h - description
+ -------------------
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_IOCORE_H
+#define KSV_IOCORE_H
+
+#include <qdir.h>
+#include <qstring.h>
+
+#include <ktrader.h>
+#include <kservice.h>
+
+template<class T> class QValueList;
+class QFileInfo;
+class QDataStream;
+
+class KSVDragList;
+class KSVData;
+
+namespace ksv
+{
+ namespace IO
+ {
+ void removeFile (const QFileInfo& info, QDir& dir,
+ QString& rich, QString& plain);
+
+ QString relToAbs (const QString& dir, const QString& rel);
+
+ void makeSymlink (const KSVData& data, int runlevel, bool start,
+ QString& rich, QString& plain);
+
+ void dissectFilename (const QString& file, QString& name, int& nr);
+
+ QString makeRelativePath (const QString& from, const QString& to);
+
+ bool saveConfiguration (QDataStream&,
+ KSVDragList** start,
+ KSVDragList** stop);
+
+ bool loadSavedConfiguration (QDataStream&,
+ QValueList<KSVData>* start,
+ QValueList<KSVData>* stop);
+
+ KTrader::OfferList servicesForFile (const QString& filename);
+ KService::Ptr preferredServiceForFile (const QString& filename);
+
+ } // namespace IO
+} // namespace ksv
+
+#endif
+
diff --git a/ksysv/Makefile.am b/ksysv/Makefile.am
new file mode 100644
index 0000000..5e8ff78
--- /dev/null
+++ b/ksysv/Makefile.am
@@ -0,0 +1,84 @@
+INCLUDES= $(all_includes)
+SUBDIRS = pics toolbar
+KDE_ICON=AUTO
+xdg_apps_DATA = ksysv.desktop
+
+bin_PROGRAMS = ksysv
+# Which sources should be compiled for ksysv.
+ksysv_SOURCES = main.cpp \
+ ActionList.cpp \
+ IOCore.cpp \
+ ksvdraglist.cpp \
+ RunlevelAuthIcon.cpp \
+ OldView.cpp \
+ Properties.cpp \
+ SpinBox.cpp \
+ ServiceDlg.cpp \
+ TopWidget.cpp \
+ Data.cpp \
+ ksv_conf.cpp \
+ ksvapplication.cpp \
+ kdltooltip.cpp \
+ ksv_core.cpp \
+ ksvdrag.cpp \
+ kscroller.cpp \
+ ksv_service.cpp \
+ leveldb.c \
+ PreferencesDialog.cpp \
+ trash.cpp \
+ pathconfig.ui \
+ ksvpathconfig.cpp \
+ miscconfig.ui \
+ ksvmiscconfig.cpp \
+ lookandfeelconfig.ui \
+ ksvlookandfeel.cpp \
+ configwizard.ui \
+ ksvconfigwizard.cpp \
+ kbusymanager.cpp
+
+# the library search path
+ksysv_METASOURCES = AUTO
+ksysv_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+ksysv_LDADD = $(LIB_KFILE) -lkdeprint
+
+# this option you can leave out. Just, if you use "make dist", you need it
+noinst_HEADERS = ActionList.h \
+ IOCore.h \
+ OldView.h \
+ Properties.h \
+ SpinBox.h \
+ Data.h \
+ ksvapplication.h \
+ ServiceDlg.h \
+ TopWidget.h \
+ kdltooltip.h \
+ ksvdrag.h \
+ ksv_service.h \
+ ksv_conf.h \
+ RunlevelAuthIcon.h \
+ ksv_core.h \
+ kscroller.h \
+ ksvdraglist.h \
+ leveldb.h \
+ PreferencesDialog.h \
+ trash.h \
+ ksvpathconfig.h \
+ ksvmiscconfig.h \
+ ksvlookandfeel.h \
+ ksvconfigwizard.h \
+ kbusymanager.h \
+ version.h
+
+# just to make sure, automake makes them
+
+messages: rc.cpp
+ $(XGETTEXT) -C *.cpp -o $(podir)/ksysv.pot
+
+rcdir = $(kde_datadir)/ksysv
+rc_DATA = ksysvui.rc
+
+kdemime_DATA = x-ksysv.desktop
+kdemimedir = $(kde_mimedir)/application
+
+textmime_DATA = x-ksysv-log.desktop
+textmimedir= $(kde_mimedir)/text
diff --git a/ksysv/OldView.cpp b/ksysv/OldView.cpp
new file mode 100644
index 0000000..6e9f7d3
--- /dev/null
+++ b/ksysv/OldView.cpp
@@ -0,0 +1,1150 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-2000 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+/*****************************************
+ ** **
+ ** Main Widget **
+ ** **
+ *****************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qprogressdialog.h>
+#include <qkeycode.h>
+#include <qmessagebox.h>
+#include <qgroupbox.h>
+#include <qaccel.h>
+#include <qscrollbar.h>
+#include <qtextedit.h>
+#include <qcstring.h>
+#include <qclipboard.h>
+#include <qheader.h>
+#include <qlabel.h>
+#include <qstylesheet.h>
+#include <qwhatsthis.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qvaluelist.h>
+#include <qsplitter.h>
+#include <qmap.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kcursor.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kaboutdata.h>
+#include <kdialog.h>
+#include <kdirwatch.h>
+#include <kcompletion.h>
+#include <krun.h>
+#include <kopenwith.h>
+#include <kmimemagic.h>
+
+#include "kbusymanager.h"
+#include "Properties.h"
+#include "kscroller.h"
+#include "IOCore.h"
+#include "ksvdraglist.h"
+#include "ksvdrag.h"
+#include "trash.h"
+#include "ksv_core.h"
+#include "ksv_conf.h"
+#include "OldView.h"
+#include "ActionList.h"
+#include "TopWidget.h"
+
+KSVContent::KSVContent (KPopupMenu* openWithMenu, KSVTopLevel* parent, const char* name)
+ : QSplitter (QSplitter::Vertical, parent, name),
+ startRL (new KSVDragList*[ksv::runlevelNumber]),
+ stopRL (new KSVDragList*[ksv::runlevelNumber]),
+ conf(KSVConfig::self()),
+ mScriptBox (0L),
+ mRunlevels (new QVBox*[ksv::runlevelNumber]),
+ mOrigin (0L),
+ mOpenWithMenu (openWithMenu), m_buffer( QCString() )
+{
+ setOpaqueResize( KGlobalSettings::opaqueResize() );
+
+ KXMLGUIFactory* factory = parent->factory();
+ mItemMenu = static_cast<KPopupMenu*> (factory->container ("item_menu", parent));
+ mItemMenu->insertTitle (i18n ("Runlevel Menu"), -1, 0);
+ mContextMenu = static_cast<KPopupMenu*> (factory->container ("list_menu", parent));
+ mContextMenu->insertTitle (i18n ("Runlevel Menu"), -1, 0);
+ mScriptMenu = static_cast<KPopupMenu*> (factory->container ("script_menu", parent));
+ mScriptMenu->insertTitle (i18n ("Services Menu"), -1, 0);
+
+ mScroller = new KScroller (this);
+ mContent = new QFrame(mScroller, "KSysV Real Content");
+
+ mScroller->setContent (mContent);
+
+ initLList();
+
+ // watch services dir
+ KDirWatch* dirwatch = KDirWatch::self();
+ dirwatch->addDir (conf->scriptPath ());
+ connect (dirwatch, SIGNAL (dirty (const QString&)),
+ this, SLOT (updateServicesAfterChange (const QString&)));
+ connect (dirwatch, SIGNAL (created (const QString&)),
+ this, SLOT (updateServicesAfterChange (const QString&)));
+ connect (dirwatch, SIGNAL (deleted (const QString&)),
+ this, SLOT (updateServicesAfterChange (const QString&)));
+
+ setSizes(KSVContent::panningFactorToSplitter (conf->panningFactor()));
+
+ // someone must have focus
+ scripts->setFocus();
+
+ // show/hide everything
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ if (conf->showRunlevel (i))
+ mRunlevels[i]->show();
+ else
+ mRunlevels[i]->hide();
+ }
+
+ textDisplay->setStyleSheet (ksv::styleSheet());
+
+ // Open With... menu
+ connect (mOpenWithMenu, SIGNAL (activated (int)), this, SLOT (openWith (int)));
+
+ calcMinSize();
+}
+
+KSVContent::~KSVContent()
+{
+ delete[] mRunlevels;
+
+ delete[] startRL;
+ delete[] stopRL;
+ delete scripts;
+ delete trash;
+ delete textDisplay ;
+
+}
+
+void KSVContent::updateServicesAfterChange (const QString& dir)
+{
+ if (!dir.startsWith(conf->scriptPath()))
+ return;
+
+ // const bool enabled = scripts->isEnabled ();
+ initScripts();
+}
+
+void KSVContent::updateRunlevelsAfterChange ()
+{
+ // MUTEX
+ KBusyManager::self()->setBusy (true);
+
+ // int i = 0;
+ for (int i = 0; i < ksv::runlevelNumber; ++i) {
+ startRL[i]->setEnabled(false);
+ startRL[i]->clear();
+
+ stopRL[i]->setEnabled(false);
+ stopRL[i]->clear();
+ }
+
+ initRunlevels();
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ startRL[i]->setEnabled(true);
+ stopRL[i]->setEnabled(true);
+ }
+
+ // refresh GUI
+ qApp->processEvents();
+
+ scripts->setFocus();
+
+ KBusyManager::self()->restore();
+}
+
+void KSVContent::initLList()
+{
+ QHBoxLayout *lay = new QHBoxLayout( mContent, KDialog::marginHint(), KDialog::spacingHint() );
+ mScriptBox = new QVBox (mContent);
+ lay->addWidget(mScriptBox);
+ mScriptBox->setSpacing (KDialog::spacingHint());
+
+ QVBox* scriptLabelBox = new QVBox (mScriptBox);
+ QLabel* servL = new QLabel (i18n("&Available\n" \
+ "Services"), scriptLabelBox);
+
+ // provide quickhelp
+ QWhatsThis::add (scriptLabelBox,
+ i18n("<p>These are the <img src=\"small|exec\"/> <strong>services</strong> available on your computer. " \
+ "To start a service, drag it onto the <em>Start</em> " \
+ "section of a runlevel.</p>" \
+ "<p>To stop one, do the same for the <em>Stop</em> section.</p>"));
+
+
+ QFont bold_font = QFont(KGlobalSettings::generalFont());
+ bold_font.setBold(TRUE);
+ servL->setFont(bold_font);
+
+ scripts = new KServiceDragList (scriptLabelBox, "Scripts");
+ scripts->setAcceptDrops (false);
+ scripts->setColumnWidthMode (KSVItem::SortNumber, QListView::Manual);
+ scripts->setColumnWidth(KSVItem::SortNumber,0);
+ scripts->setSorting (KSVItem::ServiceName);
+ scripts->header()->setResizeEnabled (false, 0);
+
+ scripts->setDefaultIcon (SmallIcon("exec"));
+ mOrigin = scripts;
+
+ // setBuddy
+ servL->setBuddy(scripts);
+
+ // doubleclick && return
+ connect (scripts, SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotScriptProperties(QListViewItem*)));
+ connect (scripts, SIGNAL (returnPressed (QListViewItem*)),
+ this, SLOT (slotScriptProperties (QListViewItem*)));
+
+ // context menus
+ connect (scripts, SIGNAL (contextMenu (KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT (popupServicesMenu (KListView*, QListViewItem*, const QPoint&)));
+
+ // for cut & copy
+ connect (scripts, SIGNAL (newOrigin ()),
+ this, SLOT (fwdOrigin ()));
+
+ // for origin updates
+ connect (scripts, SIGNAL (newOrigin (KSVDragList*)),
+ this, SLOT (fwdOrigin (KSVDragList*)));
+
+ trash = new KSVTrash(mScriptBox, "Trash");
+ connect (trash, SIGNAL (undoAction (KSVAction*)), this, SLOT (fwdUndoAction (KSVAction*)));
+ QWhatsThis::add (trash,
+ i18n ("<p>You can drag services from a runlevel onto " \
+ "the <img src=\"small|trash\"/> <strong>trashcan</strong> to " \
+ "delete them from that runlevel.</p><p>The <strong>Undo command</strong> "\
+ "can be used to restore deleted entries.</p>"));
+
+ for(int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ mRunlevels[i] = new QVBox (mContent);
+ lay->addWidget(mRunlevels[i]);
+ mRunlevels[i]->setSpacing (KDialog::spacingHint());
+
+ // create QString for label
+ QString _label (i18n("Runlevel &%1").arg(i));
+ // and for the name
+ QString _name (i18n("Runlevel %1").arg(i));
+
+ QVBox* startBox = new QVBox (mRunlevels[i]);
+ QWhatsThis::add (startBox,
+ i18n("<p>These are the services <strong>started</strong> in runlevel %1.</p>" \
+ "<p>The number shown on the left of the <img src=\"user|ksysv_start\"/> icon " \
+ "determines the order in which the services are started. " \
+ "You can arrange them via drag and drop, as long as a suitable " \
+ "<em>sorting number</em> can be generated.</p><p>If that's not possible, you have " \
+ "to change the number manually via the <strong>Properties dialog box</strong>.</p>").arg(i));
+
+ QLabel* rlL = new QLabel(_label, startBox);
+ new QLabel(i18n("Start"), startBox);
+ rlL->setFont(bold_font);
+
+ // create the "START" list:
+ startRL[i] = new KSVDragList(startBox, (_name + " START").latin1());
+ startRL[i]->setDefaultIcon(SmallIcon("ksysv_start"));
+
+ QVBox* stopBox = new QVBox (mRunlevels[i]);
+ new QLabel(i18n("Stop"), stopBox);
+ QWhatsThis::add (stopBox,
+ i18n("<p>These are the services <strong>stopped</strong> in runlevel %1.</p>" \
+ "<p>The number shown on the left of the <img src=\"user|ksysv_stop\"/> icon " \
+ "determines the order in which the services are stopped. " \
+ "You can arrange them via drag and drop, as long as a suitable " \
+ "<em>sorting number</em> can be generated.</p><p>If that's not possible, you have " \
+ "to change the number manually via the <strong>Properties dialog box</strong>.</p>").arg(i));
+
+ // create the "STOP" list:
+ stopRL[i] = new KSVDragList(stopBox, (_name + " STOP").latin1());
+ stopRL[i]->setDefaultIcon(SmallIcon("ksysv_stop"));
+
+ // set the buddy widget for the "Runlevel %i" label... => the corresponding runlevel
+ rlL->setBuddy(startRL[i]);
+
+ // for cut'n'paste
+ connect (startRL[i], SIGNAL (newOrigin ()),
+ this, SLOT (fwdOrigin ()));
+ connect (startRL[i], SIGNAL (newOrigin (KSVDragList*)),
+ this, SLOT (fwdOrigin (KSVDragList*)));
+
+ connect (stopRL[i], SIGNAL (newOrigin ()),
+ this, SLOT (fwdOrigin ()));
+ connect (stopRL[i], SIGNAL (newOrigin (KSVDragList*)),
+ this, SLOT (fwdOrigin (KSVDragList*)));
+ }
+
+ lay->addStretch(1);
+
+ connect (scripts, SIGNAL(undoAction(KSVAction*)),
+ this, SLOT(fwdUndoAction(KSVAction*)));
+
+ // add text-diplay widget
+ textDisplay = new QTextEdit( QString::null, QString::null, this, "TextDisplayWidget" );
+ textDisplay->setTextFormat( Qt::RichText );
+ textDisplay->setReadOnly( true );
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ connect (startRL[i], SIGNAL(newOrigin()), stopRL[i], SLOT(slotNewOrigin()));
+ connect (stopRL[i], SIGNAL(newOrigin()), startRL[i], SLOT(slotNewOrigin()));
+
+ connect (startRL[i], SIGNAL(undoAction(KSVAction*)),
+ this, SLOT(fwdUndoAction(KSVAction*)));
+ connect (stopRL[i], SIGNAL(undoAction(KSVAction*)),
+ this, SLOT(fwdUndoAction(KSVAction*)));
+
+ // doubleclick && return
+ connect (startRL[i], SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotDoubleClick(QListViewItem*)));
+ connect (stopRL[i], SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotDoubleClick(QListViewItem*)));
+ connect (startRL[i], SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(slotDoubleClick(QListViewItem*)));
+ connect (stopRL[i], SIGNAL(returnPressed(QListViewItem*)),
+ this, SLOT(slotDoubleClick(QListViewItem*)));
+
+ // context menus
+ connect (startRL[i], SIGNAL (contextMenu (KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT (popupRunlevelMenu (KListView*, QListViewItem*, const QPoint&)));
+ connect (stopRL[i], SIGNAL (contextMenu (KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT (popupRunlevelMenu (KListView*, QListViewItem*, const QPoint&)));
+
+ // cannot generate sorting number
+ connect (startRL[i], SIGNAL(cannotGenerateNumber()),
+ this, SLOT(fwdCannotGenerateNumber()));
+ connect (stopRL[i], SIGNAL(cannotGenerateNumber()),
+ this, SLOT(fwdCannotGenerateNumber()));
+
+ // connecting origin things for "Scripts", too
+ connect (scripts, SIGNAL(newOrigin()), startRL[i], SLOT(slotNewOrigin()));
+ connect (scripts, SIGNAL(newOrigin()), stopRL[i], SLOT(slotNewOrigin()));
+ connect (startRL[i], SIGNAL(newOrigin()), scripts, SLOT(slotNewOrigin()));
+ connect (stopRL[i], SIGNAL(newOrigin()), scripts, SLOT(slotNewOrigin()));
+
+ // use this loop for setting tooltips
+ startRL[i]->setToolTip (i18n("Drag here to start services\n" \
+ "when entering runlevel %1").arg(i));
+ stopRL[i]->setToolTip (i18n("Drag here to stop services\n" \
+ "when entering runlevel %1").arg(i));
+
+ for (int j = 0; j < ksv::runlevelNumber; ++j)
+ {
+ if (i != j)
+ {
+ connect (startRL[i], SIGNAL (newOrigin()), startRL[j], SLOT (slotNewOrigin()));
+ connect (stopRL[i], SIGNAL (newOrigin()), stopRL[j], SLOT (slotNewOrigin()));
+
+ connect (startRL[i], SIGNAL(newOrigin()), stopRL[j], SLOT(slotNewOrigin()));
+ connect (stopRL[i], SIGNAL(newOrigin()), startRL[j], SLOT(slotNewOrigin()));
+ }
+ }
+ }
+}
+
+void KSVContent::fwdUndoAction (KSVAction* a)
+{
+ emit undoAction(a);
+}
+
+void KSVContent::initScripts() {
+ QDir scriptDir = QDir(conf->scriptPath());
+ if (!scriptDir.exists())
+ return;
+
+ scriptDir.setFilter (QDir::Files | QDir::Hidden |
+ QDir::NoSymLinks | QDir::Executable);
+
+ scriptDir.setSorting (QDir::Name);
+
+ // const QFileInfoList *scriptList = scriptDir.entryInfoList();
+ QFileInfoListIterator it (*scriptDir.entryInfoList());
+
+ KCompletion* comp = ksv::serviceCompletion();
+ comp->clear ();
+
+ // clear the listview
+ scripts->setEnabled(false);
+ scripts->clear();
+
+ QFileInfo* fi; QString name;
+ while ((fi = it.current()))
+ {
+ name = fi->fileName();
+ scripts->initItem(name,
+ ksv::IO::relToAbs(conf->scriptPath(), fi->dirPath(FALSE)),
+ name, 0);
+
+ comp->addItem (name);
+
+ ++it;
+
+ // keep GUI alive
+ qApp->processEvents();
+ }
+
+ scripts->setEnabled(true);
+ scripts->setToolTip (i18n("The services available on your computer"));
+}
+
+void KSVContent::initRunlevels()
+{
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ // clear the listviews
+ startRL[i]->clear();
+ stopRL[i]->clear();
+
+ const QString _path = conf->runlevelPath() + QString("/rc%1.d").arg(i);
+
+ if (!QDir(_path).exists())
+ continue;
+
+ QDir d = QDir(_path);
+ d.setFilter( QDir::Files );
+ d.setSorting( QDir::Name );
+
+ const QFileInfoList *rlList = d.entryInfoList();
+ QFileInfoListIterator it( *rlList ); // create list iterator
+ QFileInfo* fi; // pointer for traversing
+
+ while ( (fi=it.current()) )
+ { // for each file...
+ info2Widget( fi, i);
+ ++it; // goto next list element
+
+ // keep GUI alive
+ qApp->processEvents();
+ }
+ }
+}
+
+void KSVContent::info2Widget( QFileInfo* info, int index )
+{
+ if (!info->exists())
+ return;
+
+ QString f_name = info->fileName();
+
+ QFileInfo link_info = QFileInfo(info->readLink());
+ QString l_base = link_info.fileName();
+
+ QString l_path = ksv::IO::relToAbs(conf->scriptPath(), link_info.dirPath(FALSE));
+
+ QString name;
+ int number;
+ ksv::IO::dissectFilename( f_name, name, number );
+
+ // finally insert the items...
+ if ( f_name.left(1) == "S" )
+ startRL[index]->initItem( l_base, l_path, name, number );
+ else
+ stopRL[index]->initItem( l_base, l_path, name, number );
+}
+
+void KSVContent::slotWriteSysV()
+{
+ appendLog(i18n("<vip>WRITING CONFIGURATION</vip>"),
+ i18n("** WRITING CONFIGURATION **"));
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ appendLog(i18n("<rl>RUNLEVEL %1</rl>").arg(i),
+ i18n("** RUNLEVEL %1 **").arg(i));
+
+ clearRL(i); // rm changed/deleted entries
+
+ // process "Start"
+ KSVItem* item = 0L;
+ for (QListViewItemIterator it (startRL[i]);
+ (item = static_cast<KSVItem*> (it.current()));
+ ++it)
+ {
+ if (item->isChanged() || item->isNew())
+ writeToDisk (*item->data(), i, true);
+ }
+
+ // process "Stop"
+ for (QListViewItemIterator it (stopRL[i]);
+ (item = static_cast<KSVItem*> (it.current()));
+ ++it)
+ {
+ if (item->isChanged() || item->isNew())
+ writeToDisk (*item->data(), i, false);
+ }
+
+ appendLog("<br/><br/>", "\n");
+ }
+
+ appendLog("<br/>", "");
+}
+
+void KSVContent::writeToDisk(const KSVData& _w, int _rl, bool _start) {
+ QString rich, plain;
+ ksv::IO::makeSymlink (_w, _rl, _start, rich, plain);
+ appendLog(rich, plain);
+}
+
+void KSVContent::repaintRunlevels ()
+{
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ startRL[i]->triggerUpdate();
+ stopRL[i]->triggerUpdate();
+ }
+
+ scripts->triggerUpdate();
+}
+
+void KSVContent::clearRL(int _rl)
+{
+ QString path = conf->runlevelPath() + QString("/rc%1.d").arg(_rl);
+
+ QDir dir (path);
+
+ KSVData* d = 0L;
+
+ for (QPtrListIterator<KSVData> it (startRL[_rl]->getDeletedItems());
+ (d = it.current());
+ ++it)
+ {
+ // ugly hack -> dont try to delete if entry is new (i.e. not save to disk)
+ if (d->newEntry() && d->originalRunlevel() != startRL[_rl]->name())
+ break;
+
+ QFileInfo file (path + QString("/S%1%2").arg(d->numberString()).arg(d->label()));
+
+ QString rich, plain;
+ ksv::IO::removeFile (file, dir, rich, plain);
+ appendLog(rich, plain);
+ }
+
+ // keep GUI alive
+ qApp->processEvents();
+
+ for (QPtrListIterator<KSVData> it (stopRL[_rl]->getDeletedItems());
+ (d = it.current());
+ ++it)
+ {
+ // ugly, too
+ if (d->newEntry() && d->originalRunlevel() != stopRL[_rl]->name())
+ break;
+
+ QFileInfo file (path + QString("/K%1%2").arg(d->numberString()).arg(d->label()));
+
+ QString rich, plain;
+ ksv::IO::removeFile (file, dir, rich, plain);
+ appendLog(rich, plain);
+ }
+
+ // keep GUI alive
+ qApp->processEvents();
+}
+
+void KSVContent::infoOnData (KSVItem* item)
+{
+ KSVData oldState = *item->data();
+ KSVData newState = oldState;
+ KSVEntryPropertiesDialog* props = new KSVEntryPropertiesDialog (newState, kapp->mainWidget());
+
+ connect (props, SIGNAL (editService (const QString&)),
+ this, SLOT (editService (const QString&)));
+ connect (props, SIGNAL (startService (const QString&)),
+ this, SLOT (startService (const QString&)));
+ connect (props, SIGNAL (stopService (const QString&)),
+ this, SLOT (stopService (const QString&)));
+ connect (props, SIGNAL (restartService (const QString&)),
+ this, SLOT (restartService (const QString&)));
+
+ int res = props->exec();
+
+ if (res == QDialog::Accepted
+ && !(oldState == newState && oldState.number() == newState.number()))
+ {
+ item->copy (newState);
+
+ reSortRL();
+
+ emit undoAction(new ChangeAction(getOrigin(), &oldState, &newState));
+ }
+}
+
+void KSVContent::stopService ()
+{
+ KSVContent::stopService (getOrigin()->currentItem()->filenameAndPath());
+}
+
+void KSVContent::stopService (const QString& path)
+{
+ KProcess *_proc = new KProcess();
+ _proc->clearArguments();
+
+ *_proc << path << "stop";
+
+ connect(_proc, SIGNAL(processExited(KProcess*)), this, SLOT(slotExitedProcess(KProcess*)));
+ connect(_proc, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+ connect(_proc, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+
+ // refresh textDisplay
+ appendLog(i18n("** <stop>Stopping</stop> <cmd>%1</cmd> **<br/>").arg(path),
+ i18n("** Stopping %1 **").arg(path));
+
+ _proc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
+
+ // notify parent
+ emit sigRun(path + i18n(" stop"));
+}
+
+void KSVContent::startService ()
+{
+ KSVContent::startService (getOrigin()->currentItem()->filenameAndPath());
+}
+
+void KSVContent::startService (const QString& path)
+{
+ KProcess* _proc = new KProcess();
+ _proc->clearArguments();
+
+ *_proc << path << "start";
+
+ connect(_proc, SIGNAL(processExited(KProcess*)), this, SLOT(slotExitedProcess(KProcess*)));
+ connect(_proc, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+ connect(_proc, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+
+ // refresh textDisplay
+ appendLog(i18n("** <start>Starting</start> <cmd>%1</cmd> **<br/>").arg(path),
+ i18n("** Starting %1 **").arg(path));
+
+ _proc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
+
+ // notify parent
+ emit sigRun(path + i18n(" start"));
+}
+
+void KSVContent::editService()
+{
+ editService (getOrigin()->currentItem()->filenameAndPath());
+}
+
+void KSVContent::editService (const QString& path)
+{
+ // unfortunately KRun::run() only takes an URL-list instead of a single
+ // URL as an argument.
+ KURL url; url.setPath (path); KURL::List urls; urls << url;
+ KRun::run (*ksv::IO::preferredServiceForFile (path), urls);
+}
+
+void KSVContent::restartService ()
+{
+ KSVContent::restartService (getOrigin()->currentItem()->filenameAndPath());
+}
+
+void KSVContent::restartService (const QString& path)
+{
+ // restarting
+ KProcess *_proc = new KProcess();
+ _proc->clearArguments();
+
+ *_proc << path << "restart";
+
+ connect(_proc, SIGNAL(processExited(KProcess*)), this, SLOT(slotExitDuringRestart(KProcess*)));
+ connect(_proc, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+ connect(_proc, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+
+ // refresh textDisplay
+ appendLog(i18n("** Re-starting <cmd>%1</cmd> **</br>").arg(path),
+ i18n("** Re-starting %1 **").arg(path));
+
+ _proc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
+
+ // notify parent
+ emit sigRun(path + i18n(" restart"));
+}
+
+void KSVContent::slotOutputOrError( KProcess*, char* _buffer, int _buflen) {
+ if (_buflen > 0) {
+ m_buffer += QCString( _buffer, _buflen + 1 );
+ appendLog( m_buffer );
+ }
+}
+
+void KSVContent::slotExitedProcess( KProcess* proc ) {
+ appendLog("<hr/>", "--------------");
+
+ emit sigStop();
+ delete proc;
+}
+
+void KSVContent::slotScriptsNotRemovable()
+{
+ emit sigNotRemovable();
+}
+
+void KSVContent::slotDoubleClick (QListViewItem* item) {
+ infoOnData(static_cast<KSVItem*>(item));
+}
+
+void KSVContent::slotScriptProperties(QListViewItem* item)
+{
+ KSVServicePropertiesDialog* prop =
+ new KSVServicePropertiesDialog (*static_cast<KSVItem*> (item)->data(), kapp->mainWidget());
+
+ connect (prop, SIGNAL (editService (const QString&)),
+ this, SLOT (editService (const QString&)));
+ connect (prop, SIGNAL (startService (const QString&)),
+ this, SLOT (startService (const QString&)));
+ connect (prop, SIGNAL (stopService (const QString&)),
+ this, SLOT (stopService (const QString&)));
+ connect (prop, SIGNAL (restartService (const QString&)),
+ this, SLOT (restartService (const QString&)));
+
+ prop->exec();
+
+ // delete prop;
+}
+
+void KSVContent::slotExitDuringRestart( KProcess* proc )
+{
+ delete proc;
+ proc = new KProcess(); // necessary because otherwise we still have some
+ // signals connected that screw up our output
+ proc->clearArguments();
+
+ connect(proc, SIGNAL(processExited(KProcess*)), this, SLOT(slotExitedProcess(KProcess*)));
+ connect(proc, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+ connect(proc, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotOutputOrError(KProcess*, char*, int)));
+
+ proc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
+}
+
+KSVDragList* KSVContent::getOrigin()
+{
+ return mOrigin;
+}
+
+void KSVContent::setDisplayScriptOutput(bool val)
+{
+ if (val)
+ {
+ setSizes(KSVContent::panningFactorToSplitter (conf->panningFactor()));
+ textDisplay->show();
+ }
+ else
+ {
+ conf->setPanningFactor (KSVContent::splitterToPanningFactor (sizes()));
+ textDisplay->hide();
+ }
+
+ calcMinSize();
+}
+
+int KSVContent::splitterToPanningFactor (const QValueList<int>& list)
+{
+ const int cont_size = *list.at(0);
+ const int log_size = *list.at(1);
+
+ return cont_size * 100 / (cont_size + log_size);
+}
+
+const QValueList<int>& KSVContent::panningFactorToSplitter (int panningFactor)
+{
+ static QValueList<int> res;
+ res.clear();
+
+ res << panningFactor << 100 - panningFactor;
+
+ return res;
+}
+
+void KSVContent::appendLog (const QString& rich, const QString& plain)
+{
+ static bool changed = false;
+
+ if (!changed)
+ {
+ changed = true;
+ emit logChanged();
+ }
+
+ mLogText += plain + "\n";
+ mXMLLogText += rich + "\n";
+ textDisplay->append (rich);
+}
+
+void KSVContent::appendLog(const QCString& _buffer)
+{
+ QStringList _lines = QStringList::split( "\n", QString::fromLocal8Bit( _buffer ) );
+ for ( QStringList::Iterator it = _lines.begin(); it != _lines.end(); ++it )
+ appendLog( *it, *it );
+
+ m_buffer = QCString();
+}
+
+const QString& KSVContent::log () const
+{
+ return mLogText;
+}
+
+const QString& KSVContent::xmlLog () const
+{
+ return mXMLLogText;
+}
+
+void KSVContent::fwdCannotGenerateNumber() {
+ emit cannotGenerateNumber();
+}
+
+void KSVContent::updatePanningFactor()
+{
+ conf->setPanningFactor(KSVContent::splitterToPanningFactor(sizes()));
+}
+
+void KSVContent::fwdOrigin ()
+{
+ emit newOrigin();
+}
+
+void KSVContent::fwdOrigin (KSVDragList* list)
+{
+ mOrigin = list;
+}
+
+void KSVContent::showEvent (QShowEvent* e)
+{
+ calcMinSize();
+
+ QSplitter::showEvent (e);
+}
+
+void KSVContent::reSortRL()
+{
+ getOrigin()->sort();
+}
+
+void KSVContent::pasteAppend()
+{
+ KSVDragList* list = getOrigin();
+
+ if (list)
+ {
+ KSVData data;
+
+ if (KSVDrag::decodeNative (kapp->clipboard()->data(), data))
+ {
+ KSVAction* action = 0L;
+
+ if (list->insert (data, list->lastItem(), action))
+ {
+ emit undoAction (action);
+ }
+ }
+ }
+}
+
+void KSVContent::resizeEvent (QResizeEvent* e)
+{
+ updatePanningFactor();
+
+ QSplitter::resizeEvent (e);
+}
+
+void KSVContent::moveEvent (QMoveEvent* e)
+{
+ QSplitter::moveEvent (e);
+}
+
+void KSVContent::setColors (const QColor& newNormal,
+ const QColor& newSelected,
+ const QColor& changedNormal,
+ const QColor& changedSelected)
+{
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ startRL[i]->setNewNormalColor (newNormal);
+ startRL[i]->setNewSelectedColor (newSelected);
+ startRL[i]->setChangedNormalColor (changedNormal);
+ startRL[i]->setChangedSelectedColor (changedSelected);
+ startRL[i]->viewport()->update();
+
+ stopRL[i]->setNewNormalColor (newNormal);
+ stopRL[i]->setNewSelectedColor (newSelected);
+ stopRL[i]->setChangedNormalColor (changedNormal);
+ stopRL[i]->setChangedSelectedColor (changedSelected);
+ stopRL[i]->viewport()->update();
+ }
+}
+
+void KSVContent::multiplexEnabled (bool val)
+{
+ QListView* list = getOrigin();
+
+
+ if (list)
+ {
+ list->clearSelection();
+ list->setCurrentItem (0L);
+ }
+
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ startRL[i]->setEnabled (val);
+ startRL[i]->setAcceptDrops (val);
+
+ stopRL[i]->setEnabled (val);
+ stopRL[i]->setAcceptDrops (val);
+ }
+
+ if (!val)
+ {
+ mOrigin = 0L;
+ emit newOrigin ();
+
+ KSVConfig *config = KSVConfig::self();
+ QFileInfo *file = new QFileInfo( config->scriptPath() );
+
+ if ( !file->exists() )
+ {
+ int choice = KMessageBox::warningYesNo
+ (kapp->mainWidget(),
+ i18n ("<p>You have specified that your system's init " \
+ "scripts are located in the folder " \
+ "<tt><b>%1</b></tt>, but this folder does not "\
+ "exist. You probably selected the wrong " \
+ "distribution during configuration.</p> " \
+ "<p>If you reconfigure %2, it may be possible to "\
+ "fix the problem. If you choose to reconfigure, " \
+ "you should shut down the application " \
+ "and the configuration wizard will appear the " \
+ "next time %3 is run. If you choose not to " \
+ "reconfigure, you will not be able to view or " \
+ "edit your system's init configuration.</p>" \
+ "<p>Would you like to reconfigure %4?</p>")
+ .arg (config->scriptPath())
+ .arg (kapp->aboutData()->programName())
+ .arg (kapp->aboutData()->programName())
+ .arg (kapp->aboutData()->programName()),
+ i18n("Folder Does Not Exist"),i18n("Reconfigure"),i18n("Do Not Reconfigure"));
+
+ if ( choice == KMessageBox::Yes )
+ {
+ config->setConfigured(false);
+ config->writeSettings();
+ }
+ }
+ else
+ {
+ KMessageBox::information (kapp->mainWidget(),
+ i18n ("<p>You do not have the right permissions " \
+ "to edit your system's init configuration. " \
+ "However, you are free to browse the runlevels.</p>" \
+ "<p>If you really want to edit the " \
+ "configuration, either <strong>restart</strong> " \
+ "%1 <strong>as root</strong> (or another privileged "\
+ "user), or ask your sysadmin to install %2 " \
+ "<em>suid</em> or <em>sgid</em>.</p>" \
+ "<p>The latter way is not recommended though, " \
+ "due to security issues.</p>")
+ .arg (kapp->aboutData()->programName())
+ .arg (kapp->aboutData()->programName()),
+ i18n("Insufficient Permissions"),
+ ksv::notifications[ksv::RunlevelsReadOnly]);
+ }
+
+ delete file;
+ }
+}
+
+void KSVContent::hideRunlevel (int index)
+{
+ mRunlevels[index]->hide();
+ calcMinSize();
+}
+
+void KSVContent::showRunlevel (int index)
+{
+ mRunlevels[index]->show();
+ calcMinSize();
+}
+
+void KSVContent::popupRunlevelMenu (KListView* list, QListViewItem* i, const QPoint& p)
+{
+ if (i)
+ mItemMenu->exec (p, 1);
+ else
+ {
+ if (!list->header()->rect().contains (list->mapFromGlobal(p)))
+ mContextMenu->exec (p, 1);
+ }
+}
+
+void KSVContent::popupServicesMenu (KListView*, QListViewItem* i, const QPoint& p)
+{
+ if (i)
+ {
+ mOpenWithMenu->clear();
+
+ mOpenWithOffers
+ = ksv::IO::servicesForFile (static_cast<KSVItem*>(i)->filenameAndPath());
+
+ int i = 0;
+ for (KTrader::OfferList::Iterator it = mOpenWithOffers.begin();
+ it != mOpenWithOffers.end();
+ ++it)
+ {
+ mOpenWithMenu->insertItem (SmallIconSet((*it)->icon()), (*it)->name(), i);
+ ++i;
+ }
+
+ if (i >= 1)
+ mOpenWithMenu->insertSeparator();
+
+ mOpenWithMenu->insertItem (i18n ("&Other..."), this, SLOT (openWith()));
+
+ mScriptMenu->exec (p, 1);
+ }
+}
+
+void KSVContent::openWith ()
+{
+ KURL url; url.setPath(static_cast<KSVItem*>(getOrigin()->currentItem())->filenameAndPath());
+ KURL::List urls; urls.append (url);
+
+ KRun::displayOpenWithDialog (urls);
+
+ kdDebug(3000) << "Opening with..." << endl;
+}
+
+void KSVContent::openWith (int index)
+{
+ if (index < 0)
+ return;
+
+ KService::Ptr service = *mOpenWithOffers.at (index);
+ KURL url; url.setPath(static_cast<KSVItem*>(getOrigin()->currentItem())->filenameAndPath());
+ KURL::List urls; urls.append (url);
+
+ KRun::run (*service, urls);
+
+ kdDebug(3000) << "Opening with " << service->exec() << endl;
+}
+
+void KSVContent::calcMinSize ()
+{
+ // Cryptic code alert: Changing w or h will change mMinSize
+ QCOORD& w = mMinSize.rwidth();
+ QCOORD& h = mMinSize.rheight();
+
+ w = 2 * KDialog::marginHint() + mScriptBox->sizeHint().width();
+ h = 2 * KDialog::marginHint() + mScriptBox->sizeHint().height();
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ if (mRunlevels[i]->isHidden())
+ continue;
+
+ w += KDialog::spacingHint() + mRunlevels[i]->sizeHint().width();
+ h = kMax (h, mRunlevels[i]->sizeHint().height());
+ }
+
+ mContent->layout()->setEnabled(false);
+ mContent->setMinimumSize(mMinSize);
+ mScroller->updateScrollBars();
+ mContent->layout()->setEnabled(true);
+}
+
+void KSVContent::mergeLoadedPackage (QValueList<KSVData>* start,
+ QValueList<KSVData>* stop)
+{
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ merge (start[i], startRL[i]);
+ merge (stop[i], stopRL[i]);
+ }
+}
+
+void KSVContent::merge (QValueList<KSVData>& list, KSVDragList* widget)
+{
+ typedef QMap<KSVData, bool> LoadMap;
+ LoadMap loaded;
+
+ for (QValueListIterator<KSVData> it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ KSVItem* exists = widget->match (*it);
+ if (exists)
+ {
+ KSVData oldState = *exists->data();
+ exists->setNumber ((*it).number());
+ exists->setLabel ((*it).label());
+ exists->setFilename ((*it).filename());
+ exists->setPath ((*it).path());
+ loaded[*exists->data()] = true;
+
+ if (exists->isChanged())
+ {
+ emit undoAction (new ChangeAction (widget, &oldState, exists->data()));
+ }
+ }
+ else
+ {
+ KSVItem* item = new KSVItem (widget, *it);
+ item->setNew (true);
+ loaded[*item->data()] = true;
+
+ emit undoAction (new AddAction (widget, item->data()));
+ }
+
+ kapp->processEvents ();
+ }
+
+ QPtrList<KSVItem> deleteList;
+ deleteList.setAutoDelete (true);
+
+ for (QListViewItemIterator it (widget); it.current(); ++it)
+ {
+ KSVItem* item = static_cast<KSVItem*> (it.current());
+
+ if (!loaded[*item->data()])
+ {
+ deleteList.append (item);
+
+ emit undoAction (new RemoveAction (widget, item->data()));
+ }
+
+ kapp->processEvents ();
+ }
+
+ widget->sort();
+ kapp->processEvents();
+}
+
+#include "OldView.moc"
diff --git a/ksysv/OldView.h b/ksysv/OldView.h
new file mode 100644
index 0000000..8a6899e
--- /dev/null
+++ b/ksysv/OldView.h
@@ -0,0 +1,179 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_VIEW_H
+#define KSV_VIEW_H
+
+#include <qsplitter.h>
+#include <qvaluelist.h>
+#include <qsize.h>
+
+#include <ktrader.h>
+
+class QPopupMenu;
+class QFileInfo;
+class QLabel;
+class QListViewItem;
+class QTextEdit;
+class QFrame;
+class QVBox;
+class QPixmap;
+class QLayout;
+
+class KScroller;
+class KProcess;
+class KListView;
+class QSplitter;
+class KPopupMenu;
+class KSVTrash;
+class KSVDragList;
+class KSVConfig;
+class KSVData;
+class KSVItem;
+class KSVAction;
+class KSVTopLevel;
+
+class KSVContent : public QSplitter
+{
+ Q_OBJECT
+
+public:
+ KSVContent (KPopupMenu* openWithMenu, KSVTopLevel* parent = 0, const char* name = 0);
+ ~KSVContent();
+
+ KSVDragList* getOrigin();
+
+ const QString& log() const;
+ const QString& xmlLog() const;
+
+ void setColors (const QColor& newNormal,
+ const QColor& newSelected,
+ const QColor& changedNormal,
+ const QColor& changedSelected);
+
+ void mergeLoadedPackage (QValueList<KSVData>* start,
+ QValueList<KSVData>* stop);
+
+public slots:
+ void slotWriteSysV();
+
+ void infoOnData(KSVItem* data);
+ void setDisplayScriptOutput(bool val);
+ void slotScriptProperties (QListViewItem*);
+ void multiplexEnabled (bool);
+
+ void hideRunlevel (int index);
+ void showRunlevel (int index);
+
+protected:
+ virtual void resizeEvent (QResizeEvent* e);
+ virtual void moveEvent (QMoveEvent* e);
+ virtual void showEvent (QShowEvent*);
+
+private slots:
+ void calcMinSize ();
+ void fwdOrigin (KSVDragList*);
+ void startService();
+ void startService (const QString& path);
+ void stopService();
+ void stopService (const QString& path);
+ void restartService();
+ void restartService (const QString& path);
+ void editService();
+ void editService (const QString& path);
+ void slotOutputOrError( KProcess* _p, char* _buffer, int _buflen );
+ void slotExitedProcess(KProcess* proc);
+ void slotScriptsNotRemovable();
+ void slotDoubleClick (QListViewItem*);
+ void slotExitDuringRestart(KProcess* proc);
+ void appendLog(const QString& rich, const QString& plain);
+ void appendLog(const QCString& _buffer);
+ void fwdCannotGenerateNumber();
+ void fwdOrigin();
+ void reSortRL();
+ void pasteAppend();
+ void fwdUndoAction(KSVAction*);
+ void updatePanningFactor();
+
+ void popupRunlevelMenu (KListView*, QListViewItem*, const QPoint&);
+ void popupServicesMenu (KListView*, QListViewItem*, const QPoint&);
+
+ void updateServicesAfterChange (const QString&);
+ void updateRunlevelsAfterChange ();
+
+ void repaintRunlevels ();
+
+ void openWith ();
+ void openWith (int index);
+
+signals:
+ void sigUpdateParent();
+ void sigRun (const QString&);
+ void sigStop();
+ void sigNotRemovable();
+ void cannotGenerateNumber();
+ void selected (KSVItem*);
+ void selectedScripts (KSVItem*);
+ void sizeChanged();
+
+ void undoAction (KSVAction*);
+ void logChanged();
+
+ void newOrigin();
+
+private:
+ static int splitterToPanningFactor (const QValueList<int>&);
+ static const QValueList<int>& panningFactorToSplitter (int);
+
+ void merge (QValueList<KSVData>& list, KSVDragList* widget);
+ void initLList();
+ void initScripts();
+ void initRunlevels();
+ void info2Widget (QFileInfo* info, int index);
+ void writeToDisk (const KSVData& _w, int _rl, bool _start);
+ void clearRL( int _rl );
+
+ friend class KSVTopLevel;
+
+ QFrame* mContent;
+ KScroller* mScroller;
+
+ KSVDragList** startRL;
+ KSVDragList** stopRL;
+ KSVDragList* scripts;
+
+ KPopupMenu* mItemMenu;
+ KPopupMenu* mContextMenu;
+ KPopupMenu* mScriptMenu;
+ KSVTrash* trash;
+ QTextEdit* textDisplay;
+ KSVConfig* conf;
+
+ QVBox* mScriptBox;
+ QVBox** mRunlevels;
+ QWidget* mBuffer;
+
+ KSVDragList* mOrigin;
+
+ QString mLogText, mXMLLogText;
+
+ QSize mMinSize;
+
+ KPopupMenu* mOpenWithMenu;
+ KTrader::OfferList mOpenWithOffers;
+
+ QCString m_buffer;
+};
+
+#endif
diff --git a/ksysv/PreferencesDialog.cpp b/ksysv/PreferencesDialog.cpp
new file mode 100644
index 0000000..b0a2c42
--- /dev/null
+++ b/ksysv/PreferencesDialog.cpp
@@ -0,0 +1,291 @@
+// (c) 2000 Peter Putzer
+
+#include <qframe.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qvbox.h>
+#include <qhbox.h>
+#include <qgrid.h>
+#include <qdir.h>
+#include <qcheckbox.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <kiconloader.h>
+#include <kcolorbutton.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+
+#include "ksv_conf.h"
+// #include "ksvcolorconfig.h"
+#include "ksvmiscconfig.h"
+#include "ksvpathconfig.h"
+#include "ksvlookandfeel.h"
+// #include "ksvfontconfig.h"
+#include "ksv_core.h"
+
+#include "PreferencesDialog.h"
+
+KSVPreferences::KSVPreferences (QWidget* parent)
+ : KDialogBase (IconList, i18n("Configure"), Help|Ok|Apply|Cancel, Ok,
+ parent, "KSysV Preferences", true, true),
+ mConfig (KSVConfig::self())
+{
+ setMinimumSize (sizeHint ());
+
+ /**
+ * Look & Feel Page
+ */
+ QFrame* lafPage = addPage (i18n ("Look & Feel"), QString::null, DesktopIcon ("colorize", 32));
+ mLookAndFeel = new KSVLookAndFeel (lafPage);
+ connect( mLookAndFeel, SIGNAL( configChanged() ), this, SLOT( slotChanged() ) );
+
+ QVBoxLayout* lafLayout = new QVBoxLayout (lafPage);
+ lafLayout->addWidget (mLookAndFeel);
+
+// /**
+// * Colors Page
+// */
+// QFrame* colorPage = addPage (i18n("Colors"), QString::null, DesktopIcon ("colorize", 32));
+// mColorConfig = new KSVColorConfig(colorPage);
+
+// QVBoxLayout* colorLayout = new QVBoxLayout(colorPage);
+// colorLayout->addWidget(mColorConfig);
+
+// /**
+// * Fonts Page
+// */
+// QFrame* fontPage = addPage (i18n("Fonts"), QString::null, DesktopIcon ("fonts", 32));
+// mFontConfig = new KSVFontConfig(fontPage);
+
+// QVBoxLayout* fontLayout = new QVBoxLayout (fontPage);
+// fontLayout->addWidget(mFontConfig);
+
+ /**
+ * Paths Page
+ */
+ QFrame* pathPage = addPage (i18n ("Paths"), QString::null, DesktopIcon ("kfm", 32));
+ mPathConfig = new KSVPathConfig(pathPage);
+ connect( mPathConfig, SIGNAL( configChanged() ), this, SLOT( slotChanged() ) );
+
+ QVBoxLayout *pathLayout = new QVBoxLayout (pathPage);
+ pathLayout->addWidget (mPathConfig);
+
+ /**
+ * Miscellaneous Page
+ */
+ QFrame* miscPage = addPage (i18n ("Miscellaneous"), i18n("Settings Not Fitting Anywhere Else"),
+ DesktopIcon ("misc", 32));
+ mMiscConfig = new KSVMiscConfig(miscPage);
+ connect( mMiscConfig, SIGNAL( configChanged() ), this, SLOT( slotChanged() ) );
+
+ QVBoxLayout *miscLayout = new QVBoxLayout (miscPage);
+ miscLayout->addWidget (mMiscConfig);
+
+ connect (mMiscConfig->mShowAll, SIGNAL (clicked()), this, SLOT (showAllMessages()));
+
+ reReadConfig();
+ enableButton( Apply, false );
+ configChanged = false;
+}
+
+KSVPreferences::~KSVPreferences ()
+{
+}
+
+void KSVPreferences::slotChanged()
+{
+ enableButton( Apply, true );
+ configChanged = true;
+}
+
+void KSVPreferences::reReadConfig()
+{
+ mPathConfig->mRunlevelPath->setText(mConfig->runlevelPath());
+ mPathConfig->mServicesPath->setText(mConfig->scriptPath());
+
+ mLookAndFeel->mNewNormal->setColor (mConfig->newNormalColor());
+ mLookAndFeel->mNewSelected->setColor (mConfig->newSelectedColor());
+
+ mLookAndFeel->mChangedNormal->setColor (mConfig->changedNormalColor ());
+ mLookAndFeel->mChangedSelected->setColor (mConfig->changedSelectedColor ());
+
+ mLookAndFeel->setServiceFont (mConfig->serviceFont());
+ mLookAndFeel->setNumberFont (mConfig->numberFont());
+
+ reReadMessages();
+}
+
+void KSVPreferences::slotCancel ()
+{
+ reject();
+ reReadConfig();
+}
+
+void KSVPreferences::slotApply ()
+{
+ if (checkPaths())
+ {
+ setConfig();
+ enableButton( Apply, false );
+ configChanged = false;
+ }
+}
+
+bool KSVPreferences::checkPaths ()
+{
+ bool result = true;
+
+ if (!QDir(mPathConfig->mServicesPath->text()).exists())
+ result = (KMessageBox::warningContinueCancel(this,
+ i18n ("The service folder you specified does "
+ "not exist.\n"
+ "You can continue if you want to, "
+ "or you can click Cancel "
+ "to select a new folder."),
+ i18n ("Warning"))
+ != KMessageBox::Cancel);
+
+ if (!QDir(mPathConfig->mRunlevelPath->text()).exists())
+ result = result
+ && (KMessageBox::warningContinueCancel(this,
+ i18n ("The runlevel folder you specified does "
+ "not exist.\n"
+ "You can continue if you want to, "
+ "or you can click Cancel "
+ "to select a new folder."),
+ i18n ("Warning"))
+ != KMessageBox::Cancel);
+
+ return result;
+}
+
+void KSVPreferences::slotOk ()
+{
+ if (checkPaths())
+ {
+ accept();
+ setConfig ();
+ }
+}
+
+QColor KSVPreferences::newNormal() const
+{
+ return mLookAndFeel->mNewNormal->color();
+}
+
+QColor KSVPreferences::newSelected() const
+{
+ return mLookAndFeel->mNewSelected->color();
+}
+
+QColor KSVPreferences::changedNormal() const
+{
+ return mLookAndFeel->mChangedNormal->color();
+}
+
+QColor KSVPreferences::changedSelected() const
+{
+ return mLookAndFeel->mChangedSelected->color();
+}
+
+
+KSVPreferences* KSVPreferences::self ()
+{
+ static KSVPreferences* prefs = new KSVPreferences (kapp->mainWidget());
+
+ return prefs;
+}
+
+void KSVPreferences::setConfig ()
+{
+ // if necessary, update service path
+ {
+ QString sp = mPathConfig->mServicesPath->text();
+ if (sp != mConfig->scriptPath())
+ {
+ mConfig->setScriptPath (sp);
+
+ emit updateServicesPath ();
+ }
+ }
+
+ // if necesssary, update root path for runlevels
+ {
+ QString rp = mPathConfig->mRunlevelPath->text();
+ if (rp != mConfig->runlevelPath ())
+ {
+ mConfig->setRunlevelPath (rp);
+
+ emit updateRunlevelsPath ();
+ }
+ }
+
+ // if necessary, update miscellaneous settings
+ {
+ mConfig->setShowMessage (ksv::RunlevelsReadOnly,
+ mMiscConfig->mWarnReadOnly->isChecked());
+ mConfig->setShowMessage (ksv::CouldNotGenerateSortingNumber,
+ mMiscConfig->mWarnSortingNumber->isChecked());
+ }
+
+ // if necessary, update colors
+ {
+ QColor nn = newNormal();
+ QColor ns = newSelected();
+ QColor cn = changedNormal();
+ QColor cs = changedSelected();
+
+ if (nn != mConfig->newNormalColor() ||
+ ns != mConfig->newSelectedColor() ||
+ cn != mConfig->changedNormalColor() ||
+ cs != mConfig->changedSelectedColor())
+ {
+ mConfig->setNewNormalColor (nn);
+ mConfig->setNewSelectedColor (ns);
+ mConfig->setChangedNormalColor (cn);
+ mConfig->setChangedSelectedColor (cs);
+
+ emit updateColors ();
+ }
+ }
+
+ // if necessary, update fonts
+ {
+ const QFont& sf = mLookAndFeel->serviceFont();
+ const QFont& ns = mLookAndFeel->numberFont();
+
+ if (sf != mConfig->serviceFont() || ns != mConfig->numberFont())
+ {
+ mConfig->setServiceFont (sf);
+ mConfig->setNumberFont (ns);
+
+ emit updateFonts();
+ }
+ }
+}
+
+void KSVPreferences::showAllMessages ()
+{
+ KMessageBox::enableAllMessages ();
+
+ // update checkboxes
+ reReadMessages();
+}
+
+void KSVPreferences::reReadMessages()
+{
+ mMiscConfig->mWarnReadOnly->setChecked (mConfig->showMessage (ksv::RunlevelsReadOnly));
+ mMiscConfig->mWarnSortingNumber->setChecked (mConfig->showMessage (ksv::CouldNotGenerateSortingNumber));
+}
+
+void KSVPreferences::showEvent (QShowEvent* e)
+{
+ reReadMessages();
+
+ KDialogBase::showEvent (e);
+}
+
+#include "PreferencesDialog.moc"
diff --git a/ksysv/PreferencesDialog.h b/ksysv/PreferencesDialog.h
new file mode 100644
index 0000000..ba7d938
--- /dev/null
+++ b/ksysv/PreferencesDialog.h
@@ -0,0 +1,68 @@
+// (c) 2000 Peter Putzer
+
+#ifndef PREFERENCES_DIALOG_H
+#define PREFERENCES_DIALOG_H
+
+#include <qstring.h>
+#include <kdialogbase.h>
+
+class QPushButton;
+
+class KSVLookAndFeel;
+class KSVMiscConfig;
+class KSVPathConfig;
+class KSVConfig;
+
+
+class KSVPreferences : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ static KSVPreferences* self ();
+ virtual ~KSVPreferences ();
+
+ QColor newNormal () const;
+ QColor newSelected () const;
+ QColor changedNormal () const;
+ QColor changedSelected () const;
+
+ QString runlevelPath () const;
+ QString scriptPath () const;
+
+protected:
+ virtual void showEvent (QShowEvent* e);
+
+signals:
+ void updateColors ();
+ void updateServicesPath ();
+ void updateRunlevelsPath ();
+ void updateFonts ();
+
+protected slots:
+ virtual void slotApply ();
+ virtual void slotCancel ();
+ virtual void slotOk ();
+ void slotChanged();
+
+private slots:
+ void reReadConfig();
+ void showAllMessages ();
+
+private:
+ friend class KSVTopLevel;
+
+ KSVPreferences (QWidget* parent);
+ void setConfig ();
+ bool checkPaths();
+ void reReadMessages();
+ KSVConfig* mConfig;
+
+ KSVLookAndFeel* mLookAndFeel;
+ KSVPathConfig* mPathConfig;
+ KSVMiscConfig* mMiscConfig;
+ bool configChanged;
+};
+
+
+#endif // PREFERENCES_DIALOG_H
diff --git a/ksysv/Properties.cpp b/ksysv/Properties.cpp
new file mode 100644
index 0000000..7379b74
--- /dev/null
+++ b/ksysv/Properties.cpp
@@ -0,0 +1,209 @@
+// (c) 2000 Peter Putzer
+
+#include <qframe.h>
+#include <qlabel.h>
+#include <qtextview.h>
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qbuttongroup.h>
+#include <qpushbutton.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <kiconloader.h>
+
+#include "SpinBox.h"
+#include "OldView.h"
+#include "ksv_conf.h"
+#include "ksv_core.h"
+#include "Data.h"
+#include "Properties.h"
+
+KSVServicePropertiesDialog::KSVServicePropertiesDialog (KSVData& data, QWidget* parent)
+ : KPropertiesDialog (KURL(data.filenameAndPath()),
+ parent, "KSVServicePropertiesDialog", true, false),
+ mData (data)
+{
+ KSVServicesPage* page = new KSVServicesPage (data, this);
+ insertPlugin (page);
+
+ showPage (page->pageIndex ());
+}
+
+KSVServicePropertiesDialog::~KSVServicePropertiesDialog ()
+{
+}
+
+KSVServicesPage::KSVServicesPage (KSVData& data, KPropertiesDialog* props)
+ : KPropsDlgPlugin (props),
+ mData (data),
+ mPage (props->addVBoxPage (i18n("&Service"))),
+ mIndex (props->pageIndex (mPage))
+{
+ mPage->setSpacing (KDialog::spacingHint());
+
+ QVBox* desc = new QVBox (mPage);
+ desc->setSpacing (1);
+
+ QLabel* label = new QLabel(i18n("Description:"), desc);
+ label->setFixedHeight (label->sizeHint().height());
+
+ QString text;
+ ksv::getServiceDescription (data.filename(), text);
+ mDesc = new QTextView (QString("<p>%1</p>").arg (text), QString::null, desc);
+
+ QButtonGroup* buttons = new QButtonGroup (1, Vertical, i18n ("Actions"), mPage);
+ QPushButton* b = new QPushButton (i18n ("&Edit"), buttons);
+ connect (b, SIGNAL (clicked()), props, SLOT (doEdit()));
+
+ QFrame* spacer = new QFrame (buttons);
+ spacer->setMinimumWidth (KDialog::spacingHint());
+
+ b = new QPushButton (i18n ("&Start"), buttons);
+ connect (b, SIGNAL (clicked()), props, SLOT (doStart()));
+
+ b = new QPushButton (i18n ("S&top"), buttons);
+ connect (b, SIGNAL (clicked()), props, SLOT (doStop()));
+
+ b = new QPushButton (i18n ("&Restart"), buttons);
+ connect (b, SIGNAL (clicked()), props, SLOT (doRestart()));
+}
+
+KSVServicesPage::~KSVServicesPage ()
+{
+}
+
+void KSVServicesPage::applyChanges ()
+{
+}
+
+void KSVServicePropertiesDialog::doEdit ()
+{
+ emit editService (mData.filenameAndPath ());
+}
+
+void KSVServicePropertiesDialog::doStart ()
+{
+ emit startService (mData.filenameAndPath ());
+}
+
+void KSVServicePropertiesDialog::doStop ()
+{
+ emit stopService (mData.filenameAndPath ());
+}
+
+void KSVServicePropertiesDialog::doRestart ()
+{
+ emit restartService (mData.filenameAndPath ());
+}
+
+
+KSVEntryPropertiesDialog::KSVEntryPropertiesDialog (KSVData& data, QWidget* parent)
+ : KPropertiesDialog (data.label(), parent, "KSVEntryPropertiesDialog", true),
+ mData (data)
+{
+ KSVEntryPage* page1 = new KSVEntryPage (data, this);
+ insertPlugin (page1);
+
+ KSVServicesPage* page2 = new KSVServicesPage (data, this);
+ insertPlugin (page2);
+}
+
+KSVEntryPropertiesDialog::~KSVEntryPropertiesDialog ()
+{
+}
+
+KSVEntryPage::KSVEntryPage (KSVData& data, KPropertiesDialog* props)
+ : KPropsDlgPlugin (props),
+ mData (data),
+ mPage (props->addPage (i18n("&Entry"))),
+ mIndex (props->pageIndex (mPage))
+{
+ QGridLayout* top = new QGridLayout (mPage, 4, 2, 0, KDialog::spacingHint());
+
+ QLabel* labelLabel = new QLabel (i18n ("&Name:"), mPage);
+ mLabelEdit = new KLineEdit (mPage);
+ mLabelEdit->setText (mData.label());
+ labelLabel->setBuddy (mLabelEdit);
+
+ QLabel* serviceLabel = new QLabel (i18n ("&Points to service:"), mPage);
+ mServiceEdit = new KLineEdit (mPage);
+ mServiceEdit->setCompletionObject (ksv::serviceCompletion(), true);
+ mServiceEdit->setText (mData.filename());
+ serviceLabel->setBuddy (mServiceEdit);
+
+ QLabel* numberLabel = new QLabel (i18n ("&Sorting number:"), mPage);
+ mNumberEdit = new KSVSpinBox (mPage);
+ mNumberEdit->setValue (mData.number());
+ numberLabel->setBuddy (mNumberEdit);
+
+ QLabel* iconLabel = new QLabel (mPage);
+ iconLabel->setPixmap (DesktopIcon ("ksysv", 48));
+
+ top->addWidget (labelLabel, 0, 0);
+ top->addWidget (mLabelEdit, 0, 1);
+ top->addWidget (serviceLabel, 1, 0);
+ top->addWidget (mServiceEdit, 1, 1);
+ top->addWidget (numberLabel, 2, 0);
+ top->addWidget (mNumberEdit, 2, 1);
+ top->addWidget (iconLabel, 3, 0);
+
+ connect (mServiceEdit, SIGNAL (textChanged (const QString&)),
+ this, SLOT (emitChanged()));
+ connect (mLabelEdit, SIGNAL (textChanged (const QString&)),
+ this, SLOT (emitChanged()));
+ connect (mNumberEdit, SIGNAL (valueChanged (int)),
+ this, SLOT (emitChanged()));
+}
+
+KSVEntryPage::~KSVEntryPage ()
+{
+}
+
+void KSVEntryPage::applyChanges ()
+{
+ if (mNumberEdit->value() != mData.number())
+ {
+ mData.setNumber (mNumberEdit->value());
+ }
+
+ if (mLabelEdit->text() != mData.label())
+ {
+ mData.setLabel (mLabelEdit->text());
+ }
+
+ if (mServiceEdit->text() != mData.filename())
+ {
+ mData.setFilename (mServiceEdit->text());
+ ksv::serviceCompletion ()->addItem (mData.filename());
+ }
+}
+
+void KSVEntryPage::emitChanged ()
+{
+ emit changed();
+}
+
+void KSVEntryPropertiesDialog::doEdit ()
+{
+ emit editService (mData.filenameAndPath ());
+}
+
+void KSVEntryPropertiesDialog::doStart ()
+{
+ emit startService (mData.filenameAndPath ());
+}
+
+void KSVEntryPropertiesDialog::doStop ()
+{
+ emit stopService (mData.filenameAndPath ());
+}
+
+void KSVEntryPropertiesDialog::doRestart ()
+{
+ emit restartService (mData.filenameAndPath ());
+}
+
+#include "Properties.moc"
diff --git a/ksysv/Properties.h b/ksysv/Properties.h
new file mode 100644
index 0000000..0e3225d
--- /dev/null
+++ b/ksysv/Properties.h
@@ -0,0 +1,110 @@
+// (c) 2000 Peter Putzer
+
+#ifndef PROPERTIES_H
+#define PROPERTIES_H
+
+#include <kpropertiesdialog.h>
+
+class QHBox;
+class QVBox;
+class QTextView;
+class QSpinBox;
+
+class KLineEdit;
+
+class KSVData;
+
+class KSVServicePropertiesDialog : public KPropertiesDialog
+{
+ Q_OBJECT
+
+public:
+ KSVServicePropertiesDialog (KSVData& data, QWidget* parent);
+ virtual ~KSVServicePropertiesDialog ();
+
+signals:
+ void startService (const QString&);
+ void stopService (const QString&);
+ void restartService (const QString&);
+ void editService (const QString&);
+
+private slots:
+ void doEdit ();
+ void doStart ();
+ void doStop ();
+ void doRestart ();
+
+private:
+ KSVData& mData;
+};
+
+
+class KSVEntryPropertiesDialog : public KPropertiesDialog
+{
+ Q_OBJECT
+
+public:
+ KSVEntryPropertiesDialog (KSVData& data, QWidget* parent);
+ virtual ~KSVEntryPropertiesDialog ();
+
+signals:
+ void startService (const QString&);
+ void stopService (const QString&);
+ void restartService (const QString&);
+ void editService (const QString&);
+
+private slots:
+ void doEdit ();
+ void doStart ();
+ void doStop ();
+ void doRestart ();
+
+private:
+ KSVData& mData;
+};
+
+class KSVEntryPage : public KPropsDlgPlugin
+{
+ Q_OBJECT
+
+public:
+ KSVEntryPage (KSVData& data, KPropertiesDialog* props);
+ virtual ~KSVEntryPage ();
+
+ virtual void applyChanges ();
+
+ inline int pageIndex () const { return mIndex; }
+
+private slots:
+ void emitChanged ();
+
+private:
+ KSVData& mData;
+ QFrame* mPage;
+ int mIndex;
+
+ KLineEdit* mServiceEdit;
+ KLineEdit* mLabelEdit;
+ QSpinBox* mNumberEdit;
+};
+
+class KSVServicesPage : public KPropsDlgPlugin
+{
+ Q_OBJECT
+
+public:
+ KSVServicesPage (KSVData& data, KPropertiesDialog* props);
+ virtual ~KSVServicesPage ();
+
+ virtual void applyChanges ();
+
+ inline int pageIndex () const { return mIndex; }
+
+private:
+ KSVData& mData;
+ QVBox* mPage;
+ QTextView* mDesc;
+ int mIndex;
+};
+
+#endif // PROPERTIES_H
diff --git a/ksysv/README b/ksysv/README
new file mode 100644
index 0000000..b0ac5a3
--- /dev/null
+++ b/ksysv/README
@@ -0,0 +1,33 @@
+/****************************************************************************
+* *
+* SYSTEM V INIT EDITOR *
+* for the KDE Project *
+* *
+****************************************************************************/
+
+DESCRIPTION:
+ SysV-Init Editor lets you edit your SysV-style init configuration
+ using drag'n'drop.
+
+INSTALLATION:
+ Just do a "./configure && make && make install".
+
+CONFIGURATION:
+ Through the GUI (Options/Configure...)
+
+CONTACT INFORMATION:
+ If something doesn't work (or does work :-) ) correctly, contact me:
+ Peter Putzer <putzer@kde.org>
+
+REMEMBER:
+ No warranties!
+
+BUGS:
+ See bugs.kde.org.
+
+LICENSE:
+ This program is licensed under the GNU General Public License, GPL for short.
+ See the file COPYING for details. No warranties!
+
+SPECIAL THANKS:
+ To Emanuel Pirker for his template for this README
diff --git a/ksysv/RunlevelAuthIcon.cpp b/ksysv/RunlevelAuthIcon.cpp
new file mode 100644
index 0000000..e086df1
--- /dev/null
+++ b/ksysv/RunlevelAuthIcon.cpp
@@ -0,0 +1,149 @@
+// (c) 2000 Peter Putzer <putzer@kde.org>
+
+#include <qtimer.h>
+#include <qfileinfo.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kdialog.h>
+#include <klocale.h>
+
+#include "ksv_core.h"
+#include "RunlevelAuthIcon.h"
+#include <qlabel.h>
+
+RunlevelAuthIcon::RunlevelAuthIcon (const QString& servicesPath, const QString& runlevelPath,
+ QWidget* parent, const char* name)
+ : KAuthIcon (parent, name),
+ mTimer (new QTimer (this)),
+ mServicesInfo (new QFileInfo (servicesPath)),
+ mRLInfo (new QFileInfo* [ksv::runlevelNumber]),
+ mOld (false),
+ mInterval (1000),
+ mCheckEnabled(false)
+{
+ lockText = i18n("Editing disabled - please check your permissions");
+ openLockText = i18n("Editing enabled");
+
+ lockLabel->setText (lockText);
+ lockLabel->hide();
+
+ lockPM = UserIcon ("ksysv_locked");
+ openLockPM = UserIcon ("ksysv_unlocked");
+
+ lockBox->setPixmap (lockPM);
+
+ lockBox->setMargin (1);
+ lockBox->setFrameStyle (QFrame::NoFrame);
+ lockBox->setFixedSize (lockBox->sizeHint());
+
+ connect (mTimer, SIGNAL (timeout()), this, SLOT (timerEvent()));
+ mTimer->start (mInterval);
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ mRLInfo[i] = new QFileInfo ((runlevelPath + "/rc%1.d").arg(i));
+ }
+
+ updateStatus();
+ layout->activate();
+}
+
+RunlevelAuthIcon::~RunlevelAuthIcon ()
+{
+ delete mServicesInfo;
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ delete mRLInfo[i];
+ }
+
+ delete[] mRLInfo;
+}
+
+void RunlevelAuthIcon::updateStatus ()
+{
+ if (!mCheckEnabled)
+ return;
+
+ const bool res = status();
+
+ if (mOld != res)
+ {
+ lockBox->setPixmap (res ? openLockPM : lockPM);
+ lockLabel->setText (res ? openLockText : lockText);
+
+ QToolTip::remove (this);
+ QToolTip::add (this, lockLabel->text());
+
+ mOld = res;
+ emit authChanged (res);
+ }
+ else
+ mOld = res;
+}
+
+bool RunlevelAuthIcon::status () const
+{
+ bool result = mServicesInfo->isWritable();
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ result = result && mRLInfo[i]->isWritable();
+
+ return result;
+}
+
+void RunlevelAuthIcon::timerEvent ()
+{
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ mRLInfo[i]->refresh();
+ }
+
+ mServicesInfo->refresh();
+
+ updateStatus();
+}
+
+void RunlevelAuthIcon::setServicesPath (const QString& path)
+{
+ mTimer->stop();
+
+ mServicesInfo->setFile (path);
+
+ mTimer->start(mInterval);
+}
+
+void RunlevelAuthIcon::setRunlevelPath (const QString& path)
+{
+ mTimer->stop();
+
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ mRLInfo[i]->setFile ((path + "/rc%1.d").arg(i));
+ }
+
+ mTimer->start(mInterval);
+}
+
+void RunlevelAuthIcon::setRefreshInterval (int interval)
+{
+ mInterval = interval;
+
+ mTimer->stop();
+ mTimer->start (mInterval);
+}
+
+void RunlevelAuthIcon::setCheckEnabled (bool on)
+{
+ kdDebug(3000) << "enabling authicon " << on << endl;
+ mCheckEnabled = on;
+
+ // refresh everything
+ mOld = !status();
+ timerEvent();
+}
+
+#include "RunlevelAuthIcon.moc"
diff --git a/ksysv/RunlevelAuthIcon.h b/ksysv/RunlevelAuthIcon.h
new file mode 100644
index 0000000..d33f24d
--- /dev/null
+++ b/ksysv/RunlevelAuthIcon.h
@@ -0,0 +1,49 @@
+#ifndef RUNLEVEL_AUTH_ICON_H
+#define RUNLEVEL_AUTH_ICON_H
+
+// (c) 2000 Peter Putzer <putzer@kde.org>
+#include <kauthicon.h>
+
+class QTimer;
+class QFileInfo;
+
+class RunlevelAuthIcon : public KAuthIcon
+{
+ Q_OBJECT
+ Q_PROPERTY (int refreshInterval READ refreshInterval WRITE setRefreshInterval)
+
+public:
+ RunlevelAuthIcon (const QString& scriptPath, const QString& runlevelPath,
+ QWidget* parent = 0L, const char* name = 0L);
+
+ virtual ~RunlevelAuthIcon ();
+
+ virtual bool status () const;
+
+ inline int refreshInterval () const { return mInterval; }
+ inline bool isCheckEnabled () const { return mCheckEnabled; }
+
+public slots:
+ virtual void updateStatus ();
+
+ void setServicesPath (const QString& servicesPath);
+ void setRunlevelPath (const QString& runlevelPath);
+
+ void setRefreshInterval (int);
+
+ void setCheckEnabled(bool);
+
+private slots:
+ void timerEvent ();
+
+private:
+ QTimer* mTimer;
+ QFileInfo* mServicesInfo;
+ QFileInfo** mRLInfo;
+ bool mOld;
+ int mInterval;
+
+ bool mCheckEnabled;
+};
+
+#endif // RUNLEVEL_AUTH_ICON_H
diff --git a/ksysv/ServiceDlg.cpp b/ksysv/ServiceDlg.cpp
new file mode 100644
index 0000000..0564028
--- /dev/null
+++ b/ksysv/ServiceDlg.cpp
@@ -0,0 +1,123 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qcombobox.h>
+#include <qstring.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kbuttonbox.h>
+
+#include "ksvdraglist.h"
+#include "ServiceDlg.h"
+
+#define MIN_SIZE(A) A->setMinimumSize(A->sizeHint())
+
+ServiceDlg::ServiceDlg (const QString& action, const QString& label,
+ QWidget* parent, const char* name)
+ : KDialogBase (parent, name, false, action, Apply|Close, Apply, true)
+{
+ QWidget* page = new QWidget (this);
+
+ QBoxLayout* top = new QVBoxLayout (page, 0, spacingHint());
+
+ mServices = new QComboBox (false, page);
+ QLabel* desc = new QLabel(label, page);
+ MIN_SIZE(desc);
+ desc->setBuddy(mServices);
+ MIN_SIZE(mServices);
+ mServices->setMinimumWidth(mServices->minimumSize().width() * 2);
+
+ QBoxLayout* serv_layout = new QHBoxLayout();
+ top->addLayout (serv_layout);
+ serv_layout->addWidget(desc);
+ serv_layout->addWidget(mServices);
+
+ setFixedSize (sizeHint());
+}
+
+ServiceDlg::~ServiceDlg()
+{
+}
+
+void ServiceDlg::slotApply()
+{
+ emit doAction (mMapServices[mServices->currentText()]->filenameAndPath());
+}
+
+int ServiceDlg::count() const
+{
+ return mServices->count();
+}
+
+void ServiceDlg::resetChooser(KSVDragList* list, bool edit)
+{
+ mServices->clear();
+ mMapServices.clear();
+
+ if (!list)
+ return;
+
+ // initialize the combobox
+ for (QListViewItemIterator it (list);
+ it.current();
+ ++it)
+ {
+ const KSVItem* item = static_cast<KSVItem*> (it.current());
+
+ QFileInfo info (item->filenameAndPath());
+
+ if (edit)
+ {
+ if (info.isReadable())
+ mServices->insertItem(item->label());
+
+ mMapServices[item->label()] = item;
+ }
+ else
+ {
+ if (info.isExecutable())
+ mServices->insertItem(item->label());
+
+ mMapServices[item->label()] = item;
+ }
+ }
+}
+
+void ServiceDlg::show ()
+{
+ QDialog::show ();
+
+ emit display (true);
+}
+
+void ServiceDlg::hide ()
+{
+ QDialog::hide ();
+
+ emit display (false);
+}
+
+void ServiceDlg::toggle ()
+{
+ if (isHidden())
+ show();
+ else
+ hide();
+}
+
+#include "ServiceDlg.moc"
diff --git a/ksysv/ServiceDlg.h b/ksysv/ServiceDlg.h
new file mode 100644
index 0000000..34fb69c
--- /dev/null
+++ b/ksysv/ServiceDlg.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_SERVICE_DIALOG_H
+#define KSV_SERVICE_DIALOG_H
+
+#include <kdialogbase.h>
+#include <qmap.h>
+
+class KSVDragList;
+class KSVItem;
+class QString;
+class QComboBox;
+
+class ServiceDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ ServiceDlg (const QString& action, const QString& label,
+ QWidget* parent = 0, const char* name = 0);
+ virtual ~ServiceDlg();
+
+ int count() const;
+
+ void resetChooser (KSVDragList* data, bool edit);
+
+public slots:
+ virtual void show ();
+ virtual void hide ();
+ void toggle ();
+
+private:
+ QComboBox* mServices;
+ QMap<QString,const KSVItem*> mMapServices;
+
+protected slots:
+ virtual void slotApply();
+
+signals:
+ void doAction (const QString& on);
+ void display (bool);
+};
+
+#endif
diff --git a/ksysv/SpinBox.cpp b/ksysv/SpinBox.cpp
new file mode 100644
index 0000000..63a217a
--- /dev/null
+++ b/ksysv/SpinBox.cpp
@@ -0,0 +1,87 @@
+// (c) 2000 Peter Putzer
+
+#include <qlineedit.h>
+
+#include <kdebug.h>
+
+#include "ksv_core.h"
+#include "SpinBox.h"
+
+KSVSpinBox::KSVSpinBox (QWidget* parent, const char* name)
+ : QSpinBox (0, 99, 1, parent, name),
+ KCompletionBase (),
+ mClearedSelection (false)
+{
+ KCompletion* comp = ksv::numberCompletion();
+ setCompletionObject (comp, true);
+
+ editor()->installEventFilter (this);
+
+ connect (editor(), SIGNAL (textChanged (const QString&)),
+ comp, SLOT (slotMakeCompletion (const QString&)));
+ connect (comp, SIGNAL (match (const QString&)),
+ this, SLOT (handleMatch (const QString&)));
+}
+
+KSVSpinBox::~KSVSpinBox ()
+{
+}
+
+QString KSVSpinBox::mapValueToText (int value)
+{
+ QString result;
+
+ if (value < 10)
+ result.sprintf("%.2i", value);
+ else
+ result.setNum (value);
+
+ return result;
+}
+
+void KSVSpinBox::setCompletedText (const QString& text)
+{
+ QLineEdit* e = editor ();
+ const int pos = e->cursorPosition();
+
+ e->setText (text);
+
+ e->setSelection (pos, text.length());
+ e->setCursorPosition (pos);
+}
+
+void KSVSpinBox::setCompletedItems (const QStringList& /*items*/)
+{
+ // dont know what is supposed to be in here but it has to be defined
+ // because else the lack of this damn thing is making it abstract
+}
+
+void KSVSpinBox::handleMatch (const QString& match)
+{
+ if (!match.isNull() && editor()->text().length() < 2 && !mClearedSelection)
+ setCompletedText (match);
+}
+
+bool KSVSpinBox::eventFilter (QObject* o, QEvent* e)
+{
+ Q_UNUSED(o);
+ if (e->type() == QEvent::KeyPress)
+ {
+ QKeyEvent* ke = static_cast<QKeyEvent*> (e);
+
+ switch (ke->key())
+ {
+ case Key_BackSpace:
+ case Key_Delete:
+ mClearedSelection = true;
+ break;
+
+ default:
+ mClearedSelection = false;
+ }
+ }
+
+ return false;
+}
+
+#include "SpinBox.moc"
diff --git a/ksysv/SpinBox.h b/ksysv/SpinBox.h
new file mode 100644
index 0000000..147fc88
--- /dev/null
+++ b/ksysv/SpinBox.h
@@ -0,0 +1,32 @@
+// (c) 2000 Peter Putzer
+
+#ifndef KSV_SPINBOX_H
+#define KSV_SPINBOX_H
+
+#include <qspinbox.h>
+
+#include <kcompletion.h>
+
+class KSVSpinBox : public QSpinBox, public KCompletionBase
+{
+ Q_OBJECT
+
+public:
+ KSVSpinBox (QWidget* parent, const char* name = 0L);
+ virtual ~KSVSpinBox ();
+
+ virtual bool eventFilter (QObject*, QEvent*);
+ virtual void setCompletedText (const QString&);
+ virtual void setCompletedItems (const QStringList&);
+
+protected:
+ virtual QString mapValueToText (int value);
+
+private slots:
+ void handleMatch (const QString&);
+
+private:
+ bool mClearedSelection;
+};
+
+#endif // KSV_SPINBOX_H
diff --git a/ksysv/TODO b/ksysv/TODO
new file mode 100644
index 0000000..ced6dc4
--- /dev/null
+++ b/ksysv/TODO
@@ -0,0 +1,7 @@
+TODO
+
+ - printing stuff (PARTIALLY DONE but removed... too complex)
+ - support for REALLY starting daemons on SuSE and DLD
+ - use lexical compare of items to determine whether a drop is
+ allowed
+
diff --git a/ksysv/TopWidget.cpp b/ksysv/TopWidget.cpp
new file mode 100644
index 0000000..854c9cf
--- /dev/null
+++ b/ksysv/TopWidget.cpp
@@ -0,0 +1,1109 @@
+/*
+ Requires the Qt widget libraries, available at no cost at
+ http://www.troll.no
+
+ Copyright (C) 1997-2000 Peter Putzer
+ putzer@kde.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/****************************************************************
+**
+** KSysV
+** Toplevel Widget
+**
+****************************************************************/
+
+#include <ctype.h>
+
+#include <qpopupmenu.h>
+#include <qkeycode.h>
+#include <qmessagebox.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+#include <qmultilineedit.h>
+#include <qdatetime.h>
+#include <kprinter.h>
+#include <qpaintdevicemetrics.h>
+#include <qbuttongroup.h>
+#include <qclipboard.h>
+#include <qtooltip.h>
+#include <qcheckbox.h>
+#include <qhbox.h>
+#include <qregexp.h>
+#include <qdatastream.h>
+#include <qpixmapcache.h>
+#include <qtextview.h>
+#include <qfileinfo.h>
+#include <qtextstream.h>
+#include <qwhatsthis.h>
+#include <qsimplerichtext.h>
+
+#include <kresolver.h>
+#include <ktoolbar.h>
+#include <kkeydialog.h>
+#include <kmenubar.h>
+#include <kcompletion.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kglobal.h>
+#include <khelpmenu.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstdaccel.h>
+#include <kedittoolbar.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kaboutdata.h>
+#include <kcursor.h>
+
+#include "kbusymanager.h"
+#include "ServiceDlg.h"
+#include "PreferencesDialog.h"
+#include "ActionList.h"
+#include "ksv_core.h"
+#include "ksv_conf.h"
+#include "RunlevelAuthIcon.h"
+#include "ksvdraglist.h"
+#include "Data.h"
+#include "ksvdrag.h"
+#include "OldView.h"
+#include "IOCore.h"
+#include "TopWidget.h"
+#include <qlabel.h>
+#include <kstatusbar.h>
+
+namespace Status
+{
+ enum {
+ Changed, Checklist, Writable
+ };
+} // namespace Status
+
+KSVTopLevel::KSVTopLevel()
+ : KMainWindow(0, 0L, WStyle_ContextHelp|WDestructiveClose),
+ mConfig(KSVConfig::self()),
+ mView (0L),
+ mPreferences (0L),
+
+ mEditUndo (0L), mEditCut (0L), mEditCopy (0L), mEditPaste (0L),
+ mEditProperties (0L),
+
+ mFileRevert (0L), mFileLoad (0L), mFilePrint (0L), mFilePrintLog (0L),
+ mFileSave (0L), mFileSaveAs (0L), mFileSaveLog(0L), mFileQuit (0L),
+
+ mToolsStartService (0L), mToolsStopService (0L),
+ mToolsRestartService (0L), mToolsEditService (0L),
+
+ mOptionsToggleLog (0L),
+
+ mOpenWith (0L), mOpenDefault (0L),
+
+ mUndoList (new ActionList (this, "UndoList")),
+ mRedoList (new ActionList (this, "RedoList")),
+ mStartDlg (new ServiceDlg (i18n("Start Service"),
+ i18n("&Choose which service to start:"),
+ this)),
+ mStopDlg (new ServiceDlg (i18n("Stop Service"),
+ i18n("&Choose which service to stop:"),
+ this)),
+ mRestartDlg (new ServiceDlg (i18n("Restart Service"),
+ i18n("&Choose which service to restart:"),
+ this)),
+ mEditDlg (new ServiceDlg (i18n("Edit Service"),
+ i18n("&Choose which service to edit:"),
+ this)),
+ mVisible (new QCheckBox*[ksv::runlevelNumber])
+{
+ setCaption(false);
+
+ initStatusBar(); // order dependency
+ initActions(); // order dependency
+ mView = new KSVContent (mOpenWith->popupMenu(), this, "Content"); // order dependency
+ initTools(); // order dependency
+
+ setCentralWidget(mView);
+
+ // ensure that the statusbar gets updated correctly
+ connect (mView, SIGNAL(sigRun(const QString&)), this, SLOT(slotUpdateRunning(const QString&)));
+ connect (mView, SIGNAL(sigStop()), statusBar(), SLOT(clear()));
+ connect (mView, SIGNAL(cannotGenerateNumber()), this, SLOT(catchCannotGenerateNumber()));
+ connect (mView, SIGNAL(undoAction(KSVAction*)), this, SLOT(pushUndoAction(KSVAction*)));
+ connect (mView, SIGNAL(logChanged()), this, SLOT(enableLogActions()));
+
+ // cut & copy
+ connect (mView, SIGNAL (newOrigin()),
+ this, SLOT (dispatchEdit()));
+
+ // undo
+ connect (mUndoList, SIGNAL(empty()), this, SLOT(disableUndo()));
+ connect (mUndoList, SIGNAL(filled()), this, SLOT(enableUndo()));
+
+ // and redo
+ connect (mRedoList, SIGNAL(empty()), this, SLOT(disableRedo()));
+ connect (mRedoList, SIGNAL(filled()), this, SLOT(enableRedo()));
+
+ // paste
+ connect (kapp->clipboard(), SIGNAL (dataChanged()),
+ this, SLOT (dispatchEdit()));
+
+ // init mView according to saved preferences
+ slotReadConfig();
+ initView();
+ setMinimumSize(600,400);
+
+ // restore size and position
+ move(mConfig->position()); // doesnt seem to work while unmapped
+ setAutoSaveSettings();
+
+ // start watching the directories
+ mAuth->setCheckEnabled(true);
+
+ dispatchEdit(); // disable cut & copy on startup
+}
+
+KSVTopLevel::~KSVTopLevel()
+{
+ mUndoList->clear();
+ mRedoList->clear();
+
+ delete[] mVisible;
+}
+
+void KSVTopLevel::initTools()
+{
+ connect (mStartDlg, SIGNAL(doAction(const QString&)),
+ mView, SLOT(startService(const QString&)));
+ connect (mStopDlg, SIGNAL(doAction(const QString&)),
+ mView, SLOT(editService(const QString&)));
+ connect (mRestartDlg, SIGNAL(doAction(const QString&)),
+ mView, SLOT(restartService(const QString&)));
+ connect (mEditDlg, SIGNAL(doAction(const QString&)),
+ mView, SLOT(editService(const QString&)));
+
+ connect (mStartDlg, SIGNAL (display (bool)),
+ this, SLOT (dispatchStartService (bool)));
+ connect (mStopDlg, SIGNAL (display (bool)),
+ this, SLOT (dispatchStopService (bool)));
+ connect (mRestartDlg, SIGNAL (display (bool)),
+ this, SLOT (dispatchRestartService (bool)));
+ connect (mEditDlg, SIGNAL (display (bool)),
+ this, SLOT (dispatchEditService (bool)));
+
+}
+
+void KSVTopLevel::initActions ()
+{
+ KActionCollection* coll = actionCollection();
+
+ // setup File menu
+ mFileRevert = KStdAction::revert (this, SLOT (slotClearChanges()), coll);
+ mFileRevert->setText (i18n("Re&vert Configuration"));
+
+ mFileLoad = KStdAction::open (this, SLOT (load()), coll);
+ mFileLoad->setText (i18n ("&Open..."));
+
+ mFileSave = KStdAction::save(this, SLOT(slotAcceptChanges()), coll);
+ mFileSave->setText (i18n("&Save Configuration"));
+
+ mFileSaveAs = KStdAction::saveAs (this, SLOT (saveAs ()), coll);
+
+ mFileSaveLog = KStdAction::save (this, SLOT(slotSaveLog()), coll, "ksysv_save_log");
+ mFileSaveLog->setText (i18n("Save &Log..."));
+ mFileSaveLog->setShortcut (Key_L+CTRL);
+ mFileSaveLog->setEnabled (false);
+
+ // disabled due to complexity
+ // mFilePrint = KStdAction::print (this, SLOT (print()), coll);
+
+ mFilePrintLog = KStdAction::print(this, SLOT(printLog()), coll, "ksysv_print_log");
+ mFilePrintLog->setText( i18n("&Print Log..."));
+ mFilePrintLog->setEnabled (false);
+
+ mFileQuit = KStdAction::quit(this, SLOT(close()), coll);
+
+ // setup Edit menu
+ mEditUndo = KStdAction::undo(this, SLOT(editUndo()), coll);
+ mEditUndo->setEnabled (false);
+ mEditRedo = KStdAction::redo(this, SLOT(editRedo()), coll);
+ mEditUndo->setEnabled (false);
+ mEditCut = KStdAction::cut(this, SLOT(editCut()), coll);
+ mEditCopy = KStdAction::copy(this, SLOT(editCopy()), coll);
+ mEditPaste = KStdAction::paste(this, SLOT(editPaste()), coll);
+ mPasteAppend = KStdAction::paste (this, SLOT (pasteAppend()),
+ coll, "ksysv_paste_append");
+
+ mEditProperties = new KAction (i18n("P&roperties"), 0,
+ this, SLOT(properties()),
+ coll, "ksysv_properties");
+
+ mOpenDefault = new KAction (i18n ("&Open"), 0,
+ this, SLOT (editService()),
+ coll, "ksysv_open_service");
+
+ mOpenWith = new KActionMenu (i18n ("Open &With"), coll, "ksysv_open_with");
+
+ // setup Settings menu
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+ KStdAction::keyBindings (this, SLOT(configureKeys()), coll);
+ KStdAction::configureToolbars (this, SLOT(configureToolbars()), coll);
+ KStdAction::saveOptions(this, SLOT(saveOptions()), coll);
+ KStdAction::preferences(this, SLOT(slotShowConfig()), coll);
+ mOptionsToggleLog = new KToggleAction (i18n("Show &Log"), "toggle_log", 0,
+ this, SLOT (toggleLog()),
+ coll, "ksysv_toggle_log");
+ mOptionsToggleLog->setCheckedState(i18n("Hide &Log"));
+
+ // setup Tools menu
+ mToolsStartService = new KToggleAction (i18n("&Start Service..."), "ksysv_start", 0,
+ mStartDlg, SLOT (toggle()),
+ coll, "ksysv_start_service");
+
+ mToolsStopService = new KToggleAction (i18n("&Stop Service..."), "ksysv_stop", 0,
+ mStopDlg, SLOT (toggle()),
+ coll, "ksysv_stop_service");
+
+ mToolsRestartService = new KToggleAction (i18n("&Restart Service..."), 0,
+ mRestartDlg, SLOT (toggle()),
+ coll, "ksysv_restart_service");
+
+ mToolsEditService = new KToggleAction (i18n("&Edit Service..."), 0,
+ mEditDlg, SLOT (toggle()),
+ coll, "ksysv_edit_service");
+
+ createGUI(xmlFile());
+}
+
+//
+bool KSVTopLevel::queryExit()
+{
+ uint res = KMessageBox::Continue;
+
+ if (mChanged) {
+ res = KMessageBox::warningContinueCancel(kapp->mainWidget(),
+ i18n("There are unsaved changes. Are you sure you want to quit?"),
+ i18n("Quit"),
+ KStdGuiItem::quit());
+
+ }
+
+ return res == KMessageBox::Continue;
+}
+
+void KSVTopLevel::slotClearChanges()
+{
+ if (mChanged &&
+ KMessageBox::Yes ==
+ KMessageBox::questionYesNo(kapp->mainWidget(),
+ i18n("Do you really want to revert all unsaved changes?"),
+ i18n("Revert Configuration"),
+ i18n("&Revert"),
+ KStdGuiItem::cancel()))
+ {
+ mUndoList->undoAll();
+ mRedoList->clear();
+ }
+}
+
+void KSVTopLevel::slotAcceptChanges() {
+ if (KMessageBox::Continue ==
+ KMessageBox::warningContinueCancel(kapp->mainWidget(),
+ i18n("You're about to save the changes made to your init "
+ "configuration. Wrong settings can "
+ "make your system hang on startup.\n"
+ "Do you wish to continue?"),
+ i18n("Save Configuration"),
+ KStdGuiItem::save()))
+ {
+ mView->slotWriteSysV();
+ initView();
+ }
+}
+
+void KSVTopLevel::initView()
+{
+ const bool authEnabled = mAuth->isCheckEnabled();
+ mAuth->setCheckEnabled(false);
+
+ mUndoList->clear();
+ mRedoList->clear();
+
+ mView->initScripts();
+ mView->initRunlevels();
+
+ setChanged(false);
+
+ // disable ToolsMenu_ entries when they can't do anything
+ ServiceDlg* tmp = new ServiceDlg ("","", this);
+
+ tmp->resetChooser (mView->scripts, false);
+ if (!tmp->count())
+ {
+ mToolsStartService->setEnabled (false);
+ mToolsStopService->setEnabled (false);
+ mToolsRestartService->setEnabled (false);
+ }
+ else
+ {
+ mToolsStartService->setEnabled (true);
+ mToolsStopService->setEnabled (true);
+ mToolsRestartService->setEnabled (true);
+ }
+
+ tmp->resetChooser (mView->scripts, true);
+ if (!tmp->count())
+ {
+ mToolsEditService->setEnabled (false);
+ }
+ else
+ {
+
+ mToolsEditService->setEnabled (true);
+ }
+ delete tmp;
+
+ // reset tools
+ mStartDlg->resetChooser (mView->scripts, false);
+ mStopDlg->resetChooser (mView->scripts, false);
+ mRestartDlg->resetChooser (mView->scripts, false);
+ mEditDlg->resetChooser (mView->scripts, true);
+
+ mAuth->setCheckEnabled(authEnabled);
+}
+
+void KSVTopLevel::initStatusBar()
+{
+ KStatusBar* status = statusBar();
+
+ QHBox* visBox = new QHBox (status, "visBox");
+ QButtonGroup* group = new QButtonGroup (this, "visButtonGroup");
+ group->hide();
+ connect (group, SIGNAL (clicked (int)), this, SLOT (toggleRunlevel (int)));
+
+ QWhatsThis::add (visBox, i18n ("<p>Click on the checkboxes to <strong>show</strong> or "\
+ "<strong>hide</strong> runlevels.</p> " \
+ "<p>The list of currently visible runlevels is saved "\
+ "when you use the <strong>Save Options command</strong>.</p>"));
+ QToolTip::add (visBox, i18n ("Show only the selected runlevels"));
+
+ new QLabel (i18n("Show runlevels:"), visBox, "visLabel");
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ {
+ QString label; label.setNum (i);
+
+ mVisible[i] = new QCheckBox (label, visBox, label.latin1());
+ mVisible[i]->setChecked (mConfig->showRunlevel (i));
+
+ group->insert (mVisible[i]);
+ }
+
+ QHBox* authIconBox = new QHBox (status, "AuthIconBox");
+ QWidget* strut = new QWidget (authIconBox, "Strut");
+ strut->setFixedWidth (KDialog::spacingHint());
+ mAuth = new RunlevelAuthIcon (mConfig->scriptPath(), mConfig->runlevelPath(), authIconBox);
+ connect (mAuth, SIGNAL (authChanged(bool)), mView, SLOT(multiplexEnabled(bool)));
+ connect (mAuth, SIGNAL (authChanged(bool)), this, SLOT(writingEnabled(bool)));
+
+ QWhatsThis::add (authIconBox, i18n ("<p>If the lock is closed <img src=\"user|ksysv_locked\"/>, "\
+ "you don't have the right " \
+ "<strong>permissions</strong> to edit the init configuration.</p>" \
+ "<p>Either restart %1 as root (or another more privileged user), " \
+ "or ask your sysadmin to install %1 <em>suid</em> or " \
+ "<em>sgid</em>.</p><p>The latter way is <strong>not</strong> "\
+ "recommended though, due to security issues.</p>")
+ .arg (kapp->aboutData()->programName()).arg(kapp->aboutData()->programName()));
+
+ authIconBox->setMinimumSize (authIconBox->minimumSizeHint());
+ visBox->setMinimumSize (visBox->minimumSizeHint());
+
+ status->addWidget (authIconBox, 0, false);
+ status->insertItem ("", Status::Changed, 100);
+ status->addWidget (visBox, 0, true);
+
+ status->setItemAlignment (Status::Changed, AlignLeft|AlignVCenter);
+}
+
+void KSVTopLevel::slotShowConfig()
+{
+ if (!mPreferences)
+ {
+ mPreferences = KSVPreferences::self();
+
+ connect (mPreferences, SIGNAL (updateColors ()),
+ this, SLOT (updateColors ()));
+
+ connect (mPreferences, SIGNAL (updateServicesPath ()),
+ this, SLOT (updateServicesPath ()));
+
+ connect (mPreferences, SIGNAL (updateRunlevelsPath ()),
+ this, SLOT (updateRunlevelsPath ()));
+
+ connect (mPreferences, SIGNAL (updateFonts ()),
+ mView, SLOT (repaintRunlevels ()));
+ }
+
+// mPreferences->setInitialSize (QSize (400,300), true);
+ mPreferences->exec();
+}
+
+void KSVTopLevel::updateColors ()
+{
+ ksv::serviceCompletion ()->clear ();
+
+ mView->setColors (mConfig->newNormalColor(),
+ mConfig->newSelectedColor(),
+ mConfig->changedNormalColor(),
+ mConfig->changedSelectedColor());
+}
+
+void KSVTopLevel::updateServicesPath ()
+{
+ mView->updateServicesAfterChange (mConfig->scriptPath());
+ mAuth->setServicesPath (mConfig->scriptPath());
+}
+
+void KSVTopLevel::updateRunlevelsPath ()
+{
+ mView->updateRunlevelsAfterChange ();
+ mAuth->setRunlevelPath (mConfig->runlevelPath());
+}
+
+void KSVTopLevel::slotReadConfig() {
+ setLog(mConfig->showLog());
+}
+
+void KSVTopLevel::toggleLog() {
+ const bool value = !mConfig->showLog();
+ setLog(value);
+}
+
+void KSVTopLevel::saveOptions()
+{
+ mConfig->writeSettings();
+}
+
+void KSVTopLevel::slotUpdateRunning (const QString& text)
+{
+ statusBar()->changeItem(text, Status::Changed);
+}
+
+void KSVTopLevel::editCut() {
+ KSVDragList* list = mView->getOrigin();
+
+ if (list && list->currentItem())
+ {
+ KSVDrag* mime = new KSVDrag (*list->currentItem()->data(), 0L, 0L);
+ kapp->clipboard()->setData (mime);
+
+ KSVData data = *list->currentItem()->data();
+ delete list->currentItem();
+
+ mUndoList->push (new RemoveAction (list, &data));
+ setChanged (true);
+ }
+}
+
+void KSVTopLevel::editCopy()
+{
+ KSVDragList* list = mView->getOrigin();
+
+ if (list)
+ {
+ KSVDrag* mime = new KSVDrag (*static_cast<KSVItem*> (list->currentItem()), 0L, 0L);
+ kapp->clipboard()->setData (mime);
+ }
+}
+
+void KSVTopLevel::editPaste()
+{
+ KSVDragList* list = mView->getOrigin();
+
+ if (list)
+ {
+ KSVData data;
+
+ if (KSVDrag::decodeNative (kapp->clipboard()->data(), data))
+ {
+ KSVAction* action = 0L;
+
+ if (list->insert (data, list->currentItem(), action))
+ {
+ setChanged (true);
+ mUndoList->push (new AddAction (list, list->match (data)->data()));
+ }
+ }
+ }
+ else
+ qFatal("Bug: could not get origin of \"Paste\" event.\n" \
+ "Please notify the maintainer of this program,\n" \
+ "Peter Putzer <putzer@kde.org>.");
+}
+
+void KSVTopLevel::setChanged (bool val)
+{
+ mChanged = val;
+ setCaption(val);
+
+ mFileRevert->setEnabled (val);
+ mFileSave->setEnabled (val);
+
+ // update statusbar
+ statusBar()->changeItem(val ? i18n(" Changed") : QString::null, Status::Changed);
+
+ // clear messages
+ statusBar()->clear();
+}
+
+void KSVTopLevel::properties()
+{
+ KSVDragList* list = mView->getOrigin();
+
+ if (list)
+ mView->infoOnData(list->currentItem());
+}
+
+void KSVTopLevel::scriptProperties()
+{
+ KSVDragList* list = mView->getOrigin();
+
+ if (list)
+ mView->slotScriptProperties(list->currentItem());
+}
+
+void KSVTopLevel::editUndo ()
+{
+ KSVAction* action = mUndoList->top();
+
+ mUndoList->undoLast();
+
+ mRedoList->push (action);
+}
+
+void KSVTopLevel::editRedo ()
+{
+ KSVAction* action = mRedoList->top();
+
+ mRedoList->redoLast();
+
+ setChanged (true);
+ mUndoList->push (action);
+}
+
+void KSVTopLevel::setPaste (bool val)
+{
+ mEditPaste->setEnabled (val);
+ mPasteAppend->setEnabled (val);
+}
+
+void KSVTopLevel::setLog (bool val)
+{
+ mConfig->setShowLog(val);
+
+ mOptionsToggleLog->setChecked (val);
+
+ mView->setDisplayScriptOutput(val);
+}
+
+void KSVTopLevel::writingEnabled (bool on)
+{
+ mFileLoad->setEnabled(on);
+}
+
+void KSVTopLevel::print()
+{
+// #define checkPage if (metrics.height() - y < fm.lineSpacing()) prt.newPage();
+
+// static KPrinter prt;
+// prt.setDocName(kapp->aboutData()->programName() + " Configuration");
+// prt.setCreator(kapp->aboutData()->programName());
+
+// static QPrintDialog* dlg = new QPrintDialog (&prt, this, "KSysV Print Dialog");
+// dlg->setCaption(kapp->makeStdCaption (i18n("Print")));
+
+// if (dlg->exec() == QDialog::Accepted)
+// {
+// int y = 10;
+// QPainter p;
+// p.begin( &prt );
+
+// QPaintDeviceMetrics metrics (&prt);
+
+// p.setFont (QFont("courier", 20, QFont::Bold));
+// QFontMetrics fm = p.fontMetrics();
+
+// p.drawText (10, y, i18n("%1 Configuration of %2")
+// .arg (kapp->aboutData()->programName())
+// .arg (ksv::hostname()));
+// y += fm.lineSpacing();
+
+// p.drawText (10, y, QDateTime::currentDateTime().toString());
+// y += fm.lineSpacing() * 2; // an extra empty line
+
+// for (int i = 0; i < ksv::runlevelNumber; ++i)
+// {
+// p.setFont (QFont("courier", 16, QFont::Bold));
+// QFontMetrics fm = p.fontMetrics();
+
+// p.drawText (10, y, i18n ("Runlevel %1").arg(i));
+// y += fm.lineSpacing();
+
+// checkPage
+
+// p.drawText (10, y, i18n ("Started Services"));
+// y += fm.lineSpacing() * 2; // an extra empty line
+
+// checkPage
+
+// p.setFont (QFont("courier", 10));
+// fm = p.fontMetrics();
+
+// for (QListViewItemIterator it (mView->startRL[i]);
+// it.current();
+// ++it)
+// {
+// KSVItem* item = static_cast<KSVItem*> (it.current());
+
+// y += fm.ascent();
+// p.drawText (10, y, item->toString());
+// y += fm.descent();
+
+// checkPage
+
+// }
+
+// p.setFont (QFont("courier", 16, QFont::Bold));
+// fm = p.fontMetrics();
+// y += fm.lineSpacing(); // an extra empty line
+// p.drawText (10, y, i18n ("Stopped Services"));
+// y += fm.lineSpacing() * 2; // an extra empty line
+
+// checkPage
+
+// p.setFont (QFont("courier", 10));
+// fm = p.fontMetrics();
+
+// for (QListViewItemIterator it (mView->stopRL[i]);
+// it.current();
+// ++it)
+// {
+// KSVItem* item = static_cast<KSVItem*> (it.current());
+// checkPage
+
+// y += fm.ascent();
+// p.drawText (10, y, item->toString());
+// y += fm.descent();
+// }
+// checkPage
+
+// p.setFont (QFont("courier", 16, QFont::Bold));
+// fm = p.fontMetrics();
+// y += fm.lineSpacing() * 3; // two extra empty line
+// }
+// // QStringList lines = QStringList::split ('\n', mView->log(), true);
+// // for(QStringList::Iterator it = lines.begin();
+// // it != lines.end();
+// // ++it)
+// // {
+// // y += fm.ascent();
+
+// // QString line = *it;
+// // if (line.isNull())
+// // line = " ";
+
+// // line.replace( QRegExp("\t"), " " );
+
+// // strncpy(buf,line.data(),160);
+
+// // for (int j = 0 ; j <150; j++)
+// // {
+// // if (!isprint(buf[j]))
+// // buf[j] = ' ';
+// // }
+
+// // buf[line.length()] = '\0';
+// // p.drawText( 10, y, buf );
+// // y += fm.descent();
+// // }
+
+// p.end();
+// }
+}
+
+void KSVTopLevel::printLog()
+{
+ KPrinter *prt = new KPrinter();
+ prt->setDocName(kapp->aboutData()->programName() + " Log File");
+ prt->setCreator(kapp->aboutData()->programName());
+
+ if (prt->setup(this, i18n("Print Log File")))
+ {
+ KBusyManager::self()->setBusy (true);
+
+ QPainter p (prt);
+ QPaintDeviceMetrics pm (prt);
+ const int height = pm.height();
+ const int width = pm.width();
+
+ QStringList lines = QStringList::split ('\n', mView->xmlLog(), true);
+ QStringList::Iterator line = lines.begin();
+
+ int y = 0;
+
+ {
+ QSimpleRichText rheading (i18n("<h1>KDE Sys-V Init Editor Log</h1>"),
+ QFont("times"), QString::null, ksv::styleSheet(),
+ QMimeSourceFactory::defaultFactory());
+ rheading.setWidth (&p, width);
+ int tmp_h = rheading.height();
+ QRegion region (0, y, width, tmp_h);
+ rheading.draw (&p, 0, y, region, colorGroup(), 0L);
+
+ y += tmp_h;
+
+ QSimpleRichText rdate (i18n("<h3>Printed on %1</h3><br/><br/>").arg(KGlobal::locale()->formatDateTime(QDateTime::currentDateTime())),
+ QFont("times"), QString::null, ksv::styleSheet(),
+ QMimeSourceFactory::defaultFactory());
+ rdate.setWidth (&p, width);
+ tmp_h = rdate.height();
+ QRegion r2 (0, y, width, tmp_h);
+ rdate.draw (&p, 0, y, r2, colorGroup(), 0L);
+
+ y += tmp_h;
+ }
+
+ while (line != lines.end())
+ {
+ while (y < height)
+ {
+ QSimpleRichText rich (*line, QFont("times"), QString::null, ksv::styleSheet(),
+ QMimeSourceFactory::defaultFactory());
+ rich.setWidth (&p, width);
+
+ int tmp_h = rich.height();
+ if (y + tmp_h > height)
+ break;
+
+ QRegion region (0, y, width, tmp_h);
+ rich.draw (&p, 0, y, region, colorGroup(), 0L);
+
+ y += tmp_h;
+ ++line;
+
+ if (line == lines.end())
+ goto printing_finished;
+
+ kapp->processEvents();
+ }
+
+ prt->newPage();
+ y = 0;
+ }
+
+ printing_finished:
+
+ p.end();
+
+ KBusyManager::self()->restore();
+ delete prt;
+ }
+}
+
+void KSVTopLevel::catchCannotGenerateNumber()
+{
+ if (mConfig->showMessage (ksv::CouldNotGenerateSortingNumber)) {
+ KMessageBox::information (kapp->mainWidget(),
+ i18n ("<p>Unable to generate a valid " \
+ "sorting number for this position. This means " \
+ "that there was no number available between "\
+ "the two adjacent services, and the service " \
+ "did not fit in lexically.</p>" \
+ "<p>Please adjust the sorting numbers manually "\
+ "via the <strong>Properties dialog box</strong>.</p>"),
+ i18n ("Unable to Generate Sorting Number"),
+ ksv::notifications[ksv::CouldNotGenerateSortingNumber]);
+ }
+
+ statusBar()->message (i18n ("Unable to generate sorting number. Please change manually."),
+ 5000);
+}
+
+void KSVTopLevel::closeEvent (QCloseEvent* e)
+{
+ if (KBusyManager::self()->isBusy())
+ {
+ // do not allow a close during clearing => otherwise we get a segfault
+ e->ignore();
+ return;
+ }
+
+ KMainWindow::closeEvent (e);
+}
+
+void KSVTopLevel::dispatchEdit ()
+{
+ KSVDragList* list = mView->getOrigin();
+
+ if (!list)
+ {
+ mEditCopy->setEnabled (false);
+ mEditCut->setEnabled (false);
+ mEditProperties->setEnabled (false);
+ setPaste (false);
+
+ return;
+ }
+
+ KSVItem* current = list->currentItem();
+
+ if (current) // there's a list, and it's got items...
+ {
+ mEditCopy->setEnabled (true);
+ mEditCut->setEnabled (true);
+ mEditProperties->setEnabled (true);
+ }
+ else // no current item
+ {
+ mEditCopy->setEnabled (false);
+ mEditCut->setEnabled (false);
+ mEditProperties->setEnabled (false);
+ }
+
+ if (mView->scripts == list)
+ {
+ mEditCut->setEnabled (false);
+ setPaste (false);
+ }
+ else
+ {
+ QMimeSource* mime = kapp->clipboard()->data();
+
+ if (mime && mime->provides ("application/x-ksysv"))
+ setPaste (true);
+ else
+ setPaste (false);
+ }
+}
+
+void KSVTopLevel::enableUndo()
+{
+ mEditUndo->setEnabled (true);
+}
+
+void KSVTopLevel::disableUndo()
+{
+ mEditUndo->setEnabled (false);
+ setChanged(false);
+}
+
+void KSVTopLevel::enableRedo()
+{
+ mEditRedo->setEnabled (true);
+}
+
+void KSVTopLevel::disableRedo ()
+{
+ mEditRedo->setEnabled (false);
+}
+
+void KSVTopLevel::slotSaveLog()
+{
+ static const QString& filter = ksv::logFileFilter();
+ static const QString& ext = ksv::logFileExtension();
+ QString filename = KFileDialog::getSaveFileName(0L, filter, this);
+
+ if (filename.isEmpty())
+ return;
+ else if (filename.right(ext.length()) != ext)
+ filename += ext;
+
+ QFile file(filename);
+
+ file.open( IO_WriteOnly | IO_Raw );
+ QTextStream s(&file);
+
+ s << "KDE System V Init Editor"
+ << endl
+ << QDateTime::currentDateTime().toString()
+ << endl << endl
+ << mView->log()
+ << endl;
+
+ file.close();
+}
+
+void KSVTopLevel::enableLogActions ()
+{
+ mFileSaveLog->setEnabled (true);
+ mFilePrintLog->setEnabled (true); // disabled due to complexity
+}
+
+void KSVTopLevel::setCaption (bool changed)
+{
+ setPlainCaption (kapp->makeStdCaption(KNetwork::KResolver::localHostName(), true, changed));
+}
+
+KActionCollection* KSVTopLevel::filteredActions ()
+{
+ // remove unwanted (internal) actions
+ static KActionCollection coll = *actionCollection();
+ static bool initialized = false;
+
+ if (!initialized)
+ {
+ coll.take(mPasteAppend);
+ coll.take(mOpenDefault);
+ initialized = true;
+ }
+
+ return &coll;
+}
+
+void KSVTopLevel::configureKeys ()
+{
+ KKeyDialog::configure (filteredActions(), this, true);
+}
+
+void KSVTopLevel::configureToolbars ()
+{
+ KEditToolbar dlg(filteredActions(), xmlFile(), true, this);
+ connect(&dlg, SIGNAL( newToolbarConfig() ), this, SLOT( slotNewToolbarConfig() ));
+ dlg.exec();
+}
+
+void KSVTopLevel::slotNewToolbarConfig()
+{
+ createGUI (xmlFile());
+}
+
+void KSVTopLevel::dispatchEditService (bool val)
+{
+ mToolsEditService->setChecked (val);
+}
+
+void KSVTopLevel::dispatchStartService (bool val)
+{
+ mToolsStartService->setChecked (val);
+}
+
+void KSVTopLevel::dispatchStopService (bool val)
+{
+ mToolsStopService->setChecked (val);
+}
+
+void KSVTopLevel::dispatchRestartService (bool val)
+{
+ mToolsRestartService->setChecked (val);
+}
+
+void KSVTopLevel::pasteAppend ()
+{
+ mView->pasteAppend ();
+}
+
+void KSVTopLevel::editService ()
+{
+ mView->editService ();
+}
+
+void KSVTopLevel::toggleRunlevel (int index)
+{
+ bool state = mVisible[index]->isChecked();
+
+ if (state)
+ mView->showRunlevel (index);
+ else
+ mView->hideRunlevel (index);
+
+ mConfig->setShowRunlevel (index, state);
+}
+
+void KSVTopLevel::saveAs ()
+{
+ static const QString& filter = ksv::nativeFileFilter();
+ static const QString& ext = ksv::nativeFileExtension();
+ QString filename = KFileDialog::getSaveFileName(0L, filter, this);
+
+ if (filename.isEmpty())
+ return;
+ else if (filename.right(ext.length()) != ext)
+ filename += ext;
+
+ QFile file(filename);
+ // we're busy
+ KBusyManager::self()->setBusy (true);
+
+ file.open (IO_WriteOnly | IO_Raw);
+ QDataStream s (&file);
+
+ if (ksv::IO::saveConfiguration (s, mView->startRL, mView->stopRL))
+ {
+ statusBar()->message(i18n("Configuration package saved successfully."), 5000);
+ }
+ else
+ {
+ kdDebug(3000) << "ERROR saving file" << endl;
+ }
+
+ file.close();
+
+ KBusyManager::self()->restore();
+}
+
+void KSVTopLevel::load ()
+{
+ static const QString& filter = ksv::nativeFileFilter();
+ QString filename = KFileDialog::getOpenFileName(0L, filter, this);
+
+ if (filename.isEmpty())
+ return;
+
+ QFile file(filename);
+ KBusyManager::self()->setBusy (true);
+
+ file.open (IO_ReadOnly | IO_Raw);
+ QDataStream s (&file);
+ QValueList<KSVData>* startLists = new QValueList<KSVData>[ksv::runlevelNumber];
+ QValueList<KSVData>* stopLists = new QValueList<KSVData>[ksv::runlevelNumber];
+
+ if (ksv::IO::loadSavedConfiguration (s, startLists, stopLists))
+ {
+ statusBar()->message(i18n("Configuration package loaded successfully."), 5000);
+ mView->mergeLoadedPackage (startLists, stopLists);
+ }
+ else
+ {
+ kdDebug (3000) << "ERROR loading file" << endl;
+ }
+
+ file.close();
+
+ delete[] startLists;
+ delete[] stopLists;
+
+ KBusyManager::self()->restore();
+}
+
+void KSVTopLevel::pushUndoAction (KSVAction* action)
+{
+ mRedoList->clear();
+ mUndoList->push (action);
+
+ setChanged(true);
+}
+
+#include "TopWidget.moc"
diff --git a/ksysv/TopWidget.h b/ksysv/TopWidget.h
new file mode 100644
index 0000000..6415538
--- /dev/null
+++ b/ksysv/TopWidget.h
@@ -0,0 +1,153 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_TOPWIDGET_H
+#define KSV_TOPWIDGET_H
+
+#include <kmainwindow.h>
+
+class QCheckBox;
+
+class KAction;
+class KToggleAction;
+class KActionMenu;
+class KMenuBar;
+class KStatusBar;
+class KToolBar;
+class KActionCollection;
+
+class ActionList;
+class KSVAction;
+class ServiceDlg;
+class KSVConfig;
+class KSVItem;
+class KSVContent;
+class KSVPreferences;
+class RunlevelAuthIcon;
+
+class KSVTopLevel : public KMainWindow
+{
+ Q_OBJECT
+
+public:
+ KSVTopLevel();
+ virtual ~KSVTopLevel();
+
+public slots:
+ void setCaption (bool changed);
+
+protected:
+ virtual bool queryExit();
+ virtual void closeEvent( QCloseEvent* e );
+ void initTools();
+ void initActions ();
+ void initStatusBar();
+
+ KActionCollection* filteredActions ();
+
+private slots:
+ void slotClearChanges();
+ void slotAcceptChanges();
+ void pushUndoAction (KSVAction*);
+ void slotShowConfig();
+ void slotReadConfig();
+ void pasteAppend ();
+ void toggleLog();
+ void saveOptions();
+ void slotUpdateRunning (const QString&);
+ void editCut();
+ void editCopy();
+ void editPaste();
+ void editUndo();
+ void editRedo();
+ void editService ();
+ void saveAs ();
+ void load ();
+ void print();
+ void printLog();
+ void setChanged( bool val = true );
+ void setPaste( bool val = false );
+ void properties();
+ void scriptProperties();
+ void setLog( bool val );
+ void catchCannotGenerateNumber();
+
+ void configureKeys ();
+ void configureToolbars ();
+
+ void enableUndo();
+ void disableUndo();
+ void enableRedo();
+ void disableRedo();
+
+ void dispatchEditService (bool);
+ void dispatchStartService (bool);
+ void dispatchStopService (bool);
+ void dispatchRestartService (bool);
+
+ void dispatchEdit ();
+
+ /**
+ * initialize the view (plus some other things)
+ */
+ void initView();
+
+ void slotSaveLog();
+ void enableLogActions();
+
+ void toggleRunlevel (int index);
+
+ void updateColors ();
+ void updateServicesPath ();
+ void updateRunlevelsPath ();
+
+ void writingEnabled (bool);
+ void slotNewToolbarConfig();
+
+private:
+ KSVConfig* mConfig;
+ KSVContent* mView;
+
+ KSVPreferences* mPreferences;
+
+ KAction *mEditUndo, *mEditRedo, *mEditCut, *mEditCopy, *mEditPaste,
+ *mPasteAppend, *mEditProperties;
+
+ KAction *mFileRevert, *mFileLoad, *mFilePrint, *mFilePrintLog,
+ *mFileSave, *mFileSaveAs, *mFileSaveLog, *mFileQuit;
+
+ KToggleAction *mToolsStartService, *mToolsStopService,
+ *mToolsRestartService, *mToolsEditService;
+
+ KToggleAction *mOptionsToggleLog;
+
+ KActionMenu* mOpenWith;
+ KAction* mOpenDefault;
+
+ bool mChanged;
+
+ ActionList* mUndoList;
+ ActionList* mRedoList;
+
+ ServiceDlg* mStartDlg;
+ ServiceDlg* mStopDlg;
+ ServiceDlg* mRestartDlg;
+ ServiceDlg* mEditDlg;
+
+ RunlevelAuthIcon* mAuth;
+ QCheckBox** mVisible;
+};
+
+#endif // KSV_TOPWIDGET_H
+
diff --git a/ksysv/configure.in.in b/ksysv/configure.in.in
new file mode 100644
index 0000000..e97862c
--- /dev/null
+++ b/ksysv/configure.in.in
@@ -0,0 +1,11 @@
+dnl Disabled on BSD, where it doesn't apply
+AC_MSG_CHECKING(if ksysv can be compiled)
+case "$host" in
+ *-*-*bsd-gnu) ksysv_compile=yes;;
+ *-*-*bsd*) ksysv_compile=no;;
+ *) ksysv_compile=yes;;
+esac
+AC_MSG_RESULT($ksysv_compile)
+if test "$ksysv_compile" = "no"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE ksysv"
+fi
diff --git a/ksysv/configwizard.ui b/ksysv/configwizard.ui
new file mode 100644
index 0000000..8edc980
--- /dev/null
+++ b/ksysv/configwizard.ui
@@ -0,0 +1,626 @@
+<!DOCTYPE UI><UI>
+<class>ConfigWizard</class>
+<author>Peter Putzer</author>
+<include location="global">klocale.h</include>
+<pixmapfunction>DesktopIcon</pixmapfunction>
+<widget>
+ <class>QWizard</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>ConfigWizard</cstring>
+ </property>
+ <property stdset="1">
+ <name>geometry</name>
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>394</width>
+ <height>291</height>
+ </rect>
+ </property>
+ <property stdset="1">
+ <name>caption</name>
+ <string>Configuration Wizard</string>
+ </property>
+ <property>
+ <name>layoutMargin</name>
+ </property>
+ <property>
+ <name>layoutSpacing</name>
+ </property>
+ <widget>
+ <class>QWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mOSPage</cstring>
+ </property>
+ <attribute>
+ <name>title</name>
+ <string>Operating System</string>
+ </attribute>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&lt;h3&gt;What Operating System do you use?&lt;/h3&gt;</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QFrame</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mOSSpacer</cstring>
+ </property>
+ <property stdset="1">
+ <name>frameShadow</name>
+ <enum>Plain</enum>
+ </property>
+ <property stdset="1">
+ <name>frameShape</name>
+ <enum>NoFrame</enum>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget>
+ <class>QButtonGroup</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mOSBox</cstring>
+ </property>
+ <property stdset="1">
+ <name>title</name>
+ <string>Choose Your Operating System</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>RadioButton7</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Linux</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>RadioButton8</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Other</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>Spacer1</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Vertical</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget>
+ <class>QWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistributionPage</cstring>
+ </property>
+ <attribute>
+ <name>title</name>
+ <string>Distribution</string>
+ </attribute>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>QButtonGroup</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistributionBox</cstring>
+ </property>
+ <property stdset="1">
+ <name>title</name>
+ <string>Choose Your Distribution</string>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>11</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>6</number>
+ </property>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistrib1</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Debian GNU/Linux</string>
+ </property>
+ <property stdset="1">
+ <name>checked</name>
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistrib2</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Red Hat Linux</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistrib3</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;SuSE Linux</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistrib4</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Mandrake Linux</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistrib5</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Corel Linux OS</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistrib6</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Conec&amp;tiva Linux</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QRadioButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mDistrib7</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Other</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>mDistribSpacer</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Vertical</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget>
+ <class>QWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mPathsPage</cstring>
+ </property>
+ <attribute>
+ <name>title</name>
+ <string>Paths</string>
+ </attribute>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mServicesLayout</cstring>
+ </property>
+ <property>
+ <name>layoutMargin</name>
+ </property>
+ <property>
+ <name>layoutSpacing</name>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mServicesLabel</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Service path:</string>
+ </property>
+ <property>
+ <name>buddy</name>
+ <cstring>mServicesPath</cstring>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mServicesButtonLayout</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>KLineEdit</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mServicesPath</cstring>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ </sizepolicy>
+ </property>
+ <property stdset="1">
+ <name>focusPolicy</name>
+ <enum>StrongFocus</enum>
+ </property>
+ <property>
+ <name>toolTip</name>
+ <string>Enter the path to the folder containing the services</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QPushButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mBrowseServices</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Browse...</string>
+ </property>
+ <property>
+ <name>toolTip</name>
+ <string>Select the folder containing the services</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget>
+ <class>QFrame</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mSpacer</cstring>
+ </property>
+ <property stdset="1">
+ <name>frameShadow</name>
+ <enum>Plain</enum>
+ </property>
+ <property stdset="1">
+ <name>frameShape</name>
+ <enum>NoFrame</enum>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ </sizepolicy>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mRunlevelLayout</cstring>
+ </property>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mRunlevelLabel</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&amp;Runlevel path:</string>
+ </property>
+ <property>
+ <name>buddy</name>
+ <cstring>mRunlevelPath</cstring>
+ </property>
+ </widget>
+ <widget>
+ <class>QLayoutWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mRunlevelButtonLayout</cstring>
+ </property>
+ <hbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>KLineEdit</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mRunlevelPath</cstring>
+ </property>
+ <property stdset="1">
+ <name>minimumSize</name>
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property stdset="1">
+ <name>sizePolicy</name>
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ </sizepolicy>
+ </property>
+ <property stdset="1">
+ <name>focusPolicy</name>
+ <enum>StrongFocus</enum>
+ </property>
+ <property>
+ <name>toolTip</name>
+ <string>Enter the path to the folder containing the runlevel folders</string>
+ </property>
+ </widget>
+ <widget>
+ <class>QPushButton</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mBrowseRunlevel</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>Br&amp;owse...</string>
+ </property>
+ <property>
+ <name>toolTip</name>
+ <string>Select the folder containing the runlevel folders </string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property>
+ <name>name</name>
+ <cstring>mEmptySpace</cstring>
+ </property>
+ <property stdset="1">
+ <name>orientation</name>
+ <enum>Vertical</enum>
+ </property>
+ <property stdset="1">
+ <name>sizeType</name>
+ <enum>Expanding</enum>
+ </property>
+ <property>
+ <name>sizeHint</name>
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget>
+ <class>QWidget</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>mFinishedPage</cstring>
+ </property>
+ <attribute>
+ <name>title</name>
+ <string>Configuration Complete</string>
+ </attribute>
+ <vbox>
+ <property stdset="1">
+ <name>margin</name>
+ <number>0</number>
+ </property>
+ <property stdset="1">
+ <name>spacing</name>
+ <number>0</number>
+ </property>
+ <widget>
+ <class>QLabel</class>
+ <property stdset="1">
+ <name>name</name>
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property stdset="1">
+ <name>text</name>
+ <string>&lt;h1&gt;Congratulations!&lt;/h1&gt;
+&lt;p&gt;
+You have finished the initial configuration of SysV-Init Editor. &lt;b&gt;Press&lt;/b&gt; the button labeled &lt;b&gt;Finish&lt;/b&gt; to start editing your init-configuration.
+&lt;/p&gt;</string>
+ </property>
+ <property stdset="1">
+ <name>textFormat</name>
+ <enum>RichText</enum>
+ </property>
+ <property stdset="1">
+ <name>alignment</name>
+ <set>AlignTop|AlignLeft</set>
+ </property>
+ <property>
+ <name>vAlign</name>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+</widget>
+<connections>
+ <connection>
+ <sender>mDistributionBox</sender>
+ <signal>clicked(int)</signal>
+ <receiver>ConfigWizard</receiver>
+ <slot>chooseDistribution(int)</slot>
+ </connection>
+ <connection>
+ <sender>mBrowseServices</sender>
+ <signal>clicked()</signal>
+ <receiver>ConfigWizard</receiver>
+ <slot>browseServices()</slot>
+ </connection>
+ <connection>
+ <sender>mBrowseRunlevel</sender>
+ <signal>clicked()</signal>
+ <receiver>ConfigWizard</receiver>
+ <slot>browseRunlevels()</slot>
+ </connection>
+ <slot access="protected">browseRunlevels()</slot>
+ <slot access="protected">chooseDistribution(int)</slot>
+ <slot access="protected">browseServices()</slot>
+</connections>
+</UI>
diff --git a/ksysv/genui.sh b/ksysv/genui.sh
new file mode 100755
index 0000000..579872f
--- /dev/null
+++ b/ksysv/genui.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+UIC="uic -tr i18n"
+PAGES="path misc lookandfeel"
+WIZARDS="config"
+OTHERS=""
+
+for i in ${PAGES}; do
+ ${UIC} -o ${i}config.h ${i}config.ui
+ ${UIC} -o ${i}config.cpp -impl ${i}config.h ${i}config.ui
+done
+
+for i in ${WIZARDS}; do
+ n="${i}wizard"
+ ${UIC} -o ${n}.h ${n}.ui
+ ${UIC} -o ${n}.cpp -impl ${n}.h ${n}.ui
+
+ perl -pi -e "s/qwizard\.h/kwizard\.h/" ${n}.h
+ perl -pi -e "s/QWizard/KWizard/" ${n}.{cpp,h}
+done
+
+for i in ${OTHERS}; do
+ ${UIC} -o ${i}.h ${i}.ui
+ ${UIC} -o ${i}.cpp -impl ${i}.h ${i}.ui
+done
diff --git a/ksysv/hi16-app-ksysv.png b/ksysv/hi16-app-ksysv.png
new file mode 100644
index 0000000..999809e
--- /dev/null
+++ b/ksysv/hi16-app-ksysv.png
Binary files differ
diff --git a/ksysv/hi22-app-ksysv.png b/ksysv/hi22-app-ksysv.png
new file mode 100644
index 0000000..e286b73
--- /dev/null
+++ b/ksysv/hi22-app-ksysv.png
Binary files differ
diff --git a/ksysv/hi32-app-ksysv.png b/ksysv/hi32-app-ksysv.png
new file mode 100644
index 0000000..89a85b4
--- /dev/null
+++ b/ksysv/hi32-app-ksysv.png
Binary files differ
diff --git a/ksysv/hi48-app-ksysv.png b/ksysv/hi48-app-ksysv.png
new file mode 100644
index 0000000..5845c03
--- /dev/null
+++ b/ksysv/hi48-app-ksysv.png
Binary files differ
diff --git a/ksysv/kbusymanager.cpp b/ksysv/kbusymanager.cpp
new file mode 100644
index 0000000..d6c6e9c
--- /dev/null
+++ b/ksysv/kbusymanager.cpp
@@ -0,0 +1,94 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "kbusymanager.h"
+
+#include <qvaluestack.h>
+#include <qapplication.h>
+
+#include <kcursor.h>
+#include <kapplication.h>
+
+class KBusyManager::Private
+{
+public:
+ Private()
+ : Size (-1)
+ {
+ }
+
+ ~Private()
+ {
+ }
+
+ QValueStack<bool> Stack;
+ int Size;
+};
+
+KBusyManager* KBusyManager::self ()
+{
+ static KBusyManager kb;
+
+ return &kb;
+}
+
+bool KBusyManager::isBusy () const
+{
+ return d->Stack.top();
+}
+
+void KBusyManager::setBusy (bool val)
+{
+ d->Stack.push (val);
+ d->Size++;
+
+ if (val)
+ QApplication::setOverrideCursor (KCursor::waitCursor());
+
+ kapp->mainWidget()->setEnabled (!val);
+}
+
+void KBusyManager::restore ()
+{
+ if (d->Size < 1)
+ return;
+
+ bool oldBusy = d->Stack.pop();
+
+ if (oldBusy)
+ QApplication::restoreOverrideCursor();
+
+ kapp->mainWidget()->setEnabled (!d->Stack.top());
+}
+
+KBusyManager::KBusyManager ()
+ : d (new Private())
+{
+ setBusy (false);
+}
+
+KBusyManager::~KBusyManager ()
+{
+ delete d;
+}
diff --git a/ksysv/kbusymanager.h b/ksysv/kbusymanager.h
new file mode 100644
index 0000000..2cebeaf
--- /dev/null
+++ b/ksysv/kbusymanager.h
@@ -0,0 +1,49 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef KBUSYMANAGER_H
+#define KBUSYMANAGER_H
+
+class KBusyManager
+{
+public:
+ static KBusyManager* self ();
+
+ bool isBusy () const;
+ void setBusy (bool val);
+ void restore ();
+
+ ~KBusyManager(); // to make gcc happy, should be private.
+
+private:
+ KBusyManager ();
+
+ KBusyManager& operator= (const KBusyManager&); // undefined
+
+ class Private;
+ Private* d;
+};
+
+#endif // KBUSYMANAGER_H
diff --git a/ksysv/kdltooltip.cpp b/ksysv/kdltooltip.cpp
new file mode 100644
index 0000000..a0947ce
--- /dev/null
+++ b/ksysv/kdltooltip.cpp
@@ -0,0 +1,95 @@
+/***************************************************************************
+ begin : Tue Oct 5 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#include <qrect.h>
+#include <qscrollbar.h>
+#include <qheader.h>
+
+#include <kdebug.h>
+
+#include "ksvdraglist.h"
+#include "kdltooltip.h"
+
+KDLToolTip::KDLToolTip (KSVDragList *parent, QToolTipGroup* group)
+ : QToolTip(parent, group),
+ mParent (parent)
+{
+}
+
+KDLToolTip::~KDLToolTip()
+{
+}
+
+void KDLToolTip::maybeTip (const QPoint& p)
+{
+ if (!mParent->displayToolTips())
+ return;
+
+ QString text;
+ QRect rect;
+
+ const QRect vert = mParent->verticalScrollBar()->geometry();
+ const QRect horiz = mParent->horizontalScrollBar()->geometry();
+
+ if (vert.contains(p))
+ {
+ rect = vert;
+
+ if (!mParent->commonToolTips())
+ text = mParent->verticalScrollBarTip();
+ else
+ text = mParent->tooltip();
+ }
+ else if (horiz.contains(p))
+ {
+ rect = horiz;
+ if (!mParent->commonToolTips())
+ text = mParent->horizontalScrollBarTip();
+ else
+ text = mParent->tooltip();
+
+ }
+ else
+ {
+ QPoint rp = mParent->viewport()->mapFromParent (p);
+ QListViewItem* i = mParent->itemAt (rp);
+ KSVItem* item = static_cast<KSVItem*> (i);
+
+ rect = mParent->header()->geometry();
+ if (rect.contains (p))
+ {
+ text = mParent->tooltip();
+ }
+ else if (item)
+ {
+ rect = mParent->itemRect (i);
+ rect.moveTopLeft (mParent->viewport()->mapToParent (rect.topLeft()));
+
+ text = item->tooltip();
+ }
+ else
+ {
+ rect = mParent->rect();
+
+ QListViewItem* last = mParent->lastItem();
+ if (last)
+ rect.setTop (mParent->viewport()->mapToParent (mParent->itemRect(last).bottomRight()).y());
+
+ text = mParent->tooltip();
+ }
+ }
+
+ if (!text.isEmpty())
+ tip (rect, text);
+}
diff --git a/ksysv/kdltooltip.h b/ksysv/kdltooltip.h
new file mode 100644
index 0000000..a107383
--- /dev/null
+++ b/ksysv/kdltooltip.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ begin : Tue Oct 5 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KDLTOOLTIP_H
+#define KDLTOOLTIP_H
+
+#include <qtooltip.h>
+
+class KSVDragList;
+
+/**
+ * @short custom tooltip for use in @ref KDragList
+ * @author Peter Putzer
+ */
+class KDLToolTip : public QToolTip
+{
+public:
+ KDLToolTip (KSVDragList *parent, QToolTipGroup* group = 0L);
+ virtual ~KDLToolTip();
+
+protected:
+ /**
+ * Reimplemented from QToolTip for internal reasons.
+ */
+ virtual void maybeTip (const QPoint&);
+
+private:
+ KSVDragList* mParent;
+};
+
+#endif
+
diff --git a/ksysv/kscroller.cpp b/ksysv/kscroller.cpp
new file mode 100644
index 0000000..1f69b74
--- /dev/null
+++ b/ksysv/kscroller.cpp
@@ -0,0 +1,191 @@
+// (c) 2000 Peter Putzer
+
+#include <qscrollbar.h>
+#include <qlayout.h>
+#include <qstyle.h>
+
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kapplication.h>
+
+#include "kscroller.h"
+
+class KScroller::KScrollerPrivate
+{
+public:
+ KScrollerPrivate ()
+ : setCornerWidget (0L)
+ {
+ }
+
+ ~KScrollerPrivate () {}
+
+ QWidget* setCornerWidget;
+};
+
+KScroller::KScroller (QWidget* parent, const char* name)
+ : QFrame (parent, name),
+ d (new KScrollerPrivate()),
+ mVertical (new QScrollBar (QScrollBar::Vertical, this)),
+ mHorizontal (new QScrollBar (QScrollBar::Horizontal, this)),
+ mCornerWidget (new QWidget (this)),
+ mContent (0L),
+ mVerticalOld (0),
+ mHorizontalOld (0)
+{
+ mCornerWidget->hide();
+ mVertical->hide();
+ mHorizontal->hide();
+
+ connect (mVertical, SIGNAL (valueChanged (int)),
+ this, SLOT (scrollVertical (int)));
+ connect (mHorizontal, SIGNAL (valueChanged (int)),
+ this, SLOT (scrollHorizontal (int)));
+}
+
+KScroller::~KScroller ()
+{
+ delete d;
+}
+
+void KScroller::setContent (QWidget* content)
+{
+ delete mContent;
+
+ mContent = content;
+ updateScrollBars();
+}
+
+void KScroller::setCornerWidget (QWidget* corner)
+{
+ delete mCornerWidget;
+
+ mCornerWidget = d->setCornerWidget = corner;
+
+ updateScrollBars();
+}
+
+QWidget* KScroller::cornerWidget ()
+{
+ return d->setCornerWidget;
+}
+
+void KScroller::resizeEvent (QResizeEvent* e)
+{
+ QFrame::resizeEvent (e);
+
+ updateScrollBars();
+}
+
+QSize KScroller::minimumSizeHint() const
+{
+ QSize size = sizeHint();
+ if (size.width() > 300)
+ size.setWidth(300);
+ return size;
+}
+
+QSize KScroller::sizeHint() const
+{
+ QSize size = mContent->minimumSize();
+ int extra = kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent, 0 );
+ size += QSize( extra, extra );
+ return size;
+}
+
+void KScroller::updateScrollBars ()
+{
+ int w = width();
+ int h = height();
+ QSize cs = mContent->minimumSize();
+
+ setupVertical ( cs.width(), cs.height(), w, h);
+ setupHorizontal ( cs.width(), cs.height(), w, h);
+ mContent->resize (cs);
+
+ setupCornerWidget (w, h);
+}
+
+void KScroller::setupHorizontal (int cw, int, int w, int h)
+{
+ mHorizontal->setValue (0);
+ mHorizontalOld = 0;
+
+ if (cw > w)
+ {
+ int extra = kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent, 0 );
+
+ if (!mVertical->isHidden())
+ w -= extra;
+
+ mHorizontal->setRange (0, cw - w);
+ mHorizontal->setPageStep (w);
+ mHorizontal->setLineStep (25);
+ mHorizontal->setGeometry (0, h - extra, w, extra);
+
+ mHorizontal->raise();
+ mHorizontal->show();
+ }
+ else
+ {
+ mHorizontal->hide();
+ }
+}
+
+void KScroller::setupVertical (int, int ch, int w, int h)
+{
+ mVertical->setValue (0);
+ mVerticalOld = 0;
+
+ if (ch > h)
+ {
+ int extra = kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent, 0 );
+ mVertical->setRange (0, ch - h);
+ mVertical->setPageStep (h);
+ mVertical->setLineStep (25);
+
+ mVertical->setGeometry (w - extra, 0, extra, h);
+
+ mVertical->raise();
+ mVertical->show();
+ }
+ else
+ {
+ mVertical->hide();
+ }
+}
+
+void KScroller::scrollVertical (int value)
+{
+ int amount = value - mVerticalOld;
+ mVerticalOld = value;
+
+ mContent->move (mContent->x(), mContent->y() - amount);
+}
+
+void KScroller::scrollHorizontal (int value)
+{
+ int amount = value - mHorizontalOld;
+ mHorizontalOld = value;
+
+ mContent->move (mContent->x() - amount, mContent->y());
+}
+
+void KScroller::setupCornerWidget (int w, int h)
+{
+ if (!mVertical->isHidden() && !mHorizontal->isHidden())
+ {
+ int extra = kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent, 0 );
+
+ mCornerWidget->raise();
+ mCornerWidget->setGeometry (w - extra, h - extra, extra, extra);
+
+ mCornerWidget->show();
+ }
+ else
+ {
+ mCornerWidget->hide();
+ }
+}
+
+#include "kscroller.moc"
diff --git a/ksysv/kscroller.h b/ksysv/kscroller.h
new file mode 100644
index 0000000..09329f1
--- /dev/null
+++ b/ksysv/kscroller.h
@@ -0,0 +1,150 @@
+// (c) 2000 Peter Putzer
+#ifndef KSCROLLER_H
+#define KSCROLLER_H
+
+#include <qframe.h>
+
+class QScrollBar;
+
+/**
+ * A window that automatically enables scrollbars
+ * if it's smaller than the content.
+ *
+ * @author Peter Putzer <putzer@kde.org>
+ * @version $Id$
+ */
+class KScroller : public QFrame
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Constructor.
+ *
+ * @param parent the parent of this widget (passed on as ususal).
+ * @param name the name of this widget (as above).
+ */
+ KScroller (QWidget* parent = 0L, const char* name = 0L);
+
+ /**
+ * Destructor.
+ */
+ virtual ~KScroller ();
+
+ /**
+ * @return the vertical scrollbar.
+ */
+ inline QScrollBar* verticalScrollBar () { return mVertical; }
+
+ /**
+ * @return the horizontal scrollbar.
+ */
+ inline QScrollBar* horizontalScrollBar () { return mHorizontal; }
+
+ /**
+ * @return the current content, or 0L if none set.
+ */
+ inline QWidget* content () { return mContent; }
+
+ /**
+ * @return the current corner widget, or 0L if none set.
+ */
+ QWidget* cornerWidget ();
+
+public slots:
+ /**
+ * Sets the content. Ownership is transfered to the scroller, any
+ * previously set content will be deleted!
+ *
+ * @param content has to be a child of the KScroller.
+ */
+ void setContent (QWidget* content);
+
+ /**
+ * Sets the corner widget (the small widget that's located where the vertical and horizontal scrollbars
+ * allmost meet).
+ *
+ * @param corner has to be a child of the KScroller.
+ */
+ void setCornerWidget (QWidget* corner);
+
+ /**
+ * Update the scrollbars. Call whenever you change the contents minimumSize.
+ */
+ void updateScrollBars ();
+
+protected:
+ /**
+ * Reimplemented for internal reasons, the API is not affected.
+ */
+ virtual void resizeEvent (QResizeEvent*);
+
+ /**
+ * Reimplemented for internal reasons, the API is not affected.
+ */
+ virtual QSize sizeHint() const;
+
+ /**
+ * Reimplemented for internal reasons, the API is not affected.
+ */
+ virtual QSize minimumSizeHint() const;
+
+
+private slots:
+ /**
+ * Scroll vertically.
+ *
+ * @param value is the new slider value.
+ */
+ void scrollVertical (int value);
+
+ /**
+ * Scroll horizontally.
+ *
+ * @param value is the new slider value.
+ */
+ void scrollHorizontal (int value);
+
+private:
+ /**
+ * Set up the horizontal scrollbar.
+ *
+ * @param cw is the width of the content.
+ * @param ch is the height of the content.
+ * @param w is the width of the scroller.
+ * @param h is the height of the scroller.
+ */
+ void setupHorizontal (int cw, int ch, int w, int h);
+
+ /**
+ * Set up the vertical scrollbar
+ *
+ * @param cw is the width of the content.
+ * @param ch is the height of the content.
+ * @param w is the width of the scroller.
+ * @param h is the height of the scroller.
+ */
+ void setupVertical (int cw, int ch, int w, int h);
+
+ /**
+ * Set up the corner widget.
+ *
+ * @param w is the width of the scroller.
+ * @param h is the height of the scroller.
+ */
+ void setupCornerWidget (int w, int h);
+
+ class KScrollerPrivate;
+ KScrollerPrivate* d;
+
+ QScrollBar* mVertical;
+ QScrollBar* mHorizontal;
+ QWidget* mCornerWidget;
+
+ QWidget* mContent;
+
+ int mVerticalOld;
+ int mHorizontalOld;
+};
+
+#endif // KSCROLLER_H
diff --git a/ksysv/ksv_conf.cpp b/ksysv/ksv_conf.cpp
new file mode 100644
index 0000000..aa7ce8b
--- /dev/null
+++ b/ksysv/ksv_conf.cpp
@@ -0,0 +1,224 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+// KSysV Config Object
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kmainwindow.h>
+#include <kconfig.h>
+
+#include "ksv_core.h"
+#include "ksv_conf.h"
+
+KSVConfig::KSVConfig ()
+ : mConfig (KGlobal::config())
+{
+ readSettings();
+}
+
+void KSVConfig::setPanningFactor (int val)
+{
+ mPanningFactor = val > 100 ? 100 : val;
+ mPanningFactor = mPanningFactor < 0 ? 0 : mPanningFactor;
+}
+
+void KSVConfig::readSettings()
+{
+ mConfig->setGroup("Path Settings");
+ mScriptPath = mConfig->readEntry("ScriptPath", "/etc/rc.d/init.d");
+ mRunlevelPath = mConfig->readEntry("RunlevelPath", "/etc/rc.d");
+
+ mConfig->setGroup("Other Settings");
+ mShowLog = mConfig->readBoolEntry("ShowLog", true);
+ mConfigured = mConfig->readBoolEntry("Configured", false);
+ mPanningFactor = mConfig->readNumEntry("PanningFactor", 80);
+ mShowDescription = mConfig->readBoolEntry("ShowDescription", true);
+
+ mConfig->setGroup("Colors");
+ mNewNormalColor = mConfig->readColorEntry ("New Text", &Qt::blue);
+ mNewSelectedColor = mConfig->readColorEntry ("New Selected Text", &Qt::blue);
+ mChangedNormalColor = mConfig->readColorEntry ("Changed Text", &Qt::red);
+ mChangedSelectedColor = mConfig->readColorEntry ("Changed Selected Text", &Qt::red);
+
+ mConfig->setGroup("Fonts");
+ QFont tmp = KGlobalSettings::generalFont();
+ mServiceFont = mConfig->readFontEntry ("Service Font", &tmp);
+ tmp = KGlobalSettings::fixedFont();
+ mNumberFont = mConfig->readFontEntry ("Number Font", &tmp);
+
+ readRunlevels();
+}
+
+void KSVConfig::readLegacySettings ()
+{
+ mConfig->setGroup("Path Settings");
+
+ mScriptPath = mConfig->readEntry("ScriptPath", "/etc/rc.d/init.d");
+ mRunlevelPath = mConfig->readEntry("RunlevelPath", "/etc/rc.d");
+
+ mConfig->setGroup("Other Settings");
+
+ mShowLog = mConfig->readBoolEntry("ShowLog", true);
+ mConfigured = mConfig->readBoolEntry("Configured", false);
+ mPanningFactor = mConfig->readNumEntry("PanningFactor", 80);
+ mShowDescription = mConfig->readBoolEntry("ShowDescription", true);
+ mConfig->setGroup("Colors");
+ mNewNormalColor = mConfig->readColorEntry("New", &Qt::blue);
+ mChangedNormalColor = mConfig->readColorEntry("Changed", &Qt::red);
+}
+
+void KSVConfig::writeSettings() {
+ mConfig->setGroup("Path Settings");
+ mConfig->writeEntry("ScriptPath", mScriptPath);
+ mConfig->writeEntry("RunlevelPath", mRunlevelPath);
+
+ mConfig->setGroup("Other Settings");
+ mConfig->writeEntry("ShowLog", mShowLog);
+ mConfig->writeEntry("Configured", mConfigured);
+ mConfig->writeEntry("PanningFactor", mPanningFactor);
+ mConfig->writeEntry("ShowDescription", mShowDescription);
+
+ mConfig->setGroup("Colors");
+ mConfig->writeEntry("New Text", mNewNormalColor);
+ mConfig->writeEntry("New Selected Text", mNewSelectedColor);
+ mConfig->writeEntry("Changed Text", mChangedNormalColor);
+ mConfig->writeEntry("Changed Selected Text", mChangedSelectedColor);
+
+ mConfig->setGroup("Fonts");
+ mConfig->writeEntry("Service Font", mServiceFont);
+ mConfig->writeEntry("Number Font", mNumberFont);
+
+ // save screen geometry
+ KMainWindow* mw = static_cast<KMainWindow*>(kapp->mainWidget());
+
+ if (mw)
+ {
+ mConfig->setGroup("Geometry");
+ mConfig->writeEntry("X-Position", mw->x());
+ mConfig->writeEntry("Y-Position", mw->y());
+ }
+
+ writeRunlevels();
+
+ // flush everything
+ mConfig->sync();
+}
+
+bool KSVConfig::showRunlevel (int index) const
+{
+ if (mShowRunlevel.contains (index))
+ return mShowRunlevel[index];
+ else
+ return false;
+}
+
+void KSVConfig::readRunlevels ()
+{
+ mConfig->setGroup ("Runlevels");
+
+ QValueList<int> list = mConfig->readIntListEntry ("Show Runlevels");
+
+ for (QValueList<int>::Iterator it = list.begin(); it != list.end(); ++it)
+ mShowRunlevel[*it] = true;
+
+ if (mShowRunlevel.isEmpty())
+ for (int i = 0; i < ksv::runlevelNumber; ++i)
+ mShowRunlevel[i] = true;
+}
+
+void KSVConfig::writeRunlevels ()
+{
+ QValueList<int> list;
+
+ for (QMap<int,bool>::Iterator it = mShowRunlevel.begin(); it != mShowRunlevel.end(); ++it)
+ if (it.data())
+ list.append (it.key());
+
+ mConfig->setGroup ("Runlevels");
+ mConfig->writeEntry ("Show Runlevels", list);
+}
+
+void KSVConfig::setShowRunlevel (int index, bool state)
+{
+ mShowRunlevel[index] = state;
+}
+
+QPoint KSVConfig::position() const
+{
+ mConfig->setGroup("Geometry");
+
+ return QPoint(mConfig->readNumEntry("X-Position", 0),
+ mConfig->readNumEntry("Y-Position", 0));
+}
+
+void KSVConfig::setScriptPath (const QString& path)
+{
+ mScriptPath = path;
+}
+
+void KSVConfig::setRunlevelPath (const QString& path)
+{
+ mRunlevelPath = path;
+}
+
+KSVConfig* KSVConfig::self()
+{
+ static KSVConfig conf;
+
+ return &conf;
+}
+
+void KSVConfig::setNewNormalColor (const QColor& col)
+{
+ mNewNormalColor = col;
+}
+
+void KSVConfig::setNewSelectedColor (const QColor& col)
+{
+ mNewSelectedColor = col;
+}
+
+void KSVConfig::setChangedNormalColor (const QColor& col)
+{
+ mChangedNormalColor = col;
+}
+
+void KSVConfig::setChangedSelectedColor (const QColor& col)
+{
+ mChangedSelectedColor = col;
+}
+
+void KSVConfig::setNumberFont (const QFont& font)
+{
+ mNumberFont = font;
+}
+
+void KSVConfig::setServiceFont (const QFont& font)
+{
+ mServiceFont = font;
+}
+
+void KSVConfig::setShowMessage (ksv::Messages msg, bool on)
+{
+ mConfig->setGroup("Notification Messages");
+ mConfig->writeEntry (ksv::notifications[msg], on);
+}
+
+bool KSVConfig::showMessage (ksv::Messages msg) const
+{
+ mConfig->setGroup("Notification Messages");
+ return mConfig->readBoolEntry (ksv::notifications[msg], true);
+}
+
diff --git a/ksysv/ksv_conf.h b/ksysv/ksv_conf.h
new file mode 100644
index 0000000..f17176a
--- /dev/null
+++ b/ksysv/ksv_conf.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_CONF_H
+#define KSV_CONF_H
+
+#include <qstring.h>
+#include <qpoint.h>
+#include <qfont.h>
+#include <qcolor.h>
+#include <qmap.h>
+
+#include "ksv_core.h"
+
+class KConfig;
+
+class KSVConfig
+{
+public:
+
+ inline ~KSVConfig() {}
+
+ void readSettings();
+ void readLegacySettings ();
+ void writeSettings();
+
+ void setPanningFactor (int val);
+
+ inline void setShowLog( bool val = false )
+ {
+ mShowLog = val;
+ }
+
+ void setNewNormalColor (const QColor& color);
+ void setNewSelectedColor (const QColor& color);
+ void setChangedNormalColor (const QColor& color);
+ void setChangedSelectedColor (const QColor& color);
+
+ void setServiceFont (const QFont& font);
+ void setNumberFont (const QFont& font);
+
+ void setScriptPath (const QString& path);
+ void setRunlevelPath (const QString& path);
+
+ inline void setConfigured( bool val = true )
+ {
+ mConfigured = val;
+ }
+
+ inline void setShowDescription (bool val)
+ {
+ mShowDescription = val;
+ }
+
+ inline bool showLog() const
+ {
+ return mShowLog;
+ }
+
+ inline int panningFactor() const
+ {
+ return mPanningFactor;
+ }
+
+ inline const QFont& serviceFont () const { return mServiceFont; }
+ inline const QFont& numberFont () const { return mNumberFont; }
+
+ QPoint position() const;
+
+ inline const QColor& newNormalColor () const { return mNewNormalColor; }
+ inline const QColor& newSelectedColor () const { return mNewSelectedColor; }
+
+ inline const QColor& changedNormalColor () const { return mChangedNormalColor; }
+ inline const QColor& changedSelectedColor () const { return mChangedSelectedColor; }
+
+ bool showRunlevel (int index) const;
+ void setShowRunlevel (int index, bool state);
+ void readRunlevels ();
+ void writeRunlevels ();
+
+ /**
+ * Have the necessary config entries
+ * been written?
+ */
+ inline bool isConfigured() const
+ {
+ return mConfigured;
+ }
+
+ inline const QString& scriptPath() const
+ {
+ return mScriptPath;
+ }
+
+ inline const QString& runlevelPath() const
+ {
+ return mRunlevelPath;
+ }
+
+ inline bool showDescription() const
+ {
+ return mShowDescription;
+ }
+
+ bool showMessage (ksv::Messages msg) const;
+ void setShowMessage (ksv::Messages msg, bool on);
+
+ static KSVConfig* self ();
+
+private:
+ KSVConfig ();
+
+ QString mScriptPath;
+ QString mRunlevelPath;
+ bool mShowLog;
+ bool mConfigured;
+ KConfig* mConfig;
+ int mPanningFactor;
+
+ QColor mNewNormalColor, mNewSelectedColor;
+ QColor mChangedNormalColor, mChangedSelectedColor;
+
+ bool mShowDescription;
+
+ QMap<int, bool> mShowRunlevel;
+
+ QFont mServiceFont;
+ QFont mNumberFont;
+};
+
+#endif // KSV_CONF_H
+
diff --git a/ksysv/ksv_core.cpp b/ksysv/ksv_core.cpp
new file mode 100644
index 0000000..a4e2b2c
--- /dev/null
+++ b/ksysv/ksv_core.cpp
@@ -0,0 +1,186 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#include <qpushbutton.h>
+#include <qstylesheet.h>
+
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <kcompletion.h>
+#include <klocale.h>
+#include <kglobal.h>
+
+#include "ksv_conf.h"
+#include "ksvdraglist.h"
+#include "ksv_service.h"
+#include "ksv_core.h"
+
+const int ksv::runlevelNumber = 7;
+KAboutData* ksv::about = 0L;
+
+bool ksv::getServiceDescription (const QString& path, QString& res)
+{
+ KSVService* tmp = KSVService::newService (path, KSVConfig::self()->runlevelPath());
+ res = i18n ("No description available.");
+ bool result = false;
+
+ if (tmp)
+ {
+ res = tmp->description();
+ result = true;
+ }
+
+ delete tmp;
+
+ return result;
+}
+
+QString ksv::breakWords (const QString& s, int amount)
+{
+ QString res;
+
+ int left = s.length();
+ int maximum = amount;
+ QString str = s;
+
+ while (left > maximum)
+ {
+ int pos = -1;
+ for (int i = 1; i < amount; ++i)
+ {
+ if ((pos = str.find(' ', amount - i, false)) < 0 || (pos > maximum + i))
+ continue;
+ else
+ break;
+ }
+
+ if (pos == -1) break; //handles case when no spaces
+
+ maximum = kMax (maximum, pos);
+ res += str.left(pos) + "\n";
+ left += -pos - 1;
+ str = str.right(left);
+ }
+
+ res += str;
+
+ return res;
+}
+
+const QString& ksv::copyrightSymbol ()
+{
+ static QString c = QString::fromUtf8 ("©");
+
+ return c;
+}
+
+QStyleSheet* ksv::styleSheet ()
+{
+ static QStyleSheet style;
+ static bool initialized = false;
+
+ if (!initialized)
+ {
+ QStyleSheetItem* item = new QStyleSheetItem (&style, "vip"); // very important
+ item->setLogicalFontSize (5);
+ item->setFontWeight (QFont::Bold);
+ item->setDisplayMode (QStyleSheetItem::DisplayBlock);
+
+ item = new QStyleSheetItem (&style, "rl"); // runlevel
+ item->setLogicalFontSize (4);
+ item->setFontWeight (QFont::Bold);
+// item->setDisplayMode (QStyleSheetItem::DisplayBlock);
+
+ item = new QStyleSheetItem (&style, "start"); // start section
+ item->setColor (Qt::green);
+// item->setContexts ("rl");
+
+ item = new QStyleSheetItem (&style, "stop"); // stop section
+ item->setColor (Qt::red);
+// item->setContexts ("rl");
+
+ item = new QStyleSheetItem (&style, "error"); // signal an error
+ item->setColor (Qt::red);
+ item->setLogicalFontSizeStep (1);
+
+ item = new QStyleSheetItem (&style, "cmd"); // command line
+ item->setFontFamily (KGlobalSettings::fixedFont().family());
+ }
+
+ return &style;
+}
+
+KCompletion* ksv::serviceCompletion ()
+{
+ static KCompletion comp;
+
+ return &comp;
+}
+
+KCompletion* ksv::numberCompletion ()
+{
+ static KCompletion comp;
+ static bool initialized = false;
+
+ if (!initialized)
+ {
+ for (int value = 0; value < 100; value += 10)
+ {
+ QString result = QString::number (value);
+
+ if (value < 10)
+ result.sprintf("%.2i", value);
+
+ comp.addItem (result);
+ }
+ }
+
+ return &comp;
+}
+
+const QString& ksv::logFileFilter ()
+{
+ static QString filter = "*" + ksv::logFileExtension() + "|" +
+ QString(kapp->caption() + i18n(" log files") + " (*" + ksv::logFileExtension() + ")");
+
+ return filter;
+}
+
+const QString& ksv::nativeFileFilter ()
+{
+ static QString filter = "*" + ksv::nativeFileExtension() + "|"
+ + i18n("Saved Init Configurations") + " (*" + ksv::nativeFileExtension() + ")";
+
+ return filter;
+}
+
+const QString& ksv::logFileExtension ()
+{
+ static QString ext = ".ksysv_log";
+
+ return ext;
+}
+
+const QString& ksv::nativeFileExtension ()
+{
+ static QString ext = ".ksysv";
+
+ return ext;
+}
+
+const char* ksv::notifications[] =
+{
+ "Show Runlevels ReadOnly",
+ "Show Could Not Generate Sorting Number"
+};
diff --git a/ksysv/ksv_core.h b/ksysv/ksv_core.h
new file mode 100644
index 0000000..58d1fa2
--- /dev/null
+++ b/ksysv/ksv_core.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_CORE_H
+#define KSV_CORE_H
+
+class QPushButton;
+class QStyleSheet;
+class KAboutData;
+class KCompletion;
+class KSVItem;
+
+namespace ksv
+{
+ bool getServiceDescription (const QString& path, QString& res);
+
+ QString breakWords (const QString& s, int amount);
+
+ /**
+ * \return the Unicode string for the (c) symbol.
+ */
+ const QString& copyrightSymbol ();
+
+ QStyleSheet* styleSheet ();
+
+ const QString& logFileFilter ();
+ const QString& nativeFileFilter ();
+
+ const QString& logFileExtension ();
+ const QString& nativeFileExtension ();
+
+ KCompletion* serviceCompletion ();
+ KCompletion* numberCompletion ();
+
+ extern const int runlevelNumber;
+ extern KAboutData* about;
+
+ enum Messages {
+ RunlevelsReadOnly = 0,
+ CouldNotGenerateSortingNumber
+ };
+
+ extern const char* notifications[];
+}
+
+#endif // KSV_CORE_H
+
diff --git a/ksysv/ksv_service.cpp b/ksysv/ksv_service.cpp
new file mode 100644
index 0000000..e13ab6f
--- /dev/null
+++ b/ksysv/ksv_service.cpp
@@ -0,0 +1,76 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#include <ksv_service.h>
+#include "leveldb.h"
+
+KSVService::KSVService (const QString &name, const QString &basedir)
+ : name_ (name),
+ base_ (basedir)
+{
+
+}
+
+KSVService* KSVService::newService (const QString &name, const QString &basedir)
+{
+ struct service service;
+
+ int result = ::readServiceInfo (basedir.local8Bit(), name.local8Bit(), &service );
+
+ if (!result)
+ {
+ KSVService* tmp = new KSVService(name, basedir);
+ tmp->desc_ = service.desc;
+ tmp->levels = service.levels;
+ tmp->kPriority = service.kPriority;
+ tmp->sPriority = service.sPriority;
+
+ return tmp;
+ }
+ else
+ {
+ return 0L;
+ }
+}
+
+KSVService::~KSVService()
+{
+}
+
+bool KSVService::isOn (int level) const
+{
+ return !::isOn (base_.local8Bit(), name_.local8Bit(), level );
+}
+
+bool KSVService::isConfigured (int level) const
+{
+ return !::isConfigured (base_.local8Bit(), name_.local8Bit(), level);
+}
+
+int KSVService::set (int level, bool on)
+{
+ struct service service;
+ service.name = strdup (name_.local8Bit());
+ service.desc = strdup (desc_.local8Bit());
+ service.levels = levels;
+ service.kPriority = kPriority;
+ service.sPriority = sPriority;
+
+ return ::doSetService ("/etc/rc.d", service, level, on);
+}
+
+QString KSVService::description () const
+{
+ return desc_.stripWhiteSpace();
+}
diff --git a/ksysv/ksv_service.h b/ksysv/ksv_service.h
new file mode 100644
index 0000000..cdf42e1
--- /dev/null
+++ b/ksysv/ksv_service.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_SERVICE_H
+#define KSV_SERVICE_H
+
+#include <qstring.h>
+
+/**
+ * The long description for this class goes here
+ *
+ * @short This is the short description
+ * @author Peter Putzer <putzer@kde.org>
+ * @version 0.1
+ */
+class KSVService
+{
+public:
+
+ /**
+ * Named constructor
+ */
+ static KSVService* newService (const QString &name, const QString &basedir);
+
+ /**
+ * Destructor
+ */
+ ~KSVService();
+
+ /**
+ * Is the service active in runlevel "level"?
+ */
+ bool isOn (int level) const;
+
+ /**
+ * Is the service configured for runlevel "level"?
+ */
+ bool isConfigured (int level) const;
+
+ /**
+ * Set the service on or off in runlevel "level"
+ */
+ int set( int level, bool on = true );
+
+ /**
+ * Returns the description of the service
+ */
+ QString description () const;
+
+private:
+ /**
+ * Copy Constructor
+ */
+ KSVService(const KSVService&);
+
+ /**
+ * Default Constructor
+ */
+ KSVService();
+
+protected:
+ friend class KServiceGUI;
+ friend class KServiceManagerWidget;
+
+ /**
+ * Constructor
+ */
+ KSVService (const QString &name, const QString &basedir);
+
+ /**
+ * Name of the service
+ */
+ QString name_;
+
+ /**
+ * Description of the service (i.e. what it does)
+ */
+ QString desc_;
+
+ /**
+ * Base dir for storing runlevel dirs
+ */
+ QString base_;
+
+ int levels, kPriority, sPriority;
+};
+
+#endif // KSV_SERVICE_H
diff --git a/ksysv/ksvapplication.cpp b/ksysv/ksvapplication.cpp
new file mode 100644
index 0000000..d305712
--- /dev/null
+++ b/ksysv/ksvapplication.cpp
@@ -0,0 +1,20 @@
+// (c) 2000 Peter Putzer
+
+#include <unistd.h>
+
+#include <kwin.h>
+
+#include "ksvapplication.h"
+
+int KSVApplication::newInstance ()
+{
+ QWidget* main = mainWidget();
+
+ if (main)
+ KWin::activateWindow (main->winId());
+
+ return getpid();
+}
+
+#include "ksvapplication.moc"
+
diff --git a/ksysv/ksvapplication.h b/ksysv/ksvapplication.h
new file mode 100644
index 0000000..95c4b45
--- /dev/null
+++ b/ksysv/ksvapplication.h
@@ -0,0 +1,19 @@
+// (c) 2000 Peter Putzer
+
+#ifndef KSVAPPLICATION_H
+#define KSVAPPLICATION_H
+
+#include <kuniqueapplication.h>
+
+class KSVApplication : public KUniqueApplication
+{
+ Q_OBJECT
+
+public:
+ inline KSVApplication() {}
+ virtual inline ~KSVApplication () {}
+
+ virtual int newInstance ();
+};
+
+#endif // KSVAPPLICATION_H
diff --git a/ksysv/ksvconfigwizard.cpp b/ksysv/ksvconfigwizard.cpp
new file mode 100644
index 0000000..6a197cb
--- /dev/null
+++ b/ksysv/ksvconfigwizard.cpp
@@ -0,0 +1,150 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "ksvconfigwizard.h"
+
+#include <qlayout.h>
+
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <klineedit.h>
+#include <qpushbutton.h>
+
+/*
+ * Constructs a KSVConfigWizard which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ *
+ * The wizard will by default be modeless, unless you set 'modal' to
+ * TRUE to construct a modal wizard.
+ */
+KSVConfigWizard::KSVConfigWizard (QWidget* parent, const char* name, bool modal, WFlags fl)
+ : ConfigWizard (parent, name, modal, fl),
+ mChosenDistribution (Debian)
+{
+ mDistributionBoxLayout->setSpacing (KDialog::spacingHint());
+ mDistributionBoxLayout->setMargin (KDialog::marginHint());
+
+ mSpacer->setFixedHeight (KDialog::spacingHint());
+
+ // set the default paths
+ chooseDistribution (mChosenDistribution);
+
+ // enable finish-button
+ setFinishEnabled (mFinishedPage, true);
+
+ // some connections
+ connect (this, SIGNAL (selected (const QString&)),
+ this, SLOT (selectedPage (const QString&)));
+
+ // hide cancel-button
+ cancelButton()->hide();
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KSVConfigWizard::~KSVConfigWizard()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+void KSVConfigWizard::browseServices()
+{
+ QString path = KFileDialog::getExistingDirectory(mServicesPath->text(), this);
+
+ if (!path.isEmpty())
+ mServicesPath->setText(path);
+
+ mServicesPath->setFocus();
+}
+
+void KSVConfigWizard::browseRunlevels()
+{
+ QString path = KFileDialog::getExistingDirectory(mRunlevelPath->text(), this);
+
+ if (!path.isEmpty())
+ mRunlevelPath->setText(path);
+
+ mRunlevelPath->setFocus();
+}
+
+void KSVConfigWizard::selectedPage (const QString& title)
+{
+ if (title == "Configuration Complete")
+ finishButton()->setDefault (true);
+ else
+ nextButton()->setDefault (true);
+}
+
+QString KSVConfigWizard::runlevelPath ()
+{
+ return mRunlevelPath->text();
+}
+
+QString KSVConfigWizard::servicesPath ()
+{
+ return mServicesPath->text();
+}
+
+void KSVConfigWizard::chooseDistribution(int which)
+{
+ mChosenDistribution = static_cast<Distribution> (which);
+
+ QString rlpath; QString spath;
+ switch (mChosenDistribution)
+ {
+ case Debian:
+ case Corel:
+ rlpath = "/etc";
+ spath = "/etc/init.d";
+ break;
+
+ case RedHat:
+ case Mandrake:
+ case Conectiva:
+ rlpath = "/etc/rc.d";
+ spath = "/etc/rc.d/init.d";
+ break;
+
+ case SuSE:
+ rlpath = "/etc/rc.d";
+ spath = "/etc/init.d";
+ break;
+
+ default:
+ rlpath = "/etc/rc.d";
+ spath = "/etc/rc.d/init.d";
+ }
+
+ mRunlevelPath->setText (rlpath);
+ mServicesPath->setText (spath);
+
+ if (which != Other)
+ setAppropriate (mPathsPage, false);
+ else
+ setAppropriate (mPathsPage, true);
+}
+
+#include "ksvconfigwizard.moc"
diff --git a/ksysv/ksvconfigwizard.h b/ksysv/ksvconfigwizard.h
new file mode 100644
index 0000000..35e8c7f
--- /dev/null
+++ b/ksysv/ksvconfigwizard.h
@@ -0,0 +1,66 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef KSVCONFIGWIZARD_H
+#define KSVCONFIGWIZARD_H
+#include "configwizard.h"
+
+#include <qstring.h>
+
+class KSVConfigWizard : public ConfigWizard
+{
+ Q_OBJECT
+
+public:
+ KSVConfigWizard( QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags fl = 0 );
+ ~KSVConfigWizard();
+
+public:
+ QString runlevelPath();
+ QString servicesPath();
+
+protected slots:
+ void browseRunlevels();
+ void chooseDistribution(int);
+ void browseServices();
+
+private slots:
+ void selectedPage (const QString&);
+
+private:
+ typedef enum {
+ Debian=0,
+ RedHat=1,
+ SuSE=2,
+ Mandrake=3,
+ Corel=4,
+ Conectiva=5,
+ Other=6
+ } Distribution;
+
+ Distribution mChosenDistribution;
+};
+
+#endif // KSVCONFIGWIZARD_H
diff --git a/ksysv/ksvdrag.cpp b/ksysv/ksvdrag.cpp
new file mode 100644
index 0000000..1f24417
--- /dev/null
+++ b/ksysv/ksvdrag.cpp
@@ -0,0 +1,102 @@
+// (c) 2000 Peter Putzer
+
+#include <qstring.h>
+#include <qcstring.h>
+
+#include <kurl.h>
+
+#include "Data.h"
+#include "ksvdraglist.h"
+#include "ksvdrag.h"
+
+class KSVDrag::Private
+{
+public:
+ QByteArray mNative;
+ QString mText;
+ KURL mURL;
+};
+
+KSVDrag::KSVDrag (const KSVData& item, QWidget* source, const char* name)
+ : QDragObject (source, name),
+ d (new Private())
+{
+ QDataStream ds (d->mNative, IO_ReadWrite);
+ ds << item;
+
+ d->mText = item.filenameAndPath ();
+ d->mURL.setPath (item.path() + "/" + item.filename());
+}
+
+KSVDrag::KSVDrag (const KSVItem& item, QWidget* source, const char* name)
+ : QDragObject (source, name),
+ d (new Private())
+{
+ QDataStream ds (d->mNative, IO_ReadWrite);
+ ds << *item.data();
+
+ d->mText = item.toString();
+ d->mURL.setPath (item.path() + "/" + item.filename());
+}
+
+KSVDrag::~KSVDrag ()
+{
+ delete d;
+}
+
+const char* KSVDrag::format (int i) const
+{
+ switch (i)
+ {
+ case Native:
+ return "application/x-ksysv";
+ break;
+
+ case Text:
+ return "text/plain";
+ break;
+
+ case URL:
+ return "text/uri-list";
+ break;
+
+ default:
+ return 0L;
+ }
+}
+
+QByteArray KSVDrag::encodedData (const char* format) const
+{
+ QByteArray res;
+
+ if (!strcmp (format, "application/x-ksysv"))
+ {
+ res = d->mNative;
+ }
+ else if (!strcmp (format, "text/plain"))
+ {
+ QDataStream ds (res, IO_ReadWrite);
+ ds << d->mText;
+ }
+ else if (!strcmp (format, "text/uri-list"))
+ {
+ res = QCString(d->mURL.url().latin1()).copy();
+ }
+
+ return res;
+}
+
+bool KSVDrag::decodeNative (const QMimeSource* mime, KSVData& data)
+{
+ if (mime && mime->provides ("application/x-ksysv"))
+ {
+ QDataStream ds (mime->encodedData ("application/x-ksysv"), IO_ReadOnly);
+ ds >> data;
+
+ return true;
+ }
+
+ return false;
+}
+
+#include "ksvdrag.moc"
diff --git a/ksysv/ksvdrag.h b/ksysv/ksvdrag.h
new file mode 100644
index 0000000..272f16d
--- /dev/null
+++ b/ksysv/ksvdrag.h
@@ -0,0 +1,36 @@
+// (c) 2000 Peter Putzer
+
+#ifndef KSVDRAG_H
+#define KSVDRAG_H
+
+#include <qdragobject.h>
+
+class KSVData;
+class KSVItem;
+class QWidget;
+
+class KSVDrag : public QDragObject
+{
+ Q_OBJECT
+
+public:
+ KSVDrag (const KSVData& item, QWidget* dragSource = 0L, const char* name = 0L);
+ KSVDrag (const KSVItem& item, QWidget* dragSource = 0L, const char* name = 0L);
+ virtual ~KSVDrag();
+
+ virtual const char* format (int i) const;
+ QByteArray encodedData (const char*) const;
+
+ static bool decodeNative (const QMimeSource*, KSVData&);
+
+private:
+ enum
+ {
+ Native, Text, URL
+ };
+
+ class Private;
+ Private* d;
+};
+
+#endif // KSVDRAG_H
diff --git a/ksysv/ksvdraglist.cpp b/ksysv/ksvdraglist.cpp
new file mode 100644
index 0000000..b0bd9bd
--- /dev/null
+++ b/ksysv/ksvdraglist.cpp
@@ -0,0 +1,802 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+
+#include <qpainter.h>
+#include <qdragobject.h>
+#include <qdatastream.h>
+#include <qheader.h>
+#include <qpixmapcache.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qcolor.h>
+#include <qcstring.h>
+#include <qlabel.h>
+
+#include <kapplication.h>
+#include <kpopupmenu.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kdltooltip.h"
+#include "ksv_core.h"
+#include "ksv_conf.h"
+#include "ksvdraglist.h"
+#include "ksvdrag.h"
+#include "ActionList.h"
+
+KSVItem::KSVItem (KListView* view)
+ : QListViewItem (view),
+ mData (new KSVData()),
+ mConfig (KSVConfig::self()),
+ mNewNormalColor (mConfig->newNormalColor()),
+ mNewSelectedColor (mConfig->newSelectedColor()),
+ mChangedNormalColor (mConfig->changedNormalColor()),
+ mChangedSelectedColor (mConfig->changedSelectedColor())
+{
+}
+
+KSVItem::KSVItem (const KSVItem& item)
+ : QListViewItem (item.listView()),
+ mData (new KSVData(*item.mData)),
+ mConfig (KSVConfig::self()),
+ mNewNormalColor (mConfig->newNormalColor()),
+ mNewSelectedColor (mConfig->newSelectedColor()),
+ mChangedNormalColor (mConfig->changedNormalColor()),
+ mChangedSelectedColor (mConfig->changedSelectedColor())
+
+{
+ setText (SortNumber, mData->numberString());
+ setText (ServiceName, label());
+ setIcon (*item.pixmap(Icon));
+}
+
+KSVItem::KSVItem (KSVDragList* view, const KSVData& data)
+ : QListViewItem (view),
+ mData (new KSVData (data)),
+ mConfig (KSVConfig::self()),
+ mNewNormalColor (mConfig->newNormalColor()),
+ mNewSelectedColor (mConfig->newSelectedColor()),
+ mChangedNormalColor (mConfig->changedNormalColor()),
+ mChangedSelectedColor (mConfig->changedSelectedColor())
+{
+ setText (SortNumber, mData->numberString());
+ setText (ServiceName, label());
+ setIcon (view->defaultIcon());
+}
+
+void KSVItem::copy (const KSVData& item)
+{
+ *mData = item;
+
+ setText (SortNumber, mData->numberString());
+ setText (ServiceName, mData->label());
+}
+
+QString KSVItem::key (int, bool) const
+{
+ return mData->numberString() + mData->label();
+}
+
+KSVItem::KSVItem (KListView* view, QString file, QString path, QString label, Q_INT8 nr )
+ : QListViewItem (view),
+ mData (new KSVData (file, path, label, nr)),
+ mConfig (KSVConfig::self()),
+ mNewNormalColor (mConfig->newNormalColor()),
+ mNewSelectedColor (mConfig->newSelectedColor()),
+ mChangedNormalColor (mConfig->changedNormalColor()),
+ mChangedSelectedColor (mConfig->changedSelectedColor())
+{
+ setText (ServiceName, mData->label());
+ setText (SortNumber, mData->numberString());
+}
+
+KSVItem::~KSVItem()
+{
+ delete mData;
+}
+
+void KSVItem::paintCell (QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+ switch (column)
+ {
+ case SortNumber:
+ p->setFont (mConfig->numberFont());
+ break;
+
+ case ServiceName:
+ p->setFont (mConfig->serviceFont());
+ break;
+ }
+
+ QColorGroup colors = cg;
+
+ if (mData->newEntry())
+ {
+ colors.setColor (QColorGroup::Text, mNewNormalColor);
+ colors.setColor (QColorGroup::HighlightedText, mNewSelectedColor);
+ }
+ else if (mData->changed())
+ {
+ colors.setColor (QColorGroup::Text, mChangedNormalColor);
+ colors.setColor (QColorGroup::HighlightedText, mChangedSelectedColor);
+ }
+
+ QListViewItem::paintCell (p, colors, column, width, align);
+}
+
+QString KSVItem::toString() const
+{
+ return filenameAndPath();
+}
+
+QString KSVItem::tooltip () const
+{
+ QString result;
+
+ if (mConfig->showDescription())
+ {
+ if (!ksv::getServiceDescription(filename(), result))
+ result = toString();
+ else
+ {
+ // split into nice chunks
+ result = ksv::breakWords(result.simplifyWhiteSpace(), 50);
+ }
+ }
+ else
+ {
+ result = toString();
+ }
+
+ return result;
+}
+
+
+void KSVItem::setNew ( bool val )
+{
+ mData->setNewEntry (val);
+}
+
+
+QPixmap KSVItem::paintDragIcon (const QFont& font, const QColorGroup&) const
+{
+ QFontMetrics metric (font);
+ QRect textRect = metric.boundingRect (label());
+ const QPixmap& icon = *pixmap (Icon);
+ const int margin = listView()->itemMargin();
+
+ const int width = icon.width() + margin * 2 + textRect.width();
+ const int height = kMax (icon.height(), textRect.height());
+
+ QPixmap result (width, height);
+ result.fill (white);
+
+ QPainter p (&result);
+ p.drawPixmap (0, 0, icon);
+ p.setFont (font);
+
+ p.drawText (icon.width() + margin, 0,
+ width, height,
+ AlignLeft | AlignVCenter,
+ label());
+ p.end();
+
+ QBitmap mask (width, height);
+ p.begin (&mask);
+ p.setFont (font);
+
+ p.fillRect (0, 0, width, height, color0);
+
+ p.setPen (color1);
+ p.drawPixmap (0, 0, icon.createHeuristicMask());
+
+ p.drawText (icon.width() + margin, 0,
+ width, height,
+ AlignLeft | AlignVCenter,
+ label());
+
+ QBrush brush (color0);
+ brush.setStyle(Dense5Pattern);
+ p.fillRect (0, 0, width, height, brush);
+
+ p.end();
+
+ result.setMask(mask);
+ result.setOptimization(QPixmap::BestOptim);
+ return result;
+}
+
+void KSVItem::setIcon (const QPixmap& icon)
+{
+ setPixmap (Icon, icon);
+}
+
+void KSVItem::setLabel (const QString& label)
+{
+ mData->setLabel (label);
+
+ setText (ServiceName, label);
+}
+
+void KSVItem::setRunlevel (const QString& runlevel)
+{
+ mData->setRunlevel (runlevel);
+}
+
+void KSVItem::setFilename (const QString& file)
+{
+ mData->setFilename (file);
+}
+
+void KSVItem::setNumber (Q_INT8 nr)
+{
+ mData->setNumber (nr);
+
+ setText(SortNumber, mData->numberString());
+}
+
+void KSVItem::setPath (const QString& path)
+{
+ mData->setPath (path);
+}
+
+void KSVItem::setNewNormalColor (const QColor& col)
+{
+ mNewNormalColor = col;
+}
+
+void KSVItem::setNewSelectedColor (const QColor& col)
+{
+ mNewSelectedColor = col;
+}
+
+void KSVItem::setChangedNormalColor (const QColor& col)
+{
+ mChangedNormalColor = col;
+}
+
+void KSVItem::setChangedSelectedColor (const QColor& col)
+{
+ mChangedSelectedColor = col;
+}
+
+void KSVItem::setChanged (bool val)
+{
+ mData->setChanged (val);
+}
+
+void KSVItem::setOriginalRunlevel (const QString& rl)
+{
+ mData->setOriginalRunlevel (rl);
+}
+
+
+
+//-----------------------
+// KSVDragList
+//-----------------------
+
+KSVDragList::KSVDragList ( QWidget* parent, const char* name )
+ : KListView (parent, name),
+ mItemToDrag (0L),
+ mDragMenu (new KPopupMenu (this)),
+ mDragCopyMenu (new KPopupMenu (this)),
+ mDragMoveMenu (new KPopupMenu (this)),
+ mDisplayToolTips (true),
+ mCommonToolTips (true)
+{
+ // add tooltips
+ toolTip=new KDLToolTip (this);
+
+ setDragEnabled (true);
+ setDragAutoScroll(true);
+ setAcceptDrops(true);
+ setDropVisualizer (true);
+
+ QHeader* h = header();
+ h->setClickEnabled (false);
+
+ addColumn (i18n("No.")); // SortNumber
+ // setColumnWidthMode (KSVItem::SortNumber, Manual);
+ addColumn (""); // Icon
+// setColumnWidthMode (KSVItem::Icon, Manual);
+ addColumn (i18n("Name")); // ServiceName
+// setColumnWidthMode (KSVItem::ServiceName, Manual);
+
+ h->setResizeEnabled (false, KSVItem::Icon);
+
+ setShowSortIndicator (false);
+ setAllColumnsShowFocus (true);
+
+ // multiselection is to complicated due to the sorting numbers
+ setSelectionModeExt (Single);
+
+ // init DND menu
+ mDragMenu->insertTitle (i18n("Drag Menu"));
+ mDragMenu->insertItem ("&Copy", Copy);
+ mDragMenu->insertItem ("&Move", Move);
+
+ mDragCopyMenu->insertTitle (i18n("Drag Menu"));
+ mDragCopyMenu->insertItem ("&Copy", Copy);
+
+ mDragMoveMenu->insertTitle (i18n("Drag Menu"));
+ mDragMoveMenu->insertItem ("&Move", Move);
+
+ mRMList.setAutoDelete(true);
+
+ // catch drops
+ connect (this, SIGNAL (dropped (QDropEvent*, QListViewItem*)),
+ this, SLOT (drop (QDropEvent*, QListViewItem*)));
+}
+
+KSVDragList::~KSVDragList()
+{
+ delete mDragMenu;
+ delete mDragCopyMenu;
+ delete mDragMoveMenu;
+ delete toolTip;
+}
+
+void KSVDragList::initItem (QString file, QString path, QString name, Q_INT8 nr)
+{
+ KSVItem* tmp = new KSVItem(this, file, path, name, nr);
+ tmp->setRunlevel(QObject::name());
+ tmp->setOriginalRunlevel(QObject::name());
+
+ tmp->setIcon (mIcon);
+
+ setUpdatesEnabled(false);
+
+ // marked as new in insert, we dont want that
+ tmp->setNew(false);
+ tmp->setChanged (false);
+
+ setUpdatesEnabled(true);
+ repaint(false);
+}
+
+void KSVDragList::setDefaultIcon (const QPixmap& icon)
+{
+ mIcon = icon;
+
+ for (QListViewItemIterator it (firstChild()); it.current(); ++it)
+ {
+ static_cast <KSVItem*> (it.current())->setIcon (mIcon);
+ }
+}
+
+void KSVDragList::clear ()
+{
+ KListView::clear();
+
+ clearRMList();
+}
+
+void KSVDragList::setNewNormalColor ( const QColor& col )
+{
+ mNewNormalColor = col;
+
+ KSVItem* item;
+ for (QListViewItemIterator it (firstChild());
+ (item = static_cast<KSVItem*>(it.current()));
+ ++it)
+ {
+ item->setNewNormalColor (mNewNormalColor);
+ }
+}
+
+void KSVDragList::setNewSelectedColor (const QColor& col)
+{
+ mNewSelectedColor = col;
+
+ KSVItem* item;
+ for (QListViewItemIterator it (firstChild());
+ (item = static_cast<KSVItem*>(it.current()));
+ ++it)
+ {
+ item->setNewSelectedColor (mNewSelectedColor);
+ }
+}
+
+Q_INT8 KSVDragList::generateNumber (const QString& label,
+ const KSVData* itemBelow, const KSVData* itemAbove) const
+{
+ Q_INT8 high = itemBelow ? itemBelow->number() : -1;
+ Q_INT8 low = itemAbove ? itemAbove->number() : -1;
+ Q_INT8 result = generateNumber (high, low);
+
+ if (high == result && result != -1 && label >= itemBelow->label())
+ result = -1;
+
+ if (low == result && result != -1 && label <= itemAbove->label())
+ result = -1;
+
+ return result;
+}
+
+Q_INT8 KSVDragList::generateNumber (Q_INT8 high, Q_INT8 low) const
+{
+ Q_ASSERT (high >= low || high == -1);
+
+ Q_INT8 result = -1;
+
+ if (low < 0)
+ {
+ if (high < 0)
+ result = 50;
+ else
+ result = high / 2;
+ }
+ else if (high < 0)
+ result = (100 - low) / 2 + low;
+ else
+ result = (high - low) / 2 + low;
+
+ return result;
+}
+
+void KSVDragList::setChangedNormalColor (const QColor& col)
+{
+ mChangedNormalColor = col;
+
+ KSVItem* item;
+ for (QListViewItemIterator it (firstChild());
+ (item = static_cast<KSVItem*> (it.current()));
+ ++it)
+ {
+ item->setChangedNormalColor (mChangedNormalColor);
+ }
+}
+
+void KSVDragList::setChangedSelectedColor (const QColor& col)
+{
+ mChangedSelectedColor = col;
+
+ KSVItem* item;
+ for (QListViewItemIterator it (firstChild());
+ (item = static_cast<KSVItem*> (it.current()));
+ ++it)
+ {
+ item->setChangedSelectedColor (mChangedSelectedColor);
+ }
+}
+
+KSVItem* KSVDragList::match (const KSVData& data)
+{
+ KSVItem* res = 0L;
+
+ for (QListViewItemIterator it (this);
+ (res = static_cast<KSVItem*> (it.current()));
+ ++it)
+ {
+ if (*res->data() == data)
+ break;
+ else
+ res = 0L;
+ }
+
+ return res;
+}
+
+void KSVDragList::setOrigin (bool val)
+{
+ mOrigin = val;
+
+ if (mOrigin)
+ {
+ emit newOrigin (this);
+ emit newOrigin();
+ }
+ else
+ clearSelection();
+}
+
+void KSVDragList::startDrag ()
+{
+ mItemToDrag = static_cast<KSVItem*> (currentItem());
+
+ KSVDrag* d = dynamic_cast<KSVDrag*> (dragObject());
+
+ if (d)
+ {
+ d->setPixmap (mItemToDrag->paintDragIcon (font(), colorGroup()));
+
+ d->drag();
+ }
+}
+
+//KSVDrag* KSVDragList::dragObject ()
+QDragObject* KSVDragList::dragObject ()
+{
+ if (mItemToDrag)
+ {
+ return new KSVDrag (*mItemToDrag, this);
+ }
+ else
+ return 0L;
+}
+
+bool KSVDragList::acceptDrag (QDropEvent* e) const
+{
+ e->acceptAction ();
+
+ return acceptDrops() && e->provides ("application/x-ksysv");
+}
+
+void KSVDragList::focusInEvent (QFocusEvent* e)
+{
+ KListView::focusInEvent(e);
+
+ if (!currentItem())
+ setCurrentItem (firstChild());
+
+ setOrigin(true);
+}
+
+void KSVDragList::clearRMList()
+{
+ mRMList.clear();
+}
+
+bool KSVDragList::removeFromRMList (const KSVData& item)
+{
+ KSVData* res = 0L;
+
+ for (QPtrListIterator<KSVData> it (mRMList);
+ it.current();
+ ++it)
+ {
+ res = it.current();
+
+ if (*res == item)
+ break;
+ else
+ res = 0L;
+ }
+
+ if (res)
+ return mRMList.remove (res);
+ else
+ return false;
+}
+
+bool KSVDragList::insert (const KSVData& data, const KSVData* above, const KSVData* below)
+{
+ Q_INT8 nr = generateNumber (data.label(), below, above);
+
+ if (nr > -1)
+ {
+ KSVData real (data);
+ real.setNumber (nr);
+
+ KSVItem* item = new KSVItem (this, real);
+ item->setNew (true);
+
+ return true;
+ }
+ else
+ emit cannotGenerateNumber ();
+
+ return false;
+}
+
+bool KSVDragList::insert (const KSVData& data, const KSVItem* where, KSVAction*& action)
+{
+ const KSVData* above = 0L;
+ const KSVData* below = 0L;
+
+ if (where)
+ {
+ above = where->data();
+ KSVItem* tmp = static_cast<KSVItem*> (where->nextSibling());
+ below = tmp ? tmp->data() : 0L;
+ }
+ else
+ {
+ KSVItem* tmp = static_cast<KSVItem*> (firstChild());
+ below = tmp ? tmp->data() : 0L;
+ }
+
+ bool success = false;
+ KSVItem* exists = match (data);
+ action = 0L;
+
+ if (exists)
+ {
+ if (exists->data() == above || exists->data() == below)
+ return false;
+
+ Q_INT8 nr = generateNumber (exists->label(), below, above);
+
+ if (nr == -1)
+ {
+ emit cannotGenerateNumber();
+ }
+ else
+ {
+ KSVData oldState = *exists->data();
+ exists->setNumber (nr);
+ sort();
+
+ action = new ChangeAction (this, &oldState, exists->data());
+ success = true;
+ }
+ }
+ else
+ {
+ success = insert (data, above, below);
+
+ if (success)
+ action = new AddAction (this, match (data)->data());
+ }
+
+ return success;
+}
+
+void KSVDragList::drop (QDropEvent* e, QListViewItem* after)
+{
+ KSVData data;
+ KSVDragList* source = static_cast<KSVDragList*> (e->source());
+ QPopupMenu* menu = 0L;
+
+ // hack to empty the cursor stack after DND
+ QApplication::restoreOverrideCursor();
+ QApplication::restoreOverrideCursor();
+
+ if ((!source) || (!strcmp(source->name(), "Scripts")))
+ menu = mDragCopyMenu;
+ else if (source == this)
+ menu = mDragMoveMenu;
+ else
+ menu = mDragMenu;
+
+ if (KSVDrag::decodeNative (e, data))
+ {
+ int res = -1;
+
+ if (e->action() == QDropEvent::Copy && source != this)
+ res = Copy;
+ else
+ res = menu->exec (QCursor::pos(), 1);
+
+ if (res == -1) // operation cancelled
+ return;
+
+ const bool move = res == Move;
+
+ KSVItem* tmp = static_cast<KSVItem*> (after);
+ KSVAction* action = 0L;
+ if (insert (data, tmp, action))
+ {
+ if (move && source != this)
+ {
+ KSVAction* actions[2];
+ actions [0] = new RemoveAction (source, &data);
+ actions [1] = action;
+
+ action = new CompoundAction (actions, 2);
+ delete source->match (data);
+ }
+
+ emit undoAction (action);
+ }
+ }
+}
+
+bool KSVDragList::addToRMList (const KSVData& item)
+{
+ KSVData* res = 0L;
+
+ for (QPtrListIterator<KSVData> it (mRMList);
+ it.current();
+ ++it)
+ {
+ res = it.current();
+
+ if (*res == item)
+ break;
+ else
+ res = 0L;
+ }
+
+ if (!res)
+ {
+ mRMList.append (new KSVData(item));
+ return true;
+ }
+ else
+ return false;
+}
+
+void KSVDragList::setEnabled (bool enable)
+{
+ if (enable)
+ clearWState (WState_ForceDisabled);
+ else
+ setWState (WState_ForceDisabled);
+
+ if (enable)
+ {
+ if (testWState (WState_Disabled))
+ {
+ clearWState (WState_Disabled);
+ // setBackgroundFromMode(); // this is private in QWidget...
+ // well it doesn't really matter in this case
+ enabledChange( TRUE );
+ }
+ }
+ else
+ {
+ if (!testWState(WState_Disabled))
+ {
+ if (focusWidget() == this)
+ focusNextPrevChild (TRUE);
+ setWState (WState_Disabled);
+ // setBackgroundFromMode(); // this is private in QWidget...
+ // well it doesn't really matter in this case
+ enabledChange (FALSE);
+ }
+ }
+
+ viewport()->setEnabled (enable);
+}
+
+// KServiceDragList
+
+KServiceDragList::KServiceDragList (QWidget* parent, const char* name)
+ : KSVDragList (parent, name)
+{
+}
+
+KServiceDragList::~KServiceDragList ()
+{
+}
+
+void KServiceDragList::startDrag ()
+{
+ mItemToDrag = static_cast<KSVItem*> (currentItem());
+
+ KSVDrag* d = dynamic_cast<KSVDrag*> (dragObject());
+
+ if (d)
+ {
+ d->setPixmap (mItemToDrag->paintDragIcon (font(), colorGroup()));
+
+ d->dragCopy();
+ }
+}
+
+#include "ksvdraglist.moc"
diff --git a/ksysv/ksvdraglist.h b/ksysv/ksvdraglist.h
new file mode 100644
index 0000000..f5474b8
--- /dev/null
+++ b/ksysv/ksvdraglist.h
@@ -0,0 +1,277 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSVDRAGLIST_H
+#define KSVDRAGLIST_H
+
+#include <qstring.h>
+#include <qcolor.h>
+#include <qpixmap.h>
+
+#include <klistview.h>
+
+#include "Data.h"
+
+class QPen;
+class KSVAction;
+class SimpleAction;
+class KSVDragList;
+class KPopupMenu;
+class KSVConfig;
+class KDLToolTip;
+
+class KSVItem : public QListViewItem
+{
+public:
+ typedef enum {
+ SortNumber = 0,
+ Icon,
+ ServiceName,
+ FileName,
+
+ // insert additional columns here
+
+ Last
+ } Columns;
+
+ KSVItem (KListView*);
+ KSVItem (const KSVItem&);
+ explicit KSVItem (KSVDragList*, const KSVData&);
+ KSVItem (KListView* view, QString file, QString path, QString label, Q_INT8 nr );
+ virtual ~KSVItem ();
+
+ virtual QString key (int col, bool ascending) const;
+
+ inline bool isChanged() const { return mData->changed(); }
+
+ inline bool isNumChanged() const { return mData->numberChanged(); }
+ inline bool isLabelChanged() const { return mData->labelChanged(); }
+ inline bool isNew() const { return mData->newEntry(); }
+
+ inline const QString& oldFilename() const { return mData->oldFilename(); }
+ inline const QString& filename() const { return mData->filename(); }
+ inline const QString& oldLabel() const { return mData->oldLabel(); }
+ inline const QString& label() const { return mData->label(); }
+ inline const QString& runlevel() const { return mData->runlevel(); }
+
+ inline QString filenameAndPath() const { return mData->filenameAndPath (); }
+
+ inline const QString& path() const { return mData->path(); }
+
+ inline Q_INT8 number() const { return mData->number(); }
+ inline Q_INT8 oldNumber() const { return mData->oldNumber(); }
+
+ void copy (const KSVData&);
+
+ KSVData* data () { return mData; }
+ const KSVData* data () const { return mData; }
+
+ QString toString () const;
+
+ inline bool operator== (const KSVItem & rhs) const { return mData == rhs.mData; }
+
+ inline const QColor& newNormalColor () const
+ {
+ return mNewNormalColor;
+ }
+
+ inline const QColor& changedNormalColor () const
+ {
+ return mChangedNormalColor;
+ }
+
+ inline QString originalRunlevel() const { return mData->originalRunlevel(); }
+
+ void setIcon (const QPixmap& icon);
+ void setLabel (const QString& label);
+ void setFilename (const QString& file);
+ void setRunlevel (const QString& runlevel);
+ void setNumber (Q_INT8 nr);
+ void setPath (const QString& path);
+ void setChanged (bool);
+ void setNewNormalColor (const QColor&);
+ void setChangedNormalColor (const QColor&);
+ void setNewSelectedColor (const QColor&);
+ void setChangedSelectedColor (const QColor&);
+ void setNew (bool);
+ void setOriginalRunlevel (const QString&);
+
+ inline void setNumberChanged (bool val) { mData->setNumberChanged (val); }
+
+ QString tooltip () const;
+ virtual void paintCell (QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+protected:
+ friend class KSVDragList;
+ friend class KServiceDragList;
+
+ QPixmap paintDragIcon (const QFont& f, const QColorGroup& g) const;
+
+private:
+ friend class KSVDrag;
+
+ KSVData* mData;
+ KSVConfig* mConfig;
+
+ QColor mNewNormalColor;
+ QColor mNewSelectedColor;
+ QColor mChangedNormalColor;
+ QColor mChangedSelectedColor;
+};
+
+class KSVDragList : public KListView
+{
+ Q_OBJECT
+
+public:
+ KSVDragList ( QWidget* parent = 0, const char* name = 0 );
+ virtual ~KSVDragList();
+
+ virtual void clear();
+
+ inline bool displayToolTips () const { return mDisplayToolTips; }
+ inline bool commonToolTips () const { return mCommonToolTips; }
+
+ inline const QString& tooltip () const { return mToolTip; }
+ inline const QString& horizontalScrollBarTip () const { return mHorizontalTip; }
+ inline const QString& verticalScrollBarTip () const { return mVerticalTip; }
+
+ virtual void initItem (QString file, QString path, QString name, Q_INT8 nr);
+ QPtrList<KSVData>& getDeletedItems() { return mRMList; }
+
+ /**
+ * @return whether this is the currently "selected" KSVDragList.
+ */
+ inline bool isOrigin() const { return mOrigin; }
+
+ inline KSVItem* currentItem() { return static_cast<KSVItem*> (KListView::currentItem()); }
+
+ inline KSVItem* lastItem () { return static_cast<KSVItem*> (KListView::lastItem()); }
+
+ /**
+ * @return true if the insertion was successful.
+ */
+ bool insert (const KSVData& data, const KSVData* above = 0L, const KSVData* below = 0L);
+
+ bool insert (const KSVData& data, const KSVItem* where, KSVAction*& action);
+
+ inline const QPixmap& defaultIcon() const { return mIcon; }
+
+ bool removeFromRMList (const KSVData&);
+ bool addToRMList (const KSVData&);
+ void clearRMList();
+
+ KSVItem* match (const KSVData&);
+
+ inline void setDisplayToolTips (bool val) { mDisplayToolTips = val; }
+ inline void setCommonToolTips (bool val) { mCommonToolTips = val; }
+ inline void setHorizontalScrollBarTip (const QString& t) { mHorizontalTip = t; }
+ inline void setVerticalScrollBarTip (const QString& t) { mVerticalTip = t; }
+ inline void setToolTip (const QString& t) { mToolTip = t; }
+
+public slots:
+ void setNewNormalColor (const QColor &);
+ void setChangedNormalColor (const QColor &);
+ void setNewSelectedColor (const QColor &);
+ void setChangedSelectedColor (const QColor &);
+
+ void setOrigin (bool);
+ inline void slotNewOrigin() { setOrigin (false); }
+
+ void setDefaultIcon (const QPixmap& icon);
+
+ void drop (QDropEvent*, QListViewItem*);
+
+ virtual void setEnabled (bool);
+
+protected:
+ virtual void focusInEvent (QFocusEvent*);
+ virtual bool acceptDrag (QDropEvent*) const;
+ virtual QDragObject* dragObject ();
+// virtual KSVDrag* dragObject ();
+
+ virtual void startDrag ();
+
+ /**
+ * Generates a sorting number for an item at
+ * the given index by taking the average of the item
+ * above and the item below.
+ */
+ Q_INT8 generateNumber (Q_INT8 high, Q_INT8 low) const;
+
+ /**
+ * A convenience function that also takes the label into account
+ */
+ Q_INT8 generateNumber (const QString& label, const KSVData* itemAbove, const KSVData* itemBelow) const;
+
+ KSVItem* mItemToDrag;
+
+private:
+ QPixmap mIcon;
+
+ bool mOrigin;
+ QPtrList<KSVData> mRMList;
+
+ QColor mNewNormalColor;
+ QColor mNewSelectedColor;
+ QColor mChangedNormalColor;
+ QColor mChangedSelectedColor;
+
+ KPopupMenu* mDragMenu;
+ KPopupMenu* mDragCopyMenu;
+ KPopupMenu* mDragMoveMenu;
+ KDLToolTip* toolTip;
+ typedef enum { Copy, Move } DragAction;
+
+ QString mToolTip, mHorizontalTip, mVerticalTip;
+ bool mDisplayToolTips, mCommonToolTips;
+
+signals:
+ void newOrigin();
+ void newOrigin (KSVDragList*);
+
+ void cannotGenerateNumber();
+ void undoAction(KSVAction*);
+};
+
+class KServiceDragList : public KSVDragList
+{
+public:
+ KServiceDragList (QWidget* parent = 0L, const char* name = 0L);
+ virtual ~KServiceDragList ();
+
+protected:
+ virtual void startDrag ();
+};
+
+#endif
diff --git a/ksysv/ksvlookandfeel.cpp b/ksysv/ksvlookandfeel.cpp
new file mode 100644
index 0000000..29e4de5
--- /dev/null
+++ b/ksysv/ksvlookandfeel.cpp
@@ -0,0 +1,93 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "ksvlookandfeel.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kdialog.h>
+#include <kfontdialog.h>
+
+/*
+ * Constructs a KSVLookAndFeel which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ */
+KSVLookAndFeel::KSVLookAndFeel( QWidget* parent, const char* name, WFlags fl )
+ : LookAndFeel( parent, name, fl )
+{
+ mTopLayout->setSpacing (KDialog::spacingHint());
+ mColorGrid->setSpacing (KDialog::spacingHint());
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KSVLookAndFeel::~KSVLookAndFeel()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+/*
+ * protected slot
+ */
+void KSVLookAndFeel::chooseNumberFont()
+{
+ KFontDialog::getFont (mNumberFont, false, this);
+ setNumberFont (mNumberFont);
+ emit configChanged();
+}
+
+/*
+ * protected slot
+ */
+void KSVLookAndFeel::chooseServiceFont()
+{
+ KFontDialog::getFont (mServiceFont, false, this);
+ setServiceFont (mServiceFont);
+ emit configChanged();
+}
+
+void KSVLookAndFeel::setServiceFont (const QFont& font)
+{
+ mServiceFontPreview->setFont(font);
+ mServiceFontPreview->setText(font.family() + " " + QString::number(font.pointSize()));
+
+ mServiceFont = font;
+}
+
+void KSVLookAndFeel::setNumberFont (const QFont& font)
+{
+ mNumberFontPreview->setFont(font);
+ mNumberFontPreview->setText(font.family() + " " + QString::number(font.pointSize()));
+
+ mNumberFont = font;
+}
+
+void KSVLookAndFeel::slotChanged()
+{
+ emit configChanged();
+}
+#include "ksvlookandfeel.moc"
diff --git a/ksysv/ksvlookandfeel.h b/ksysv/ksvlookandfeel.h
new file mode 100644
index 0000000..5e59a91
--- /dev/null
+++ b/ksysv/ksvlookandfeel.h
@@ -0,0 +1,39 @@
+/**
+ * Released under the GNU General Public License, version 2.
+ *
+ * Copyright (c) 2000 Peter Putzer <putzer@kde.org>
+ */
+
+#ifndef KSVLOOKANDFEEL_H
+#define KSVLOOKANDFEEL_H
+#include "lookandfeelconfig.h"
+
+#include <qfont.h>
+class KSVLookAndFeel : public LookAndFeel
+{
+ Q_OBJECT
+
+public:
+ KSVLookAndFeel( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+ ~KSVLookAndFeel();
+
+ inline const QFont& serviceFont() const { return mServiceFont; }
+ inline const QFont& numberFont() const { return mNumberFont; }
+
+ void setServiceFont (const QFont& font);
+ void setNumberFont (const QFont& font);
+
+signals:
+ void configChanged();
+
+protected slots:
+ void chooseServiceFont();
+ void chooseNumberFont();
+ void slotChanged();
+
+private:
+ QFont mServiceFont;
+ QFont mNumberFont;
+};
+
+#endif // KSVLOOKANDFEEL_H
diff --git a/ksysv/ksvmiscconfig.cpp b/ksysv/ksvmiscconfig.cpp
new file mode 100644
index 0000000..05e9126
--- /dev/null
+++ b/ksysv/ksvmiscconfig.cpp
@@ -0,0 +1,64 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "ksvmiscconfig.h"
+
+#include <qgroupbox.h>
+#include <qlayout.h>
+
+#include <kdialog.h>
+
+/*
+ * Constructs a KSVMiscConfig which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ */
+KSVMiscConfig::KSVMiscConfig( QWidget* parent, const char* name, WFlags fl )
+ : MiscConfiguration( parent, name, fl )
+{
+ mSpacer->setFixedHeight (KDialog::spacingHint());
+
+ // Messages
+ mMessagesBoxLayout->setMargin (KDialog::marginHint());
+ mMessagesBoxLayout->setSpacing(KDialog::spacingHint());
+
+// // Editor
+// mEditorBoxLayout->setMargin (KDialog::marginHint());
+// mEditorBoxLayout->setSpacing (KDialog::spacingHint());
+}
+
+void KSVMiscConfig::slotChanged()
+{
+ emit configChanged();
+}
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KSVMiscConfig::~KSVMiscConfig()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+#include "ksvmiscconfig.moc"
+
diff --git a/ksysv/ksvmiscconfig.h b/ksysv/ksvmiscconfig.h
new file mode 100644
index 0000000..8195d00
--- /dev/null
+++ b/ksysv/ksvmiscconfig.h
@@ -0,0 +1,47 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef KSVMISCCONFIG_H
+#define KSVMISCCONFIG_H
+#include "miscconfig.h"
+
+class KSVMiscConfig : public MiscConfiguration
+{
+ Q_OBJECT
+
+public:
+ KSVMiscConfig( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+ ~KSVMiscConfig();
+
+signals:
+ void configChanged();
+
+protected slots:
+ void slotChanged();
+
+};
+
+#endif // KSVMISCCONFIG_H
+
diff --git a/ksysv/ksvpathconfig.cpp b/ksysv/ksvpathconfig.cpp
new file mode 100644
index 0000000..bf7be35
--- /dev/null
+++ b/ksysv/ksvpathconfig.cpp
@@ -0,0 +1,75 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "ksvpathconfig.h"
+
+#include <klineedit.h>
+#include <kfiledialog.h>
+
+/*
+ * Constructs a KSVPathConfig which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ */
+KSVPathConfig::KSVPathConfig( QWidget* parent, const char* name, WFlags fl )
+ : PathConfiguration( parent, name, fl )
+{
+ mSpacer->setFixedHeight (KDialog::spacingHint());
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KSVPathConfig::~KSVPathConfig()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+void KSVPathConfig::browseServices()
+{
+ QString path = KFileDialog::getExistingDirectory(mServicesPath->text(), this);
+
+ if (!path.isEmpty())
+ mServicesPath->setText(path);
+
+ mServicesPath->setFocus();
+}
+
+void KSVPathConfig::browseRunlevels()
+{
+ QString path = KFileDialog::getExistingDirectory(mRunlevelPath->text(), this);
+
+ if (!path.isEmpty())
+ mRunlevelPath->setText(path);
+
+ mRunlevelPath->setFocus();
+}
+
+void KSVPathConfig::slotChanged()
+{
+ emit configChanged();
+}
+
+#include "ksvpathconfig.moc"
+
diff --git a/ksysv/ksvpathconfig.h b/ksysv/ksvpathconfig.h
new file mode 100644
index 0000000..8cced64
--- /dev/null
+++ b/ksysv/ksvpathconfig.h
@@ -0,0 +1,49 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef KSVPATHCONFIG_H
+#define KSVPATHCONFIG_H
+#include "pathconfig.h"
+
+class KSVPathConfig : public PathConfiguration
+{
+ Q_OBJECT
+
+public:
+ KSVPathConfig( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+ ~KSVPathConfig();
+
+signals:
+ void configChanged();
+
+protected slots:
+ void browseRunlevels();
+ void browseServices();
+ void slotChanged();
+
+};
+
+#endif // KSVPATHCONFIG_H
+
diff --git a/ksysv/ksysv.desktop b/ksysv/ksysv.desktop
new file mode 100644
index 0000000..6cbb8e5
--- /dev/null
+++ b/ksysv/ksysv.desktop
@@ -0,0 +1,72 @@
+[Desktop Entry]
+Name=KSysV
+Name[ar]=برنامج KSysV
+Name[bn]=কে-সিস-ভি
+Name[pt_BR]=KSysV
+Name[th]=แก้ไขการเริ่มระบบแบบ SysV - K
+GenericName=SysV-Init Editor
+GenericName[ar]=محرر SysV-Init
+GenericName[bg]=Редактор на SysV-Init
+GenericName[bn]=সিস-ভি-আইনিট সম্পাদক
+GenericName[br]=Aozer deraouiñ SysV
+GenericName[bs]=SysV Init Editor
+GenericName[ca]=Editor de l'init SysV
+GenericName[cs]=SysV-Init editor
+GenericName[cy]=Golygydd SysV-Init
+GenericName[el]=Επεξεργαστής SysV-Init
+GenericName[es]= Editor de inicio SysV
+GenericName[et]=SysV-Init redaktor
+GenericName[eu]=SysV Init editorea
+GenericName[fa]=ویرایشگر آغازین SysV
+GenericName[fi]=SysV-Init -asetusmuokkain
+GenericName[fr]=Éditeur de l'initialisation SysV
+GenericName[ga]=Eagarthóir SysV-Init
+GenericName[gl]=Editor de Inicio SysV
+GenericName[he]=מנהל השירותים
+GenericName[hr]=Uređivač SysV-Init
+GenericName[hu]=Szolgáltatáskezelő
+GenericName[is]=SysV Init-stjóri
+GenericName[it]=Editor per SysV-Init
+GenericName[ja]=SystemV 起動スクリプトエディタ
+GenericName[ka]=SysV-Init რედაქტორი
+GenericName[kk]=SysV-Init редакторы
+GenericName[km]=កម្មវិធី​និពន្ធ SysV-Init
+GenericName[ko]=SysV Init 편집기
+GenericName[lt]=SysV-Init redaktorius
+GenericName[mk]=Уредувач на SysV-Init
+GenericName[mt]=Editur SysV-Init
+GenericName[nb]=SysV-init-redigering
+GenericName[nds]=Editor för SysV-Init
+GenericName[ne]=SysV-Init सम्पादक
+GenericName[nn]=SysV-init-redigering
+GenericName[pa]=SysV-Init ਸੰਪਾਦਕ
+GenericName[pl]=Edytor Startu SysV
+GenericName[pt]=Editor de SysV-Init
+GenericName[pt_BR]=Editor do SysV-Init
+GenericName[ro]=Manager de servicii SysV
+GenericName[ru]=Редактор сценариев SysV
+GenericName[se]=Sysv-init-doaimmaheapmi
+GenericName[sk]=SysV-Init editor
+GenericName[sl]=Urejevalnik začetnih nastavitev SysV
+GenericName[sr]=Уређивач SysV-init-а
+GenericName[sr@Latn]=Uređivač SysV-init-a
+GenericName[sv]=Sys V-starteditor
+GenericName[th]=แก้ไขการเริ่มระบบแบบ SysV
+GenericName[tr]=SysV-Init Düzenleyici
+GenericName[uk]=Редактор KSysV-Init
+GenericName[vi]=SysV-Bộ sửa Init
+GenericName[wa]=Aspougneu po SysV-Init
+GenericName[zh_CN]=SysV Init 编辑器
+GenericName[zh_HK]=SysV-Init 編輯器
+GenericName[zh_TW]=SysV-Init 編輯器
+MimeType=
+Exec=ksysv -caption "%c" %i %m
+Icon=ksysv
+Path=
+DocPath=ksysv/index.html
+Type=Application
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+X-KDE-SubstituteUID=true
+Categories=Qt;KDE;System;
diff --git a/ksysv/ksysvui.rc b/ksysv/ksysvui.rc
new file mode 100644
index 0000000..11a79b5
--- /dev/null
+++ b/ksysv/ksysvui.rc
@@ -0,0 +1,96 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="ksysv" version="3">
+ <MenuBar noMerge="1">
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_revert"/>
+ <Action name="file_open"/>
+ <Separator line_separator="true"/>
+ <Action name="file_save"/>
+ <Action name="file_save_as"/>
+ <Action name="ksysv_save_log"/>
+ <Separator line_separator="true"/>
+ <Action name="ksysv_print_log"/>
+ <Separator line_separator="true"/>
+ <Action name="file_quit"/>
+ </Menu>
+
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator line_separator="true"/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Separator line_separator="true"/>
+ <Action name="ksysv_properties"/>
+ </Menu>
+
+ <Menu name="tools"><text>&amp;Tools</text>
+ <Action name="ksysv_start_service"/>
+ <Action name="ksysv_stop_service"/>
+ <Action name="ksysv_restart_service"/>
+ <Separator line_separator="true"/>
+ <Action name="ksysv_edit_service"/>
+ </Menu>
+
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Merge name="StandardToolBarMenuHandler" />
+ <Action name="ksysv_toggle_log"/>
+ <Separator line_separator="true"/>
+ <Action name="options_save_options"/>
+ <Separator line_separator="true"/>
+ <Action name="options_configure_keybinding"/>
+ <Action name="options_configure_toolbars"/>
+ <Action name="options_configure"/>
+ </Menu>
+
+ <Menu name="help"><text>&amp;Help</text>
+ <Action name="help_contents"/>
+ <Action name="help_whats_this"/>
+ <Separator line_separator="true"/>
+ <Action name="help_report_bug"/>
+ <Separator line_separator="true"/>
+ <Action name="help_about_app"/>
+ <Action name="help_about_kde"/>
+ </Menu>
+ </MenuBar>
+
+ <ToolBar fullWidth="true" name="mainToolBar" noMerge="1">
+ <text>Main Toolbar</text>
+ <Action name="file_revert"/>
+ <Action name="file_save"/>
+ <Separator line_separator="true"/>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator line_separator="true"/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="ksysv_toggle_log"/>
+ </ToolBar>
+
+ <Menu name="item_menu">
+ <text>Runlevel Menu</text>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Separator/>
+ <Action name="ksysv_properties"/>
+ </Menu>
+
+ <Menu name="script_menu">
+ <text>Services Menu</text>
+ <Action name="edit_copy"/>
+ <Separator/>
+ <Action name="ksysv_open_service"/>
+ <Action name="ksysv_open_with"/>
+ <Separator/>
+ <Action name="ksysv_properties"/>
+ </Menu>
+
+ <Menu name="list_menu">
+ <text>Runlevel Menu</text>
+ <Action name="ksysv_paste_append"/>
+ </Menu>
+
+</kpartgui>
diff --git a/ksysv/leveldb.c b/ksysv/leveldb.c
new file mode 100644
index 0000000..149cb3b
--- /dev/null
+++ b/ksysv/leveldb.c
@@ -0,0 +1,353 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : Modifications (C) 1999 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <locale.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Changes
+ 2000-08-04 - Peter Putzer <putzer@kde.org>
+ fixed compilation on *BSD (use GLOB_NOCHECK & strcmp instead of
+ checking for GLOB_NOMATCH)
+
+ 1999-04-11 - Peter Putzer <putzer@kde.org>
+ modified leveldb.h for use with C++
+
+ 1998-09-22 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ i18n for init.d scripts (eg.: description(pt_BR) is a brazilian
+ portuguese description for the package)
+*/
+
+#define _(String) String
+
+#include "leveldb.h"
+
+int parseLevels(const char* str, int emptyOk) {
+ const char* chptr = str;
+ int rc = 0;
+
+ if (!str || !strlen(str))
+ return emptyOk ? 0 : -1;
+
+ while (*chptr) {
+ if (!isdigit(*chptr) || *chptr > '6') return -1;
+ rc |= 1 << (*chptr - '0');
+ chptr++;
+ }
+
+ return rc;
+}
+
+int readServiceInfo(const char* RUNLEVELS, const char * name, struct service * service) {
+ char * filename = (char *) malloc(strlen(name) + strlen(RUNLEVELS) + 50);
+ int fd, i;
+ struct stat sb;
+ char * bufstart, * bufstop, * start, * end, * next;
+ struct service serv = { NULL, -1, -1, -1, NULL };
+ char overflow;
+ char english;
+ char is_my_lang = 0;
+ char levelbuf[20];
+ char * lang = getenv ("LANG"),
+ * final_parenthesis,
+ * english_desc = NULL;
+ char my_lang_loaded = 0;
+
+ sprintf(filename, "%s/init.d/%s", RUNLEVELS, name);
+
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ {
+ free(filename);
+ return -1;
+ }
+ free(filename);
+ fstat(fd, &sb);
+
+ bufstart = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (bufstart == ((caddr_t) -1)) {
+ close(fd);
+ return -1;
+ }
+
+ bufstop = bufstart + sb.st_size;
+ close(fd);
+
+ next = bufstart;
+ while (next < bufstop && (serv.levels == -1 || !serv.desc)) {
+ start = next;
+
+ while (isspace(*start) && start < bufstop) start++;
+ if (start == bufstop) break;
+
+ end = strchr(start, '\n');
+ if (!end)
+ next = end = bufstop;
+ else
+ next = end + 1;
+
+ if (*start != '#') continue;
+
+ start++;
+ while (isspace(*start) && start < end) start++;
+ if (start == end) continue;
+
+ if (!strncmp(start, "chkconfig:", 10)) {
+ start += 10;
+ while (isspace(*start) && start < end) start++;
+ if (start == end) {
+ if (serv.desc) free(serv.desc);
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+
+ if ((sscanf(start, "%19s %d %d%c", levelbuf,
+ &serv.sPriority, &serv.kPriority, &overflow) != 4) ||
+ overflow != '\n') {
+ if (serv.desc) free(serv.desc);
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+
+ if (!strcmp(levelbuf, "-"))
+ serv.levels = 0;
+ else
+ serv.levels = parseLevels(levelbuf, 0);
+ if (serv.levels == -1) {
+ if (serv.desc) free(serv.desc);
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+ } else if (!strncmp(start, "description", 11)) {
+ start += 11;
+
+ english = *start == ':';
+
+ if (!english) {
+ if (*start != '(') {
+ if (serv.desc) free(serv.desc);
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+
+ ++start;
+ final_parenthesis = strchr (start, ')');
+
+ if (final_parenthesis == NULL || final_parenthesis - start > 5) {
+ if (serv.desc) free(serv.desc);
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+
+ is_my_lang = lang ? strncmp (lang, start, strlen (lang)) == 0 : 0;
+ start = final_parenthesis + 2;
+ } else ++start;
+
+ while (isspace(*start) && start < end) start++;
+ if (start == end) {
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+ {
+ char* desc = malloc(end - start + 1);
+ strncpy(desc, start, end - start);
+ desc[end - start] = '\0';
+
+ start = next;
+
+ while (desc[strlen(desc) - 1] == '\\') {
+ desc[strlen(desc) - 1] = '\0';
+ start = next;
+
+ while (isspace(*start) && start < bufstop) start++;
+ if (start == bufstop || *start != '#') {
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+
+ start++;
+
+ while (isspace(*start) && start < bufstop) start++;
+ if (start == bufstop) {
+ munmap(bufstart, sb.st_size);
+ return 1;
+ }
+
+ end = strchr(start, '\n');
+ if (!end)
+ next = end = bufstop;
+ else
+ next = end + 1;
+
+ i = strlen(desc);
+ desc = realloc(desc, i + end - start + 1);
+ strncat(desc, start, end - start);
+ desc[i + end - start] = '\0';
+
+ start = next;
+ }
+
+ if (desc) {
+ if (my_lang_loaded) {
+ free(desc);
+ } else if (is_my_lang) {
+ if (serv.desc)
+ free(serv.desc);
+
+ serv.desc = desc;
+ break;
+ } else if (english) {
+ if (serv.desc)
+ free(serv.desc);
+
+ if (english_desc)
+ free (english_desc);
+
+ english_desc = desc;
+ } else free (desc);
+ }
+ }
+ }
+ }
+
+ munmap(bufstart, sb.st_size);
+
+ if (!serv.desc) {
+ if (english_desc)
+ serv.desc = english_desc;
+ } else if (english_desc)
+ free (english_desc);
+
+ if ((serv.levels == -1 ) || !serv.desc) {
+ return 1;
+ }
+
+ serv.name = strdup(name);
+
+ *service = serv;
+ return 0;
+}
+
+/* returns -1 on error */
+int currentRunlevel(void) {
+ FILE * p;
+ char response[50];
+
+ p = popen("/sbin/runlevel", "r");
+ if (!p) return -1;
+
+ if (!fgets(response, sizeof(response), p)) {
+ pclose(p);
+ return -1;
+ }
+
+ pclose(p);
+
+ if (response[1] != ' ' || !isdigit(response[2]) || response[3] != '\n')
+ return -1;
+
+ return response[2] - '0';
+}
+
+int findServiceEntries(const char* RUNLEVELS, const char* name, int level, glob_t * globresptr) {
+ char match[200];
+ glob_t globres;
+ int rc;
+
+ sprintf(match, "%s/rc%d.d/[SK][0-9][0-9]%s", RUNLEVELS, level, name);
+
+ rc = glob(match, GLOB_ERR | GLOB_NOSORT | GLOB_NOCHECK, NULL, &globres);
+
+ if (rc) {
+ fprintf(stderr, _("failed to glob pattern %s: %s\n"), match,
+ strerror(errno));
+ return 1;
+ } else if (!strcmp(match, globres.gl_pathv[0])) {
+ globresptr->gl_pathc = 0;
+ return 0;
+ }
+
+ *globresptr = globres;
+ return 0;
+}
+
+int isConfigured(const char* RUNLEVELS, const char* name, int level) {
+ glob_t globres;
+
+ if (findServiceEntries(RUNLEVELS, name, level, &globres))
+ exit(1);
+
+ if (!globres.gl_pathc)
+ return 0;
+
+ globfree(&globres);
+ return 1;
+}
+
+int isOn(const char* RUNLEVELS, const char* name, int level) {
+ glob_t globres;
+
+ if (level == -1) {
+ level = currentRunlevel();
+ if (level == -1) {
+ fprintf(stderr, _("cannot determine current run level\n"));
+ return 0;
+ }
+ }
+
+ if (findServiceEntries(RUNLEVELS, name, level, &globres))
+ exit(1);
+
+ if (!globres.gl_pathc || !strstr(globres.gl_pathv[0], "/S"))
+ return 0;
+
+ globfree(&globres);
+ return 1;
+}
+
+int doSetService(const char* RUNLEVELS, struct service s, int level, int on) {
+ int priority = on ? s.sPriority : s.kPriority;
+ char linkname[200];
+ char linkto[200];
+ glob_t globres;
+ int i;
+
+ if (!findServiceEntries(RUNLEVELS, s.name, level, &globres)) {
+ for (i = 0; (unsigned int) i < globres.gl_pathc; i++)
+ unlink(globres.gl_pathv[i]);
+ if (globres.gl_pathc) globfree(&globres);
+ }
+
+ sprintf(linkname, "%s/rc%d.d/%c%02d%s", RUNLEVELS, level,
+ on ? 'S' : 'K', priority, s.name);
+ sprintf(linkto, "../init.d/%s", s.name);
+
+ unlink(linkname); /* just in case */
+ if (symlink(linkto, linkname)) {
+ fprintf(stderr, _("failed to make symlink %s: %s\n"), linkname,
+ strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/ksysv/leveldb.h b/ksysv/leveldb.h
new file mode 100644
index 0000000..e18d202
--- /dev/null
+++ b/ksysv/leveldb.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1999 by Red Hat Software
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+/* modifications (c) 1999 Peter Putzer */
+
+#ifndef H_LEVELDB
+#define H_LEVELDB
+
+
+#ifdef __cplusplus
+
+extern "C" {
+#endif
+
+#include <glob.h>
+
+struct service {
+ char * name;
+ int levels, kPriority, sPriority;
+ char * desc;
+};
+
+int parseLevels(const char * str, int emptyOk);
+
+/* returns 0 on success, 1 if the service is not chkconfig-able, -1 if an
+ I/O error occurs (in which case errno can be checked) */
+int readServiceInfo(const char* RUNLEVELS, const char* name, struct service * service);
+int currentRunlevel(void);
+int isOn(const char* RUNLEVELS, const char* name, int where);
+int isConfigured(const char* RUNLEVELS, const char* name, int level);
+int doSetService(const char* RUNLEVELS, struct service s, int level, int on);
+int findServiceEntries(const char* RUNLEVELS, const char* name, int level, glob_t * globresptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ksysv/lookandfeelconfig.ui b/ksysv/lookandfeelconfig.ui
new file mode 100644
index 0000000..bedd940
--- /dev/null
+++ b/ksysv/lookandfeelconfig.ui
@@ -0,0 +1,500 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>LookAndFeel</class>
+<comment>Look &amp; Feel configuration for SysV-Init Editor</comment>
+<author>Peter Putzer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>LookAndFeel</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>532</width>
+ <height>303</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Look &amp; Feel</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>mFontBox</cstring>
+ </property>
+ <property name="title">
+ <string>Fonts</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="QLayoutWidget">
+ <property name="name">
+ <cstring>mTopLayout</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="2">
+ <property name="name">
+ <cstring>mChooseNumberFont</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;hoose...</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>mServiceFontPreview</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>dummy-font</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>mNumberFontPreview</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="text">
+ <string>dummy-font</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>mServiceFontLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Services:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mChooseServiceFont</cstring>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>mNumberFontLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Sorting numbers:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mChooseNumberFont</cstring>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>mChooseServiceFont</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Choose...</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>mSpacer</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>mColorBox</cstring>
+ </property>
+ <property name="title">
+ <string>Colors</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="QLayoutWidget">
+ <property name="name">
+ <cstring>mColorGrid</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="KColorButton" row="2" column="1">
+ <property name="name">
+ <cstring>mChangedNormal</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="text">
+ <string>Dummy</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose a color for changed services</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Use the &lt;strong&gt;Select Color dialog box&lt;/strong&gt; to pick a text color for &lt;em&gt;services that have been changed&lt;/em&gt; (either order/sorting number or name).&lt;/p&gt;
+&lt;p&gt;Changed service entries will be distinguished by this color.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>mChangedNormalLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Changed:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mChangedNormal</cstring>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>mNewNormal</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="text">
+ <string>Dummy</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose a color for service new to a runlevel</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Use the &lt;strong&gt;Select Color dialog box&lt;/strong&gt; to pick a text color for &lt;em&gt;services new to a runlevel&lt;/em&gt;.&lt;/p&gt;
+&lt;p&gt;New service entries will be distinguished by this color.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>mNewNormalLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;New:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mNewNormal</cstring>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="KColorButton" row="3" column="1">
+ <property name="name">
+ <cstring>mChangedSelected</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="text">
+ <string>Dummy</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose a color for changed services that are selected</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Use the &lt;strong&gt;Select Color dialog box&lt;/strong&gt; to pick a selected text color for &lt;em&gt;services that have been changed&lt;/em&gt; (either order/sorting number or name).&lt;/p&gt;
+&lt;p&gt;Changed service entries will be distinguished by this color while they are selected.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>mNewSelected</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="text">
+ <string>Dummy</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose a color for services new to a runlevel that are selected</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Use the &lt;strong&gt;Select Color dialog box&lt;/strong&gt; to pick a selected text color for &lt;em&gt;services new to a runlevel&lt;/em&gt;.&lt;/p&gt;
+&lt;p&gt;New service entries will be distinguished by this color while they are selected.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>mNewSelectedLabel</cstring>
+ </property>
+ <property name="text">
+ <string>New &amp;&amp; &amp;selected:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mNewSelected</cstring>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>mChangedSelectedLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Changed &amp;&amp; s&amp;elected:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mChangedSelected</cstring>
+ </property>
+ <property name="hAlign" stdset="0">
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <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>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>mChooseServiceFont</sender>
+ <signal>clicked()</signal>
+ <receiver>LookAndFeel</receiver>
+ <slot>chooseServiceFont()</slot>
+ </connection>
+ <connection>
+ <sender>mChooseNumberFont</sender>
+ <signal>clicked()</signal>
+ <receiver>LookAndFeel</receiver>
+ <slot>chooseNumberFont()</slot>
+ </connection>
+ <connection>
+ <sender>mNewNormal</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>LookAndFeel</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>mNewSelected</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>LookAndFeel</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>mChangedNormal</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>LookAndFeel</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>mChangedSelected</sender>
+ <signal>changed(const QColor&amp;)</signal>
+ <receiver>LookAndFeel</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>mChooseServiceFont</tabstop>
+ <tabstop>mChooseNumberFont</tabstop>
+ <tabstop>mNewNormal</tabstop>
+ <tabstop>mNewSelected</tabstop>
+ <tabstop>mChangedNormal</tabstop>
+ <tabstop>mChangedSelected</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">klocale.h</include>
+</includes>
+<slots>
+ <slot access="protected">chooseNumberFont()</slot>
+ <slot access="protected">chooseServiceFont()</slot>
+ <slot access="protected">slotChanged()</slot>
+</slots>
+<pixmapfunction>DesktopIcon</pixmapfunction>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksysv/main.cpp b/ksysv/main.cpp
new file mode 100644
index 0000000..4dd0e09
--- /dev/null
+++ b/ksysv/main.cpp
@@ -0,0 +1,103 @@
+ /***************************************************************************
+ copyright : (C) 1997-2000 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "ksvapplication.h"
+#include "ksv_conf.h"
+#include "ksvconfigwizard.h"
+#include "TopWidget.h"
+#include "version.h"
+
+using namespace std;
+
+#if (defined(DEBUG) && !(defined(NDEBUG) || defined(NO_DEBUG)))
+#define KSYSV_DEBUG(x) x
+#else
+#define KSYSV_DEBUG(x) do { } while (0)
+#endif
+
+static void myMessageOutput( QtMsgType type, const char *msg )
+{
+ switch ( type ) {
+ case QtDebugMsg:
+ KSYSV_DEBUG(cerr << "Debug: " << msg << endl);
+ break;
+ case QtWarningMsg:
+ KSYSV_DEBUG(cerr << "Warning: " << msg << endl);
+ break;
+ case QtFatalMsg:
+ cerr << "Fatal: " << msg << endl;
+ abort(); // dump core on purpose
+ }
+}
+
+int main( int argc, char **argv ) {
+ // install own message handler that ignores debug-msg when DEBUG is not defined
+ qInstallMsgHandler(myMessageOutput);
+
+ KAboutData about("ksysv", I18N_NOOP("SysV-Init Editor"), KSYSV_VERSION_STRING,
+ I18N_NOOP ("Editor for Sys-V like init configurations"),
+ KAboutData::License_GPL,
+ "Copyright (c) 1997-2000, Peter Putzer.",
+ I18N_NOOP ("Similar to Red Hat's" \
+ "\"tksysv\", but SysV-Init Editor allows\n" \
+ "drag-and-drop, as well as keyboard use."));
+ about.addAuthor ("Peter Putzer", I18N_NOOP("Main developer"), "putzer@kde.org");
+ ksv::about = &about;
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KUniqueApplication::addCmdLineOptions ();
+
+ if (!KUniqueApplication::start()) {
+ cerr << "SysV-Init Editor is already running!" << endl;
+ return -1;
+ }
+
+ KSVApplication app;
+
+ // session-management
+ if (kapp->isRestored())
+ RESTORE(KSVTopLevel)
+ else
+ {
+ KSVConfig* conf = KSVConfig::self();
+ if (!conf->isConfigured())
+ {
+ KSVConfigWizard* w = new KSVConfigWizard(0, "ConfigWizard", true);
+ w->exec();
+
+ conf->setConfigured(true);
+ conf->setRunlevelPath (w->runlevelPath());
+ conf->setScriptPath (w->servicesPath());
+ conf->writeSettings();
+ }
+
+ KSVTopLevel* top = new KSVTopLevel();
+ app.setMainWidget(top);
+ top->show();
+ }
+ // end session-management
+
+ return app.exec();
+}
+
diff --git a/ksysv/miscconfig.ui b/ksysv/miscconfig.ui
new file mode 100644
index 0000000..0cfebe2
--- /dev/null
+++ b/ksysv/miscconfig.ui
@@ -0,0 +1,186 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>MiscConfiguration</class>
+<author>Peter Putzer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>MiscConfiguration</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>332</width>
+ <height>137</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Miscellaneous</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>mMessagesBox</cstring>
+ </property>
+ <property name="title">
+ <string>Informational Messages</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </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="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout12</cstring>
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>mShowAllLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Show all messages again:</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>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>mShowAll</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Show All</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>mWarnReadOnly</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Warn if not allowed to write configuration</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>mWarnSortingNumber</cstring>
+ </property>
+ <property name="text">
+ <string>Warn &amp;if unable to generate a sorting number</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>mSpacer</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</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>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>mWarnReadOnly</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MiscConfiguration</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>mWarnSortingNumber</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>MiscConfiguration</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in declaration">klocale.h</include>
+</includes>
+<slots>
+ <slot access="protected">slotChanged()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/ksysv/pathconfig.ui b/ksysv/pathconfig.ui
new file mode 100644
index 0000000..c59a96f
--- /dev/null
+++ b/ksysv/pathconfig.ui
@@ -0,0 +1,294 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>PathConfiguration</class>
+<comment>Path configuration for KSysV</comment>
+<author>Peter Putzer</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PathConfiguration</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>305</width>
+ <height>168</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Path Configuration</string>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>mServicesLayout</cstring>
+ </property>
+ <property name="layoutMargin" stdset="0">
+ </property>
+ <property name="layoutSpacing" stdset="0">
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>mServicesLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Service path:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mServicesPath</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>mServicesButtonLayout</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>mServicesPath</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the path to the folder containing the services</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>mBrowseServices</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Browse...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Select the folder containing the services</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>mSpacer</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>mRunlevelLayout</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>mRunlevelLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Runlevel path:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mRunlevelPath</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>mRunlevelButtonLayout</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>mRunlevelPath</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>StrongFocus</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the path to the folder containing the runlevel folders</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>mBrowseRunlevel</cstring>
+ </property>
+ <property name="text">
+ <string>Br&amp;owse...</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Select the folder containing the runlevel folders </string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>mEmptySpace</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>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>mBrowseServices</sender>
+ <signal>clicked()</signal>
+ <receiver>PathConfiguration</receiver>
+ <slot>browseServices()</slot>
+ </connection>
+ <connection>
+ <sender>mBrowseRunlevel</sender>
+ <signal>clicked()</signal>
+ <receiver>PathConfiguration</receiver>
+ <slot>browseRunlevels()</slot>
+ </connection>
+ <connection>
+ <sender>mServicesPath</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PathConfiguration</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>mRunlevelPath</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>PathConfiguration</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>mServicesPath</tabstop>
+ <tabstop>mBrowseServices</tabstop>
+ <tabstop>mRunlevelPath</tabstop>
+ <tabstop>mBrowseRunlevel</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">klocale.h</include>
+ <include location="global" impldecl="in declaration">kdialog.h</include>
+</includes>
+<slots>
+ <slot access="protected">browseServices()</slot>
+ <slot access="protected">browseRunlevels()</slot>
+ <slot access="protected">slotChanged()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/ksysv/pics/Makefile.am b/ksysv/pics/Makefile.am
new file mode 100644
index 0000000..e60bc77
--- /dev/null
+++ b/ksysv/pics/Makefile.am
@@ -0,0 +1,7 @@
+#KDE_ICON = ksysv
+# add here all files
+pics_DATA = ksysv_start.png ksysv_locked.png ksysv_unlocked.png \
+ ksysv_restart.png ksysv_stop.png
+
+# this is the directory, where all datas are installed
+picsdir = $(kde_datadir)/ksysv/pics
diff --git a/ksysv/pics/ksysv_locked.png b/ksysv/pics/ksysv_locked.png
new file mode 100644
index 0000000..03480e3
--- /dev/null
+++ b/ksysv/pics/ksysv_locked.png
Binary files differ
diff --git a/ksysv/pics/ksysv_restart.png b/ksysv/pics/ksysv_restart.png
new file mode 100644
index 0000000..8f4ad31
--- /dev/null
+++ b/ksysv/pics/ksysv_restart.png
Binary files differ
diff --git a/ksysv/pics/ksysv_start.png b/ksysv/pics/ksysv_start.png
new file mode 100644
index 0000000..debff53
--- /dev/null
+++ b/ksysv/pics/ksysv_start.png
Binary files differ
diff --git a/ksysv/pics/ksysv_stop.png b/ksysv/pics/ksysv_stop.png
new file mode 100644
index 0000000..5decccd
--- /dev/null
+++ b/ksysv/pics/ksysv_stop.png
Binary files differ
diff --git a/ksysv/pics/ksysv_unlocked.png b/ksysv/pics/ksysv_unlocked.png
new file mode 100644
index 0000000..a52d790
--- /dev/null
+++ b/ksysv/pics/ksysv_unlocked.png
Binary files differ
diff --git a/ksysv/pics/stop.png b/ksysv/pics/stop.png
new file mode 100644
index 0000000..1cabc6e
--- /dev/null
+++ b/ksysv/pics/stop.png
Binary files differ
diff --git a/ksysv/toolbar/Makefile.am b/ksysv/toolbar/Makefile.am
new file mode 100644
index 0000000..e5515a8
--- /dev/null
+++ b/ksysv/toolbar/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON = AUTO
diff --git a/ksysv/toolbar/cr16-action-toggle_log.png b/ksysv/toolbar/cr16-action-toggle_log.png
new file mode 100644
index 0000000..e2a44ec
--- /dev/null
+++ b/ksysv/toolbar/cr16-action-toggle_log.png
Binary files differ
diff --git a/ksysv/trash.cpp b/ksysv/trash.cpp
new file mode 100644
index 0000000..8420687
--- /dev/null
+++ b/ksysv/trash.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-2000 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+// Trash Can
+
+#include <qtooltip.h>
+#include <qlabel.h>
+#include <qpainter.h>
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "ksvdraglist.h"
+#include "ksvdrag.h"
+#include "ActionList.h"
+#include "trash.h"
+
+KSVTrash::KSVTrash (QWidget* parent, const char* name)
+ : QFrame (parent, name),
+ mKIL (KGlobal::iconLoader()),
+ mLabel (new QLabel(this)),
+ mOpen (false)
+{
+ setLineWidth(1);
+ setMidLineWidth(0);
+
+ setFrameStyle (QFrame::StyledPanel | QFrame::Sunken);
+
+ mLabel->setPixmap(mKIL->loadIcon("trashcan_empty", KIcon::Desktop));
+ mPixmapWidth = mLabel->pixmap()->width();
+ mLabel->setGeometry(5, 7, mPixmapWidth, mPixmapWidth);
+
+ QToolTip::add(mLabel, i18n("Drag here to remove services"));
+ QToolTip::add(this, i18n("Drag here to remove services"));
+
+ setMinimumSize(sizeHint());
+ setAcceptDrops(true);
+
+ mLabel->installEventFilter(this);
+ mLabel->setAcceptDrops(true);
+}
+
+KSVTrash::~KSVTrash()
+{
+}
+
+void KSVTrash::dropEvent (QDropEvent* e)
+{
+ KSVData data;
+ KSVDragList* list = static_cast<KSVDragList*> (e->source());
+
+ if (list && strcmp (list->name(), "Scripts") && KSVDrag::decodeNative (e, data))
+ {
+ e->accept();
+
+ emit undoAction (new RemoveAction (list, &data));
+ delete list->match (data);
+ }
+ else
+ e->ignore();
+
+ if (mOpen)
+ {
+ mLabel->repaint();
+ mOpen = false;
+ }
+}
+
+void KSVTrash::dragMoveEvent ( QDragMoveEvent* e )
+{
+ if (e->provides ("application/x-ksysv") &&
+ e->source() && strcmp (e->source()->name(), "Scripts"))
+ {
+ QPainter p;
+
+ p.begin(mLabel);
+ p.drawPixmap( 0, 0, mKIL->loadIcon("trashcan_full", KIcon::Desktop) );
+ p.end();
+
+ mOpen = true;
+ e->accept();
+ }
+ else
+ e->ignore();
+}
+
+void KSVTrash::dragLeaveEvent ( QDragLeaveEvent* )
+{
+ if (mOpen)
+ {
+ mLabel->repaint();
+ mOpen = false;
+ }
+}
+
+bool KSVTrash::eventFilter( QObject *, QEvent *e )
+{
+ switch (e->type())
+ {
+ case QEvent::DragMove:
+ dragMoveEvent ( static_cast<QDragMoveEvent*> (e) );
+ return true;
+ break;
+
+ case QEvent::DragLeave:
+ dragLeaveEvent ( static_cast<QDragLeaveEvent*> (e) );
+ return true;
+ break;
+
+ case QEvent::Drop:
+ dropEvent ( static_cast<QDropEvent*> (e) );
+ return true;
+ break;
+
+ default:
+ return false;
+ }
+}
+
+QSize KSVTrash::sizeHint() const
+{
+ static QSize size = QSize (mPixmapWidth + 2 * 5, mPixmapWidth + 2 * 7);
+
+ return size;
+}
+
+#include "trash.moc"
diff --git a/ksysv/trash.h b/ksysv/trash.h
new file mode 100644
index 0000000..7772d19
--- /dev/null
+++ b/ksysv/trash.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ begin : Sun Oct 3 1999
+ copyright : (C) 1997-99 by Peter Putzer
+ email : putzer@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; version 2. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSV_TRASH_H
+#define KSV_TRASH_H
+
+#include <qframe.h>
+#include <qpixmap.h>
+#include <qstring.h>
+
+// forward declarations
+class QLabel;
+class KIconLoader;
+class KSVItem;
+class KSVAction;
+
+class KSVTrash : public QFrame
+{
+ Q_OBJECT
+
+public:
+ KSVTrash (QWidget* parent = 0, const char* name = 0);
+ virtual ~KSVTrash();
+
+ virtual QSize sizeHint() const;
+
+protected:
+ /**
+ * Overridden from @ref QDropSite
+ */
+ virtual void dragMoveEvent ( QDragMoveEvent* );
+
+ /**
+ * Overridden from @ref QDropSite
+ */
+ virtual void dragLeaveEvent ( QDragLeaveEvent* );
+
+ /**
+ * Overridden from @ref QDropSite
+ */
+ virtual void dropEvent ( QDropEvent* );
+
+ virtual bool eventFilter ( QObject*, QEvent* );
+
+private:
+ KIconLoader* mKIL;
+ QLabel* mLabel;
+ bool mOpen;
+ int mPixmapWidth;
+
+signals:
+ void undoAction (KSVAction*);
+};
+
+#endif
diff --git a/ksysv/version.h b/ksysv/version.h
new file mode 100644
index 0000000..6b5ea67
--- /dev/null
+++ b/ksysv/version.h
@@ -0,0 +1,32 @@
+/*
+** Copyright (C) 2000 Peter Putzer <putzer@kde.org>
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef KSV_VERSION_H
+#define KSV_VERSION_H
+
+#define KSYSV_VERSION_STRING "1.3.9"
+
+#endif // KSV_VERSION_H
+
diff --git a/ksysv/x-ksysv-log.desktop b/ksysv/x-ksysv-log.desktop
new file mode 100644
index 0000000..30e4d66
--- /dev/null
+++ b/ksysv/x-ksysv-log.desktop
@@ -0,0 +1,68 @@
+[Desktop Entry]
+Comment=SysV-Init Editor Log File
+Comment[ar]=ملف محرّر سجل الوقائع SysV-Init
+Comment[az]=SysV-Init Editor Qeyd Faylı
+Comment[be]=Часопіс рэдактара SysV-Init
+Comment[bg]=Редактор на инициализиращите нива
+Comment[bn]= সিস-ভি-আইনিট সম্পাদক কার্যবিবরণী ফাইল
+Comment[bs]=SysV-Init Editor log datoteka
+Comment[ca]=Fitxer de registre de l'editor init SysV
+Comment[cs]=Záznamový soubor programu SysV-Init editoru
+Comment[cy]=Ffeil Cofnodi Golygydd SysV-Init
+Comment[da]=SysV-Init editor logfil
+Comment[de]=Protokolldatei des SysV-Init-Editors
+Comment[el]=Αρχείο καταχωρήσεων επεξεργαστή SysV-Init
+Comment[eo]=protokoldosiero de SysV-Prepar-Redaktilo
+Comment[es]=Archivo de registro del Editor de inicio SysV
+Comment[et]=SysV-Init redaktori logifail
+Comment[eu]=SysV-abioko editorearen logfitxategia
+Comment[fa]=پروندۀ ثبت ویرایشگر آغازین SysV
+Comment[fi]=SysV-init-editorin lokitiedosto
+Comment[fr]=Journal de l'éditeur de configuration de démarrage SysV
+Comment[ga]=Logchomhad don eagarthóir SysV-Init
+Comment[gl]=Ficheiro de Rexisto do Editor de Início SysV
+Comment[he]=קובץ רישום של מנהל השירותים
+Comment[hi]=सिस-वी-इनिट संपादक लॉग फ़ाइल
+Comment[hr]=Datoteka zapisnika uređivača SysV-Init
+Comment[hu]=SysV-Init (szolgáltatáskezelő) naplófájl
+Comment[is]=SysV-Init stjóra annáll
+Comment[it]=File di log dell'editor di SysV-Init
+Comment[ja]=SystemV 起動スクリプトエディタのログファイル
+Comment[ka]=SysV-Init რედაქტორის ჟურნალი
+Comment[kk]=SysV-Init редактордың журналы
+Comment[km]=ឯកសារ​កំណត់​ហេតុ​កម្មវិធី​និពន្ធ SysV-Init
+Comment[ko]=SysV-Init 편집기 로그 파일
+Comment[lt]=SysV-Init redaktoriaus žurnalas
+Comment[mk]=Дневник на уредувачот на SysV-Init
+Comment[mt]=Logfile ta' l-editur SysV-Init
+Comment[nb]=Loggfil for SysV-init-redigering
+Comment[nds]=Logbook för den SysV-Init-Editor
+Comment[ne]=SysV-Init सम्पादक लग फाइल
+Comment[nl]=Logbestand van SysV-Init Editor
+Comment[nn]=Loggfil for SysV-init-redigering
+Comment[pa]=SysV-Init ਸੰਪਾਦਕ ਲਾੱਗ ਫਾਇਲ਼
+Comment[pl]=Plik dziennika edytora SysV-Init
+Comment[pt]=Registo do Editor System V Init
+Comment[pt_BR]=Arquivo de Registro do Editor do SysV-Init
+Comment[ro]=Fişier jurnal al managerului de servicii SysV
+Comment[ru]=Журнал редактора SysV-Init
+Comment[se]=Sysv-init-doaimmaheami gozihanfiila
+Comment[sk]=Súbor záznamu SysV-Init editora
+Comment[sl]=Datoteka z dnevnikom SysV-Init
+Comment[sr]=Дневник уређивача SysV-init-а
+Comment[sr@Latn]=Dnevnik uređivača SysV-init-a
+Comment[sv]=Editor för Sysv-Init-loggfiler
+Comment[ta]=SysV-Init திருத்துபவர் பதிவுக்கோப்பு
+Comment[tg]=Муҳаррири Файли Вориди SysV-Init
+Comment[th]=แฟ้มบันทึกการทำงานของเครื่องมือแก้ไขการเริ่มระบบแบบ SysV
+Comment[tr]=SysV-Inıt Düzenleyici Günlük Dosyası
+Comment[uk]=Файл журналу редактора SysV-Init
+Comment[vi]=Tập tin ghi lưu bộ sửa SysV-Init
+Comment[wa]=Fitchî djournå di l' aspougneu po SysV-Init
+Comment[zh_CN]=SysV-Init 编辑器记录文件
+Comment[zh_HK]=SysV-Init 編輯器記錄檔案
+Comment[zh_TW]=SysV Init 編輯器記錄檔案
+Icon=ksysv
+Type=MimeType
+MimeType=text/x-ksysv-log
+Patterns=*.ksysv_log;
diff --git a/ksysv/x-ksysv.desktop b/ksysv/x-ksysv.desktop
new file mode 100644
index 0000000..8e6f73a
--- /dev/null
+++ b/ksysv/x-ksysv.desktop
@@ -0,0 +1,78 @@
+[Desktop Entry]
+Comment=Saved Init Configuration
+Comment[af]=Gestoor Init Opstelling
+Comment[ar]=إعدادات Init المحفوظة
+Comment[az]=Qeyd Edilmiş Init Quraşdırması
+Comment[be]=Запісаныя настаўленні ініцыялізацыі
+Comment[bg]=Настройване на инициализиращите нива
+Comment[bn]=সংরক্ষিত আইনিট কনফিগারেশন
+Comment[br]=Kefluniañ deraouiñ enrollet
+Comment[bs]=Spremljena Init postavka
+Comment[ca]=S'ha desat la configuració init
+Comment[cs]=Uložené nastavení inicializačních schémat
+Comment[cy]=Wedi cadw furfweddiad Init
+Comment[da]=Gemt Init-indstilling
+Comment[de]=Gespeicherte Init-Einstellungen
+Comment[el]=Αποθηκευμένες ρυθμίσεις Init
+Comment[eo]=Konservita Preparagordo
+Comment[es]=Configuración de inicio guardada
+Comment[et]=Salvestatud Initi konfiguratsioon
+Comment[eu]=Init konfigurazio gordea
+Comment[fa]=پیکربندی آغازین ذخیره‌شده
+Comment[fi]=Tallennetut Init-asetukset
+Comment[fo]=Hevur goymt upprunaliga uppsetinging
+Comment[fr]=Sauvegarde de la configuration de démarrage
+Comment[ga]=Cumraíocht Tosaithe Sábháilte
+Comment[gl]=Configuración de Init Guardada
+Comment[he]=תצורת אתחול שמורה
+Comment[hi]=इनिट कॉन्फ़िगरेशन सहेजा
+Comment[hr]=Spremljena Init konfiguracija
+Comment[hu]=Elmentett Init beállítás
+Comment[id]=Konfigurasi Saved Init
+Comment[is]=Vistaðar Init stillingar
+Comment[it]=Configurazione di Init salvata
+Comment[ja]=保存されている起動スクリプトの設定
+Comment[ka]=Init-ის შენახული კონფიგურაცია
+Comment[kk]=Сақталған инициализацияның баптаулары
+Comment[km]=ការ​កំណត់​រចនា​សម្ព័ន្ធ Init ដែល​បាន​រក្សា​ទុក
+Comment[ko]=Init 설정을 저장했습니다
+Comment[lt]=Įrašytos Init parinktys
+Comment[lv]=Saglabātā Init Konfigurācija
+Comment[mk]=Зачувана конфигурација на Init
+Comment[mn]=Хадгалагдсан Инит Тохиргоо
+Comment[ms]=Konfigurasi Init yang Disimpan
+Comment[mt]=Konfigurazzjoni mistura tal-Init
+Comment[nb]=Lagret oppstartsoppsett
+Comment[nds]=Sekert Init-Instellen
+Comment[ne]=बचत गरिएको Init कन्फिगरेसन
+Comment[nl]=Opgeslagen Init-configuratie
+Comment[nn]=Lagra init-oppsett
+Comment[pa]=ਸੰਭਾਲੀ Init ਸੰਰਚਨਾ
+Comment[pl]=Zapisana konfiguracja startowa systemu
+Comment[pt]=Configuração do Init
+Comment[pt_BR]=Configuração do Init Salva
+Comment[ro]=Configuraţie de iniţializare salvată
+Comment[ru]=Сохранённые настройки инициализации
+Comment[se]=Vurkii init-heivehusat
+Comment[sk]=Uložená konfigurácia init
+Comment[sl]=Shranjena uvodna sestava
+Comment[sr]=Сачувана почетна подешавања
+Comment[sr@Latn]=Sačuvana početna podešavanja
+Comment[sv]=Sparad startinställning
+Comment[ta]=Init வடிவமைப்பு சேமிக்கப்பட்டது
+Comment[tg]=Танзимотҳои оғози нигоҳ дошта
+Comment[th]=บันทึกค่าปรับแต่งของการเริ่มระบบ
+Comment[tr]=Kaydedilmiş Init Yapılandırması
+Comment[uk]=Збережена конфігурація процесу Init
+Comment[ven]=Khonofiguresheni yo vhulungelwaho khayo
+Comment[vi]=Cấu hình Init đã lưu
+Comment[wa]=Apontiaedje d' enondaedje schapé
+Comment[xh]=Uqwalaselo olugciniweyo lwe Init
+Comment[zh_CN]=已保存的 Init 配置
+Comment[zh_HK]=已儲存 Init 設定
+Comment[zh_TW]=已儲存起始設定
+Comment[zu]=Uhlanganiselo olugciniwe lwe Init
+Icon=ksysv
+Type=MimeType
+MimeType=application/x-ksysv-package
+Patterns=*.ksysv;
diff --git a/kuser/AUTHORS b/kuser/AUTHORS
new file mode 100644
index 0000000..f3913c9
--- /dev/null
+++ b/kuser/AUTHORS
@@ -0,0 +1,2 @@
+Denis Perchine <dyp@perchine.com>
+Szombathelyi Gyrgy <gyurco@freemail.hu> \ No newline at end of file
diff --git a/kuser/ChangeLog b/kuser/ChangeLog
new file mode 100644
index 0000000..9457e68
--- /dev/null
+++ b/kuser/ChangeLog
@@ -0,0 +1,47 @@
+29/04/2000: Simplified quota.cpp(becames 2 times smaller). Please test it.
+28/04/2000: Move KUser to actions.
+ User is shown in delete user message box.
+ Use operator[] for list item access.
+ Use & instead of pointers to objects (cosy for []).
+ Rename mainDlg to mainView.
+ Move all global objects out of mainView.
+24/03/2000: Move quota ifdef code to kuqconf.h.
+ Error messages are without flags now.
+12/07/1999: fgetpwent/getpwent/fgetgrent/getgrent issue fixed (FreeBSD have no
+ fxx funcs. Thanks to Hans Petter Bieker <zerium@traad.lavvu.no>.
+24/04/1999: change _KU_FIRST_USER to KU_FIRST_USER, and put a define for it into
+ globals.h <duncan@kde.org>
+24/04/1999: Bug 'Group properties did show nothing in 'Other Users' listbox.'
+ fixed, documentation in SGML created.
+23/04/1999: User create and delete postpone logic implemented.
+04/04/1999: Bug #1133 'new fixes dont create new user home directory anymore'
+01/04/1999: Bug #895 'Kuser doesn't restore the permissions on /etc/shadow.'
+
+19990328: added #ifdef's to kuser.cpp and kgroup.cpp so that if
+ _KU_FIRST_USER is defined to be, say, 500, then UID's and GID's
+ for regular users start at 500. If _KU_FIRST_USER is not defined,
+ they start at 1001, the default, as before. _KU_FIRST_USER can
+ be defined in kdeadmin/config.h. (This is to make it easy to
+ compile kuser for compatibitlity with RedHat, where regular users
+ start at UID 500, and the User Private Group scheme is used for
+ GID's.) <duncan@kde.org>
+
+
+22/12/98: RedHat awared issues added.
+ Private group mechanism implemented. Works both for
+ add and delete.
+
+12/10/98: Simple property dialog added
+
+04/10/98: Use layouts in Edit group dialog (QtArch is rulez!!!)
+
+04/10/98: Patch by Rudolf Weber <rw@weber.ravnet.de> incorporated in part
+ if NIS support.
+ NIS support.
+ It is possible to create homedir when adding user.
+ It is possible to create mailbox when adding user.
+ It is possible to remove homedir when removing user.
+ It is possible to remove processes when removing user.
+ It is possible to remove crontabs when removing user.
+ It is possible to remove mailbox when removing user.
+ Preferences dialog added.
diff --git a/kuser/Makefile.am b/kuser/Makefile.am
new file mode 100644
index 0000000..d431ec5
--- /dev/null
+++ b/kuser/Makefile.am
@@ -0,0 +1,60 @@
+INCLUDES = -I.. -I$(top_srcdir)/kuser $(all_includes)
+
+# May be -D_XU_QUOTA -D_XU_SHADOW
+#AM_CXXFLAGS = $(KU_NIS) $(KU_QUOTA) $(QUOTACTL) -D_KU_DEBUG
+
+kuser_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kuser_LDADD = $(LIB_KDEUI) $(LIBCRYPT) $(LIBSHADOW) $(LIBGEN) $(LIB_KABC) -lkntlm
+
+####### Files
+
+kuser_SOURCES = \
+ mainWidget.cpp editGroup.cpp kuservw.cpp \
+ kgroupvw.cpp delUser.cpp \
+ kuser.cpp kgroup.cpp main.cpp mainView.cpp \
+ propdlg.cpp misc.cpp pwddlg.cpp \
+ addUser.cpp editDefaults.cpp \
+ kglobal.cpp sid.cpp\
+ kuserfiles.cpp kgroupfiles.cpp kuserldap.cpp kgroupldap.cpp \
+ kusersystem.cpp kgroupsystem.cpp selectconn.cpp\
+ sha1.cpp kuserprefs.kcfgc \
+ filessettings.ui generalsettings.ui ldapsettings.ui ldapsamba.ui passwordpolicy.ui
+
+kuser_METASOURCES = AUTO
+
+# the following are only useful, if you want to use "make dist"
+noinst_HEADERS = \
+ mainWidget.h editGroup.h kuservw.h \
+ kuser.h mainView.h kgroup.h delUser.h \
+ kgroupvw.h propdlg.h globals.h misc.h \
+ pwddlg.h addUser.h \
+ editDefaults.h selectconn.h sha1.h sid.h kglobal_.h \
+ kusersystem.h kgroupsystem.h kuserfiles.h kgroupfiles.h kuserldap.h kgroupldap.h
+
+kde_kcfg_DATA = kuser.kcfg
+
+EDITABLE = $(noinst_HEADERS) $(kuser_SOURCES) Makefile.am
+
+EXTRA_DIST = README AUTHORS THANKS kuser.desktop
+
+rcdir = $(kde_datadir)/kuser
+rc_DATA = kuserui.rc
+
+# the programs get installed in $(prefix)/bin
+bin_PROGRAMS = kuser
+
+# the subdirs we have. Better would be to include pic here too
+SUBDIRS = pic toolbar icon
+
+xdg_apps_DATA = kuser.desktop
+
+edit::
+ xemacs -fn "-edict-fixed-medium-r-*-*-*-120-*-*-*-*-koi8-r" -geometry 142x41+0+0 $(EDITABLE)&
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kuser.pot
+
+pot::
+ /usr/local/bin/xgettext -ki18n -o kuser.pot -p ../po -d kuser -C -n *.cpp
+ /usr/local/bin/msgmerge --strict -v -o $(podir)/kuser.pot
+ mv $(podir)/ru/kuser.po
diff --git a/kuser/README b/kuser/README
new file mode 100644
index 0000000..b163125
--- /dev/null
+++ b/kuser/README
@@ -0,0 +1,19 @@
+This version of KUser is based on the work of:
+Denis Perchine <dyp@perchine.com>
+
+Original README:
+----------------------
+KUser is rewritten XUser which was written in XForms.
+It supports:
+Solaris
+Linux
+Irix
+FreeBSD
+HPUX
+
+ATTENTION: BACKUP ALL OF YOUR DATA. THIS PROGRAM MAY DESTROY
+IT. BE CAREFUL.
+----------------------
+
+If you found a bug please post a bug report to the KDE bug database:
+http://bugs.kde.org
diff --git a/kuser/THANKS b/kuser/THANKS
new file mode 100644
index 0000000..12a1af7
--- /dev/null
+++ b/kuser/THANKS
@@ -0,0 +1,20 @@
+Great thanks to:
+
+Paul Kendall <paul@orion.co.nz> (for Irix quota support,
+ his beautiful ktablevw classes and some minor patches)
+Bernhard Rosenkraenzer <bero@redhat.com> (for some glibc2 fixes)
+Alex Zepeda <garbanzo@hooked.net> (for FreeBSD support)
+Mario Weilguni <mweilguni@sime.com> (for some usefull comments and suggestions)
+Michael Rodionov <marod@solo.iis.nsk.su> (for his icons)
+Chia-liang Kao <clkao@tc.neto.net> (for some typo corrections)
+Uwe Thiem <uwe@uwix.alt.na> (for some Aplha notes)
+Bernd Johannes Wuebben <wuebben@math.cornell.edu> (for some defines corrections)
+Christophe Prudhomme <Christophe.Prudhomme@asci.fr> (for HP-UX notes and usefull suggestions)
+Joerg Bornschein <theodor@disorder.ruhr.de> (for transparent pixmaps)
+Clemens Drews <clemens.drews@hamburg.snafu.de> (for small password fix)
+Kevin Street <street@iname.com> (for big FreeBSD patch)
+Rudolf Weber <rw@weber.ravnet.de> (for NIS-related patch and some other futures)
+Duncan Haldane <f.d.m.haldane@cwix.com> (for RedHat specific issues and testing)
+Hans Petter Bieker <zerium@traad.lavvu.no> (for FreeBSD fgetpwent/getpwent/fgetr
+gent/getgrent fixes)
+"Steven M. Schultz" <sms@TO.GD-ES.COM> (for BSDI support)
diff --git a/kuser/TODO b/kuser/TODO
new file mode 100644
index 0000000..9be5109
--- /dev/null
+++ b/kuser/TODO
@@ -0,0 +1,29 @@
+Must do soon (these are very easy):
+- Implement UID->SID like in ldapsam (Requires introducing the algorithmic RID base). - Ready
+- Newer samba schema support (new attributes in sambaSamAccount in Samba>=3.0.6). - Ready
+- Support LDAP entries with more objectclasses than we handle (part of #95366). - Ready for users (lazy to do for groups)
+
+Other:
+- Add Kerberos support - Native kerberos protocols or LDAP backed?
+ I prefer to add it to the LDAP backend, but first I need to find an
+ LDAP-backed KDC. I heard that Heimdal can do this.
+- Filtering users and groups, and implement it in backends, so it would
+ be possible to use server-side filtering (mainly in LDAP)
+- Find next available UID and RID using LDAP sorting control - need an
+ ldap server which implements this control. Also I don't know is this a
+ good idea or not.
+- Proper cross-check between user and group SIDs.
+- Issue a warning if Unix/Samba account settings are not consistent with
+ each other (e.g the group of primary group ID != group of primary group SID).
+- Other consistency checks (unique user/group IDs, unique SIDs, etc...).
+- Copy data between backends.
+- Update docs
+
+And some TODOs from the past which are still unsolved:
+- Add 'Help' button to user and group properties dialogs.
+- Add right mouse popup
+- Replace call of rm with own procedure.
+- Use QFile for file operations.
+- How about having group name(s) next to the Full name of a user in the upper
+ panel, and similarly user names for a group in the lower pannel -- in a
+ separate column?
diff --git a/kuser/addUser.cpp b/kuser/addUser.cpp
new file mode 100644
index 0000000..4bd957e
--- /dev/null
+++ b/kuser/addUser.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <qdir.h>
+#include <qgroupbox.h>
+
+#include <kdebug.h>
+
+#include "kglobal_.h"
+#include "misc.h"
+
+#include "addUser.h"
+#include <kmessagebox.h>
+
+addUser::addUser( KU::KUser *AUser, bool useprivategroup,
+ QWidget *parent, const char *name ) :
+ propdlg( AUser, useprivategroup, parent, name )
+{
+ QGroupBox *group = new QGroupBox(frontpage);
+ group->setTitle(i18n("New Account Options"));
+ QVBoxLayout *groupLayout = new QVBoxLayout(group, marginHint(), spacingHint());
+ groupLayout->addSpacing(group->fontMetrics().lineSpacing());
+ groupLayout->setAutoAdd(true);
+ createhome = new QCheckBox(i18n("Create home folder"), group);
+ createhome->setChecked(true);
+ copyskel = new QCheckBox(i18n("Copy skeleton"), group);
+ connect(createhome, SIGNAL(toggled(bool)), copyskel, SLOT(setEnabled(bool)));
+ frontlayout->addMultiCellWidget(group, frontrow, frontrow, 0, 2);
+
+ if ( useprivategroup ) pbprigr->setEnabled( false );
+}
+
+void addUser::slotOk()
+{
+ KU::KUser *user = mUsers.first();
+
+ if ( !check() ) return;
+
+ mergeUser( user, user );
+
+ if ( ( user->getCaps() & KU::KUser::Cap_POSIX ) &&
+ kug->getUsers().lookup( user->getUID() ) ) {
+ KMessageBox::sorry( 0, i18n("User with UID %1 already exists.").arg( user->getUID() ) );
+ return;
+ }
+
+ if ( ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) &&
+ ( user->getCaps() & KU::KUser::Cap_Samba ) ) {
+ if ( kug->getUsers().lookup_sam( user->getSID().getRID() ) ) {
+ KMessageBox::sorry( 0, i18n("User with RID %1 already exists.").arg( user->getSID().getRID() ) );
+ return;
+ }
+ }
+
+ if (createhome->isChecked())
+ {
+ user->setCreateHome(true);
+ user->setCreateMailBox(true);
+ }
+ if (copyskel->isChecked())
+ {
+ user->setCopySkel(true);
+ }
+
+ if (user->getCreateHome() && !checkHome())
+ return;
+
+ if (user->getCreateMailBox() && !checkMailBox())
+ user->setCreateMailBox(false);
+
+ saveg();
+ accept();
+}
+
+bool addUser::checkHome()
+{
+ KU::KUser *user = mUsers.first();
+
+ struct stat s;
+ int r;
+
+ QString h_dir = user->getHomeDir();
+ r = stat( QFile::encodeName(h_dir), &s );
+
+ if ( (r == -1) && (errno == ENOENT) )
+ return true;
+
+ if (r == 0) {
+ if (S_ISDIR(s.st_mode)) {
+ if ( KMessageBox::
+ warningContinueCancel ( 0,
+ i18n("Folder %1 already exists!\n%2 may become owner and permissions may change.\nDo you really want to use %3?").
+ arg(h_dir).arg(user->getName()).arg(h_dir), QString::null, KStdGuiItem::cont() ) == KMessageBox::Cancel )
+
+ return false;
+ else
+ return true;
+ } else
+ KMessageBox::error( 0, i18n("%1 is not a folder.").arg(h_dir) );
+ } else
+ KMessageBox::error( 0, i18n("stat() failed on %1.").arg(h_dir) );
+
+ return false;
+}
+
+bool addUser::checkMailBox()
+{
+ QString mailboxpath;
+ KU::KUser *user = mUsers.first();
+
+ struct stat s;
+ int r;
+
+ mailboxpath = QFile::decodeName(MAIL_SPOOL_DIR) + "/" + user->getName();
+ r = stat(QFile::encodeName(mailboxpath), &s);
+
+ if ((r == -1) && (errno == ENOENT))
+ return true;
+
+ if (r == 0)
+ if (S_ISREG(s.st_mode))
+ KMessageBox::error( 0, i18n("Mailbox %1 already exists (uid=%2).")
+ .arg(mailboxpath)
+ .arg(s.st_uid) );
+ else
+ KMessageBox::error( 0, i18n("%1 exists but is not a regular file.")
+ .arg(mailboxpath) );
+ else
+ KMessageBox::error( 0, i18n("stat() failed on %1.").arg(mailboxpath) );
+
+ return false;
+}
+#include "addUser.moc"
diff --git a/kuser/addUser.h b/kuser/addUser.h
new file mode 100644
index 0000000..786bdea
--- /dev/null
+++ b/kuser/addUser.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_ADDUSER_H_
+#define _KU_ADDUSER_H_
+
+#include <qcheckbox.h>
+#include "propdlg.h"
+
+class addUser: public propdlg {
+ Q_OBJECT
+public:
+ addUser(KU::KUser *AUser, bool useprivategroup,
+ QWidget *parent = 0, const char *name = 0 );
+
+ void setCreateHomeDir(bool b)
+ { createhome->setChecked(b); }
+
+ void setCopySkel(bool b)
+ { copyskel->setChecked(b); }
+
+protected slots:
+ virtual void slotOk();
+protected:
+ bool checkHome();
+ bool checkMailBox();
+
+ QCheckBox *createhome;
+ QCheckBox *copyskel;
+};
+
+#endif // _KU_ADDUSER_H
+
+
diff --git a/kuser/configure.in.in b/kuser/configure.in.in
new file mode 100644
index 0000000..353857b
--- /dev/null
+++ b/kuser/configure.in.in
@@ -0,0 +1,64 @@
+dnl this is for kuser:
+
+AC_DEFUN([KUSER_CRYPT_TESTS], [
+ AC_REQUIRE([KDE_MISC_TESTS]) dnl for LIBCRYPT
+ AC_REQUIRE([KDE_SHADOWPASSWD]) dnl for LIBSHADOW and LIBGEN
+])
+
+KUSER_CRYPT_TESTS
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(crypt.h fcntl.h mntent.h linux/quota.h linux/unistd.h \
+ paths.h sys/fs/ufs_quota.h sys/mntent.h sys/mnttab.h \
+ sys/quota.h sys/time.h unistd.h sys/params.h sys/param.h \
+ signal.h sys/mount.h sys/fcntl.h)
+
+case "$host" in
+*irix*) AC_DEFINE(HAVE_IRIX, 1, [Irix])
+ ;;
+*linux*) AC_DEFINE(HAVE_LINUX, 1, [Linux])
+ ;;
+esac
+
+AC_ARG_WITH(hometemplate, [ --with-hometemplate use specified template for homedir [default=/home/%U] ], ku_hometemplate="$withval", ku_hometemplate="/home/%U")
+AC_DEFINE_UNQUOTED(KU_HOMETEMPLATE, "$ku_hometemplate",[default template for homedir])
+
+AC_ARG_WITH(first-uid, [ --with-first-uid first normal user ID [default=500] ], ku_firstuid="$withval", ku_firstuid="500")
+AC_DEFINE_UNQUOTED(KU_FIRSTUID, $ku_firstuid, [first user ID])
+AC_SUBST(KU_FIRSTUID)
+
+AC_ARG_WITH(first-gid, [ --with-first-gid first normal group ID [default=500] ], ku_firstgid="$withval", ku_firstgid="500")
+AC_DEFINE_UNQUOTED(KU_FIRSTGID, $ku_firstgid, [first group ID])
+AC_SUBST(KU_FIRSTGID)
+
+AC_ARG_WITH(private-groups, [ --with-private-groups user private groups [default=no] ], ku_userprivategroup="$withval", ku_userprivategroup="no")
+if test "$ku_userprivategroup" = "yes"; then
+ ku_userprivategroup="true"
+else
+ ku_userprivategroup="false"
+fi
+AC_DEFINE_UNQUOTED(KU_USERPRIVATEGROUP, $ku_userprivategroup, [private groups])
+
+AC_ARG_WITH(home-perm, [ --with-home-perm home directory permissions [default=0700] ], ku_homedir_perm="$withval", ku_homedir_perm="0700")
+AC_DEFINE_UNQUOTED(KU_HOMEDIR_PERM, $ku_homedir_perm, [home directory permissions])
+AC_SUBST(KU_HOMEDIR_PERM)
+
+AC_ARG_WITH(mailbox-perm, [ --with-mailbox-perm mailbox permissions [default=0660] ], ku_mailbox_perm="$withval", ku_mailbox_perm="0660")
+AC_DEFINE_UNQUOTED(KU_MAILBOX_PERM, $ku_mailbox_perm, [mailbox permissions])
+AC_SUBST(KU_MAILBOX_PERM)
+
+AC_ARG_WITH(mailbox-gid, [ --with-mailbox-gid mailbox gid [default=0] ], ku_mailbox_gid="$withval", ku_mailbox_gid="0")
+AC_DEFINE_UNQUOTED(KU_MAILBOX_GID, $ku_mailbox_gid, [mailbox gid])
+AC_SUBST(KU_MAILBOX_GID)
+
+KDE_CHECK_FUNC_EXT(fgetpwent, [#include <pwd.h>], [(void) fgetpwent(0)], [], FGETPWENT)
+KDE_CHECK_FUNC_EXT(fgetgrent, [#include <grp.h>], [(void) fgetgrent(0)], [], FGETGRENT)
+KDE_CHECK_FUNC_EXT(fgetspent, [#include <shadow.h>], [(void) fgetspent(0)], [], FGETSPENT)
+
+AC_LANG_SAVE
+dnl AC_C_BIGENDIAN has a bug (one of its tests uses "main()" instead of
+dnl "int main()") so C++ compilers would break. Thats why we switch languages
+AC_C_BIGENDIAN
+AC_LANG_RESTORE
diff --git a/kuser/delUser.cpp b/kuser/delUser.cpp
new file mode 100644
index 0000000..1d545bc
--- /dev/null
+++ b/kuser/delUser.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2002 Waldo Bastian <bastian@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "delUser.h"
+
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qfile.h>
+
+#include <klocale.h>
+
+delUser::delUser(KU::KUser *AUser, QWidget *parent, const char *name)
+ : KDialogBase( parent, name, true, i18n("Delete User"),
+ KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true )
+{
+ QVBox *page = makeVBoxMainWidget();
+ new QLabel( i18n("<p>Deleting user <b>%1</b>"
+ "<p>Also perform the following actions:").arg(AUser->getName()),
+ page);
+ m_deleteHomeDir = new QCheckBox(i18n("Delete &home folder: %1").arg(AUser->getHomeDir()), page);
+ QString mailboxpath = QFile::decodeName(MAIL_SPOOL_DIR) + "/" + AUser->getName();
+ m_deleteMailBox = new QCheckBox(i18n("Delete &mailbox: %1").arg(mailboxpath), page);
+ setButtonGuiItem(KDialogBase::Ok, KStdGuiItem::del());
+}
+
+#include "delUser.moc"
diff --git a/kuser/delUser.h b/kuser/delUser.h
new file mode 100644
index 0000000..0317a9b
--- /dev/null
+++ b/kuser/delUser.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2002 Waldo Bastian <bastian@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+
+#ifndef _KU_DELUSER_H_
+#define _KU_DELUSER_H_
+
+#include <kdialogbase.h>
+#include <qcheckbox.h>
+
+#include "kuser.h"
+
+class delUser: public KDialogBase {
+ Q_OBJECT
+public:
+ delUser(KU::KUser *AUser, QWidget *parent = 0, const char *name = 0);
+
+ bool getDeleteHomeDir()
+ { return m_deleteHomeDir->isChecked(); }
+ bool getDeleteMailBox()
+ { return m_deleteMailBox->isChecked(); }
+
+private:
+ QCheckBox *m_deleteHomeDir;
+ QCheckBox *m_deleteMailBox;
+};
+
+#endif // _KU_DELUSER_H
+
+
diff --git a/kuser/editDefaults.cpp b/kuser/editDefaults.cpp
new file mode 100644
index 0000000..82aba32
--- /dev/null
+++ b/kuser/editDefaults.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <kdebug.h>
+
+#include <ktabwidget.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+#include <klineedit.h>
+#include <knuminput.h>
+#include <kpushbutton.h>
+#include <kabc/ldapconfigwidget.h>
+#include <kabc/ldapurl.h>
+
+#include "editDefaults.h"
+#include "generalsettings.h"
+#include "filessettings.h"
+#include "ldapsettings.h"
+#include "ldapsamba.h"
+#include "passwordpolicy.h"
+#include "misc.h"
+
+editDefaults::editDefaults( KConfigSkeleton *config, QWidget *parent, const char *name ) :
+ KConfigDialog( parent, name, config, IconList,
+ Default|Ok|Apply|Cancel|Help, Ok, true )
+{
+ KTabWidget *page1 = new KTabWidget( this );
+ page1->setMargin( KDialog::marginHint() );
+
+ GeneralSettings *page1a = new GeneralSettings( this );
+ page1a->kcfg_shell->insertItem( i18n("<Empty>" ) );
+ page1a->kcfg_shell->insertStringList( readShells() );
+ page1->addTab( page1a, i18n("Connection") );
+ PasswordPolicy *page1b = new PasswordPolicy( this );
+ page1->addTab( page1b, i18n("Password Policy") );
+ addPage( page1, i18n("General"), "", i18n("General Settings") );
+
+ FilesSettings *page2 = new FilesSettings( this );
+ addPage( page2, i18n("Files"), "", i18n("File Source Settings") );
+
+ KTabWidget *page3 = new KTabWidget( this );
+ page3->setMargin( KDialog::marginHint() );
+ ldconf =
+ new KABC::LdapConfigWidget(
+ KABC::LdapConfigWidget::W_USER |
+ KABC::LdapConfigWidget::W_PASS |
+ KABC::LdapConfigWidget::W_BINDDN |
+ KABC::LdapConfigWidget::W_REALM |
+ KABC::LdapConfigWidget::W_HOST |
+ KABC::LdapConfigWidget::W_PORT |
+ KABC::LdapConfigWidget::W_VER |
+ KABC::LdapConfigWidget::W_DN |
+ KABC::LdapConfigWidget::W_SECBOX |
+ KABC::LdapConfigWidget::W_AUTHBOX,
+ page3 );
+ page3->addTab( ldconf, i18n("Connection") );
+
+ LdapSettings *page3b = new LdapSettings( this );
+ page3->addTab( page3b, i18n("Settings") );
+
+ page3c = new LdapSamba( this );
+ connect( page3c->domQuery, SIGNAL(clicked()), SLOT(slotQueryClicked()) );
+ page3->addTab( page3c, i18n("Samba") );
+ addPage( page3, i18n("LDAP"), "", i18n("LDAP Source Settings") );
+}
+
+void editDefaults::slotQueryClicked()
+{
+ KABC::LDAPUrl _url = ldconf->url();
+
+ mResult.clear();
+ mCancelled = true;
+ mDomain.name = "";
+ mDomain.sid = "";
+ mDomain.ridbase = 1000;
+
+ QStringList attrs;
+ QString filter = "(objectClass=sambaDomain)";
+ QString dom = page3c->kcfg_samdomain->text();
+ if ( !dom.isEmpty() ) filter = "(&(sambaDomainName=" + dom + ")"+filter+")";
+ attrs.append("sambaDomainName");
+ attrs.append("sambaSID");
+ attrs.append("sambaAlgorithmicRidBase");
+ _url.setAttributes( attrs );
+ _url.setScope( KABC::LDAPUrl::One );
+ _url.setExtension( "x-dir", "base" );
+ _url.setFilter( filter );
+
+ kdDebug() << "sendQuery url: " << _url.prettyURL() << endl;
+ mLdif.startParsing();
+ KIO::Job *job = KIO::get( _url, true, false );
+// job->addMetaData("no-auth-prompt","true");
+ connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
+ this, SLOT( loadData( KIO::Job*, const QByteArray& ) ) );
+ connect( job, SIGNAL( result( KIO::Job* ) ),
+ this, SLOT( loadResult( KIO::Job* ) ) );
+
+ mProg = new KProgressDialog( this, 0, i18n("LDAP Query"), _url.prettyURL(), true );
+ mProg->progressBar()->setValue( 0 );
+ mProg->progressBar()->setTotalSteps( 1 );
+ mProg->exec();
+ delete mProg;
+ if ( mCancelled ) {
+ kdDebug(5700) << "query cancelled!" << endl;
+ job->kill( true );
+ } else {
+ if ( !mErrorMsg.isEmpty() )
+ KMessageBox::error( this, mErrorMsg );
+ else {
+ mDomain = mResult.first();
+ if ( !mDomain.name.isEmpty() && !mDomain.sid.isEmpty() ) {
+ page3c->kcfg_samdomain->setText( mDomain.name );
+ page3c->kcfg_samdomsid->setText( mDomain.sid );
+ page3c->kcfg_samridbase->setValue( mDomain.ridbase );
+ }
+ }
+ }
+ kdDebug() << "domQueryx" << endl;
+}
+
+void editDefaults::loadData( KIO::Job*, const QByteArray& d )
+{
+ KABC::LDIF::ParseVal ret;
+
+ if ( d.size() ) {
+ mLdif.setLDIF( d );
+ } else {
+ mLdif.endLDIF();
+ }
+ do {
+ ret = mLdif.nextItem();
+ switch ( ret ) {
+ case KABC::LDIF::Item:
+ if ( mLdif.attr() == "sambaDomainName" )
+ mDomain.name = QString::fromUtf8( mLdif.val(), mLdif.val().size() );
+ else if ( mLdif.attr() == "sambaSID" )
+ mDomain.sid = QString::fromUtf8( mLdif.val(), mLdif.val().size() );
+ else if ( mLdif.attr() == "sambaAlgorithmicRidBase" )
+ mDomain.ridbase = QString::fromUtf8( mLdif.val(), mLdif.val().size() ).toUInt();
+ break;
+ case KABC::LDIF::EndEntry:
+ mProg->progressBar()->advance( 1 );
+ if ( !mDomain.name.isEmpty() && !mDomain.sid.isEmpty() )
+ mResult.push_back( mDomain );
+ mDomain.sid = "";
+ mDomain.name = "";
+ mDomain.ridbase = 1000;
+ break;
+
+ }
+ } while ( ret != KABC::LDIF::MoreData );
+}
+
+void editDefaults::loadResult( KIO::Job* job)
+{
+ int error = job->error();
+ if ( error && error != KIO::ERR_USER_CANCELED )
+ mErrorMsg = job->errorString();
+ else
+ mErrorMsg = "";
+
+ mCancelled = false;
+ mProg->close();
+}
+
+#include "editDefaults.moc"
diff --git a/kuser/editDefaults.h b/kuser/editDefaults.h
new file mode 100644
index 0000000..dbe9dd6
--- /dev/null
+++ b/kuser/editDefaults.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_EDITDEFAULTS_H_
+#define _KU_EDITDEFAULTS_H_
+
+#include <qmemarray.h>
+#include <kconfigdialog.h>
+#include <kprogress.h>
+#include <kabc/ldif.h>
+#include "ldapsamba.h"
+
+class LdapSamba;
+namespace KABC { class LdapConfigWidget; }
+namespace KIO { class Job; }
+
+typedef struct SambaDomain {
+ QString name;
+ QString sid;
+ uint ridbase;
+};
+
+class editDefaults : public KConfigDialog {
+ Q_OBJECT
+public:
+ editDefaults( KConfigSkeleton *config, QWidget* parent, const char * name = 0 );
+private:
+ KProgressDialog *mProg;
+ LdapSamba *page3c;
+ KABC::LdapConfigWidget *ldconf;
+ KABC::LDIF mLdif;
+ bool mCancelled;
+ QString mErrorMsg;
+ QValueList<SambaDomain> mResult;
+ SambaDomain mDomain;
+private slots:
+ void slotQueryClicked();
+ void loadData( KIO::Job*, const QByteArray& d );
+ void loadResult( KIO::Job* job);
+};
+
+#endif // _KU_EDITDEFAULTS_H_
diff --git a/kuser/editGroup.cpp b/kuser/editGroup.cpp
new file mode 100644
index 0000000..1ef74d8
--- /dev/null
+++ b/kuser/editGroup.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qvalidator.h>
+#include <qwhatsthis.h>
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kpushbutton.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#include "kglobal_.h"
+#include "editGroup.h"
+
+editGroup::editGroup(KU::KGroup *akg, bool samba, bool add,
+ QWidget* parent, const char* name)
+ : KDialogBase(parent, name, true, i18n("Group Properties"), Ok | Cancel, Ok, true)
+{
+ kg = akg;
+ mAdd = add;
+ mSamba = samba;
+ mOldName = kg->getName();
+ SID sid = kg->getSID();
+ ro = kug->getGroups().getCaps() & KU::KGroups::Cap_ReadOnly;
+
+ RID rid;
+ rid.rid = 512; rid.name = i18n("Domain Admins"); rid.desc = i18n("Admins"); mRids.append( rid );
+ rid.rid = 513; rid.name = i18n("Domain Users"); rid.desc = i18n("Users"); mRids.append( rid );
+ rid.rid = 514; rid.name = i18n("Domain Guests"); rid.desc = i18n("Guests"); mRids.append( rid );
+
+ QFrame *page = makeMainWidget();
+ QGridLayout *layout = new QGridLayout( page, 10, 3, marginHint(), spacingHint() );
+ QLabel *lb;
+
+ lb = new QLabel( page );
+ lb->setText(i18n("Group number:"));
+ legid = new KLineEdit(page);
+ // ensure it fits at least 20 characters
+ legid->setText( "XXXXXXXXXXXXXXXXXXX" );
+ legid->setText( QString::number(kg->getGID()) );
+ legid->setValidator( new QIntValidator(this) );
+ legid->setEnabled( mAdd );
+ legid->setReadOnly( ro );
+ lb->setBuddy( legid );
+ layout->addWidget( lb, 0, 0 );
+ layout->addMultiCellWidget( legid, 0, 0, 1, 2 );
+
+ if ( mSamba ) {
+ lb = new QLabel( page );
+ lb->setText(i18n("Group rid:"));
+ lerid = new KComboBox( page );
+ lerid->setEditable( !ro );
+ QValueList<RID>::Iterator it;
+ for ( it = mRids.begin(); it != mRids.end(); ++it ) {
+ lerid->insertItem( QString::number( (*it).rid ) + " - " + (*it).name );
+ }
+
+ lerid->setCurrentText( QString::number( sid.getRID() ) );
+ lerid->setValidator (new QIntValidator(this) );
+ lerid->setEnabled( mAdd );
+ connect( lerid, SIGNAL(activated(int)), SLOT(ridSelected(int)) );
+ lb->setBuddy( lerid );
+ layout->addWidget( lb, 1, 0 );
+ layout->addMultiCellWidget( lerid, 1, 1, 1, 2 );
+ }
+
+ lb = new QLabel( page );
+ lb->setText(i18n("Group name:"));
+
+ legrpname = new KLineEdit( page );
+ // ensure it fits at least 20 characters
+ legrpname->setText( "XXXXXXXXXXXXXXXXXXX" );
+ legrpname->setText( kg->getName() );
+ legrpname->setReadOnly( ro );
+ legrpname->setFocus();
+ lb->setBuddy( legrpname );
+ layout->addWidget( lb, 2, 0 );
+ layout->addMultiCellWidget( legrpname, 2, 2, 1, 2 );
+
+ if ( mSamba ) {
+ lb = new QLabel( page );
+ lb->setText(i18n("Description:"));
+ ledesc = new KLineEdit(page);
+ ledesc->setText( kg->getDesc() );
+ ledesc->setReadOnly( ro );
+ lb->setBuddy( ledesc );
+ layout->addWidget( lb, 3, 0 );
+ layout->addMultiCellWidget( ledesc, 3, 3, 1, 2 );
+
+ lb = new QLabel( page );
+ lb->setText(i18n("Display name:"));
+ ledispname = new KLineEdit(page);
+ ledispname->setText( kg->getDisplayName() );
+ ledispname->setReadOnly( ro );
+ lb->setBuddy( ledispname );
+ layout->addWidget( lb, 4, 0 );
+ layout->addMultiCellWidget( ledispname, 4, 4, 1, 2 );
+
+ lb = new QLabel( page );
+ lb->setText(i18n("Type:"));
+ letype = new KComboBox( page );
+ letype->insertItem( i18n("Domain") );
+ letype->insertItem( i18n("Local") );
+ letype->insertItem( i18n("Builtin") );
+ switch ( kg->getType() ) {
+ case 2:
+ letype->setCurrentItem( 0 );
+ break;
+ case 4:
+ letype->setCurrentItem( 1 );
+ break;
+ case 5:
+ letype->setCurrentItem( 2 );
+ break;
+ }
+ lb->setBuddy( letype );
+ layout->addWidget( lb, 5, 0 );
+ layout->addMultiCellWidget( letype, 5, 5, 1, 2 );
+
+ lb = new QLabel( page );
+ lb->setText(i18n("Domain SID:"));
+ ledomsid = new KLineEdit(page);
+ ledomsid->setText( sid.getDOM() );
+ ledomsid->setReadOnly( ro );
+ lb->setBuddy( ledomsid );
+ layout->addWidget( lb, 6, 0 );
+ layout->addMultiCellWidget( ledomsid, 6, 6, 1, 2 );
+
+ cbsamba = new QCheckBox( i18n("Disable Samba group information"), page );
+ layout->addMultiCellWidget( cbsamba, 7, 7, 0, 2 );
+ connect( cbsamba, SIGNAL(toggled(bool)), ledesc, SLOT(setDisabled(bool)) );
+ connect( cbsamba, SIGNAL(toggled(bool)), ledispname, SLOT(setDisabled(bool)) );
+ connect( cbsamba, SIGNAL(toggled(bool)), letype, SLOT(setDisabled(bool)) );
+ connect( cbsamba, SIGNAL(toggled(bool)), ledomsid, SLOT(setDisabled(bool)) );
+ if ( mAdd ) connect( cbsamba, SIGNAL(toggled(bool)), lerid, SLOT(setDisabled(bool)) );
+ if ( !mAdd ) cbsamba->setChecked( !( kg->getCaps() & KU::KGroup::Cap_Samba ) );
+ }
+
+ m_list_in = new KListView(page);
+ m_list_in->setFullWidth(true); // Single column, full widget width.
+ m_list_in->addColumn(i18n("Users in Group"));
+ m_list_in->setSelectionMode( QListView::Extended );
+ layout->addWidget( m_list_in, 8, 0 );
+
+ QVBox *vbox = new QVBox(page);
+ QPushButton *btadd = new QPushButton(i18n("Add <-"), vbox);
+ QPushButton *btdel = new QPushButton(i18n("Remove ->"), vbox);
+ layout->addWidget( vbox, 8, 1 );
+
+ m_list_notin = new KListView(page);
+ m_list_notin->setFullWidth(true); // Single column, full widget width.
+ m_list_notin->addColumn(i18n("Users NOT in Group"));
+ m_list_notin->setSelectionMode(QListView::Extended);
+ layout->addWidget( m_list_notin, 8, 2 );
+// QString whatstr = i18n("Select the users that should be in this kg->");
+// QWhatsThis::add(m_list, whatstr);
+// connect(this,SIGNAL(okClicked(void)),
+ //this,SLOT(okClicked()));
+
+
+ for (unsigned int i = 0; i<kug->getUsers().count(); i++) {
+ KU::KUser *user;
+ user = kug->getUsers()[i];
+ QString userName = user->getName();
+ if ( kg->lookup_user(userName) || user->getGID() == kg->getGID() ) {
+ KListViewItem *item = new KListViewItem(m_list_in, userName);
+ if ( user->getGID() == kg->getGID() ) item->setSelectable( false );
+ } else {
+ new KListViewItem(m_list_notin, userName);
+ }
+ }
+
+ connect(btadd, SIGNAL(clicked()), SLOT(addClicked()));
+ connect(btdel, SIGNAL(clicked()), SLOT(delClicked()));
+
+ if ( ro ) {
+ btadd->setEnabled( false );
+ btdel->setEnabled( false );
+ }
+}
+
+editGroup::~editGroup()
+{
+}
+
+void editGroup::ridSelected( int index )
+{
+ lerid->setCurrentText( QString::number( mRids[ index ].rid ) );
+ legrpname->setText( mRids[ index ].name );
+ ledesc->setText( mRids[ index ].desc );
+ ledispname->setText( mRids[ index ].name );
+}
+
+void editGroup::addClicked()
+{
+ QListViewItem *item, *next;
+ QString name;
+
+ item = m_list_notin->firstChild();
+ while ( item ) {
+ next = item->nextSibling();
+ if ( item->isSelected() ) {
+ name = item->text( 0 );
+ delete item;
+ item = new KListViewItem( m_list_in, name );
+ }
+ item = next;
+ }
+}
+
+void editGroup::delClicked()
+{
+ QListViewItem *item, *next;
+ QString name;
+
+ item = m_list_in->firstChild();
+ while ( item ) {
+ next = item->nextSibling();
+ if ( item->isSelected() ) {
+ name = item->text( 0 );
+ delete item;
+ item = new KListViewItem( m_list_notin, name );
+ }
+ item = next;
+ }
+}
+
+void editGroup::slotOk()
+{
+ if ( ro ) {
+ reject();
+ return;
+ }
+
+ SID sid;
+ kg->clear();
+ QString s;
+ s = legid->text();
+
+ if ( mSamba && !cbsamba->isChecked() ) {
+ sid.setDOM( ledomsid->text() );
+ sid.setRID( lerid->currentText() );
+ }
+
+ if ( legrpname->text().isEmpty() ) {
+ KMessageBox::sorry( 0,
+ i18n("You need to type a group name.") );
+ return;
+ }
+
+ if ( legrpname->text() != mOldName &&
+ kug->getGroups().lookup( legrpname->text() ) ) {
+
+ KMessageBox::sorry( 0,
+ i18n("Group with name %1 already exists.").arg(legrpname->text()) );
+ return;
+ }
+
+ if ( mAdd ) {
+ if ( mSamba && !cbsamba->isChecked() && kug->getGroups().lookup_sam( sid ) ) {
+ KMessageBox::sorry( 0,
+ i18n("Group with SID %1 already exists.").arg( sid.getSID() ) );
+ return;
+ }
+ if (kug->getGroups().lookup(s.toInt())) {
+ KMessageBox::sorry( 0,
+ i18n("Group with gid %1 already exists.").arg(s.toInt()) );
+ return;
+ }
+ }
+
+ kg->setName(legrpname->text());
+ kg->setGID(s.toInt());
+ if ( mSamba && !cbsamba->isChecked() ) {
+ kg->setCaps ( KU::KGroup::Cap_Samba );
+ kg->setSID( sid );
+ switch ( letype->currentItem() ) {
+ case 0:
+ kg->setType( 2 );
+ break;
+ case 1:
+ kg->setType( 4 );
+ break;
+ case 2:
+ kg->setType( 5 );
+ break;
+ }
+ kg->setDesc( ledesc->text() );
+ kg->setDisplayName( ledispname->text() );
+ } else {
+ kg->setCaps( 0 );
+ kg->setSID( QString::null );
+ kg->setDesc( QString::null );
+ kg->setDisplayName( QString::null );
+ kg->setType( 0 );
+ }
+
+ QListViewItem *item;
+ item = m_list_in->firstChild();
+ while ( item ) {
+ kg->addUser( item->text( 0 ) );
+ item = item->nextSibling();
+ }
+ accept();
+}
+
+#include "editGroup.moc"
diff --git a/kuser/editGroup.h b/kuser/editGroup.h
new file mode 100644
index 0000000..3d6334b
--- /dev/null
+++ b/kuser/editGroup.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+
+#ifndef _KU_EDITGROUP_H_
+#define _KU_EDITGROUP_H_
+
+#include <qcheckbox.h>
+#include <kdialogbase.h>
+#include <klistview.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+
+#include "kgroup.h"
+
+class editGroup : public KDialogBase
+{
+ Q_OBJECT
+public:
+
+ editGroup(KU::KGroup *akg, bool samba, bool add,
+ QWidget* parent = NULL, const char* name = NULL);
+
+ virtual ~editGroup();
+
+protected slots:
+ virtual void slotOk();
+ void addClicked();
+ void delClicked();
+ void ridSelected( int index );
+
+private:
+ bool mSamba, mAdd;
+ bool ro;
+ KU::KGroup *kg;
+ KListView *m_list_in,*m_list_notin;
+ KLineEdit *legrpname;
+ KLineEdit *legid;
+ KComboBox *lerid;
+ KLineEdit *ledom;
+ KLineEdit *ledispname;
+ KLineEdit *ledesc;
+ KLineEdit *ledomsid;
+ KComboBox *letype;
+ QCheckBox *cbsamba;
+ QString mOldName;
+ typedef struct _RID {
+ uint rid;
+ QString name,desc;
+ } RID;
+ QValueList<RID> mRids;
+};
+#endif // _KU_EDITGROUP_H_
diff --git a/kuser/filessettings.ui b/kuser/filessettings.ui
new file mode 100644
index 0000000..078578d
--- /dev/null
+++ b/kuser/filessettings.ui
@@ -0,0 +1,225 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>FilesSettings</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>FilesSettings</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>405</width>
+ <height>315</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Local User Database Files</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Group file:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_groupsrc</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Password file:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_passwdsrc</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_passwdsrc</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_groupsrc</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Shadow password file:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_shadowsrc</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="2">
+ <property name="name">
+ <cstring>kcfg_shadowsrc</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="2">
+ <property name="name">
+ <cstring>kcfg_gshadowsrc</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Shadow group file:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_gshadowsrc</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kcfg_md5shadow</cstring>
+ </property>
+ <property name="text">
+ <string>MD5 shadow passwords</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>NIS Settings</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>NIS password source:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_nispasswdsrc</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>NIS group source:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_nisgroupsrc</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel5_2</cstring>
+ </property>
+ <property name="text">
+ <string>NIS minimum UID:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_nisminuid</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel6_2</cstring>
+ </property>
+ <property name="text">
+ <string>NIS minimum GID:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_nismingid</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_nispasswdsrc</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_nisgroupsrc</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_nisminuid</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_nismingid</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kuser/generalsettings.ui b/kuser/generalsettings.ui
new file mode 100644
index 0000000..d486db7
--- /dev/null
+++ b/kuser/generalsettings.ui
@@ -0,0 +1,240 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>GeneralSettings</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>GeneralSettings</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>311</width>
+ <height>237</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Source of user/group database:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_source</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>Files</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>LDAP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>System</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_source</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_homepath</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>First normal GID:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_firstGID</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Home path template:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_homepath</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Shell:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_shell</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_shell</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_3_2</cstring>
+ </property>
+ <property name="text">
+ <string>First normal UID:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_firstUID</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_firstGID</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_firstUID</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_createHomeDir</cstring>
+ </property>
+ <property name="text">
+ <string>Create home folder</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_copySkel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Copy skeleton to home folder</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_userPrivateGroup</cstring>
+ </property>
+ <property name="text">
+ <string>User private groups</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Default group:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_defaultgroup</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>kcfg_defaultgroup</cstring>
+ </property>
+ <property name="maxValue">
+ <number>65536</number>
+ </property>
+ </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>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kcfg_userPrivateGroup</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_defaultgroup</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_createHomeDir</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_copySkel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>kcfg_source</tabstop>
+ <tabstop>kcfg_shell</tabstop>
+ <tabstop>kcfg_homepath</tabstop>
+ <tabstop>kcfg_firstUID</tabstop>
+ <tabstop>kcfg_firstGID</tabstop>
+ <tabstop>kcfg_createHomeDir</tabstop>
+ <tabstop>kcfg_copySkel</tabstop>
+ <tabstop>kcfg_userPrivateGroup</tabstop>
+</tabstops>
+<slots>
+ <slot>kcfg_createHomeDir_toggled( bool )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kuser/globals.h b/kuser/globals.h
new file mode 100644
index 0000000..dde58a5
--- /dev/null
+++ b/kuser/globals.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_GLOBALS_H_
+#define _KU_GLOBALS_H_
+
+#define _KU_VERSION "2.1"
+
+#include <config.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <kconfig.h>
+#include "kuserprefs.h"
+
+#define KU_BACKUP_EXT ".bak"
+#define KU_CREATE_EXT ".new"
+
+#ifdef HAVE_PATHS_H
+ #define SHELL_FILE _PATH_SHELLS
+ #define MAIL_SPOOL_DIR _PATH_MAILDIR
+#else
+ #define SHELL_FILE "/etc/shells"
+ #define MAIL_SPOOL_DIR "/var/spool/mail"
+#endif
+
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ #undef HAVE_SHADOW
+ #include <pwd.h>
+ #define PASSWORD_FILE _PATH_MASTERPASSWD
+ #define PASSWORD_FILE_MASK S_IRUSR | S_IWUSR
+ #define PWMKDB _PATH_PWD_MKDB" -p "PASSWORD_FILE
+ #define SKELDIR "/usr/share/skel"
+ #define SKEL_FILE_PREFIX "dot"
+ #define CRONTAB_DIR "/var/cron/tabs"
+#else
+ #define PASSWORD_FILE "/etc/passwd"
+ #define PASSWORD_FILE_MASK S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
+ #define PWMKDB "cd /var/yp; make 2>&1 >> /var/log/kuser"
+ #define GRMKDB "cd /var/yp; make 2>&1 >> /var/log/kuser"
+ #define SKELDIR "/etc/skel"
+ #define SKEL_FILE_PREFIX ""
+ #define CRONTAB_DIR "/var/spool/cron"
+#endif
+
+#define GROUP_FILE "/etc/group"
+#define GROUP_FILE_MASK S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
+
+#endif // _KU_GLOBALS_H_
diff --git a/kuser/icon/Makefile.am b/kuser/icon/Makefile.am
new file mode 100644
index 0000000..9f07108
--- /dev/null
+++ b/kuser/icon/Makefile.am
@@ -0,0 +1,3 @@
+
+KDE_ICON = kuser
+
diff --git a/kuser/icon/hi128-app-kuser.png b/kuser/icon/hi128-app-kuser.png
new file mode 100644
index 0000000..f28f704
--- /dev/null
+++ b/kuser/icon/hi128-app-kuser.png
Binary files differ
diff --git a/kuser/icon/hi16-app-kuser.png b/kuser/icon/hi16-app-kuser.png
new file mode 100644
index 0000000..8f69e2b
--- /dev/null
+++ b/kuser/icon/hi16-app-kuser.png
Binary files differ
diff --git a/kuser/icon/hi22-app-kuser.png b/kuser/icon/hi22-app-kuser.png
new file mode 100644
index 0000000..396b19a
--- /dev/null
+++ b/kuser/icon/hi22-app-kuser.png
Binary files differ
diff --git a/kuser/icon/hi32-app-kuser.png b/kuser/icon/hi32-app-kuser.png
new file mode 100644
index 0000000..a5cbf22
--- /dev/null
+++ b/kuser/icon/hi32-app-kuser.png
Binary files differ
diff --git a/kuser/icon/hi48-app-kuser.png b/kuser/icon/hi48-app-kuser.png
new file mode 100644
index 0000000..d8b241c
--- /dev/null
+++ b/kuser/icon/hi48-app-kuser.png
Binary files differ
diff --git a/kuser/icon/hi64-app-kuser.png b/kuser/icon/hi64-app-kuser.png
new file mode 100644
index 0000000..57c5726
--- /dev/null
+++ b/kuser/icon/hi64-app-kuser.png
Binary files differ
diff --git a/kuser/kglobal.cpp b/kuser/kglobal.cpp
new file mode 100644
index 0000000..93a7cce
--- /dev/null
+++ b/kuser/kglobal.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <kapplication.h>
+
+#include "kglobal_.h"
+#include "kuserfiles.h"
+#include "kgroupfiles.h"
+#include "kuserldap.h"
+#include "kgroupldap.h"
+#include "kusersystem.h"
+#include "kgroupsystem.h"
+
+KUserGlobals::KUserGlobals()
+{
+ cfg = 0;
+
+ users = 0;
+ groups = 0;
+}
+
+void KUserGlobals::initCfg( const QString &connection )
+{
+ if ( cfg ) {
+ cfg->writeConfig();
+ delete cfg;
+ }
+ cfg = new KUserPrefsBase( kapp->sharedConfig(), connection );
+ cfg->readConfig();
+}
+
+void KUserGlobals::init()
+{
+ if ( users ) delete users;
+ if ( groups ) delete groups;
+ SID::setAlgRidBase( cfg->samridbase() );
+ kdDebug() << "Algorithmic RID base: " << SID::getAlgRidBase() << endl;
+ switch ( cfg->source() ) {
+ case KUserPrefsBase::EnumSource::Files:
+ users = new KUserFiles( cfg );
+ groups = new KGroupFiles( cfg );
+ break;
+ case KUserPrefsBase::EnumSource::LDAP:
+ users = new KUserLDAP( cfg );
+ groups = new KGroupLDAP( cfg );
+ break;
+ case KUserPrefsBase::EnumSource::System:
+ users = new KUserSystem( cfg );
+ groups = new KGroupSystem( cfg );
+ break;
+ }
+}
+
+KUserGlobals::~KUserGlobals()
+{
+ delete users;
+ delete groups;
+ delete cfg;
+}
+
+KU::KUsers &KUserGlobals::getUsers()
+{
+ return (*users);
+}
+
+KU::KGroups &KUserGlobals::getGroups()
+{
+ return (*groups);
+}
diff --git a/kuser/kglobal_.h b/kuser/kglobal_.h
new file mode 100644
index 0000000..2cf8dbe
--- /dev/null
+++ b/kuser/kglobal_.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_GLOBAL_H_
+#define _KU_GLOBAL_H_
+
+#include "kuser.h"
+#include "kgroup.h"
+
+class KUserGlobals {
+public:
+ KUserGlobals();
+ ~KUserGlobals();
+ void init();
+ void initCfg( const QString &connection );
+
+ KUserPrefsBase *kcfg() { return cfg; }
+ KU::KUsers &getUsers();
+ KU::KGroups &getGroups();
+
+private:
+
+ KU::KUsers *users;
+ KU::KGroups *groups;
+
+ KUserPrefsBase *cfg;
+};
+
+extern KUserGlobals *kug;
+
+#endif //_KU_GLOBAL_H_
diff --git a/kuser/kgroup.cpp b/kuser/kgroup.cpp
new file mode 100644
index 0000000..44fc31c
--- /dev/null
+++ b/kuser/kgroup.cpp
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <qstring.h>
+
+#include <kdebug.h>
+
+#include "kglobal_.h"
+#include "kgroup.h"
+#include "misc.h"
+
+KU::KGroup::KGroup()
+{
+ pwd = QString::fromLatin1("*");
+ gid = 0;
+ type = 2;
+ caps = 0;
+}
+
+KU::KGroup::KGroup(KU::KGroup *group)
+{
+ copy( group );
+}
+
+KU::KGroup::~KGroup()
+{
+}
+
+void KU::KGroup::copy( const KU::KGroup *group )
+{
+ if ( group != this ) {
+ caps = group->caps;
+ name = group->name;
+ pwd = group->pwd;
+ gid = group->gid;
+ sid = group->sid;
+ type = group->type;
+ displayname = group->displayname;
+ desc = group->desc;
+ u = group->u;
+ }
+}
+
+void KU::KGroup::setCaps( int data )
+{
+ caps = data;
+}
+
+int KU::KGroup::getCaps()
+{
+ return caps;
+}
+
+const QString &KU::KGroup::getName() const
+{
+ return name;
+}
+
+const QString &KU::KGroup::getPwd() const
+{
+ return pwd;
+}
+
+gid_t KU::KGroup::getGID() const
+{
+ return gid;
+}
+
+const SID &KU::KGroup::getSID() const
+{
+ return sid;
+}
+
+int KU::KGroup::getType() const
+{
+ return type;
+}
+
+const QString &KU::KGroup::getDisplayName() const
+{
+ return displayname;
+}
+
+const QString &KU::KGroup::getDesc() const
+{
+ return desc;
+}
+
+void KU::KGroup::setName(const QString &data)
+{
+ name = data;
+}
+
+void KU::KGroup::setPwd(const QString &data)
+{
+ pwd = data;
+}
+
+void KU::KGroup::setGID(gid_t data)
+{
+ gid = data;
+}
+
+void KU::KGroup::setSID(const SID &data)
+{
+ sid = data;
+}
+
+void KU::KGroup::setType(int data)
+{
+ type = data;
+}
+
+void KU::KGroup::setDisplayName(const QString &data)
+{
+ displayname = data;
+}
+
+void KU::KGroup::setDesc(const QString &data)
+{
+ desc = data;
+}
+
+bool KU::KGroup::lookup_user(const QString &name)
+{
+ return (u.find(name) != u.end());
+}
+
+bool KU::KGroup::addUser(const QString &name)
+{
+ if (!lookup_user(name)) {
+ u.append(name);
+ return true;
+ } else
+ return false;
+}
+
+bool KU::KGroup::removeUser(const QString &name)
+{
+ return ( u.remove(name) > 0 );
+}
+
+uint KU::KGroup::count() const
+{
+ return u.count();
+}
+
+QString KU::KGroup::user(uint i)
+{
+ return u[i];
+}
+
+void KU::KGroup::clear()
+{
+ u.clear();
+}
+
+KU::KGroups::KGroups(KUserPrefsBase *cfg)
+{
+ mGroups.setAutoDelete(TRUE);
+ mCfg = cfg;
+}
+
+KU::KGroup *KU::KGroups::lookup(const QString &name)
+{
+ KU::KGroup *group;
+ QPtrListIterator<KU::KGroup> it( mGroups );
+
+ while ( (group = it.current()) != 0 && group->getName() != name ) ++it;
+ return group;
+}
+
+KU::KGroup *KU::KGroups::lookup(gid_t gid)
+{
+ KU::KGroup *group;
+ QPtrListIterator<KU::KGroup> it( mGroups );
+
+ while ( (group = it.current()) != 0 && group->getGID() != gid ) ++it;
+ return group;
+}
+
+KU::KGroup *KU::KGroups::lookup_sam( const SID &sid )
+{
+ KU::KGroup *group;
+ QPtrListIterator<KU::KGroup> it( mGroups );
+
+ while ( (group = it.current()) != 0 && group->getSID() != sid ) ++it;
+ return group;
+}
+
+KU::KGroup *KU::KGroups::lookup_sam( const QString &sid )
+{
+ KU::KGroup *group;
+ QPtrListIterator<KU::KGroup> it( mGroups );
+
+ while ( (group = it.current()) != 0 && group->getSID().getSID() != sid ) ++it;
+ return group;
+}
+
+KU::KGroup *KU::KGroups::lookup_sam( uint rid )
+{
+ KU::KGroup *group;
+ QPtrListIterator<KU::KGroup> it( mGroups );
+
+ while ( (group = it.current()) != 0 && group->getSID().getRID() != rid ) ++it;
+ return group;
+}
+
+gid_t KU::KGroups::first_free()
+{
+ gid_t t;
+
+ for (t = mCfg->firstGID(); t<65534; t++)
+ if (lookup(t) == NULL)
+ return t;
+
+ return NO_FREE;
+}
+
+uint KU::KGroups::first_free_sam()
+{
+ uint t;
+
+ for (t = 30000; t<65534; t++)
+ if (lookup_sam(t) == NULL)
+ return t;
+
+ return 0;
+}
+
+KU::KGroups::~KGroups()
+{
+ mGroups.clear();
+}
+
+KU::KGroup *KU::KGroups::operator[](uint num)
+{
+ return mGroups.at(num);
+}
+
+KU::KGroup *KU::KGroups::first()
+{
+ return mGroups.first();
+}
+
+KU::KGroup *KU::KGroups::next()
+{
+ return mGroups.next();
+}
+
+uint KU::KGroups::count() const
+{
+ return mGroups.count();
+}
+
+const QString &KU::KGroups::getDOMSID() const
+{
+ return domsid;
+}
+
+void KU::KGroups::add(KU::KGroup *group)
+{
+ kdDebug() << "adding group: " << group->getName() << " gid: " << group->getGID() << endl;
+ mAdd.append( group );
+}
+
+void KU::KGroups::del(KU::KGroup *group)
+{
+ kdDebug() << "deleting group: " << group->getName() << " gid: " << group->getGID() << endl;
+ mDel.append( group );
+}
+
+void KU::KGroups::mod(KU::KGroup *gold, const KU::KGroup &gnew)
+{
+ kdDebug() << "modify group " << gnew.getName() << " gid: " << gnew.getGID() << endl;
+ mMod.insert( gold, gnew );
+}
+
+void KU::KGroups::commit()
+{
+ kdDebug() << "KU::KGroups::commit()" << endl;
+ KU::KGroup *group;
+ DelIt dit( mDelSucc );
+ AddIt ait( mAddSucc );
+ ModIt mit = mModSucc.begin();
+
+ while ( mit != mModSucc.end() ) {
+ *(mit.key()) = mit.data();
+ mit++;
+ }
+ while ( (group = dit.current()) != 0 ) {
+ ++dit;
+ mGroups.remove( group );
+ }
+ while ( (group = ait.current()) != 0 ) {
+ ++ait;
+ mGroups.append( group );
+ }
+ cancelMods();
+}
+
+void KU::KGroups::cancelMods()
+{
+ KU::KGroup *group;
+ while ( (group = mAdd.first()) ) {
+ delete group;
+ mAdd.remove();
+ }
+ mDel.clear();
+ mMod.clear();
+}
diff --git a/kuser/kgroup.h b/kuser/kgroup.h
new file mode 100644
index 0000000..c91f496
--- /dev/null
+++ b/kuser/kgroup.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_GROUP_H_
+#define _KU_GROUP_H_
+
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+
+#include "kuserprefs.h"
+#include "sid.h"
+
+namespace KU {
+
+class KGroup {
+public:
+ KGroup();
+ KGroup(KGroup *group);
+ ~KGroup();
+
+ enum Cap {
+ Cap_Samba = 1
+ };
+
+ void copy(const KGroup *group);
+ void setCaps( int data );
+ int getCaps();
+
+ const QString &getName() const;
+ const QString &getPwd() const;
+ gid_t getGID() const;
+ const SID &getSID() const;
+ int getType() const;
+ const QString &getDisplayName() const;
+ const QString &getDesc() const;
+
+ void setName(const QString &data);
+ void setPwd(const QString &data);
+ void setGID(gid_t data);
+ void setSID(const SID &data);
+ void setType(int data);
+ void setDisplayName(const QString &data);
+ void setDesc(const QString &data);
+
+ bool addUser(const QString &name);
+ bool removeUser(const QString &name);
+ bool lookup_user(const QString &name);
+ uint count() const;
+ QString user(uint i);
+ void clear();
+
+protected:
+ QString
+ name,
+ pwd;
+ gid_t gid;
+
+//samba attributes
+ SID sid;
+ int type;
+ int caps;
+ QString displayname;
+ QString desc;
+
+ QStringList u;
+};
+
+class KGroups {
+public:
+ enum Cap {
+ Cap_ReadOnly = 1,
+ Cap_Passwd = 2,
+ Cap_Shadow = 4,
+ Cap_Samba = 8
+ };
+
+ typedef QPtrListIterator<KGroup> DelIt;
+ typedef QPtrListIterator<KGroup> AddIt;
+ typedef QMapIterator<KGroup*, KGroup> ModIt;
+
+ QPtrList<KGroup> mDelSucc;
+ QPtrList<KGroup> mAddSucc;
+ QMap<KGroup*, KGroup> mModSucc;
+
+ KGroups( KUserPrefsBase *cfg );
+ virtual ~KGroups();
+
+ int getCaps() const { return caps; }
+ const QString &getDOMSID() const;
+
+ KGroup *lookup( const QString &name );
+ KGroup *lookup( gid_t gid );
+ KGroup *lookup_sam( const SID &sid );
+ KGroup *lookup_sam( const QString &sid );
+ KGroup *lookup_sam( uint rid );
+
+ KGroup *first();
+ KGroup *next();
+ KGroup *operator[](uint num);
+ uint count() const;
+
+ void add(KGroup *group);
+ void del(KGroup *group);
+ void mod(KGroup *gold, const KGroup &gnew);
+ void commit();
+ void cancelMods();
+
+ enum {
+ NO_FREE = (gid_t) -1
+ };
+
+ virtual gid_t first_free();
+ virtual uint first_free_sam();
+ virtual bool reload() = 0;
+ virtual bool dbcommit() = 0;
+
+protected:
+ KUserPrefsBase *mCfg;
+ QPtrList<KGroup> mGroups;
+
+ QPtrList<KGroup> mDel;
+ QPtrList<KGroup> mAdd;
+ QMap<KGroup*, KGroup> mMod;
+ int caps;
+ QString domsid;
+};
+
+}
+
+#endif // _KU_GROUP_H_
diff --git a/kuser/kgroupfiles.cpp b/kuser/kgroupfiles.cpp
new file mode 100644
index 0000000..bab8841
--- /dev/null
+++ b/kuser/kgroupfiles.cpp
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "globals.h"
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <qstring.h>
+#include <qdir.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+
+#include "kglobal_.h"
+#include "kgroupfiles.h"
+#include "misc.h"
+#include "editDefaults.h"
+
+KGroupFiles::KGroupFiles( KUserPrefsBase *cfg ) : KGroups( cfg )
+{
+ gs_backuped = FALSE;
+ gr_backuped = FALSE;
+ gn_backuped = FALSE;
+
+ smode = 0400;
+ mode = 0644;
+ uid = 0;
+ gid = 0;
+
+ caps = Cap_Passwd;
+
+ reload();
+}
+
+KGroupFiles::~KGroupFiles()
+{
+ mGroups.clear();
+}
+
+bool KGroupFiles::reload()
+{
+ struct group *p;
+ KU::KGroup *tmpKG = 0;
+ struct stat st;
+ QString filename;
+ QString group_filename;
+ QString nisgroup_filename;
+ int rc = 0;
+ int group_errno = 0;
+ int nisgroup_errno = 0;
+ char processing_file = '\0';
+ #define GROUP 0x01
+ #define NISGROUP 0x02
+ #define MAXFILES 2
+
+ // Prepare to read KUser configuration
+
+ group_filename = mCfg->groupsrc();
+ nisgroup_filename = mCfg->nisgroupsrc();
+ if(!group_filename.isEmpty()) {
+ processing_file = processing_file | GROUP;
+ filename.append(group_filename);
+ }
+
+ // Start reading group file(s)
+
+ for(int k = 0; k < MAXFILES; k++) {
+ rc = stat(QFile::encodeName(filename), &st);
+ if(rc != 0) {
+ KMessageBox::error( 0, i18n("stat call on file %1 failed: %2\nCheck KUser settings.").
+ arg(filename).arg(QString::fromLatin1(strerror(errno))) );
+ if( (processing_file & GROUP) != 0 ) {
+ group_errno = errno;
+ if(!nisgroup_filename.isEmpty()) {
+ processing_file = processing_file & ~GROUP;
+ processing_file = processing_file | NISGROUP;
+ filename.truncate(0);
+ filename.append(nisgroup_filename);
+ }
+ continue;
+ }
+ else{
+ nisgroup_errno = errno;
+ break;
+ }
+ }
+
+ mode = st.st_mode;
+ uid = st.st_uid;
+ gid = st.st_gid;
+
+ // We are reading our configuration specified group file
+#ifdef HAVE_FGETGRENT
+ FILE *fgrp = fopen(QFile::encodeName(filename), "r");
+ QString tmp;
+ if (fgrp == NULL) {
+ KMessageBox::error( 0, i18n("Error opening %1 for reading.").arg(filename) );
+ return FALSE;
+ }
+
+ while ((p = fgetgrent(fgrp)) != NULL) {
+#else
+ setgrent();
+ while ((p = getgrent()) != NULL) {
+#endif
+ tmpKG = new KU::KGroup();
+ tmpKG->setGID(p->gr_gid);
+ tmpKG->setName(QString::fromLocal8Bit(p->gr_name));
+ tmpKG->setPwd(QString::fromLocal8Bit(p->gr_passwd));
+
+ char *u_name;
+ int i = 0;
+ while ((u_name = p->gr_mem[i])!=0) {
+ tmpKG->addUser(QString::fromLocal8Bit(u_name));
+ i++;
+ }
+
+ mGroups.append(tmpKG);
+ }
+
+ // End reading filename
+
+#ifdef HAVE_FGETGRENT
+ fclose(fgrp);
+#else
+ endgrent();
+#endif
+ if(!nisgroup_filename.isEmpty()) {
+ if(nisgroup_filename == group_filename)
+ break;
+ processing_file = processing_file & ~GROUP;
+ processing_file = processing_file | NISGROUP;
+ filename.truncate(0);
+ filename.append(nisgroup_filename);
+ }
+ else
+ break;
+
+ } // end of processing files, for loop
+
+ if( (group_errno == 0) && (nisgroup_errno == 0) )
+ return(TRUE);
+ if( (group_errno != 0) && (nisgroup_errno != 0) )
+ return(FALSE);
+ else
+ return(TRUE);
+}
+
+bool KGroupFiles::save()
+{
+ kdDebug() << "KGroupFiles::save() " << endl;
+ FILE *group_fd = NULL;
+ FILE *gshadow_fd = NULL;
+ FILE *nisgroup_fd = NULL;
+ gid_t mingid = 0;
+ int nis_groups_written = 0;
+ gid_t tmp_gid = 0;
+ QString tmpGe, tmpSe, tmp2;
+ QString group_filename, new_group_filename;
+ QString gshadow_filename, new_gshadow_filename;
+ QString nisgroup_filename, new_nisgroup_filename;
+
+ char errors_found = '\0';
+ #define NOMINGID 0x01
+ #define NONISGROUP 0x02
+
+ // read KUser configuration info
+
+ group_filename = mCfg->groupsrc();
+ new_group_filename = group_filename + QString::fromLatin1(KU_CREATE_EXT);
+#ifdef HAVE_SHADOW
+ gshadow_filename = mCfg->gshadowsrc();
+ if ( !KStandardDirs::exists( gshadow_filename ) )
+ gshadow_filename = QString::null;
+ else
+ new_gshadow_filename = gshadow_filename + QString::fromLatin1(KU_CREATE_EXT);
+#endif
+ nisgroup_filename = mCfg->nisgroupsrc();
+ new_nisgroup_filename = nisgroup_filename + QString::fromLatin1(KU_CREATE_EXT);
+ if( nisgroup_filename != group_filename ) {
+ mingid = mCfg->nismingid();
+ }
+
+ // Backup file(s)
+
+ if(!group_filename.isEmpty()) {
+ if (!gr_backuped) {
+ if ( !backup(group_filename) ) return false;
+ gr_backuped = TRUE;
+ }
+ }
+ if(!gshadow_filename.isEmpty()) {
+ if (!gs_backuped) {
+ if ( !backup(gshadow_filename) ) return false;
+ gs_backuped = TRUE;
+ }
+ }
+ if(!nisgroup_filename.isEmpty() && (nisgroup_filename != group_filename)) {
+ if (!gn_backuped) {
+ if ( !backup(nisgroup_filename) ) return false;
+ gn_backuped = TRUE;
+ }
+ }
+
+ // Open file(s)
+
+ if(!group_filename.isEmpty()) {
+ if((group_fd = fopen(QFile::encodeName(new_group_filename), "w")) == NULL) {
+ KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(new_group_filename) );
+ return false;
+ }
+ }
+
+ if(!gshadow_filename.isEmpty()) {
+ if((gshadow_fd = fopen(QFile::encodeName(new_gshadow_filename), "w")) == NULL) {
+ KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(new_gshadow_filename) );
+ if ( group_fd ) fclose ( group_fd );
+ return false;
+ }
+ }
+
+ if(!nisgroup_filename.isEmpty() && (nisgroup_filename != group_filename)) {
+ if((nisgroup_fd = fopen(QFile::encodeName(new_nisgroup_filename), "w")) == NULL) {
+ KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(new_nisgroup_filename) );
+ if ( group_fd ) fclose ( group_fd );
+ if ( gshadow_fd ) fclose ( gshadow_fd );
+ return false;
+ }
+ }
+
+ QPtrListIterator<KU::KGroup> it( mGroups );
+ KU::KGroup *gr;
+ bool addok = false;
+
+ gr = (*it);
+
+ while (true) {
+
+ if ( gr == 0 ) {
+ if ( addok ) break;
+ it = QPtrListIterator<KU::KGroup> ( mAdd );
+ gr = (*it);
+ addok = true;
+ if ( gr == 0 ) break;
+ };
+
+ if ( mDel.containsRef( gr ) ) {
+ ++it;
+ gr = (*it);
+ continue;
+ }
+ if ( mMod.contains( gr ) ) gr = &( mMod[ gr ] );
+
+#ifdef HAVE_SHADOW
+ if ( addok && !mCfg->gshadowsrc().isEmpty() )
+ gr->setPwd("x");
+#endif
+
+ tmpGe = gr->getName();
+ tmpGe.replace( ',', "_" );
+ tmpGe.replace( ':', "_" );
+ gr->setName( tmpGe );
+
+ tmp_gid = gr->getGID();
+ tmpGe += ":" +
+ gr->getPwd() + ":" +
+ QString::number( gr->getGID() ) + ":";
+ tmpSe = gr->getName() + ":!::";
+ for (uint j=0; j<gr->count(); j++) {
+ if (j != 0) {
+ tmpGe += ',';
+ tmpSe += ',';
+ }
+ gr->user( j ).replace( ',', "_" );
+ gr->user( j ).replace( ':', "_" );
+ tmpGe += gr->user( j) ;
+ tmpSe += gr->user( j );
+ }
+ tmpGe += '\n'; tmpSe += '\n';
+
+ if( (nisgroup_fd != 0) && (mingid != 0) ) {
+ if(mingid <= tmp_gid) {
+ fputs(tmpGe.local8Bit(), nisgroup_fd);
+ nis_groups_written++;
+ ++it;
+ gr = (*it);
+ continue;
+ }
+ }
+
+ if( (nisgroup_fd != 0) && (mingid == 0) ) {
+ errors_found = errors_found | NOMINGID;
+ }
+
+ if( (nisgroup_fd == 0) && (mingid != 0) ) {
+ errors_found = errors_found | NONISGROUP;
+ }
+
+ fputs( tmpGe.local8Bit(), group_fd );
+ if ( gshadow_fd ) fputs( tmpSe.local8Bit(), gshadow_fd );
+ ++it;
+ gr = (*it);
+ }
+
+ if(group_fd) {
+ fclose(group_fd);
+ chmod(QFile::encodeName(new_group_filename), mode);
+ chown(QFile::encodeName(new_group_filename), uid, gid);
+ rename(QFile::encodeName(new_group_filename),
+ QFile::encodeName(group_filename));
+ }
+
+ if(gshadow_fd) {
+ fclose(gshadow_fd);
+ chmod(QFile::encodeName(new_gshadow_filename), mode);
+ chown(QFile::encodeName(new_gshadow_filename), uid, gid);
+ rename(QFile::encodeName(new_gshadow_filename),
+ QFile::encodeName(gshadow_filename));
+ }
+
+ if(nisgroup_fd) {
+ fclose(nisgroup_fd);
+ chmod(QFile::encodeName(nisgroup_filename), mode);
+ chown(QFile::encodeName(nisgroup_filename), uid, gid);
+ rename(QFile::encodeName(new_nisgroup_filename),
+ QFile::encodeName(nisgroup_filename));
+ }
+
+ if( (errors_found & NOMINGID) != 0 ) {
+ KMessageBox::error( 0, i18n("Unable to process NIS group file without a minimum GID specified.\nPlease update KUser settings (File Source Settings).") );
+ }
+
+ if( (errors_found & NONISGROUP) != 0 ) {
+ KMessageBox::error( 0, i18n("Specifying NIS minimum GID requires NIS file(s).\nPlease update KUser settings (File Source Settings).") );
+ }
+
+#ifdef GRMKDB
+ if( (nis_groups_written > 0) || (nisgroup_filename == group_filename) ) {
+ if (system(GRMKDB) != 0) {
+ KMessageBox::error( 0, i18n("Unable to build NIS group databases.") );
+ return FALSE;
+ }
+ }
+#endif
+
+ return TRUE;
+}
+
+bool KGroupFiles::dbcommit()
+{
+ bool ret;
+ mode_t mode;
+
+ kdDebug() << "KGroupFiles dbcommit" << endl;
+ mAddSucc.clear();
+ mDelSucc.clear();
+ mModSucc.clear();
+ if ( mDel.isEmpty() && mAdd.isEmpty() && mMod.isEmpty() )
+ return true;
+
+ mode = umask(0077);
+ ret = save();
+ umask( mode );
+ if ( !ret ) return false;
+
+ mDelSucc = mDel;
+ mAddSucc = mAdd;
+ mModSucc = mMod;
+ mDel.clear();
+ mAdd.clear();
+ mMod.clear();
+
+ return true;
+}
+
diff --git a/kuser/kgroupfiles.h b/kuser/kgroupfiles.h
new file mode 100644
index 0000000..b2725bc
--- /dev/null
+++ b/kuser/kgroupfiles.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_GROUPFILES_H_
+#define _KU_GROUPFILES_H_
+
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+
+#include "kgroup.h"
+
+class KGroupFiles : public KU::KGroups {
+public:
+ KGroupFiles( KUserPrefsBase *cfg );
+ virtual ~KGroupFiles();
+
+ virtual bool reload();
+ virtual bool dbcommit();
+
+private:
+ int gr_backuped;
+ int gn_backuped;
+ int gs_backuped;
+
+ int mode, smode;
+ uid_t uid;
+ gid_t gid;
+
+ bool save();
+};
+
+#endif // _KU_GROUPFILES_H_
+
diff --git a/kuser/kgroupldap.cpp b/kuser/kgroupldap.cpp
new file mode 100644
index 0000000..1a84148
--- /dev/null
+++ b/kuser/kgroupldap.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <qstring.h>
+#include <qdir.h>
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#include "kglobal_.h"
+#include "kgroupldap.h"
+#include "misc.h"
+#include "editDefaults.h"
+
+#include "kgroupldap.moc"
+
+KGroupLDAP::KGroupLDAP( KUserPrefsBase *cfg ) : KU::KGroups( cfg )
+{
+ mGroups.setAutoDelete(TRUE);
+
+ if ( mCfg->ldapssl() )
+ mUrl.setProtocol("ldaps");
+ else
+ mUrl.setProtocol("ldap");
+
+ mUrl.setHost( mCfg->ldaphost() );
+ mUrl.setPort( mCfg->ldapport() );
+ mUrl.setDn( mCfg->ldapgroupbase() + "," + mCfg->ldapdn() );
+ if ( !mCfg->ldapanon() ) {
+ mUrl.setUser( mCfg->ldapuser() );
+ mUrl.setPass( mCfg->ldappassword() );
+ }
+ mUrl.setFilter( mCfg->ldapgroupfilter() );
+
+ if ( mCfg->ldaptls() ) mUrl.setExtension("x-tls","");
+ if ( mCfg->ldapsasl() ) {
+ mUrl.setExtension( "x-sasl", "" );
+ mUrl.setExtension( "x-mech", mCfg->ldapsaslmech() );
+ }
+
+ mUrl.setScope(KABC::LDAPUrl::One);
+ mUrl.setExtension("x-dir","base");
+
+ caps = Cap_Passwd;
+ if ( mCfg->ldapsam() ) {
+ caps |= Cap_Samba;
+ domsid = mCfg->samdomsid();
+ }
+
+ reload();
+}
+
+KGroupLDAP::~KGroupLDAP()
+{
+ mGroups.clear();
+}
+
+QString KGroupLDAP::getRDN( KU::KGroup *group )
+{
+ switch ( mCfg->ldapgrouprdn() ) {
+ case KUserPrefsBase::EnumLdapgrouprdn::cn:
+ return "cn=" + group->getName();
+ case KUserPrefsBase::EnumLdapgrouprdn::gidNumber:
+ return "gidNumber=" + QString::number( group->getGID() );
+ default:
+ return "";
+ }
+}
+
+void KGroupLDAP::result( KIO::Job *job )
+{
+ delete mProg;
+ mCancel = false;
+ if ( job->error() ) {
+ QString errstr = job->errorString();
+ if ( !errstr.isEmpty() ) {
+ if ( ldif.isEmpty() )
+ KMessageBox::error( 0, errstr );
+ else
+ KMessageBox::detailedError( 0, errstr, QString::fromUtf8( ldif, ldif.size()-1 ) );
+ }
+ mOk = false;
+ } else {
+ mOk = true;
+ }
+}
+
+void KGroupLDAP::data( KIO::Job*, const QByteArray& data )
+{
+ if ( data.size() ) {
+ mParser.setLDIF( data );
+ } else {
+ mParser.endLDIF();
+ }
+
+ KABC::LDIF::ParseVal ret;
+ QString name, val;
+ QByteArray value;
+ do {
+ ret = mParser.nextItem();
+ switch ( ret ) {
+ case KABC::LDIF::Item:
+ name = mParser.attr().lower();
+ value = mParser.val();
+ val = QString::fromUtf8( value, value.size() );
+ if ( name == "objectclass" ) {
+ if ( val.lower() == "sambagroupmapping" )
+ mGroup->setCaps( KU::KGroup::Cap_Samba );
+ } else if ( name == "gidnumber" )
+ mGroup->setGID( val.toLong() );
+ else if ( name == "cn" )
+ mGroup->setName( val );
+ else if ( name == "userpassword" )
+ mGroup->setPwd( val );
+ else if ( name == "memberuid" )
+ mGroup->addUser( val );
+ else if ( name == "sambasid" )
+ mGroup->setSID( val );
+ else if ( name == "sambagrouptype" )
+ mGroup->setType( val.toInt() );
+ else if ( name == "displayname" )
+ mGroup->setDisplayName( val );
+ else if ( name == "description" )
+ mGroup->setDesc( val );
+ break;
+ case KABC::LDIF::EndEntry: {
+ KU::KGroup newGroup;
+ mGroups.append( new KU::KGroup( mGroup ) );
+ mGroup->copy( &newGroup );
+ if ( ( mGroups.count() & 7 ) == 7 ) {
+ mProg->progressBar()->advance( mAdv );
+ if ( mProg->progressBar()->progress() == 0 ) mAdv = 1;
+ if ( mProg->progressBar()->progress() == mProg->progressBar()->totalSteps()-1 ) mAdv = -1;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } while ( ret != KABC::LDIF::MoreData );
+}
+
+bool KGroupLDAP::reload()
+{
+ kdDebug() << "KGroupLDAP::reload()" << endl;
+ mGroup = new KU::KGroup();
+ mParser.startParsing();
+
+ mProg = new KProgressDialog( 0, "", "", i18n("Loading Groups From LDAP"), true );
+ mProg->setAutoClose( false );
+ mProg->progressBar()->setFormat( "" );
+ mProg->progressBar()->setTotalSteps( 100 );
+ mAdv = 1;
+ mCancel = true;
+ ldif = "";
+
+ KIO::Job *job = KIO::get( mUrl, true, false );
+ connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
+ this, SLOT( data( KIO::Job*, const QByteArray& ) ) );
+ connect( job, SIGNAL( result( KIO::Job* ) ),
+ this, SLOT( result( KIO::Job* ) ) );
+ mProg->exec();
+ if ( mCancel ) job->kill();
+
+ delete mGroup;
+ return( mOk );
+}
+
+bool KGroupLDAP::dbcommit()
+{
+ mAddSucc.clear();
+ mDelSucc.clear();
+ mModSucc.clear();
+ mAdd.first();
+ mDel.first();
+ mAddGroup = 0; mDelGroup = 0; mGroup = 0;
+ ldif = "";
+
+ mProg = new KProgressDialog( 0, "", i18n("LDAP Operation"), "", true );
+ KIO::Job *job = KIO::put( mUrl, -1, false, false, false );
+ connect( job, SIGNAL( dataReq( KIO::Job*, QByteArray& ) ),
+ this, SLOT( putData( KIO::Job*, QByteArray& ) ) );
+ connect( job, SIGNAL( result( KIO::Job* ) ),
+ this, SLOT( result( KIO::Job* ) ) );
+ mProg->exec();
+ return( mOk );
+}
+
+void KGroupLDAP::putData( KIO::Job*, QByteArray& data )
+{
+ ModIt mit = mMod.begin();
+
+ if ( mAddGroup ) {
+ mAddSucc.append( mAddGroup );
+ mAdd.remove();
+ mAddGroup = 0;
+ }
+ if ( mDelGroup ) {
+ mDelSucc.append( mDelGroup );
+ mDel.remove();
+ mDelGroup = 0;
+ }
+ if ( mGroup ) {
+ mModSucc.insert( mGroup, mit.data() );
+ mMod.remove( mit );
+ mit = mMod.begin();
+ mGroup = 0;
+ }
+
+ if ( (mAddGroup = mAdd.current()) ) {
+ addData( mAddGroup );
+ data = ldif;
+ } else if ( mit != mMod.end() ) {
+ mGroup = mit.key();
+ modData( &(mit.data()) );
+ data = ldif;
+ } else if ( (mDelGroup = mDel.current()) ) {
+ delData( mDelGroup );
+ data = ldif;
+ } else
+ data.resize(0);
+}
+
+void KGroupLDAP::addData( KU::KGroup *group )
+{
+ ldif = "dn: " + getRDN( group ).utf8() + "," +
+ mUrl.dn().utf8() + "\n" + "objectclass: posixGroup\n";
+
+ ldif +=
+ KABC::LDIF::assembleLine( "cn", group->getName() ) + "\n" +
+ KABC::LDIF::assembleLine( "gidnumber", QString::number(group->getGID()) ) + "\n" +
+ KABC::LDIF::assembleLine( "userpassword", group->getPwd() ) + "\n";
+ for ( uint i=0; i < group->count(); i++ ) {
+ ldif += KABC::LDIF::assembleLine( "memberuid", group->user(i) ) + "\n";
+ }
+ if ( ( getCaps() & Cap_Samba ) && ( group->getCaps() & KU::KGroup::Cap_Samba ) ) {
+ ldif += "objectclass: sambagroupmapping\n" +
+ KABC::LDIF::assembleLine( "sambasid", group->getSID().getSID() ) + "\n" +
+ KABC::LDIF::assembleLine( "displayname", group->getDisplayName() ) + "\n" +
+ KABC::LDIF::assembleLine( "description", group->getDesc() ) + "\n" +
+ KABC::LDIF::assembleLine( "sambagrouptype", QString::number( group->getType() ) ) + "\n";
+ }
+ ldif += "\n\n";
+ kdDebug() << "ldif: " << ldif << endl;
+}
+
+void KGroupLDAP::delData( KU::KGroup *group )
+{
+ ldif = "dn: " + getRDN( group ).utf8() + "," +
+ mUrl.dn().utf8() + "\n" + "changetype: delete\n\n";
+ kdDebug() << "ldif: " << ldif << endl;
+}
+
+void KGroupLDAP::modData( KU::KGroup *group )
+{
+ QString oldrdn = getRDN( mGroup );
+ QString newrdn = getRDN( group );
+
+ ldif = "";
+ if ( oldrdn != newrdn ) {
+ ldif = "dn: " + oldrdn.utf8() + "," + mUrl.dn().utf8() + "\n" +
+ "changetype: modrdn\n" +
+ "newrdn: " + newrdn.utf8() + "\n" +
+ "deleteoldrdn: 1\n\n";
+ }
+
+ ldif += "dn: " + newrdn.utf8() + "," + mUrl.dn().utf8() + "\n" +
+ "changetype: modify\n" +
+ "replace: objectclass\n" +
+ "objectclass: posixgroup\n";
+ if ( ( getCaps() & Cap_Samba ) && ( group->getCaps() & KU::KGroup::Cap_Samba ) ) {
+ ldif += "objectclass: sambagroupmapping\n";
+ }
+ ldif +=
+ "-\nreplace: cn\n" +
+ KABC::LDIF::assembleLine( "cn", group->getName() ) +
+ "\n-\nreplace: gidnumber\n" +
+ KABC::LDIF::assembleLine( "gidnumber", QString::number(group->getGID()) ) +
+ "\n-\nreplace: userpassword\n" +
+ KABC::LDIF::assembleLine( "userpassword", group->getPwd() ) +
+ "\n-\nreplace: memberuid\n";
+ for ( uint i=0; i < group->count(); i++ ) {
+ ldif += KABC::LDIF::assembleLine( "memberuid", group->user(i)) + "\n";
+ }
+ if ( getCaps() & Cap_Samba ) {
+ if ( group->getCaps() & KU::KGroup::Cap_Samba ) {
+ ldif +=
+ "-\nreplace: sambasid\n" +
+ KABC::LDIF::assembleLine( "sambasid", group->getSID().getSID() ) +
+ "\n-\nreplace: displayname\n" +
+ KABC::LDIF::assembleLine( "displayname", group->getDisplayName() ) +
+ "\n-\nreplace: description\n" +
+ KABC::LDIF::assembleLine( "description", group->getDesc() ) +
+ "\n-\nreplace: sambagrouptype\n" +
+ KABC::LDIF::assembleLine( "sambagrouptype", QString::number( group->getType() ) ) + "\n";
+ } else {
+ ldif += "-\nreplace: sambasid\n";
+ ldif += "-\nreplace: displayname\n";
+ ldif += "-\nreplace: description\n";
+ ldif += "-\nreplace: sambagrouptype\n";
+ ldif += "-\nreplace: sambasidlist\n";
+ }
+ }
+
+ ldif += "-\n\n";
+ kdDebug() << "ldif: " << ldif << endl;
+}
diff --git a/kuser/kgroupldap.h b/kuser/kgroupldap.h
new file mode 100644
index 0000000..ece0185
--- /dev/null
+++ b/kuser/kgroupldap.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_GROUPLDAP_H_
+#define _KU_GROUPLDAP_H_
+
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+
+#include <kprogress.h>
+#include <kabc/ldapurl.h>
+#include <kabc/ldif.h>
+#include <kio/job.h>
+
+#include "kgroup.h"
+
+class KGroupLDAP : public QObject, public KU::KGroups {
+Q_OBJECT
+public:
+ KGroupLDAP( KUserPrefsBase *cfg );
+ virtual ~KGroupLDAP();
+
+ virtual bool reload();
+ virtual bool dbcommit();
+
+private slots:
+ void data( KIO::Job*, const QByteArray& );
+ void putData( KIO::Job *job, QByteArray& data );
+ void result( KIO::Job* );
+private:
+ KABC::LDIF mParser;
+ KABC::LDAPUrl mUrl;
+ KProgressDialog *mProg;
+
+ KU::KGroup *mGroup, *mDelGroup, *mAddGroup;
+
+ bool first, mOk, mCancel;
+ int mAdv;
+ QCString ldif;
+
+ QString getRDN( KU::KGroup *group );
+ void addData( KU::KGroup *group );
+ void delData( KU::KGroup *group );
+ void modData( KU::KGroup *group );
+};
+
+#endif // _KU_GROUPLDAP_H_
+
diff --git a/kuser/kgroupsystem.cpp b/kuser/kgroupsystem.cpp
new file mode 100644
index 0000000..1cb2f13
--- /dev/null
+++ b/kuser/kgroupsystem.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "globals.h"
+#include <errno.h>
+#include <grp.h>
+
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+
+#include "kglobal_.h"
+#include "kgroupsystem.h"
+#include "misc.h"
+
+KGroupSystem::KGroupSystem( KUserPrefsBase *cfg ) : KU::KGroups( cfg )
+{
+ caps = Cap_ReadOnly | Cap_Passwd;
+
+ reload();
+}
+
+KGroupSystem::~KGroupSystem()
+{
+ mGroups.clear();
+}
+
+bool KGroupSystem::reload()
+{
+ struct group *p;
+ KU::KGroup *tmpKG = 0;
+
+ setgrent();
+ while ((p = getgrent()) != NULL) {
+ tmpKG = new KU::KGroup();
+ tmpKG->setGID(p->gr_gid);
+ tmpKG->setName(QString::fromLocal8Bit(p->gr_name));
+ tmpKG->setPwd(QString::fromLocal8Bit(p->gr_passwd));
+
+ char *u_name;
+ int i = 0;
+ while ((u_name = p->gr_mem[i])!=0) {
+ tmpKG->addUser(QString::fromLocal8Bit(u_name));
+ i++;
+ }
+
+ mGroups.append(tmpKG);
+ }
+
+ endgrent();
+ return true;
+}
diff --git a/kuser/kgroupsystem.h b/kuser/kgroupsystem.h
new file mode 100644
index 0000000..b26dea8
--- /dev/null
+++ b/kuser/kgroupsystem.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_GROUPSYSTEM_H_
+#define _KU_GROUPSYSTEM_H_
+
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+
+#include "kgroup.h"
+
+class KGroupSystem : public KU::KGroups {
+public:
+ KGroupSystem( KUserPrefsBase *cfg );
+ virtual ~KGroupSystem();
+
+ virtual bool reload();
+ virtual bool dbcommit() { return true; }
+};
+
+#endif // _KU_GROUPSYSTEM_H_
+
diff --git a/kuser/kgroupvw.cpp b/kuser/kgroupvw.cpp
new file mode 100644
index 0000000..2641554
--- /dev/null
+++ b/kuser/kgroupvw.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "kglobal_.h"
+#include "misc.h"
+
+#include "kgroupvw.h"
+
+
+KGroupViewItem::KGroupViewItem(KListView *parent, KU::KGroup *aku)
+ : KListViewItem(parent), mGroup(aku)
+{
+}
+
+int KGroupViewItem::compare( QListViewItem *i, int col, bool ascending ) const
+{
+ switch ( col ) {
+ case 0: {
+ gid_t gid1, gid2;
+
+ gid1 = mGroup->getGID();
+ gid2 = ((KGroupViewItem*) i)->mGroup->getGID();
+
+ if ( gid1 == gid2 ) return 0;
+ return ( gid1 < gid2) ? -1: 1;
+ }
+ case 2: {
+ uint rid1,rid2;
+ rid1 = mGroup->getSID().getRID();
+ rid2 = ((KGroupViewItem*) i)->mGroup->getSID().getRID();
+ if ( rid1 == rid2 ) return 0;
+ return ( rid1 < rid2) ? -1: 1;
+ }
+ default:
+ return QListViewItem::compare( i, col, ascending );
+ }
+}
+
+QString KGroupViewItem::text(int num) const
+{
+ switch(num)
+ {
+ case 0: return QString::number(mGroup->getGID());
+ case 1: return mGroup->getName();
+ case 2: return ( mGroup->getCaps() & KU::KGroup::Cap_Samba ) ?
+ mGroup->getSID().getDOM() : QString::null;
+ case 3: return ( mGroup->getCaps() & KU::KGroup::Cap_Samba ) ?
+ QString::number( mGroup->getSID().getRID() ) : QString::null;
+ case 4: {
+ if ( mGroup->getCaps() & KU::KGroup::Cap_Samba ) {
+ switch ( mGroup->getType() ) {
+ case 2: return i18n("Domain");
+ case 4: return i18n("Local");
+ case 5: return i18n("Builtin");
+ default: return i18n("Unknown");
+ }
+ } else {
+ return QString::null;
+ }
+ }
+ case 5: return mGroup->getDisplayName();
+ case 6: return mGroup->getDesc();
+ }
+ return QString::null;
+}
+
+
+KGroupView::KGroupView(QWidget *parent, const char *name)
+ : KListView( parent, name )
+{
+ setSelectionMode( QListView::Extended );
+}
+
+KGroupView::~KGroupView()
+{
+}
+
+void KGroupView::insertItem(KU::KGroup *aku)
+{
+ KGroupViewItem *groupItem = new KGroupViewItem(this, aku);
+ KListView::insertItem(groupItem);
+}
+
+void KGroupView::removeItem(KU::KGroup *aku)
+{
+ KGroupViewItem *groupItem = (KGroupViewItem *)firstChild();
+
+ while(groupItem)
+ {
+ if (groupItem->group() == aku)
+ {
+ delete groupItem;
+ return;
+ }
+ groupItem = (KGroupViewItem*) groupItem->nextSibling();
+ }
+}
+
+void KGroupView::init()
+{
+ while ( columns() > 2 ) {
+ removeColumn( 2 );
+ }
+ setAllColumnsShowFocus(true);
+
+ if ( columns() < 2 ) {
+ addColumn(i18n("GID"));
+ setColumnAlignment(0, AlignRight);
+ addColumn(i18n("Group Name"));
+ }
+ if ( kug->getGroups().getCaps() & KU::KGroups::Cap_Samba ) {
+ addColumn(i18n("Domain SID"));
+ addColumn(i18n("RID"));
+ addColumn(i18n("Type"));
+ addColumn(i18n("Display Name"));
+ addColumn(i18n("Description"));
+ }
+}
+
+KU::KGroup *KGroupView::getCurrentGroup()
+{
+ KGroupViewItem *groupItem = (KGroupViewItem *)currentItem();
+ if (!groupItem) return 0;
+
+ return groupItem->group();
+}
+
+#include "kgroupvw.moc"
diff --git a/kuser/kgroupvw.h b/kuser/kgroupvw.h
new file mode 100644
index 0000000..4667f8c
--- /dev/null
+++ b/kuser/kgroupvw.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_GROUPVW_H_
+#define _KU_GROUPVW_H_
+
+#include <qwidget.h>
+
+#include <klistview.h>
+
+#include "kgroup.h"
+
+class KGroupViewItem : public KListViewItem
+{
+public:
+ KGroupViewItem(KListView *parent, KU::KGroup *aku);
+ KU::KGroup *group() { return mGroup; }
+private:
+ virtual QString text ( int ) const;
+ virtual int compare( QListViewItem *i, int col, bool ascending ) const;
+
+ KU::KGroup *mGroup;
+};
+
+class KGroupView : public KListView
+{
+ Q_OBJECT
+
+public:
+ KGroupView( QWidget* parent = 0, const char* name = 0 );
+
+ virtual ~KGroupView();
+
+ void insertItem(KU::KGroup *aku);
+ void removeItem(KU::KGroup *aku);
+ KU::KGroup *getCurrentGroup();
+ void init();
+};
+
+#endif // _KGROUPVW_H_
diff --git a/kuser/kuser.cpp b/kuser/kuser.cpp
new file mode 100644
index 0000000..2fd9ff1
--- /dev/null
+++ b/kuser/kuser.cpp
@@ -0,0 +1,1053 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "globals.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <qstring.h>
+#include <qdir.h>
+
+#include "kglobal_.h"
+#include "kuser.h"
+#include "misc.h"
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <kdebug.h>
+#include <kio/netaccess.h>
+#include <kurl.h>
+
+// class KUser
+
+KU::KUser::KUser()
+{
+ p_change = 0;
+ p_expire = -1;
+ p_uid = 0;
+ p_gid = 100;
+
+ s_min = 0;
+ s_max = 99999;
+ s_warn = 7;
+ s_inact = -1;
+// s_flag = 0;
+ caps = 0;
+ isCreateHome = false;
+ isCreateMailBox = false;
+ isCopySkel = false;
+ isDeleteHome = false;
+ isDeleteMailBox = false;
+
+ isDisabled = true;
+}
+
+KU::KUser::KUser(const KU::KUser *user)
+{
+ copy(user);
+}
+
+void KU::KUser::copy(const KU::KUser *user)
+{
+ if ( user != this ) {
+ caps = user->caps;
+ p_name = user->p_name;
+ p_surname = user->p_surname;
+ p_email = user->p_email;
+ p_pwd = user->p_pwd;
+ p_dir = user->p_dir;
+ p_shell = user->p_shell;
+ p_fname = user->p_fname;
+ p_office = user->p_office;
+ p_ophone = user->p_ophone;
+ p_hphone = user->p_hphone;
+ p_class = user->p_class;
+ p_change = user->p_change;
+ p_expire = user->p_expire;
+ p_office1 = user->p_office1;
+ p_office2 = user->p_office2;
+ p_address = user->p_address;
+
+ p_uid = user->p_uid;
+ p_gid = user->p_gid;
+
+ s_pwd = user->s_pwd;
+ s_min = user->s_min;
+ s_max = user->s_max;
+ s_warn = user->s_warn;
+ s_inact = user->s_inact;
+ s_flag = user->s_flag;
+
+ sam_lmpwd = user->sam_lmpwd;
+ sam_ntpwd = user->sam_ntpwd;
+ sam_loginscript = user->sam_loginscript;
+ sam_profile = user->sam_profile;
+ sam_homedrive = user->sam_homedrive;
+ sam_homepath = user->sam_homepath;
+ sam_workstations = user->sam_workstations;
+ sam_domain = user->sam_domain;
+ sid = user->sid;
+ pgroup_sid = user->pgroup_sid;
+
+ isCreateHome = user->isCreateHome;
+ isCreateMailBox = user->isCreateMailBox;
+ isDeleteHome = user->isDeleteHome;
+ isDeleteMailBox = user->isDeleteMailBox;
+ isCopySkel = user->isCopySkel;
+ isDisabled = user->isDisabled;
+ }
+}
+
+KU::KUser::~KUser()
+{
+}
+
+void KU::KUser::setCaps( int data )
+{
+ caps = data;
+}
+
+int KU::KUser::getCaps()
+{
+ return caps;
+}
+
+bool KU::KUser::getDeleteHome()
+{
+ return isDeleteHome;
+}
+
+bool KU::KUser::getDeleteMailBox()
+{
+ return isDeleteMailBox;
+}
+
+bool KU::KUser::getCreateHome()
+{
+ return isCreateHome;
+}
+
+bool KU::KUser::getCreateMailBox()
+{
+ return isCreateMailBox;
+}
+
+bool KU::KUser::getCopySkel()
+{
+ return isCopySkel;
+}
+
+const QString &KU::KUser::getName() const
+{
+ return p_name;
+}
+
+const QString &KU::KUser::getSurname() const
+{
+ return p_surname;
+}
+
+const QString &KU::KUser::getEmail() const
+{
+ return p_email;
+}
+
+const QString &KU::KUser::getPwd() const
+{
+ return p_pwd;
+}
+
+const QString &KU::KUser::getHomeDir() const
+{
+ return p_dir;
+}
+
+const QString &KU::KUser::getShell() const
+{
+ return p_shell;
+}
+
+const QString &KU::KUser::getFullName() const
+{
+ return p_fname;
+}
+
+bool KU::KUser::getDisabled() const
+{
+ return isDisabled;
+}
+
+// FreeBSD apparently uses the GECOS fields differently than other Unices.
+// Create some better named functions to make the FreeBSD code clear
+const QString &KU::KUser::getOffice() const
+{
+ return p_office;
+}
+
+const QString &KU::KUser::getWorkPhone() const
+{
+ return p_ophone;
+}
+
+const QString &KU::KUser::getHomePhone() const
+{
+ return p_hphone;
+}
+
+// New fields needed for the FreeBSD /etc/master.passwd file
+const QString &KU::KUser::getClass() const
+{
+ return p_class;
+}
+
+const QString &KU::KUser::getOffice1() const
+{
+ return p_office1;
+}
+
+const QString &KU::KUser::getOffice2() const
+{
+ return p_office2;
+}
+
+const QString &KU::KUser::getAddress() const
+{
+ return p_address;
+}
+
+uid_t KU::KUser::getUID() const
+{
+ return p_uid;
+}
+
+gid_t KU::KUser::getGID() const
+{
+ return p_gid;
+}
+
+const QString &KU::KUser::getSPwd() const
+{
+ return s_pwd;
+}
+
+time_t KU::KUser::getLastChange() const
+{
+ return p_change;
+}
+
+int KU::KUser::getMin() const
+{
+ return s_min;
+}
+
+int KU::KUser::getMax() const
+{
+ return s_max;
+}
+
+int KU::KUser::getWarn() const
+{
+ return s_warn;
+}
+
+int KU::KUser::getInactive() const
+{
+ return s_inact;
+}
+
+int KU::KUser::getFlag() const
+{
+ return s_flag;
+}
+
+time_t KU::KUser::getExpire() const
+{
+ return p_expire;
+}
+
+const QString &KU::KUser::getLMPwd() const // sam_lmpwd,
+{
+ return sam_lmpwd;
+}
+
+const QString &KU::KUser::getNTPwd() const //sam_ntpwd,
+{
+ return sam_ntpwd;
+}
+
+const QString &KU::KUser::getLoginScript() const //sam_loginscript,
+{
+ return sam_loginscript;
+}
+
+const QString &KU::KUser::getProfilePath() const // sam_profile,
+{
+ return sam_profile;
+}
+
+const QString &KU::KUser::getHomeDrive() const //sam_homedrive,
+{
+ return sam_homedrive;
+}
+
+const QString &KU::KUser::getHomePath() const //sam_homepath;
+{
+ return sam_homepath;
+}
+
+const QString &KU::KUser::getWorkstations() const //sam_workstation;
+{
+ return sam_workstations;
+}
+
+const QString &KU::KUser::getDomain() const //sam_domain;
+{
+ return sam_domain;
+}
+
+const SID &KU::KUser::getSID() const //sid,
+{
+ return sid;
+}
+
+const SID &KU::KUser::getPGSID() const //pgroup_sid;
+{
+ return pgroup_sid;
+}
+
+void KU::KUser::setName(const QString &data)
+{
+ p_name = data;
+}
+
+void KU::KUser::setSurname(const QString &data)
+{
+ p_surname = data;
+}
+
+void KU::KUser::setEmail(const QString &data)
+{
+ p_email = data;
+}
+
+void KU::KUser::setPwd(const QString &data)
+{
+ p_pwd = data;
+}
+
+void KU::KUser::setHomeDir(const QString &data)
+{
+ p_dir = data;
+}
+
+void KU::KUser::setShell(const QString &data)
+{
+ p_shell = data;
+}
+
+void KU::KUser::setFullName(const QString &data)
+{
+ p_fname = data;
+}
+
+void KU::KUser::setDisabled(bool data)
+{
+ isDisabled = data;
+}
+
+// FreeBSD apparently uses the GECOS fields differently than other Unices.
+// Create some better named functions to make the FreeBSD code clear
+void KU::KUser::setOffice(const QString &data)
+{
+ p_office = data;
+}
+
+void KU::KUser::setWorkPhone(const QString &data)
+{
+ p_ophone = data;
+}
+
+void KU::KUser::setHomePhone(const QString &data)
+{
+ p_hphone = data;
+}
+
+// New fields needed for the FreeBSD /etc/master.passwd file
+void KU::KUser::setClass(const QString &data)
+{
+ p_class = data;
+}
+
+void KU::KUser::setLastChange(time_t data)
+{
+ p_change = data;
+}
+
+void KU::KUser::setExpire(time_t data)
+{
+ p_expire = data;
+}
+
+void KU::KUser::setOffice1(const QString &data)
+{
+ p_office1 = data;
+}
+
+void KU::KUser::setOffice2(const QString &data)
+{
+ p_office2 = data;
+}
+
+void KU::KUser::setAddress(const QString &data)
+{
+ p_address = data;
+}
+
+void KU::KUser::setUID(uid_t data)
+{
+ p_uid = data;
+}
+
+void KU::KUser::setGID(gid_t data)
+{
+ p_gid = data;
+}
+
+void KU::KUser::setSPwd(const QString &data)
+{
+ s_pwd = data;
+}
+
+void KU::KUser::setMin(int data)
+{
+ s_min = data;
+}
+
+void KU::KUser::setMax(int data)
+{
+ s_max = data;
+}
+
+void KU::KUser::setWarn(int data)
+{
+ s_warn = data;
+}
+
+void KU::KUser::setInactive(int data)
+{
+ s_inact = data;
+}
+
+void KU::KUser::setLMPwd( const QString &data ) // sam_lmpwd,
+{
+ sam_lmpwd = data;
+}
+
+void KU::KUser::setNTPwd( const QString &data ) //sam_ntpwd,
+{
+ sam_ntpwd = data;
+}
+
+void KU::KUser::setLoginScript( const QString &data ) //sam_loginscript,
+{
+ sam_loginscript = data;
+}
+
+void KU::KUser::setProfilePath( const QString &data) // sam_profile,
+{
+ sam_profile = data;
+}
+
+void KU::KUser::setHomeDrive( const QString &data ) //sam_homedrive,
+{
+ sam_homedrive = data;
+}
+
+void KU::KUser::setHomePath( const QString &data ) //sam_homepath;
+{
+ sam_homepath = data;
+}
+
+void KU::KUser::setWorkstations( const QString &data ) //sam_workstation;
+{
+ sam_workstations = data;
+}
+
+void KU::KUser::setDomain( const QString &data ) //sam_domain
+{
+ sam_domain = data;
+}
+
+void KU::KUser::setSID( const SID &data ) //sid,
+{
+ sid = data;
+}
+
+void KU::KUser::setPGSID( const SID &data ) //pgroup_sid;
+{
+ pgroup_sid = data;
+}
+
+void KU::KUser::setFlag(int data)
+{
+ s_flag = data;
+}
+
+void KU::KUser::setCreateHome(bool data)
+{
+ isCreateHome = data;
+}
+
+void KU::KUser::setCreateMailBox(bool data)
+{
+ isCreateMailBox = data;
+}
+
+void KU::KUser::setCopySkel(bool data)
+{
+ isCopySkel = data;
+}
+
+void KU::KUser::setDeleteHome(bool data)
+{
+ isDeleteHome = data;
+}
+
+void KU::KUser::setDeleteMailBox(bool data)
+{
+ isDeleteMailBox = data;
+}
+
+int KU::KUser::createHome()
+{
+
+ if(p_dir.isNull() || p_dir.isEmpty()) {
+ KMessageBox::sorry( 0, i18n("Cannot create home folder for %1: it is null or empty.").arg(p_name) );
+ return(0);
+ }
+ if (mkdir(QFile::encodeName(p_dir), 0700) != 0) {
+ if (errno != EEXIST)
+ {
+ KMessageBox::error( 0, i18n("Cannot create home folder %1.\nError: %2").arg(p_dir).arg(QString::fromLocal8Bit(strerror(errno))) );
+ return(0);
+ }
+ }
+
+ if (chown(QFile::encodeName(p_dir), p_uid, p_gid) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change owner of home folder %1.\nError: %2").arg(p_dir).arg(QString::fromLocal8Bit(strerror(errno))) );
+ return(1);
+ }
+
+ if (chmod(QFile::encodeName(p_dir), KU_HOMEDIR_PERM) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change permissions on home folder %1.\nError: %2").arg(p_dir).arg(QString::fromLocal8Bit(strerror(errno))) );
+ return(1);
+ }
+ return(1);
+}
+
+int KU::KUser::tryCreate(const QString &dir)
+{
+ struct stat sb;
+ int rc = 0;
+
+ rc = stat(QFile::encodeName(dir), &sb);
+ if (rc == 0) {
+ if (S_ISDIR(sb.st_mode)) {
+ if (KMessageBox::warningContinueCancel( 0,
+ i18n("Folder %1 already exists!\nWill make %2 owner and change permissions.\nDo you want to continue?").arg(dir).arg(p_name),
+ QString::null, KStdGuiItem::cont() ) == KMessageBox::Continue) {
+
+ if (chown(QFile::encodeName(dir), p_uid, p_gid) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change owner of %1 folder.\nError: %2") .arg(dir).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+ return(0);
+ } else {
+ KMessageBox::information( 0, i18n("Folder %1 left 'as is'.\nVerify ownership and permissions for user %2 who may not be able to log in!").arg(dir).arg(p_name) );
+ return(-1);
+ }
+ } else {
+ KMessageBox::information( 0, i18n("%1 exists and is not a folder. User %2 will not be able to log in!").arg(dir).arg(p_name) );
+ return(-1);
+ }
+ } else {
+ if (errno == ENOENT) {
+ if (mkdir(QFile::encodeName(dir), 0700) != 0) {
+ KMessageBox::error( 0, i18n("Cannot create %1 folder.\nError: %2").arg(dir).arg(QString::fromLocal8Bit(strerror(errno))));
+ return(-1);
+ }
+ if (chown(QFile::encodeName(dir), p_uid, p_gid) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change owner of %1 folder.\nError: %2").arg(dir).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+ return(0);
+ } else {
+ KMessageBox::error( 0, i18n("stat call on %1 failed.\nError: %2").arg(dir).arg(QString::fromLocal8Bit(strerror(errno))) );
+ return(-1);
+ }
+ }
+}
+
+int KU::KUser::createMailBox()
+{
+ QString mailboxpath;
+ int fd;
+ mailboxpath = QFile::decodeName(MAIL_SPOOL_DIR) + "/" + p_name;
+ if((fd = open(QFile::encodeName(mailboxpath), O_CREAT|O_EXCL|O_WRONLY,
+ S_IRUSR|S_IWUSR)) < 0) {
+ if (errno != EEXIST)
+ {
+ KMessageBox::error( 0, i18n("Cannot create %1: %2")
+ .arg(mailboxpath)
+ .arg(QString::fromLocal8Bit(strerror(errno))) );
+ return -1;
+ }
+ }
+
+ close(fd);
+
+ if (chown(QFile::encodeName(mailboxpath), p_uid, KU_MAILBOX_GID) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change owner on mailbox: %1\nError: %2")
+ .arg(mailboxpath).arg(QString::fromLocal8Bit(strerror(errno))) );
+ return -1;
+ }
+
+ if (chmod(QFile::encodeName(mailboxpath), KU_MAILBOX_PERM) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change permissions on mailbox: %1\nError: %2")
+ .arg(mailboxpath).arg(QString::fromLocal8Bit(strerror(errno))) );
+ return -1;
+ }
+
+ return 0;
+}
+
+void KU::KUser::copyDir(const QString &srcPath, const QString &dstPath)
+{
+ mode_t mode;
+ QDir s(srcPath);
+ QDir d(dstPath);
+
+ QString dot = QString::fromLatin1(".");
+ QString dotdot = QString::fromLatin1("..");
+
+ s.setFilter( QDir::All | QDir::Hidden | QDir::System );
+
+ for (uint i=0; i<s.count(); i++) {
+ QString name(s[i]);
+
+ if (name == dot)
+ continue;
+ if (name == dotdot)
+ continue;
+
+ QString filename(s.filePath(name));
+
+ QFileInfo info(filename);
+ mode = 0;
+ if ( info.permission(QFileInfo::ReadOwner) ) mode |= S_IRUSR;
+ if ( info.permission(QFileInfo::WriteOwner) ) mode |= S_IWUSR;
+ if ( info.permission(QFileInfo::ExeOwner) ) mode |= S_IXUSR;
+ if ( info.permission(QFileInfo::ReadGroup) ) mode |= S_IRGRP;
+ if ( info.permission(QFileInfo::WriteGroup) ) mode |= S_IWGRP;
+ if ( info.permission(QFileInfo::ExeGroup) ) mode |= S_IXGRP;
+ if ( info.permission(QFileInfo::ReadOther) ) mode |= S_IROTH;
+ if ( info.permission(QFileInfo::WriteOther) ) mode |= S_IWOTH;
+ if ( info.permission(QFileInfo::ExeOther) ) mode |= S_IXOTH;
+
+ if ( info.isSymLink() ) {
+ QString link = info.readLink();
+
+ if (symlink(QFile::encodeName(link),QFile::encodeName(d.filePath(name))) != 0) {
+ KMessageBox::error( 0, i18n("Error creating symlink %1.\nError: %2")
+ .arg(d.filePath(s[i])).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+ } else if ( info.isDir() ) {
+ QDir dir(filename);
+
+ d.mkdir(name, FALSE);
+ copyDir(s.filePath(name), d.filePath(name));
+
+ if (chown(QFile::encodeName(d.filePath(name)), p_uid, p_gid) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change owner of folder %1.\nError: %2")
+ .arg(d.filePath(s[i])).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+
+ if (chmod(QFile::encodeName(d.filePath(name)), mode) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change permissions on folder %1.\nError: %2")
+ .arg(d.filePath(s[i])).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+
+ } else {
+ if (copyFile(filename, d.filePath(name)) == -1) {
+ continue;
+ }
+
+ if (chown(QFile::encodeName(d.filePath(name)), p_uid, p_gid) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change owner of file %1.\nError: %2")
+ .arg(d.filePath(s[i])).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+
+ if (chmod(QFile::encodeName(d.filePath(name)), mode) != 0) {
+ KMessageBox::error( 0, i18n("Cannot change permissions on file %1.\nError: %2")
+ .arg(d.filePath(s[i])).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+ }
+ }
+}
+
+int KU::KUser::copySkel()
+{
+ QDir s(QFile::decodeName(SKELDIR));
+ QDir d(p_dir);
+ mode_t mode;
+
+ if (!s.exists()) {
+ KMessageBox::error( 0, i18n("Folder %1 does not exist, cannot copy skeleton for %2.").arg(s.absPath()).arg(p_name) );
+ return (-1);
+ }
+
+ if (!d.exists()) {
+ KMessageBox::error( 0, i18n("Folder %1 does not exist, cannot copy skeleton.").arg(d.absPath()) );
+ return (-1);
+ }
+
+ mode = umask(0007);
+ copyDir(s.absPath(), d.absPath());
+ umask( mode );
+
+ return 0;
+}
+
+int KU::KUser::removeHome()
+{
+ struct stat sb;
+
+ if (!stat(QFile::encodeName(p_dir), &sb))
+ if (S_ISDIR(sb.st_mode) && sb.st_uid == p_uid) {
+ if (!KIO::NetAccess::del(KURL::fromPathOrURL(p_dir))) {
+ KMessageBox::error( 0, i18n("Cannot remove home folder %1.\nError: %2")
+ .arg(p_dir).arg(KIO::NetAccess::lastErrorString()) );
+ }
+ } else {
+ KMessageBox::error( 0, i18n("Removal of home folder %1 failed (uid = %2, gid = %3).").arg(p_dir).arg(sb.st_uid).arg(sb.st_gid) );
+ }
+ else {
+ KMessageBox::error( 0, i18n("stat call on file %1 failed.\nError: %2")
+ .arg(p_dir).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+
+ return 0;
+}
+
+//TODO: remove at jobs too.
+
+int KU::KUser::removeCrontabs()
+{
+ QString file;
+ QString command;
+
+ file = QFile::decodeName(CRONTAB_DIR) + "/" + p_name;
+ if ( access(QFile::encodeName(file), F_OK) == 0 ) {
+ command = QString::fromLatin1("crontab -u %1 -r").arg(KProcess::quote(p_name));
+ if ( system(QFile::encodeName(command)) != 0 ) {
+ KMessageBox::error( 0, i18n("Cannot remove crontab %1.\nError: %2")
+ .arg(command).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+ }
+
+ return 0;
+}
+
+int KU::KUser::removeMailBox()
+{
+ QString file;
+
+ file = QFile::decodeName(MAIL_SPOOL_DIR) + "/" + p_name;
+ if (remove(QFile::encodeName(file)) != 0) {
+ KMessageBox::error( 0, i18n("Cannot remove mailbox %1.\nError: %2")
+ .arg(file).arg(QString::fromLocal8Bit(strerror(errno))) );
+ }
+
+ return 0;
+}
+
+int KU::KUser::removeProcesses()
+{
+ // be paranoid -- kill all processes owned by that user, if not root.
+
+ if (p_uid != 0)
+ switch (fork()) {
+ case 0:
+ setuid(p_uid);
+ kill(-1, 9);
+ _exit(0);
+ break;
+ case -1:
+ KMessageBox::error( 0,
+ i18n("Cannot fork while trying to kill processes for uid %1.").arg(p_uid) );
+ break;
+ }
+
+ return 0;
+}
+
+KU::KUsers::KUsers(KUserPrefsBase *cfg)
+{
+ mUsers.setAutoDelete(TRUE);
+ mCfg = cfg;
+}
+
+KU::KUsers::~KUsers()
+{
+ mUsers.clear();
+}
+
+const QString &KU::KUsers::getDOMSID() const
+{
+ return domsid;
+}
+
+void KU::KUsers::parseGecos( const char *gecos, QString &name,
+ QString &field1, QString &field2, QString &field3 )
+{
+ int no = 0;
+ const char *s = gecos;
+ const char *pos = NULL;
+ // At least one part of the string exists
+ for(;;) {
+ pos = strchr(s, ',');
+ QString val;
+ if(pos == NULL)
+ val = QString::fromLocal8Bit(s);
+ else
+ val = QString::fromLocal8Bit(s, (int)(pos-s));
+
+ switch(no) {
+ case 0: name = val; break;
+ case 1: field1 = val; break;
+ case 2: field2 = val; break;
+ case 3: field3 = val; break;
+ }
+ if(pos == NULL) break;
+ s = pos+1;
+ no++;
+ }
+}
+
+void KU::KUsers::fillGecos(KU::KUser *user, const char *gecos)
+{
+ QString name,field1,field2,field3;
+ parseGecos( gecos, name, field1, field2, field3 );
+ user->setFullName( name );
+ caps & Cap_BSD ? user->setOffice( field1 ) : user->setOffice1( field1 );
+ caps & Cap_BSD ? user->setWorkPhone( field2 ) : user->setOffice2( field2 );
+ caps & Cap_BSD ? user->setHomePhone( field3 ) : user->setAddress( field3 );
+}
+
+bool KU::KUsers::doCreate(KU::KUser *user)
+{
+ QString h_dir;
+
+ if(user->getCreateMailBox()) {
+ user->createMailBox();
+ user->setCreateMailBox(false);
+ }
+
+ if(user->getCreateHome()) {
+ if(user->createHome()) {
+ user->setCreateHome(false);
+ } else {
+ return false; // if createHome fails, copySkel is irrelevant!
+ }
+
+ if(user->getCopySkel()) {
+ if((user->copySkel()) == 0) {
+ user->setCopySkel(false);
+ }
+ }
+
+ }
+ return TRUE;
+}
+
+bool KU::KUsers::doDelete( KU::KUser *user )
+{
+ kdDebug() << "delete user: " << user->getName() << " uid: " << user->getUID() << endl;
+ if ( user->isDeleteHome ) {
+ user->removeHome();
+ user->removeCrontabs();
+ }
+ if ( user->isDeleteMailBox )
+ user->removeMailBox();
+/*
+ user->removeProcesses();
+*/
+ return TRUE;
+}
+
+KU::KUser *KU::KUsers::lookup(const QString & name)
+{
+ KU::KUser *user;
+ QPtrListIterator<KU::KUser> it( mUsers );
+
+ while ( (user = it.current()) != 0 && user->getName() != name ) ++it;
+ return user;
+}
+
+KU::KUser *KU::KUsers::lookup(uid_t uid)
+{
+ KU::KUser *user;
+ QPtrListIterator<KU::KUser> it( mUsers );
+
+ while ( (user = it.current()) != 0 && user->getUID() != uid ) ++it;
+ return user;
+}
+
+KU::KUser *KU::KUsers::lookup_sam( const SID &sid )
+{
+ KU::KUser *user;
+ QPtrListIterator<KU::KUser> it( mUsers );
+
+ while ( (user = it.current()) != 0 && user->getSID() != sid ) ++it;
+ return user;
+}
+
+KU::KUser *KU::KUsers::lookup_sam( const QString &sid )
+{
+ KU::KUser *user;
+ QPtrListIterator<KU::KUser> it( mUsers );
+
+ while ( (user = it.current()) != 0 && user->getSID().getSID() != sid ) ++it;
+ return user;
+}
+
+KU::KUser *KU::KUsers::lookup_sam( uint rid )
+{
+ KU::KUser *user;
+ QPtrListIterator<KU::KUser> it( mUsers );
+
+ while ( (user = it.current()) != 0 && user->getSID().getRID() != rid ) ++it;
+ return user;
+}
+
+uid_t KU::KUsers::first_free()
+{
+ uid_t t;
+
+ for (t = mCfg->firstUID() ; t<65534; t++)
+ if (lookup(t) == NULL)
+ return t;
+
+ return NO_FREE;
+}
+
+uint KU::KUsers::first_free_sam()
+{
+ uint t;
+
+ for (t = 1000; t<65534; t++)
+ if (lookup_sam(t) == NULL)
+ return t;
+
+ return 0;
+}
+
+uint KU::KUsers::count() const
+{
+ return mUsers.count();
+}
+
+KU::KUser *KU::KUsers::operator[](uint num)
+{
+ return mUsers.at(num);
+}
+
+KU::KUser *KU::KUsers::first()
+{
+ return mUsers.first();
+}
+
+KU::KUser *KU::KUsers::next()
+{
+ return mUsers.next();
+}
+
+void KU::KUsers::add(KU::KUser *user)
+{
+ mAdd.append( user );
+}
+
+void KU::KUsers::del(KU::KUser *user)
+{
+ mDel.append( user );
+}
+
+void KU::KUsers::mod(KU::KUser *uold, const KU::KUser &unew)
+{
+ mMod.insert( uold, unew );
+}
+
+void KU::KUsers::commit()
+{
+ kdDebug() << "KU::KUsers::commit()" << endl;
+ KU::KUser *user;
+ DelIt dit( mDelSucc );
+ AddIt ait( mAddSucc );
+ ModIt mit = mModSucc.begin();
+
+//commit modifications
+ while ( mit != mModSucc.end() ) {
+ *(mit.key()) = mit.data();
+ mit++;
+ }
+//commit deletes
+ while ( (user = dit.current()) != 0 ) {
+ ++dit;
+ doDelete( user );
+ mUsers.remove( user );
+ }
+//commit additions
+ while ( (user = ait.current()) != 0 ) {
+ ++ait;
+ doCreate( user );
+ mUsers.append( user );
+ }
+
+//clear the unsuccessful modifications
+ cancelMods();
+}
+
+void KU::KUsers::cancelMods()
+{
+ KU::KUser *user;
+ while ( (user = mAdd.first()) ) {
+ delete user;
+ mAdd.remove();
+ }
+ mDel.clear();
+ mMod.clear();
+}
diff --git a/kuser/kuser.desktop b/kuser/kuser.desktop
new file mode 100644
index 0000000..b28b25f
--- /dev/null
+++ b/kuser/kuser.desktop
@@ -0,0 +1,104 @@
+[Desktop Entry]
+Name=KUser
+Name[af]=Kuser
+Name[ar]=برنامج KUser
+Name[bn]=কে-ব্যবহারকারী
+Name[eo]=Uzantoadministrilo
+Name[fo]=KNýtari
+Name[hi]=के-यूज़र
+Name[is]=KNotandi
+Name[lv]=KLietotājs
+Name[mn]=КДЕ Хэрэглэгч
+Name[nb]=KBruker
+Name[ne]=केडीई प्रयोगकर्ता
+Name[pa]=ਕੇ-ਉਪਭੋਗਤਾ
+Name[pl]=Użytkownicy
+Name[ro]=Manager de utilizatori
+Name[sv]=Kuser
+Name[ta]=கேபயனீட்டாளர்
+Name[tg]=KИстифодакунанда
+Name[th]=จัดการบัญชีผู้ใช้ - K
+Name[uz]=Foydalanuvchilar
+Name[uz@cyrillic]=Фойдаланувчилар
+GenericName=User Manager
+GenericName[af]=Gebruiker Bestuurder
+GenericName[ar]=مسيير المستخدمين
+GenericName[az]=İstifadəçi İdarəçisi
+GenericName[be]=Кіраванне карыстальнікамі
+GenericName[bg]=Управление на потребителите
+GenericName[bn]=ব্যবহারকারী ম্যানেজার
+GenericName[br]=Merour an arveriaded
+GenericName[bs]=Upravljanje korisnicima
+GenericName[ca]=Gestor d'usuaris
+GenericName[cs]=Správce uživatelů
+GenericName[cy]=Rheolydd Defnyddwyr
+GenericName[da]=Brugerhåndtering
+GenericName[de]=Benutzerverwaltung
+GenericName[el]=Διαχειριστής χρηστών
+GenericName[eo]=Administrilo por la uzantoj de la komputilo
+GenericName[es]=Administrador de usuarios
+GenericName[et]=Kasutajate haldamine
+GenericName[eu]=Erabiltzaile kudeatzailea
+GenericName[fa]=مدیر کاربر
+GenericName[fi]=Käyttäjienhallinta
+GenericName[fo]=Nýtarahandfarari
+GenericName[fr]=Gestionnaire d'utilisateurs
+GenericName[ga]=Bainisteoir Úsáideora
+GenericName[gl]=Xestor de Usuários
+GenericName[he]=מנהל משתמשים
+GenericName[hi]=उपयोक्ता प्रबंधक
+GenericName[hr]=Upravljanje korisnicima
+GenericName[hu]=Felhasználókezelő
+GenericName[is]=Notandastjóri
+GenericName[it]=Gestore utenti
+GenericName[ja]=ユーザマネージャ
+GenericName[ka]=მომხმარებელთა მმართველი
+GenericName[kk]=Пайдаланушылар менеджерx
+GenericName[km]=កម្មវិធី​គ្រប់គ្រង​អ្នក​ប្រើ
+GenericName[ko]=사용자 관리자
+GenericName[lt]=Naudotojų tvarkyklė
+GenericName[lv]=Lietotāju Menedžeris
+GenericName[mk]=Менаџер на корисници
+GenericName[mn]=Хэрэглэгч Зохицуулагч
+GenericName[ms]=Pengurus Pengguna
+GenericName[mt]=Manager tal-users
+GenericName[nb]=Brukerbehandler
+GenericName[nds]=Bruker-Pleger
+GenericName[ne]=प्रयोगकर्ता प्रबन्धक
+GenericName[nl]=Gebruikersbeheerder
+GenericName[nn]=Brukarhandsamar
+GenericName[pa]=ਉਪਭੋਗਤਾ ਪਰਬੰਧਕ
+GenericName[pl]=Menedżer użytkowników
+GenericName[pt]=Gestor de Utilizadores
+GenericName[pt_BR]=Gerenciador de Usuários
+GenericName[ro]=Manager de utilizatori
+GenericName[ru]=Управление пользователями
+GenericName[se]=Geavaheaddjiid gieđahalli
+GenericName[sk]=Správca užívateľov
+GenericName[sl]=Upravljalnik uporabnikov
+GenericName[sr]=Менаџер корисника
+GenericName[sr@Latn]=Menadžer korisnika
+GenericName[sv]=Användarhanterare
+GenericName[ta]=பயனீட்டாளர் மேலாளர்
+GenericName[tg]=Роҳбари Истифодакунанда
+GenericName[th]=เครื่องมือจัดการบัญชีผู้ใช้
+GenericName[tr]=Kullanıcı Yöneticisi
+GenericName[uk]=Менеджер користувачів
+GenericName[uz]=Foydalanuvchilar boshqaruvchisi
+GenericName[uz@cyrillic]=Фойдаланувчилар бошқарувчиси
+GenericName[ven]=Murangaphanda wa Mushumisi
+GenericName[vi]=Bộ quản lý người dùng
+GenericName[wa]=Manaedjeu d' uzeus
+GenericName[xh]=Umphathi We Calendar
+GenericName[zh_CN]=用户管理程序
+GenericName[zh_HK]=用戶管理員
+GenericName[zh_TW]=使用者管理程式
+GenericName[zu]=Umphathi we Calendar
+Exec=kuser %i %m -caption "%c"
+Icon=kuser
+Type=Application
+DocPath=kuser/index.html
+Terminal=false
+X-KDE-StartupNotify=true
+X-KDE-SubstituteUID=true
+Categories=Qt;KDE;System;
diff --git a/kuser/kuser.h b/kuser/kuser.h
new file mode 100644
index 0000000..4e3c24e
--- /dev/null
+++ b/kuser/kuser.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_USER_H_
+#define _KU_USER_H_
+
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include "globals.h"
+#include "sid.h"
+
+namespace KU {
+
+class KUsers;
+
+class KUser {
+public:
+ enum Cap {
+ Cap_POSIX = 1,
+ Cap_Samba = 2
+ };
+ KUser();
+ KUser(const KUser *user);
+ ~KUser();
+
+ void copy(const KUser *user);
+ void setCaps( int data );
+ int getCaps();
+
+//General
+ const QString &getName() const;
+ const QString &getSurname() const;
+ const QString &getEmail() const;
+ const QString &getPwd() const;
+ const QString &getHomeDir() const;
+ const QString &getShell() const;
+ const QString &getFullName() const;
+
+ uid_t getUID() const;
+ uid_t getGID() const;
+ bool getDisabled() const;
+
+ void setName(const QString &data);
+ void setSurname(const QString &data);
+ void setEmail(const QString &data);
+ void setPwd(const QString &data);
+ void setHomeDir(const QString &data);
+ void setShell(const QString &data);
+ void setFullName(const QString &data);
+
+ void setUID(uid_t data);
+ void setGID(uid_t data);
+ void setDisabled(bool data);
+
+//gecos
+//--BSD gecos
+ const QString &getOffice() const;
+ const QString &getWorkPhone() const;
+ const QString &getHomePhone() const;
+ const QString &getClass() const;
+//--BSD end
+ const QString &getOffice1() const;
+ const QString &getOffice2() const;
+ const QString &getAddress() const;
+
+//--BSD
+ void setOffice(const QString &data);
+ void setWorkPhone(const QString &data);
+ void setHomePhone(const QString &data);
+ void setClass(const QString &data);
+//--BSD end
+ void setOffice1(const QString &data);
+ void setOffice2(const QString &data);
+ void setAddress(const QString &data);
+
+//shadow
+ const QString &getSPwd() const;
+ time_t getExpire() const;
+ time_t getLastChange() const;
+ int getMin() const;
+ int getMax() const;
+ int getWarn() const;
+ int getInactive() const;
+ int getFlag() const;
+
+ void setSPwd(const QString &data);
+ void setLastChange(time_t data);
+ void setMin(int data);
+ void setMax(int data);
+ void setWarn(int data);
+ void setInactive(int data);
+ void setExpire(time_t data);
+ void setFlag(int data);
+
+//samba
+ const QString &getLMPwd() const; // sam_lmpwd,
+ const QString &getNTPwd() const; //sam_ntpwd,
+ const QString &getLoginScript() const; //sam_loginscript,
+ const QString &getProfilePath() const; // sam_profile,
+ const QString &getHomeDrive() const; //sam_homedrive,
+ const QString &getHomePath() const; //sam_homepath;
+ const QString &getWorkstations() const; //sam_workstations
+ const QString &getDomain() const; //sam_domain
+ const SID &getSID() const; //sid,
+ const SID &getPGSID() const; //pgroup_sid;
+
+ void setLMPwd( const QString &data ); // sam_lmpwd,
+ void setNTPwd( const QString &data ); //sam_ntpwd,
+ void setLoginScript( const QString &data ); //sam_loginscript,
+ void setProfilePath( const QString &data); // sam_profile,
+ void setHomeDrive( const QString &data ); //sam_homedrive,
+ void setHomePath( const QString &data ); //sam_homepath;
+ void setWorkstations( const QString &data ); //sam_workstations
+ void setDomain( const QString &data ); //sam_domain
+ void setSID( const SID &data ); //sid,
+ void setPGSID( const SID &data ); //pgroup_sid;
+
+//Administrative
+ bool getCreateHome();
+ bool getCreateMailBox();
+ bool getCopySkel();
+ bool getDeleteHome();
+ bool getDeleteMailBox();
+
+ void setCreateHome(bool data);
+ void setCreateMailBox(bool data);
+ void setCopySkel(bool data);
+ void setDeleteHome(bool data);
+ void setDeleteMailBox(bool data);
+
+protected:
+ friend class KUsers;
+
+ int createHome();
+ int tryCreate(const QString &dir);
+ int createMailBox();
+ int copySkel();
+
+ int removeHome();
+ int removeCrontabs();
+ int removeMailBox();
+ int removeProcesses();
+
+ void copyDir(const QString &srcPath, const QString &dstPath);
+
+ int caps;
+ QString
+ p_name, // parsed pw information
+ p_surname,
+ p_email,
+ p_pwd,
+ p_dir,
+ p_shell,
+ p_fname, // parsed comment information
+ p_office1,
+ p_office2,
+ p_address,
+//BSD
+ p_office,
+ p_ophone,
+ p_hphone,
+ p_class;
+ time_t
+ p_change,
+ p_expire;
+//BSD end
+ uid_t p_uid;
+ gid_t p_gid;
+
+ QString
+ s_pwd, // parsed shadow password
+ sam_lmpwd,
+ sam_ntpwd,
+ sam_loginscript,
+ sam_profile,
+ sam_homedrive,
+ sam_homepath,
+ sam_workstations,
+ sam_domain;
+ SID
+ sid,
+ pgroup_sid;
+ signed int
+ s_min, // days until pwchange allowed.
+ s_max, // days before change required
+ s_warn, // days warning for expiration
+ s_inact, // days before account inactive
+ s_flag; // reserved for future use
+ bool
+ isDisabled, // account disabled?
+ isCreateHome, // create homedir
+ isCreateMailBox, // create mailbox
+ isCopySkel, // copy skeleton
+ isDeleteHome, // delete home dir
+ isDeleteMailBox; // delete mailbox
+};
+
+class KUsers {
+public:
+ enum Cap {
+ Cap_ReadOnly = 1,
+ Cap_Passwd = 2,
+ Cap_Shadow = 4,
+ Cap_InetOrg = 8,
+ Cap_Samba = 16,
+ Cap_Disable_POSIX = 32,
+ Cap_BSD = 64
+ };
+ typedef QPtrListIterator<KUser> DelIt;
+ typedef QPtrListIterator<KUser> AddIt;
+ typedef QMapIterator<KUser*, KUser> ModIt;
+
+ QPtrList<KUser> mDelSucc;
+ QPtrList<KUser> mAddSucc;
+ QMap<KUser*, KUser> mModSucc;
+
+ KUsers(KUserPrefsBase *cfg);
+ virtual ~KUsers();
+ KUser *lookup(const QString & name);
+ KUser *lookup(uid_t uid);
+ KUser *lookup_sam( const SID &sid );
+ KUser *lookup_sam( const QString &sid );
+ KUser *lookup_sam( uint rid );
+
+ int getCaps() { return caps; }
+ const QString &getDOMSID() const;
+
+ KUser *first();
+ KUser *next();
+ uint count() const;
+ KUser *operator[](uint num);
+
+ void add( KUser *user );
+ void del( KUser *user );
+ void mod( KUser *uold, const KUser &unew );
+ void commit();
+ void cancelMods();
+
+ enum {
+ NO_FREE = (uid_t) -1
+ };
+
+ /**
+ * May be reimplemented in descendant classes.
+ * It should return the first available UID, or KUsers::NO_FREE if no more UID.
+ */
+ virtual uid_t first_free();
+ /**
+ * May be reimplemented in descendant classes.
+ * It should return the first available user RID, or 0 if no more RID.
+ */
+ virtual uint first_free_sam();
+ /**
+ * Must be reimplemented in various backends. It should encode @param password
+ * into the appropriate fields in @param user.
+ */
+ virtual void createPassword( KUser *user, const QString &password ) = 0;
+ /**
+ * Must load the users from the storage backend.
+ */
+ virtual bool reload() = 0;
+ /**
+ * Must write changes (in mDel, mAdd and mMod) to the storage backend. It must
+ * write successful modifications into mDelSucc, mAddSucc and mModSucc.
+ */
+ virtual bool dbcommit() = 0;
+
+protected:
+ QPtrList<KUser> mUsers;
+ int caps;
+ KUserPrefsBase *mCfg;
+
+ QPtrList<KUser> mDel;
+ QPtrList<KUser> mAdd;
+ QMap<KUser*, KUser> mMod;
+
+ QString domsid;
+
+ bool doCreate( KUser *user );
+ bool doDelete( KUser *user );
+ void parseGecos( const char *gecos, QString &name,
+ QString &field1, QString &field2, QString &field3 );
+ void fillGecos( KUser *user, const char *gecos );
+
+};
+
+} //namespace KU
+
+#endif // _KU_USER_H_
diff --git a/kuser/kuser.kcfg b/kuser/kuser.kcfg
new file mode 100644
index 0000000..a1ec974
--- /dev/null
+++ b/kuser/kuser.kcfg
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>qfile.h</include>
+ <include>kapplication.h</include>
+ <include>config.h</include>
+
+ <kcfgfile arg="true">
+ <parameter name="connection"/>
+ </kcfgfile>
+
+ <group name="general">
+ <entry name="connection" type="String">
+ <label>Default connection</label>
+ <default>default</default>
+ </entry>
+ <entry name="showsys" type="Bool">
+ <label>Show system users</label>
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="connection-$(connection)">
+ <entry name="source" type="Enum">
+ <label>The source of the user and group database</label>
+ <whatsthis>This option allows you to select where the user/group data stored. Currently three storage backends are supported. &lt;BR&gt;&lt;B&gt;Files&lt;/B&gt; stores user/group data in traditional /etc/passwd and /etc/group flat files. &lt;BR&gt;&lt;B&gt;LDAP&lt;/B&gt; stores data in a directory server using the posixAccount and posixGroup object classes; this backend allows the management of Samba users/groups via the sambaSamAccount object class.&lt;BR&gt;&lt;B&gt;System&lt;/B&gt; provides a read-only access to all users and groups which your installation knows about.</whatsthis>
+ <choices>
+ <choice name="Files"/>
+ <choice name="LDAP"/>
+ <choice name="System"/>
+ </choices>
+ <default>Files</default>
+ </entry>
+ <entry name="shell" type="String">
+ <label>Shell</label>
+ <whatsthis>This option allows you to select the shell which will be the default for new users.</whatsthis>
+ </entry>
+ <entry name="homepath" type="String">
+ <label>Home path template</label>
+ <whatsthis>This option specifies the UNIX home path template for new users. The '%U' macro will replaced with the actual user name.</whatsthis>
+ <default code="true">QFile::decodeName(KU_HOMETEMPLATE)</default>
+ </entry>
+ <entry name="firstUID" type="Int">
+ <label>First UID</label>
+ <whatsthis>This options specifies the first user ID where searching for an available UID starts.</whatsthis>
+ <default code="true">KU_FIRSTUID</default>
+ </entry>
+ <entry name="firstGID" type="Int">
+ <label>First GID</label>
+ <whatsthis>This options specifies the first group ID where searching for an available GID starts.</whatsthis>
+ <default code="true">KU_FIRSTGID</default>
+ </entry>
+ <entry name="createHomeDir" type="Bool">
+ <label>Create home folder</label>
+ <whatsthis>If this option is checked then a home directory will created for the new user.</whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="copySkel" type="Bool">
+ <label>Copy skeleton to home folder</label>
+ <whatsthis>If this option is checked then the contents of the skeleton folder will copied to the new user's home directory</whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="userPrivateGroup" type="Bool">
+ <label>User private groups</label>
+ <whatsthis>If this option is enabled, new user creation will create a private group named as the user, and the primary group of the user will assigned to this private group.</whatsthis>
+ <default code="true">KU_USERPRIVATEGROUP</default>
+ </entry>
+ <entry name="defaultgroup" type="Int">
+ <label>Default primary group</label>
+ <whatsthis>This is the default primary group which will be assigned to a newly created user.</whatsthis>
+ <default>100</default>
+ </entry>
+
+ <entry name="smin" type="Int">
+ <label>smin</label>
+ <default>0</default>
+ </entry>
+ <entry name="smax" type="Int">
+ <label>smax</label>
+ <default>-1</default>
+ </entry>
+ <entry name="swarn" type="Int">
+ <label>swarn</label>
+ <default>-1</default>
+ </entry>
+ <entry name="sinact" type="Int">
+ <label>sinact</label>
+ <default>-1</default>
+ </entry>
+ <entry name="sexpire" type="DateTime">
+ <label>sexpire</label>
+ <whatsthis>This setting is for specifying a date when user accounts will expire.</whatsthis>
+ <default code="true">QDateTime(QDate(1970,1,1))</default>
+ </entry>
+ <entry name="sneverexpire" type="Bool">
+ <label>sneverexpire</label>
+ <whatsthis>Check this if you want to user accounts never expire.</whatsthis>
+ <default>true</default>
+ </entry>
+
+ <entry name="passwdsrc" type="String">
+ <label>Password file</label>
+ <whatsthis>This specifies the users database file (usually /etc/passwd).</whatsthis>
+ <default>/etc/passwd</default>
+ </entry>
+ <entry name="groupsrc" type="String">
+ <label>Group file</label>
+ <whatsthis>This specifies the groups database file (usually /etc/group).</whatsthis>
+ <default>/etc/group</default>
+ </entry>
+ <entry name="md5shadow" type="Bool">
+ <label>MD5 Shadow passwords</label>
+ <whatsthis>Check this if you want the passwords in the shadow file MD5 hashed. Leave this unchecked if DES encryption should be used.</whatsthis>
+ </entry>
+ <entry name="shadowsrc" type="String">
+ <label>Shadow password file</label>
+ <whatsthis>Specifies the shadow password file (usually /etc/shadow). Leave this empty if your system does not use a shadow password file.</whatsthis>
+ <default>/etc/shadow</default>
+ </entry>
+ <entry name="gshadowsrc" type="String">
+ <label>Group shadow file</label>
+ <whatsthis>Specifies the shadow group file (usually /etc/gshadow). Leave this empty if your system does not use a shadow group file.</whatsthis>
+ <default>/etc/gshadow</default>
+ </entry>
+ <entry name="nispasswdsrc" type="String">
+ <label>NIS password source</label>
+ </entry>
+ <entry name="nisminuid" type="Int">
+ <label>NIS minimum UID</label>
+ </entry>
+ <entry name="nisgroupsrc" type="String">
+ <label>NIS group source</label>
+ </entry>
+ <entry name="nismingid" type="Int">
+ <label>NIS minimum GID</label>
+ </entry>
+
+ <entry name="ldapuser" type="String">
+ <label>LDAP User</label>
+ </entry>
+ <entry name="ldappassword" type="Password">
+ <label>LDAP Password</label>
+ </entry>
+ <entry name="ldaprealm" type="String">
+ <label>LDAP SASL Realm</label>
+ </entry>
+ <entry name="ldapbinddn" type="String">
+ <label>LDAP Bind DN</label>
+ </entry>
+ <entry name="ldaphost" type="String">
+ <label>LDAP Host</label>
+ </entry>
+ <entry name="ldapport" type="Int">
+ <label>LDAP Port</label>
+ <default>389</default>
+ </entry>
+ <entry name="ldapver" type="Int">
+ <label>LDAP version</label>
+ <default>3</default>
+ </entry>
+ <entry name="ldapsizelimit" type="Int">
+ <label>LDAP Size limit</label>
+ <default>0</default>
+ </entry>
+ <entry name="ldaptimelimit" type="Int">
+ <label>LDAP Time limit</label>
+ <default>0</default>
+ </entry>
+ <entry name="ldapdn" type="String">
+ <label>LDAP Base DN</label>
+ </entry>
+ <entry name="ldapfilter" type="String">
+ <label>LDAP Filter</label>
+ </entry>
+ <entry name="ldapnosec" type="Bool">
+ <label>LDAP no encryption</label>
+ <default>false</default>
+ </entry>
+ <entry name="ldaptls" type="Bool">
+ <label>LDAP TLS</label>
+ <default>true</default>
+ </entry>
+ <entry name="ldapssl" type="Bool">
+ <label>LDAP SSL</label>
+ <default>false</default>
+ </entry>
+ <entry name="ldapanon" type="Bool">
+ <label>LDAP Anonymous</label>
+ <default>false</default>
+ </entry>
+ <entry name="ldapsimple" type="Bool">
+ <label>LDAP Simple auth</label>
+ <default>true</default>
+ </entry>
+ <entry name="ldapsasl" type="Bool">
+ <label>LDAP SASL auth</label>
+ <default>false</default>
+ </entry>
+ <entry name="ldapsaslmech" type="String">
+ <label>LDAP SASL mechanism</label>
+ <default>LOGIN</default>
+ </entry>
+ <entry name="ldapuserbase" type="String">
+ <label>LDAP User container</label>
+ <whatsthis>This specifies where to store users' entries relative to the LDAP base DN.</whatsthis>
+ <default>ou=People</default>
+ </entry>
+ <entry name="ldapuserfilter" type="String">
+ <label>LDAP User filter</label>
+ <whatsthis>This specifies the filter used for user entries.</whatsthis>
+ </entry>
+ <entry name="ldapgroupbase" type="String">
+ <label>LDAP Group container</label>
+ <whatsthis>This specifies where to store groups' entries relative to the LDAP base DN.</whatsthis>
+ <default>ou=Group</default>
+ </entry>
+ <entry name="ldapgroupfilter" type="String">
+ <label>LDAP Group filter</label>
+ <whatsthis>This specifies the filter used for group entries.</whatsthis>
+ </entry>
+ <entry name="ldapuserrdn" type="Enum">
+ <label>LDAP User RDN prefix</label>
+ <whatsthis>This specifies what prefix will used for user entries.</whatsthis>
+ <choices>
+ <choice name="uid"/>
+ <choice name="uidNumber"/>
+ <choice name="cn"/>
+ </choices>
+ <default>uid</default>
+ </entry>
+ <entry name="ldapcnfullname" type="Bool">
+ <label>Store the user's full name in the cn attribute</label>
+ <whatsthis>Check this if the user's full name should be stored in the cn (Canonical Name) attribute.</whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="ldapgecos" type="Bool">
+ <label>Update the gecos field</label>
+ <whatsthis>Check this if the gecos attribute should be updated.</whatsthis>
+ <default>false</default>
+ </entry>
+ <entry name="ldapshadow" type="Bool">
+ <label>Manage LDAP shadowAccount objectclass</label>
+ <whatsthis>Check this if the shadowAccount object should be used in the users' entries. It allows to enforce password change/expiration policies.</whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="ldapstructural" type="Enum">
+ <label>LDAP Structural objectclass</label>
+ <whatsthis>This option allows to specify the structural objectclass used with users' entries. If you want to use these entries not just for authentication, but for an addressbook, too, then choose inetOrgPerson.</whatsthis>
+ <choices>
+ <choice name="account"/>
+ <choice name="inetOrgPerson"/>
+ </choices>
+ <default>account</default>
+ </entry>
+ <entry name="ldapgrouprdn" type="Enum">
+ <label>LDAP Group RDN prefix</label>
+ <whatsthis>This specifies what prefix will used for group entries.</whatsthis>
+ <choices>
+ <choice name="cn"/>
+ <choice name="gidNumber"/>
+ </choices>
+ <default>cn</default>
+ </entry>
+ <entry name="ldappasswordhash" type="Enum">
+ <label>LDAP Password hash method</label>
+ <whatsthis>This specifies the password hashing method. The most secure is SSHA.</whatsthis>
+ <choices>
+ <choice name="Clear"/>
+ <choice name="CRYPT"/>
+ <choice name="MD5"/>
+ <choice name="SMD5"/>
+ <choice name="SHA"/>
+ <choice name="SSHA"/>
+ </choices>
+ <default>SSHA</default>
+ </entry>
+ <entry name="ldapsam" type="Bool">
+ <label>Enable samba account management</label>
+ <whatsthis>Check this if you want to use the user/group entries in a Samba domain. KUser will create sambaSamAccount objectclass for each entry which is usable with the ldapsam passdb backend with Samba version greater than 3.0.</whatsthis>
+ </entry>
+ <entry name="samdomain" type="String">
+ <label>Samba domain name</label>
+ <whatsthis>This specifies the samba domain name.</whatsthis>
+ </entry>
+ <entry name="samdomsid" type="String">
+ <label>Samba domain SID</label>
+ <whatsthis>This specifies the domain Security IDentifier. It is unique in a single domain. You can query the value of the domain SID with 'net getlocalsid domain_name'.</whatsthis>
+ </entry>
+ <entry name="samridbase" type="Int">
+ <label>Algorithmic RID base</label>
+ <whatsthis>This value is an offset for the algorithmic mapping from uids and gids to rids. The default (and minimum) value is 1000, it must be even, and the LDAP database and smb.conf must store the same values.</whatsthis>
+ <default>1000</default>
+ </entry>
+ <entry name="samloginscript" type="String">
+ <label>Samba login script</label>
+ <whatsthis>This specifies a name of a login script (in the `Netlogon` share) which will be executed as the user logs in to a Windows machine.</whatsthis>
+ </entry>
+ <entry name="samhomedrive" type="String">
+ <label>Samba home drive</label>
+ <whatsthis>Specifies a drive letter where the user's home directory will automatically mapped when he/she logs into a Windows machine.</whatsthis>
+ </entry>
+ <entry name="samprofilepath" type="String">
+ <label>Samba profile path template</label>
+ <whatsthis>This specifies the location of the roaming profile of the user. The '%U' macro will be replaced with the actual user name.</whatsthis>
+ </entry>
+ <entry name="samhomepath" type="String">
+ <label>Samba home path template</label>
+ <whatsthis>This specifies the location of the home directory of the user. This field is meaningful only for Windows machines. The '%U' macro will be replaced with the actual user name.</whatsthis>
+ </entry>
+ <entry name="lanmanhash" type="Bool">
+ <label>Store LanManager hashed password</label>
+ <whatsthis>Store the LanManager hashed password in the sambaLMPassword attribute. Check this if you have older clients (Win9x series and before) on your network.</whatsthis>
+ <default>false</default>
+ </entry>
+
+ </group>
+</kcfg>
diff --git a/kuser/kuserfiles.cpp b/kuser/kuserfiles.cpp
new file mode 100644
index 0000000..5c987bc
--- /dev/null
+++ b/kuser/kuserfiles.cpp
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "globals.h"
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SHADOW
+#include <shadow.h>
+#endif
+
+#include <qstring.h>
+#include <qdir.h>
+
+#include "kglobal_.h"
+#include "kuserfiles.h"
+#include "misc.h"
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include "editDefaults.h"
+
+KUserFiles::KUserFiles(KUserPrefsBase *cfg) : KUsers( cfg )
+{
+ pw_backuped = FALSE;
+ pn_backuped = FALSE;
+ s_backuped = FALSE;
+
+ pwd_mode = 0644;
+ pwd_uid = 0;
+ pwd_gid = 0;
+
+ sdw_mode = 0600;
+ sdw_uid = 0;
+ sdw_gid = 0;
+
+ mUsers.setAutoDelete(TRUE);
+
+ caps = Cap_Passwd;
+#ifdef HAVE_SHADOW
+ if ( !mCfg->shadowsrc().isEmpty() ) caps |= Cap_Shadow;
+#endif
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ caps |= Cap_BSD;
+#endif
+
+ reload();
+}
+
+KUserFiles::~KUserFiles()
+{
+}
+
+bool KUserFiles::reload() {
+ if (!loadpwd())
+ return FALSE;
+
+ if (!loadsdw())
+ return FALSE;
+
+ return TRUE;
+}
+
+// Load passwd file
+
+bool KUserFiles::loadpwd()
+{
+ passwd *p;
+ KU::KUser *tmpKU = 0;
+ struct stat st;
+ QString filename;
+ QString passwd_filename;
+ QString nispasswd_filename;
+ int rc = 0;
+ int passwd_errno = 0;
+ int nispasswd_errno = 0;
+ char processing_file = '\0';
+ #define P_PASSWD 0x01
+ #define P_NISPASSWD 0x02
+ #define MAXFILES 2
+
+ // Read KUser configuration
+
+ passwd_filename = mCfg->passwdsrc();
+ nispasswd_filename = mCfg->nispasswdsrc();
+
+ // Handle unconfigured environments
+
+ if(passwd_filename.isEmpty() && nispasswd_filename.isEmpty()) {
+ mCfg->setPasswdsrc( PASSWORD_FILE );
+ mCfg->setGroupsrc( GROUP_FILE );
+ passwd_filename = mCfg->passwdsrc();
+ KMessageBox::error( 0, i18n("KUser sources were not configured.\nLocal passwd source set to %1\nLocal group source set to %2.").arg(mCfg->passwdsrc().arg(mCfg->groupsrc())) );
+ }
+
+ if(!passwd_filename.isEmpty()) {
+ processing_file = processing_file | P_PASSWD;
+ filename.append(passwd_filename);
+ }
+
+ // Start reading passwd file(s)
+
+ for(int i = 0; i < MAXFILES; i++) {
+ rc = stat(QFile::encodeName(filename), &st);
+ if(rc != 0) {
+ KMessageBox::error( 0, i18n("Stat call on file %1 failed: %2\nCheck KUser settings.").arg(filename).arg(QString::fromLocal8Bit(strerror(errno))) );
+ if( (processing_file & P_PASSWD) != 0 ) {
+ passwd_errno = errno;
+ if(!nispasswd_filename.isEmpty()) {
+ processing_file = processing_file & ~P_PASSWD;
+ processing_file = processing_file | P_NISPASSWD;
+ filename.truncate(0);
+ filename.append(nispasswd_filename);
+ }
+ continue;
+ }
+ else{
+ nispasswd_errno = errno;
+ break;
+ }
+ }
+
+ pwd_mode = st.st_mode & 0666;
+ pwd_uid = st.st_uid;
+ pwd_gid = st.st_gid;
+
+ // We are reading our configuration specified passwd file
+ QString tmp;
+
+#ifdef HAVE_FGETPWENT
+ FILE *fpwd = fopen(QFile::encodeName(filename), "r");
+ if(fpwd == NULL) {
+ KMessageBox::error( 0, i18n("Error opening %1 for reading.").arg(filename) );
+ return FALSE;
+ }
+
+ while ((p = fgetpwent(fpwd)) != NULL) {
+#else
+ setpwent(); //This should be enough for BSDs
+ while ((p = getpwent()) != NULL) {
+#endif
+ tmpKU = new KU::KUser();
+ tmpKU->setCaps( KU::KUser::Cap_POSIX );
+ tmpKU->setUID(p->pw_uid);
+ tmpKU->setGID(p->pw_gid);
+ tmpKU->setName(QString::fromLocal8Bit(p->pw_name));
+ tmp = QString::fromLocal8Bit( p->pw_passwd );
+ if ( tmp != "x" && tmp != "*" && !tmp.startsWith("!") )
+ tmpKU->setDisabled( false );
+ else
+ tmpKU->setDisabled( true );
+ if ( tmp.startsWith("!") ) tmp.remove(0, 1);
+ tmpKU->setPwd( tmp );
+ tmpKU->setHomeDir(QString::fromLocal8Bit(p->pw_dir));
+ tmpKU->setShell(QString::fromLocal8Bit(p->pw_shell));
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ tmpKU->setClass(QString::fromLatin1(p->pw_class));
+ tmpKU->setLastChange(p->pw_change);
+ tmpKU->setExpire(p->pw_expire);
+#endif
+
+ if ((p->pw_gecos != 0) && (p->pw_gecos[0] != 0))
+ fillGecos(tmpKU, p->pw_gecos);
+ mUsers.append(tmpKU);
+ }
+
+ // End reading passwd_filename
+
+#ifdef HAVE_FGETPWENT
+ fclose(fpwd);
+#else
+ endpwent();
+#endif
+ if((!nispasswd_filename.isEmpty()) && (nispasswd_filename != passwd_filename)) {
+ processing_file = processing_file & ~P_PASSWD;
+ processing_file = processing_file | P_NISPASSWD;
+ filename.truncate(0);
+ filename.append(nispasswd_filename);
+ }
+ else
+ break;
+
+ } // end of processing files, for loop
+
+ if( (passwd_errno == 0) && (nispasswd_errno == 0) )
+ return (TRUE);
+ if( (passwd_errno != 0) && (nispasswd_errno != 0) )
+ return (FALSE);
+ else
+ return(TRUE);
+}
+
+// Load shadow passwords
+
+bool KUserFiles::loadsdw()
+{
+#ifdef HAVE_SHADOW
+ QString shadow_file,tmp;
+ struct spwd *spw;
+ KU::KUser *up = NULL;
+ struct stat st;
+
+ shadow_file = mCfg->shadowsrc();
+ if ( shadow_file.isEmpty() )
+ return TRUE;
+
+ stat( QFile::encodeName(shadow_file), &st);
+ sdw_mode = st.st_mode & 0666;
+ sdw_uid = st.st_uid;
+ sdw_gid = st.st_gid;
+
+#ifdef HAVE_FGETSPENT
+ FILE *f;
+ kdDebug() << "open shadow file: " << shadow_file << endl;
+ if ((f = fopen( QFile::encodeName(shadow_file), "r")) == NULL) {
+ KMessageBox::error( 0, i18n("Error opening %1 for reading.").arg(shadow_file) );
+ caps &= ~Cap_Shadow;
+ return TRUE;
+ }
+ while ((spw = fgetspent( f ))) { // read a shadow password structure
+#else
+ setspent();
+ while ((spw = getspent())) { // read a shadow password structure
+#endif
+
+ kdDebug() << "shadow entry: " << spw->sp_namp << endl;
+ if ((up = lookup(QString::fromLocal8Bit(spw->sp_namp))) == NULL) {
+ KMessageBox::error( 0, i18n("No /etc/passwd entry for %1.\nEntry will be removed at the next `Save'-operation.").arg(QString::fromLocal8Bit(spw->sp_namp)) );
+ continue;
+ }
+
+ tmp = QString::fromLocal8Bit( spw->sp_pwdp );
+ if ( tmp.startsWith("!!") || tmp == "*" ) {
+ up->setDisabled( true );
+ tmp.remove( 0, 2 );
+ } else
+ up->setDisabled( false );
+
+ up->setSPwd( tmp ); // cp the encrypted pwd
+ up->setLastChange( daysToTime( spw->sp_lstchg ) );
+ up->setMin(spw->sp_min);
+ up->setMax(spw->sp_max);
+#ifndef _SCO_DS
+ up->setWarn(spw->sp_warn);
+ up->setInactive(spw->sp_inact);
+ up->setExpire( daysToTime( spw->sp_expire ) );
+ up->setFlag(spw->sp_flag);
+#endif
+ }
+
+#ifdef HAVE_FGETSPENT
+ fclose(f);
+#else
+ endspent();
+#endif
+
+#endif // HAVE_SHADOW
+ return TRUE;
+}
+
+// Save password file
+
+#define escstr(a,b) tmp2 = user->a(); \
+ tmp2.replace(':',"_"); \
+ tmp2.replace(',',"_"); \
+ user->b( tmp2 );
+
+
+bool KUserFiles::savepwd()
+{
+ FILE *passwd_fd = NULL;
+ FILE *nispasswd_fd = NULL;
+ uid_t minuid = 0;
+ int nis_users_written = 0;
+ uid_t tmp_uid = 0;
+ QString s;
+ QString s1;
+ QString tmp, tmp2;
+ QString passwd_filename;
+ QString nispasswd_filename;
+
+
+ char errors_found = '\0';
+ #define NOMINUID 0x01
+ #define NONISPASSWD 0x02
+
+ // Read KUser configuration info
+
+ passwd_filename = mCfg->passwdsrc();
+ nispasswd_filename = mCfg->nispasswdsrc();
+ QString new_passwd_filename =
+ passwd_filename + QString::fromLatin1(KU_CREATE_EXT);
+ QString new_nispasswd_filename =
+ nispasswd_filename+QString::fromLatin1(KU_CREATE_EXT);
+
+ if( nispasswd_filename != passwd_filename ) {
+ minuid = mCfg->nisminuid();
+ }
+
+ // Backup file(s)
+
+ if(!passwd_filename.isEmpty()) {
+ if (!pw_backuped) {
+ if (!backup(passwd_filename)) return FALSE;
+ pw_backuped = TRUE;
+ }
+ }
+ if(!nispasswd_filename.isEmpty() &&
+ (nispasswd_filename != passwd_filename)) {
+ if (!pn_backuped) {
+ if (!backup(nispasswd_filename)) return FALSE;
+ pn_backuped = TRUE;
+ }
+ }
+
+ // Open file(s)
+
+ if(!passwd_filename.isEmpty()) {
+ if ((passwd_fd =
+ fopen(QFile::encodeName(new_passwd_filename),"w")) == NULL)
+ KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(passwd_filename) );
+ }
+
+ if(!nispasswd_filename.isEmpty() && (nispasswd_filename != passwd_filename)){
+ if ((nispasswd_fd =
+ fopen(QFile::encodeName(new_nispasswd_filename),"w")) == NULL)
+ KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(nispasswd_filename) );
+ }
+
+ QPtrListIterator<KU::KUser> it( mUsers );
+ KU::KUser *user;
+ bool addok = false;
+ user = (*it);
+ while (true) {
+ if ( user == 0 ) {
+ if ( addok ) break;
+ it = QPtrListIterator<KU::KUser> ( mAdd );
+ user = (*it);
+ addok = true;
+ if ( user == 0 ) break;
+ };
+ if ( mDel.containsRef( user ) ) {
+ ++it;
+ user = (*it);
+ continue;
+ }
+ if ( mMod.contains( user ) ) user = &( mMod[ user ] );
+
+ tmp_uid = user->getUID();
+ if ( caps & Cap_Shadow )
+ tmp = "x";
+ else {
+ tmp = user->getPwd();
+ if ( user->getDisabled() && tmp != "x" && tmp != "*" )
+ tmp = "!" + tmp;
+ }
+
+ escstr( getName, setName );
+ escstr( getHomeDir, setHomeDir );
+ escstr( getShell, setShell );
+ escstr( getName, setName );
+ escstr( getFullName, setFullName );
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ escstr( getClass, setClass );
+ escstr( getOffice, setOffice );
+ escstr( getWorkPhone, setWorkPhone );
+ escstr( getHomePhone, setHomePhone );
+ s =
+ user->getName() + ":" +
+ tmp + ":" +
+ QString::number( user->getUID() ) + ":" +
+ QString::number( user->getGID() ) + ":" +
+ user->getClass() + ":" +
+ QString::number( user->getLastChange() ) + ":" +
+ QString::number( user->getExpire() ) + ":";
+
+ s1 =
+ user->getFullName() + "," +
+ user->getOffice() + "," +
+ user->getWorkPhone() + "," +
+ user->getHomePhone();
+#else
+ escstr( getOffice1, setOffice1 );
+ escstr( getOffice2, setOffice2 );
+ escstr( getAddress, setAddress );
+ s =
+ user->getName() + ":" +
+ tmp + ":" +
+ QString::number( user->getUID() ) + ":" +
+ QString::number( user->getGID() ) + ":";
+
+ s1 =
+ user->getFullName() + "," +
+ user->getOffice1() + "," +
+ user->getOffice2() + "," +
+ user->getAddress();
+
+#endif
+ for (int j=(s1.length()-1); j>=0; j--) {
+ if (s1[j] != ',')
+ break;
+ s1.truncate(j);
+ }
+
+ s += s1 + ":" +
+ user->getHomeDir() + ":" +
+ user->getShell() + "\n";
+
+ if( (nispasswd_fd != 0) && (minuid != 0) ) {
+ if (minuid <= tmp_uid) {
+ fputs(s.local8Bit().data(), nispasswd_fd);
+ nis_users_written++;
+ ++it;
+ user = (*it);
+ continue;
+ }
+ }
+
+ if( (nispasswd_fd != 0) && (minuid == 0) ) {
+ errors_found = errors_found | NOMINUID;
+ }
+
+ if( (nispasswd_fd == 0) && (minuid != 0) ) {
+ errors_found = errors_found | NONISPASSWD;
+ }
+ kdDebug() << s << endl;
+ fputs(s.local8Bit().data(), passwd_fd);
+
+ ++it;
+ user = (*it);
+ }
+
+ if(passwd_fd) {
+ fclose(passwd_fd);
+ chmod(QFile::encodeName(new_passwd_filename), pwd_mode);
+ chown(QFile::encodeName(new_passwd_filename), pwd_uid, pwd_gid);
+ rename(QFile::encodeName(new_passwd_filename),
+ QFile::encodeName(passwd_filename));
+ }
+
+ if(nispasswd_fd) {
+ fclose(nispasswd_fd);
+ chmod(QFile::encodeName(new_nispasswd_filename), pwd_mode);
+ chown(QFile::encodeName(new_nispasswd_filename), pwd_uid, pwd_gid);
+ rename(QFile::encodeName(new_nispasswd_filename),
+ QFile::encodeName(nispasswd_filename));
+ }
+
+ if( (errors_found & NOMINUID) != 0 ) {
+ KMessageBox::error( 0, i18n("Unable to process NIS passwd file without a minimum UID specified.\nPlease update KUser settings (Files).") );
+ }
+
+ if( (errors_found & NONISPASSWD) != 0 ) {
+ KMessageBox::error( 0, i18n("Specifying NIS minimum UID requires NIS file(s).\nPlease update KUser settings (Files).") );
+ }
+
+ // need to run a utility program to build /etc/passwd, /etc/pwd.db
+ // and /etc/spwd.db from /etc/master.passwd
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ if (system(PWMKDB) != 0) {
+ KMessageBox::error( 0, i18n("Unable to build password database.") );
+ return FALSE;
+ }
+#else
+ if( (nis_users_written > 0) || (nispasswd_filename == passwd_filename) ) {
+ if (system(PWMKDB) != 0) {
+ KMessageBox::error( 0, i18n("Unable to build password databases.") );
+ return FALSE;
+ }
+ }
+#endif
+
+ return TRUE;
+}
+
+#undef escstr
+
+// Save shadow passwords file
+
+bool KUserFiles::savesdw()
+{
+#ifdef HAVE_SHADOW
+ bool addok = false;
+ QString tmp;
+ FILE *f;
+ struct spwd *spwp;
+ struct spwd s;
+ KU::KUser *up;
+ QString shadow_file = mCfg->shadowsrc();
+ QString new_shadow_file = shadow_file+QString::fromLatin1(KU_CREATE_EXT);
+
+ if ( shadow_file.isEmpty() )
+ return TRUE;
+
+ if (!s_backuped) {
+ if (!backup(shadow_file)) return FALSE;
+ s_backuped = TRUE;
+ }
+
+ if ((f = fopen(QFile::encodeName(new_shadow_file), "w")) == NULL) {
+ KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(new_shadow_file) );
+ return FALSE;
+ }
+
+ s.sp_namp = (char *)malloc(200);
+ s.sp_pwdp = (char *)malloc(200);
+
+ QPtrListIterator<KU::KUser> it( mUsers );
+ up = (*it);
+ while (true) {
+
+ if ( up == 0 ) {
+ if ( addok ) break;
+ it = QPtrListIterator<KU::KUser> ( mAdd );
+ up = (*it);
+ addok = true;
+ if ( up == 0 ) break;
+ };
+
+ if ( mDel.containsRef( up ) ) {
+ ++it;
+ up = (*it);
+ continue;
+ }
+ if ( mMod.contains( up ) ) up = &( mMod[ up ] );
+
+ strncpy( s.sp_namp, up->getName().local8Bit(), 200 );
+ if ( up->getDisabled() )
+ strncpy( s.sp_pwdp, QString("!!" + up->getSPwd()).local8Bit(), 200 );
+ else
+ strncpy( s.sp_pwdp, up->getSPwd().local8Bit(), 200 );
+
+ s.sp_lstchg = timeToDays( up->getLastChange() );
+ s.sp_min = up->getMin();
+ s.sp_max = up->getMax();
+#ifndef _SCO_DS
+ s.sp_warn = up->getWarn();
+ s.sp_inact = up->getInactive();
+ s.sp_expire = timeToDays( up->getExpire() );
+ s.sp_flag = up->getFlag();
+#endif
+ spwp = &s;
+ putspent(spwp, f);
+
+ ++it;
+ up = (*it);
+ }
+ fclose(f);
+
+ chmod(QFile::encodeName(new_shadow_file), sdw_mode);
+ chown(QFile::encodeName(new_shadow_file), sdw_uid, sdw_gid);
+ rename(QFile::encodeName(new_shadow_file),
+ QFile::encodeName(shadow_file));
+
+ free(s.sp_namp);
+ free(s.sp_pwdp);
+#endif // HAVE_SHADOW
+ return TRUE;
+}
+
+
+void KUserFiles::createPassword( KU::KUser *user, const QString &password )
+{
+ if ( caps & Cap_Shadow ) {
+ user->setSPwd( encryptPass( password, mCfg->md5shadow() ) );
+ user->setPwd( QString::fromLatin1("x") );
+ } else
+ user->setPwd( encryptPass( password, false ) );
+}
+
+bool KUserFiles::dbcommit()
+{
+ bool ret;
+ mode_t mode;
+
+ mAddSucc.clear();
+ mDelSucc.clear();
+ mModSucc.clear();
+ if ( mDel.isEmpty() && mAdd.isEmpty() && mMod.isEmpty() )
+ return true;
+
+ mode = umask(0077);
+ ret = savepwd();
+ if ( ret && ( caps & Cap_Shadow ) ) ret = savesdw();
+ umask( mode );
+ if ( !ret ) return false;
+
+ mDelSucc = mDel;
+ mAddSucc = mAdd;
+ mModSucc = mMod;
+ mDel.clear();
+ mAdd.clear();
+ mMod.clear();
+ return TRUE;
+}
diff --git a/kuser/kuserfiles.h b/kuser/kuserfiles.h
new file mode 100644
index 0000000..bb19c45
--- /dev/null
+++ b/kuser/kuserfiles.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KUSERFILES_H_
+#define _KUSERFILES_H_
+
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include "kuser.h"
+
+class KUserFiles : public KU::KUsers {
+public:
+ KUserFiles(KUserPrefsBase *cfg);
+ virtual ~KUserFiles();
+
+ virtual bool dbcommit();
+ virtual bool reload();
+ virtual void createPassword( KU::KUser *user, const QString &password );
+
+private:
+ bool pw_backuped;
+ bool pn_backuped;
+ bool s_backuped;
+
+ mode_t pwd_mode;
+ mode_t sdw_mode;
+
+ uid_t pwd_uid;
+ gid_t pwd_gid;
+
+ uid_t sdw_uid;
+ gid_t sdw_gid;
+
+ bool loadpwd();
+ bool loadsdw();
+
+ bool savepwd();
+ bool savesdw();
+};
+#endif // _KUSERFILES_H_
+
diff --git a/kuser/kuserldap.cpp b/kuser/kuserldap.cpp
new file mode 100644
index 0000000..9eb6afe
--- /dev/null
+++ b/kuser/kuserldap.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ *
+ * This mProgram is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kmessagebox.h>
+#include <kio/kntlm.h>
+
+#include "kglobal_.h"
+#include "kuserldap.h"
+#include "misc.h"
+#include "sha1.h"
+
+#include "kuserldap.moc"
+
+KUserLDAP::KUserLDAP(KUserPrefsBase *cfg) : KU::KUsers( cfg )
+{
+ schemaversion = 0;
+
+ if ( mCfg->ldapssl() )
+ mUrl.setProtocol("ldaps");
+ else
+ mUrl.setProtocol("ldap");
+
+ mUrl.setHost( mCfg->ldaphost() );
+ mUrl.setPort( mCfg->ldapport() );
+ mUrl.setDn( mCfg->ldapuserbase() + "," + mCfg->ldapdn() );
+ if ( !mCfg->ldapanon() ) {
+ mUrl.setUser( mCfg->ldapuser() );
+ mUrl.setPass( mCfg->ldappassword() );
+ }
+ mUrl.setFilter( mCfg->ldapuserfilter() );
+
+ if ( mCfg->ldaptls() ) mUrl.setExtension( "x-tls", "" );
+ if ( mCfg->ldapsasl() ) {
+ mUrl.setExtension( "x-sasl", "" );
+ mUrl.setExtension( "x-mech", mCfg->ldapsaslmech() );
+ }
+
+ mUrl.setScope(KABC::LDAPUrl::One);
+ mUrl.setExtension("x-dir","base");
+
+ caps = Cap_Passwd | Cap_Disable_POSIX;
+ if ( mCfg->ldapshadow() ) caps |= Cap_Shadow;
+ if ( mCfg->ldapstructural() ==
+ KUserPrefsBase::EnumLdapstructural::inetOrgPerson )
+ caps |= Cap_InetOrg;
+
+ if ( mCfg->ldapsam() ) {
+ caps |= Cap_Samba;
+ domsid = mCfg->samdomsid();
+ }
+
+ reload();
+}
+
+KUserLDAP::~KUserLDAP()
+{
+ mUsers.clear();
+}
+
+void KUserLDAP::result( KIO::Job *job )
+{
+ delete mProg;
+ mCancel = false;
+ if ( job->error() ) {
+ QString errstr = job->errorString();
+ if ( !errstr.isEmpty() ) {
+ if ( ldif.isEmpty() )
+ KMessageBox::error( 0, errstr );
+ else
+ KMessageBox::detailedError( 0, errstr, QString::fromUtf8( ldif, ldif.size()-1 ) );
+ }
+ mOk = false;
+ } else {
+ mOk = true;
+ }
+}
+
+void KUserLDAP::data( KIO::Job *, const QByteArray& data )
+{
+ if ( data.size() ) {
+ mParser.setLDIF( data );
+ } else {
+ mParser.endLDIF();
+ }
+
+ KABC::LDIF::ParseVal ret;
+ QString name, val;
+ QByteArray value;
+ do {
+ ret = mParser.nextItem();
+ switch ( ret ) {
+ case KABC::LDIF::Item:
+ name = mParser.attr().lower();
+ value = mParser.val();
+ val = QString::fromUtf8( value, value.size() );
+ if ( name == "objectclass" ) {
+ if ( val.lower() == "posixaccount" )
+ mUser->setCaps( mUser->getCaps() | KU::KUser::Cap_POSIX );
+ else if ( val.lower() == "sambasamaccount" )
+ mUser->setCaps( mUser->getCaps() | KU::KUser::Cap_Samba );
+ else if ( val.lower() != "inetorgperson" &&
+ val.lower() != "shadowaccount" &&
+ val.lower() != "account" )
+ mOc.append( val );
+
+ } else if ( name == "uidnumber" )
+ mUser->setUID( val.toLong() );
+ else if ( name == "gidnumber" )
+ mUser->setGID( val.toLong() );
+ else if ( name == "uid" || name == "userid" )
+ mUser->setName( val );
+ else if ( name == "sn" )
+ mUser->setSurname( val );
+ else if ( name == "mail" )
+ mUser->setEmail( val );
+ else if ( name == "homedirectory" )
+ mUser->setHomeDir( val );
+ else if ( name == "loginshell" )
+ mUser->setShell( val );
+ else if ( name == "postaladdress" )
+ mUser->setAddress( val );
+ else if ( name == "telephonenumber" ) {
+ if ( mUser->getOffice1().isEmpty() )
+ mUser->setOffice1( val );
+ else
+ mUser->setOffice2( val );
+ } else if ( name == "gecos" ) {
+ QString name, f1, f2, f3;
+ parseGecos( QCString( value.data(), value.size()+1 ), name, f1, f2, f3 );
+ if ( mUser->getFullName().isEmpty() ) mUser->setFullName( val );
+ if ( mUser->getOffice1().isEmpty() ) mUser->setOffice1( f1 );
+ if ( mUser->getOffice2().isEmpty() ) mUser->setOffice2( f1 );
+ if ( mUser->getAddress().isEmpty() ) mUser->setAddress( f1 );
+ } else if ( name == "cn" ) {
+ if ( mUser->getFullName().isEmpty() || mCfg->ldapcnfullname() )
+ mUser->setFullName( val );
+ if ( mUser->getName().isEmpty() )
+ mUser->setName( val );
+ } else if ( name == "displayname" ) {
+ mUser->setFullName( val );
+ } else if ( name == "userpassword" ) {
+ if ( !val.isEmpty() ) mUser->setDisabled( false );
+ mUser->setPwd( val );
+ } else if ( name == "shadowlastchange" ) {
+ if ( mUser->getLastChange() == 0 ) //sambapwdlastset is more precise
+ mUser->setLastChange( daysToTime( val.toLong() ) );
+ } else if ( name == "shadowmin" )
+ mUser->setMin( val.toInt() );
+ else if ( name == "shadowmax" )
+ mUser->setMax( val.toLong() );
+ else if ( name == "shadowwarning" )
+ mUser->setWarn( val.toLong() );
+ else if ( name == "shadowinactive" )
+ mUser->setInactive( val.toLong() );
+ else if ( name == "shadowexpire" )
+ mUser->setExpire( val.toLong() );
+ else if ( name == "shadowflag" )
+ mUser->setFlag( val.toLong() );
+ else if ( name == "sambaacctflags" ) {
+ if ( !val.contains( 'D' ) ) mUser->setDisabled( false );
+ } else if ( name == "sambasid" )
+ mUser->setSID( val );
+ else if ( name == "sambaprimarygroupsid" )
+ mUser->setPGSID( val );
+ else if ( name == "sambalmpassword" )
+ mUser->setLMPwd( val );
+ else if ( name == "sambantpassword" )
+ mUser->setNTPwd( val );
+ else if ( name == "sambahomepath" )
+ mUser->setHomePath( val );
+ else if ( name == "sambahomedrive" )
+ mUser->setHomeDrive( val );
+ else if ( name == "sambalogonscript" )
+ mUser->setLoginScript( val );
+ else if ( name == "sambaprofilepath" )
+ mUser->setProfilePath( val );
+ else if ( name == "sambauserworkstations" )
+ mUser->setWorkstations( val );
+ else if ( name == "sambadomainname" )
+ mUser->setDomain( val );
+ else if ( name == "sambapwdlastset" )
+ mUser->setLastChange( val.toLong() );
+ //these new attributes introduced around samba 3.0.6
+ else if ( name == "sambapasswordhistory" || name == "sambalogonhours" )
+ schemaversion = 1;
+ break;
+ case KABC::LDIF::EndEntry: {
+ KU::KUser emptyUser, *newUser;
+ kdDebug() << "new user: " << mUser->getName() << endl;
+ newUser = new KU::KUser( mUser );
+ mUsers.append( newUser );
+ if ( !mOc.isEmpty() ) {
+ mObjectClasses.insert( newUser, mOc );
+ kdDebug() << "user: " << newUser->getName() << " other objectclasses: " << mOc.join(",") << endl;
+ }
+ mOc.clear();
+ mUser->copy( &emptyUser );
+ mUser->setDisabled( true );
+
+ if ( ( mUsers.count() & 7 ) == 7 ) {
+ mProg->progressBar()->advance( mAdv );
+ if ( mProg->progressBar()->progress() == 0 ) mAdv = 1;
+ if ( mProg->progressBar()->progress() == mProg->progressBar()->totalSteps()-1 ) mAdv = -1;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+ } while ( ret != KABC::LDIF::MoreData );
+}
+
+bool KUserLDAP::reload()
+{
+ kdDebug() << "kuserldap::reload()" << endl;
+ mObjectClasses.clear();
+ mOc.clear();
+ mUser = new KU::KUser();
+ mUser->setPwd( "" );
+ mUser->setSPwd( "" );
+ mParser.startParsing();
+ mCancel = true;
+ mProg = new KProgressDialog( 0, "", "", i18n("Loading Users From LDAP"), true );
+ mProg->setAutoClose( false );
+ mProg->progressBar()->setFormat("");
+ mProg->progressBar()->setTotalSteps( 100 );
+ mAdv = 1;
+ ldif = "";
+
+ KIO::Job *job = KIO::get( mUrl, true, false );
+ connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
+ this, SLOT( data( KIO::Job*, const QByteArray& ) ) );
+ connect( job, SIGNAL( result( KIO::Job* ) ),
+ this, SLOT( result( KIO::Job* ) ) );
+// job->addMetaData( "SERVER_CTRL0", "1.2.840.113556.1.4.473 true: uidNumber");
+ mProg->exec();
+ if ( mCancel ) job->kill();
+ delete mUser;
+ return( mOk );
+}
+
+QString KUserLDAP::getRDN(KU::KUser *user)
+{
+ switch ( mCfg->ldapuserrdn() ) {
+ case KUserPrefsBase::EnumLdapuserrdn::uid:
+ return "uid=" + user->getName();
+ case KUserPrefsBase::EnumLdapuserrdn::uidNumber:
+ return "uidNumber=" + QString::number( user->getUID() );
+ case KUserPrefsBase::EnumLdapuserrdn::cn: {
+ QString cn = mCfg->ldapcnfullname() ? user->getFullName() : user->getName();
+ if ( cn.isEmpty() ) cn = user->getName();
+ return "cn=" + cn;
+ }
+ }
+ return "";
+}
+
+void KUserLDAP::createPassword( KU::KUser *user, const QString &password )
+{
+ switch ( mCfg->ldappasswordhash() ) {
+ case KUserPrefsBase::EnumLdappasswordhash::Clear:
+ user->setPwd( password );
+ break;
+ case KUserPrefsBase::EnumLdappasswordhash::CRYPT:
+ user->setPwd( "{CRYPT}" + encryptPass( password, false ) );
+ break;
+ case KUserPrefsBase::EnumLdappasswordhash::MD5: {
+ KMD5 md5( password.utf8() );
+ user->setPwd( "{MD5}" + md5.base64Digest() );
+ break;
+ }
+ case KUserPrefsBase::EnumLdappasswordhash::SMD5: {
+ QCString salt = genSalt( 4 );
+ QCString pwd = password.utf8() + salt;
+ KMD5::Digest digest;
+ QByteArray hash(20);
+
+ KMD5 md5( pwd );
+ md5.rawDigest( digest );
+ memcpy( hash.data(), digest, 16 );
+ memcpy( &(hash.data()[16]), salt.data(), 4 );
+ user->setPwd( "{SMD5}" + KCodecs::base64Encode( hash ) );
+ break;
+ }
+ case KUserPrefsBase::EnumLdappasswordhash::SHA: {
+ struct sha1_ctx ctx;
+ QByteArray hash(20);
+
+ sha1_init( &ctx );
+ sha1_update( &ctx, (const Q_UINT8*) password.utf8().data(),
+ password.utf8().length() );
+ sha1_final( &ctx, (Q_UINT8*) hash.data() );
+ user->setPwd( "{SHA}" + KCodecs::base64Encode( ( hash ) ) );
+ break;
+ }
+ case KUserPrefsBase::EnumLdappasswordhash::SSHA: {
+ struct sha1_ctx ctx;
+ QByteArray hash(24);
+ QCString salt = genSalt( 4 );
+ QCString pwd = password.utf8() + salt;
+
+ sha1_init( &ctx );
+ sha1_update( &ctx, (const Q_UINT8*) pwd.data(), pwd.length() );
+ sha1_final( &ctx, (Q_UINT8*) hash.data() );
+ memcpy( &(hash.data()[ 20 ]), salt.data(), 4 );
+ user->setPwd( "{SSHA}" + KCodecs::base64Encode( ( hash ) ) );
+ break;
+ }
+ }
+
+ if ( caps & Cap_Samba ) {
+ Q_UINT8 hex[33];
+
+ QByteArray ntlmhash;
+ ntlmhash = KNTLM::ntlmHash( password );
+ unsigned char *hash = (unsigned char*) ntlmhash.data();
+
+ snprintf( (char*) &hex, 33,
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ hash[0], hash[1], hash[2], hash[3], hash[4], hash[5],
+ hash[6], hash[7], hash[8], hash[9], hash[10], hash[11],
+ hash[12], hash[13], hash[14], hash[15]);
+
+ user->setNTPwd( QString::fromLatin1( (const char*) &hex, 32 ) );
+
+ if ( mCfg->lanmanhash() ) {
+
+ QByteArray lmhash;
+ lmhash = KNTLM::lmHash( password );
+ unsigned char *hash = (unsigned char*) lmhash.data();
+ snprintf( (char*) &hex, 33,
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ hash[0], hash[1], hash[2], hash[3], hash[4], hash[5],
+ hash[6], hash[7], hash[8], hash[9], hash[10], hash[11],
+ hash[12], hash[13], hash[14], hash[15]);
+
+ user->setLMPwd( QString::fromLatin1( (const char*) &hex, 32 ) );
+ } else {
+ user->setLMPwd( "" );
+ }
+ }
+}
+
+void KUserLDAP::getLDIF( KU::KUser *user, bool mod )
+{
+ QString gecos, cn, pwd, samflags;
+ ldif.resize( 0 );
+
+ pwd = user->getPwd();
+ if ( user->getDisabled() ) pwd = "";
+
+ cn = mCfg->ldapcnfullname() ? user->getFullName() : user->getName();
+ if ( cn.isEmpty() ) cn = user->getName();
+
+ gecos = QString::fromLatin1("%1,%2,%3,%4")
+ .arg(user->getFullName())
+ .arg(user->getOffice1())
+ .arg(user->getOffice2())
+ .arg(user->getAddress());
+
+ samflags = "[U";
+ samflags += user->getDisabled() ? 'D' : ' ';
+ samflags += " ]";
+
+ ldif = "";
+
+ if ( mod ) {
+ QString oldrdn = getRDN( mUser );
+ QString newrdn = getRDN( user );
+
+ if ( oldrdn != newrdn ) {
+ ldif = "dn: " + oldrdn.utf8() + "," + mUrl.dn().utf8() + "\n" +
+ "changetype: modrdn\n" +
+ "newrdn: " + newrdn.utf8() + "\n" +
+ "deleteoldrdn: 1\n\n";
+ }
+ }
+
+ ldif += "dn: " + getRDN( user ).utf8() + "," + mUrl.dn().utf8() + "\n";
+ if ( mod ) {
+ ldif += "changetype: modify\n";
+ ldif += "replace: objectClass\n";
+ }
+
+ if ( caps & Cap_InetOrg )
+ ldif += "objectClass: inetOrgPerson\n";
+ else
+ ldif += "objectClass: account\n";
+
+ if ( user->getCaps() & KU::KUser::Cap_POSIX ) {
+ ldif += "objectClass: posixAccount\n";
+ }
+ if ( ( caps & Cap_Shadow ) && ( user->getCaps() & KU::KUser::Cap_POSIX ) ) {
+ ldif += "objectClass: shadowAccount\n";
+ }
+ if ( ( caps & Cap_Samba ) && ( user->getCaps() & KU::KUser::Cap_Samba ) ) {
+ ldif += "objectClass: sambaSamAccount\n";
+ }
+ if ( mod && mObjectClasses.contains( mUser ) ) {
+ QStringList ocs = mObjectClasses[ mUser ];
+ kdDebug() << user->getName() << " has additional objectclasses: " << ocs.join(",") << endl;
+ QValueListIterator<QString> it;
+ for ( it = ocs.begin(); it != ocs.end(); ++it ) {
+ ldif += "objectClass: ";
+ ldif += (*it).utf8();
+ ldif += "\n";
+ }
+ }
+
+ if ( mod ) ldif += "-\nreplace: cn\n";
+ ldif += KABC::LDIF::assembleLine( "cn", cn )+"\n";
+ if ( caps & Cap_InetOrg ) {
+ if ( mod ) ldif += "-\nreplace: uid\n";
+ ldif += KABC::LDIF::assembleLine( "uid", user->getName() ) + "\n";
+ } else {
+ if ( mod ) ldif += "-\nreplace: userid\n";
+ ldif += KABC::LDIF::assembleLine( "userid", user->getName() ) + "\n";
+ }
+ if ( mod ) ldif += "-\n";
+
+ if ( ( user->getCaps() & KU::KUser::Cap_POSIX ) || ( caps & Cap_InetOrg ) ) {
+ if ( mod ) ldif += "replace: userpassword\n";
+ ldif += KABC::LDIF::assembleLine( "userpassword", pwd )+"\n";
+ if ( mod ) ldif += "-\n";
+ }
+
+ if ( user->getCaps() & KU::KUser::Cap_POSIX ) {
+ if ( mod ) ldif += "replace: uidnumber\n";
+ ldif += KABC::LDIF::assembleLine( "uidnumber",
+ QString::number( user->getUID() ) )+"\n";
+ if ( mod ) ldif += "-\nreplace: gidnumber\n";
+ ldif += KABC::LDIF::assembleLine( "gidnumber",
+ QString::number( user->getGID() ) )+"\n";
+ if ( mod ) ldif += "-\nreplace: gecos\n";
+ ldif += KABC::LDIF::assembleLine( "gecos", !mCfg->ldapgecos() ? QCString() :
+ QCString( gecos.latin1() ) )+"\n";
+ if ( mod ) ldif += "-\nreplace: homedirectory\n";
+ ldif += KABC::LDIF::assembleLine( "homedirectory",
+ user->getHomeDir() )+"\n";
+ if ( mod ) ldif += "-\nreplace: loginshell\n";
+ ldif += KABC::LDIF::assembleLine( "loginshell",
+ user->getShell() )+"\n";
+ if ( mod ) ldif += "-\n";
+ } else {
+ if ( mod ) {
+ ldif += "replace: uidnumber\n";
+ ldif += "-\nreplace: gidnumber\n";
+ ldif += "-\nreplace: homedirectory\n";
+ ldif += "-\nreplace: loginshell\n";
+ ldif += "-\nreplace: gecos\n";
+ ldif += "-\n";
+ }
+ }
+
+ if ( caps & Cap_InetOrg ) {
+ if ( mod ) ldif += "replace: sn\n";
+ ldif += KABC::LDIF::assembleLine( "sn", user->getSurname() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: mail\n";
+ ldif += KABC::LDIF::assembleLine( "mail", user->getEmail() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: displayName\n";
+ ldif += KABC::LDIF::assembleLine( "displayname", user->getFullName() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: postaladdress\n";
+ ldif += KABC::LDIF::assembleLine( "postaladdress", user->getAddress() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: telephoneNumber\n";
+ ldif += KABC::LDIF::assembleLine( "telephoneNumber", user->getOffice1() ) + "\n";
+ ldif += KABC::LDIF::assembleLine( "telephoneNumber", user->getOffice2() ) + "\n";
+ if ( mod ) ldif += "-\n";
+ }
+
+ if ( caps & Cap_Samba ) {
+ if ( user->getCaps() & KU::KUser::Cap_Samba ) {
+ if ( mod ) ldif += "replace: sambadomainname\n";
+ ldif += KABC::LDIF::assembleLine( "sambadomainname", user->getDomain() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambauserworkstations\n";
+ ldif += KABC::LDIF::assembleLine( "sambauserworkstations", user->getWorkstations() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambahomepath\n";
+ ldif += KABC::LDIF::assembleLine( "sambahomepath", user->getHomePath() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambahomedrive\n";
+ ldif += KABC::LDIF::assembleLine( "sambahomedrive", user->getHomeDrive() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambalogonscript\n";
+ ldif += KABC::LDIF::assembleLine( "sambalogonscript", user->getLoginScript() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambaprofilepath\n";
+ ldif += KABC::LDIF::assembleLine( "sambaprofilepath", user->getProfilePath() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambalmpassword\n";
+ ldif += KABC::LDIF::assembleLine( "sambalmpassword", user->getLMPwd() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambantpassword\n";
+ ldif += KABC::LDIF::assembleLine( "sambantpassword", user->getNTPwd() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambasid\n";
+ ldif += KABC::LDIF::assembleLine( "sambasid", user->getSID().getSID() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambaacctflags\n";
+ ldif += KABC::LDIF::assembleLine( "sambaacctflags", samflags ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambaprimarygroupsid\n";
+ ldif += KABC::LDIF::assembleLine( "sambaprimarygroupsid",
+ user->getPGSID().getSID() ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambapwdlastset\n";
+ ldif += KABC::LDIF::assembleLine( "sambapwdlastset",
+ QString::number( user->getLastChange() ) ) + "\n";
+ if ( mod ) ldif += "-\nreplace: sambakickofftime\n";
+ if ( user->getExpire() != -1 ) ldif +=
+ KABC::LDIF::assembleLine( "sambakickofftime",
+ QString::number( user->getExpire() ) ) + "\n";
+ if ( mod ) ldif += "-\n";
+ } else {
+ if ( mod ) {
+ ldif += "replace: sambahomepath\n";
+ ldif += "-\nreplace: sambahomedrive\n";
+ ldif += "-\nreplace: sambalogonscript\n";
+ ldif += "-\nreplace: sambaprofilepath\n";
+ ldif += "-\nreplace: sambalmpassword\n";
+ ldif += "-\nreplace: sambantpassword\n";
+ ldif += "-\nreplace: sambasid\n";
+ ldif += "-\nreplace: sambaacctflags\n";
+ ldif += "-\nreplace: sambaprimarygroupsid\n";
+ ldif += "-\nreplace: sambapwdlastset\n";
+ ldif += "-\nreplace: sambakickofftime\n";
+ ldif += "-\nreplace: sambalogontime\n";
+ ldif += "-\nreplace: sambalogofftime\n";
+ ldif += "-\nreplace: sambapwdcanchange\n";
+ ldif += "-\nreplace: sambapwdmustchange\n";
+ ldif += "-\nreplace: sambauserworkstations\n";
+ ldif += "-\nreplace: sambadomainname\n";
+ ldif += "-\nreplace: sambamungeddial\n";
+ ldif += "-\nreplace: sambabadpasswordcount\n";
+ ldif += "-\nreplace: sambabadpasswordtime\n";
+ ldif += "-\nreplace: sambadomainname\n";
+ if ( schemaversion > 0 ) {
+ ldif += "-\nreplace: sambapasswordhistory\n";
+ ldif += "-\nreplace: sambalogonhours\n";
+ }
+ ldif += "-\n";
+ }
+ }
+ }
+
+ if ( caps & Cap_Shadow ) {
+ if ( user->getCaps() & KU::KUser::Cap_POSIX ) {
+ if ( mod ) ldif += "replace: shadowlastchange\n"; //sambapwdlastset
+ ldif += KABC::LDIF::assembleLine( "shadowlastchange",
+ QString::number( timeToDays( user->getLastChange() ) ) ) + "\n";
+ if ( mod ) ldif += "-\nreplace: shadowmin\n"; //sambaPwdCanChange
+ ldif += KABC::LDIF::assembleLine( "shadowmin",
+ QString::number( user->getMin() ) ) + "\n";
+ if ( mod ) ldif += "-\nreplace: shadowmax\n"; //sambaPwdMustChange
+ ldif += KABC::LDIF::assembleLine( "shadowmax",
+ QString::number( user->getMax() ) ) + "\n";
+ if ( mod ) ldif += "-\nreplace: shadowwarning\n";
+ ldif += KABC::LDIF::assembleLine( "shadowwarning",
+ QString::number( user->getWarn() ) ) + "\n";
+ if ( mod ) ldif += "-\nreplace: shadowinactive\n";
+ ldif += KABC::LDIF::assembleLine( "shadowinactive",
+ QString::number( user->getInactive() ) ) + "\n";
+ if ( mod ) ldif += "-\nreplace: shadowexpire\n"; //sambaKickoffTime
+ ldif += KABC::LDIF::assembleLine( "shadowexpire",
+ QString::number( timeToDays( user->getExpire() ) ) ) + "\n";
+ if ( mod ) ldif += "-\nreplace: shadowflag\n";
+ ldif += KABC::LDIF::assembleLine( "shadowflag",
+ QString::number( user->getFlag() ) ) + "\n";
+ if ( mod ) ldif += "-\n";
+ } else {
+ if ( mod ) {
+ ldif += "replace: shadowlastchange\n";
+ ldif += "-\nreplace: shadowmin\n";
+ ldif += "-\nreplace: shadowmax\n";
+ ldif += "-\nreplace: shadowwarning\n";
+ ldif += "-\nreplace: shadowinactive\n";
+ ldif += "-\nreplace: shadowexpire\n";
+ ldif += "-\nreplace: shadowflag\n";
+ ldif += "-\n";
+ }
+ }
+ }
+ ldif += "\n";
+// kdDebug() << "ldif: " << ldif << endl;
+}
+
+void KUserLDAP::delData( KU::KUser *user )
+{
+ ldif = "dn: " + getRDN( user ).utf8() + "," + mUrl.dn().utf8() + "\n" +
+ "changetype: delete\n\n";
+}
+
+bool KUserLDAP::dbcommit()
+{
+ mAddSucc.clear();
+ mDelSucc.clear();
+ mModSucc.clear();
+ mAdd.first();
+ mDel.first();
+ mAddUser = 0; mDelUser = 0; mUser = 0;
+
+ mProg = new KProgressDialog( 0, "", i18n("LDAP Operation"), "", true );
+ KIO::Job *job = KIO::put( mUrl, -1, false, false, false );
+ connect( job, SIGNAL( dataReq( KIO::Job*, QByteArray& ) ),
+ this, SLOT( putData( KIO::Job*, QByteArray& ) ) );
+ connect( job, SIGNAL( result( KIO::Job* ) ),
+ this, SLOT( result( KIO::Job* ) ) );
+ mProg->exec();
+ return( mOk );
+}
+
+void KUserLDAP::putData( KIO::Job *, QByteArray& data )
+{
+ ModIt mit = mMod.begin();
+
+ if ( mAddUser ) {
+ mAddSucc.append( mAddUser );
+ mAdd.remove();
+ mAddUser = 0;
+ }
+ if ( mDelUser ) {
+ kdDebug() << "delete ok for: " << mDelUser->getName() << endl;
+ mDelSucc.append( mDelUser );
+ if ( mObjectClasses.contains( mDelUser ) ) {
+ kdDebug() << "deleting additonal objectclasses!" << endl;
+ mObjectClasses.remove( mDelUser );
+ }
+ mDel.remove();
+ mDelUser = 0;
+ }
+ if ( mUser ) {
+ mModSucc.insert( mUser, mit.data() );
+ mMod.remove( mit );
+ mit = mMod.begin();
+ mUser = 0;
+ }
+
+ if ( (mAddUser = mAdd.current()) ) {
+ getLDIF( mAddUser, false );
+ data = ldif;
+ } else if ( mit != mMod.end() ) {
+ mUser = mit.key();
+ getLDIF( &(mit.data()), true );
+ data = ldif;
+ } else if ( (mDelUser = mDel.current()) ) {
+ kdDebug() << "deleting: " << mDelUser->getName() << endl;
+ delData( mDelUser );
+ data = ldif;
+ } else
+ data.resize(0);
+}
diff --git a/kuser/kuserldap.h b/kuser/kuserldap.h
new file mode 100644
index 0000000..8d921c1
--- /dev/null
+++ b/kuser/kuserldap.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KUSERLDAP_H_
+#define _KUSERLDAP_H_
+
+#include <sys/types.h>
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include <kprogress.h>
+#include <kabc/ldapurl.h>
+#include <kabc/ldif.h>
+#include <kio/job.h>
+
+#include "kuser.h"
+
+class KUserLDAP : public QObject, public KU::KUsers {
+Q_OBJECT
+public:
+ KUserLDAP(KUserPrefsBase *cfg);
+ virtual ~KUserLDAP();
+
+ virtual bool reload();
+ virtual bool dbcommit();
+
+private slots:
+ void data( KIO::Job*, const QByteArray& );
+ void putData( KIO::Job *job, QByteArray& data );
+ void result( KIO::Job* );
+private:
+ KABC::LDIF mParser;
+ KABC::LDAPUrl mUrl;
+ KProgressDialog *mProg;
+ bool mOk, mCancel;
+ KU::KUser *mUser, *mDelUser, *mAddUser;
+ int mAdv;
+ QCString ldif;
+ int schemaversion;
+ QStringList mOc;
+ QMap<KU::KUser*, QStringList> mObjectClasses;
+
+ QString getRDN( KU::KUser *user );
+ void getLDIF( KU::KUser *user, bool mod );
+ void delData( KU::KUser *user );
+
+ virtual void createPassword( KU::KUser *user, const QString &password );
+};
+
+#endif // _KUSERLDAP_H_
diff --git a/kuser/kuserprefs.kcfgc b/kuser/kuserprefs.kcfgc
new file mode 100644
index 0000000..c9519e1
--- /dev/null
+++ b/kuser/kuserprefs.kcfgc
@@ -0,0 +1,20 @@
+# Code generation options for kconfig_compiler
+File=kuser.kcfg
+ClassName=KUserPrefsBase
+SetUserTexts=true
+#
+# Singleton=false
+#
+# Inherits=KConfigSkeleton
+#
+# IncludeFiles=libkdepim/kpimprefs.h
+#
+# MemberVariables=public
+#
+### The following line includes the file exampleprefs_base_addon.h
+### It can be used to add extra functions and variables to the
+### class.
+# CustomAdditions=true
+#
+### Provide setFooBar(int) style functions
+Mutators=true
diff --git a/kuser/kusersystem.cpp b/kuser/kusersystem.cpp
new file mode 100644
index 0000000..ef0247f
--- /dev/null
+++ b/kuser/kusersystem.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "globals.h"
+#include <errno.h>
+#include <pwd.h>
+#ifdef HAVE_SHADOW
+#include <shadow.h>
+#endif
+
+#include <qstring.h>
+
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include "kglobal_.h"
+#include "misc.h"
+#include "kusersystem.h"
+
+KUserSystem::KUserSystem(KUserPrefsBase *cfg) : KU::KUsers( cfg )
+{
+ mUsers.setAutoDelete(TRUE);
+
+ caps = Cap_ReadOnly | Cap_Passwd;
+#ifdef HAVE_SHADOW
+ if ( !mCfg->shadowsrc().isEmpty() ) caps |= Cap_Shadow;
+#endif
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ caps |= Cap_BSD;
+#endif
+
+ reload();
+}
+
+KUserSystem::~KUserSystem()
+{
+}
+
+bool KUserSystem::reload()
+{
+ if (!loadpwd())
+ return FALSE;
+
+ if (!loadsdw())
+ return FALSE;
+
+ return TRUE;
+}
+
+// Load passwd file
+
+bool KUserSystem::loadpwd()
+{
+ passwd *p;
+ KU::KUser *tmpKU = 0;
+ QString tmp;
+
+ setpwent(); //This should be enough for BSDs
+ while ((p = getpwent()) != NULL) {
+ tmpKU = new KU::KUser();
+ tmpKU->setUID(p->pw_uid);
+ tmpKU->setGID(p->pw_gid);
+ tmpKU->setName(QString::fromLocal8Bit(p->pw_name));
+ tmp = QString::fromLocal8Bit( p->pw_passwd );
+ if ( tmp != "x" && tmp != "*" && !tmp.startsWith("!") )
+ tmpKU->setDisabled( false );
+ else
+ tmpKU->setDisabled( true );
+ if ( tmp.startsWith("!") ) tmp.remove(0, 1);
+ tmpKU->setPwd( tmp );
+ tmpKU->setHomeDir(QString::fromLocal8Bit(p->pw_dir));
+ tmpKU->setShell(QString::fromLocal8Bit(p->pw_shell));
+#if defined(__FreeBSD__) || defined(__bsdi__)
+ tmpKU->setClass(QString::fromLatin1(p->pw_class));
+ tmpKU->setLastChange(p->pw_change);
+ tmpKU->setExpire(p->pw_expire);
+#endif
+
+ if ((p->pw_gecos != 0) && (p->pw_gecos[0] != 0))
+ fillGecos(tmpKU, p->pw_gecos);
+ mUsers.append(tmpKU);
+ }
+
+ endpwent();
+ return(TRUE);
+}
+
+// Load shadow passwords
+
+bool KUserSystem::loadsdw()
+{
+#ifdef HAVE_SHADOW
+ struct spwd *spw;
+ KU::KUser *up = NULL;
+ QString tmp;
+
+ setspent();
+ while ((spw = getspent())) { // read a shadow password structure
+
+ if ((up = lookup(QString::fromLocal8Bit(spw->sp_namp))) == NULL) {
+ continue;
+ }
+
+ tmp = QString::fromLocal8Bit( spw->sp_pwdp );
+ if ( tmp.startsWith("!!") || tmp == "*" ) {
+ up->setDisabled( true );
+ tmp.remove( 0, 2 );
+ } else
+ up->setDisabled( false );
+
+ up->setSPwd( tmp ); // cp the encrypted pwd
+ up->setLastChange( daysToTime( spw->sp_lstchg ) );
+ up->setMin(spw->sp_min);
+ up->setMax(spw->sp_max);
+#ifndef _SCO_DS
+ up->setWarn(spw->sp_warn);
+ up->setInactive(spw->sp_inact);
+ up->setExpire( daysToTime( spw->sp_expire ) );
+ up->setFlag(spw->sp_flag);
+#endif
+ }
+
+ endspent();
+#endif //HAVE_SHADOW
+ return true;
+}
diff --git a/kuser/kusersystem.h b/kuser/kusersystem.h
new file mode 100644
index 0000000..b982447
--- /dev/null
+++ b/kuser/kusersystem.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_USERSYSTEM_H_
+#define _KU_USERSYSTEM_H_
+
+#include <sys/types.h>
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include "kuser.h"
+
+class KUserSystem : public KU::KUsers {
+public:
+ KUserSystem(KUserPrefsBase *cfg);
+ virtual ~KUserSystem();
+
+ virtual bool dbcommit() { return true; }
+ virtual bool reload();
+ virtual void createPassword( KU::KUser * /*user*/, const QString & /*password*/ ) {}
+
+private:
+
+ bool loadpwd();
+ bool loadsdw();
+};
+#endif // _KU_USERSYSTEM_H_
+
diff --git a/kuser/kuserui.rc b/kuser/kuserui.rc
new file mode 100644
index 0000000..6e0a93f
--- /dev/null
+++ b/kuser/kuserui.rc
@@ -0,0 +1,36 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kuser">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="select_conn"/>
+ <Action name="reload"/>
+ </Menu>
+ <Menu name="user"><text>&amp;User</text>
+ <Action name="add_user"/>
+ <Action name="edit_user"/>
+ <Action name="delete_user"/>
+ <Action name="set_password_user"/>
+ </Menu>
+ <Menu name="group"><text>&amp;Group</text>
+ <Action name="add_group"/>
+ <Action name="edit_group"/>
+ <Action name="delete_group"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="show_sys" append="show_merge"/>
+ </Menu>
+ </MenuBar>
+ <ToolBar fullWidth="true" name="mainToolBar">
+ <Action name="add_user"/>
+ <Action name="edit_user"/>
+ <Action name="delete_user"/>
+ <Separator/>
+ <Action name="add_group"/>
+ <Action name="edit_group"/>
+ <Action name="delete_group"/>
+ <Separator/>
+ <Action name="reload"/>
+ <Separator/>
+ </ToolBar>
+</kpartgui>
+
diff --git a/kuser/kuservw.cpp b/kuser/kuservw.cpp
new file mode 100644
index 0000000..766700c
--- /dev/null
+++ b/kuser/kuservw.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "kglobal_.h"
+#include "misc.h"
+
+#include "kuservw.h"
+
+
+KUserViewItem::KUserViewItem(KListView *parent, KU::KUser *aku)
+ : KListViewItem(parent), mUser(aku)
+{
+}
+
+int KUserViewItem::compare( QListViewItem *i, int col, bool ascending ) const
+{
+ if ( col == 0 ) {
+ uid_t uid1, uid2;
+
+ uid1 = mUser->getUID();
+ uid2 = ((KUserViewItem*) i)->mUser->getUID();
+
+ if ( uid1 == uid2 ) return 0;
+ return ( uid1 < uid2) ? -1: 1;
+ } else {
+ return QListViewItem::compare( i, col, ascending );
+ }
+}
+
+void KUserViewItem::paintCell( QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment )
+{
+ QColorGroup _cg( cg );
+ QColor c = _cg.text();
+
+ if ( mUser->getDisabled() )
+ _cg.setColor( QColorGroup::Text, KGlobalSettings::visitedLinkColor() );
+
+ KListViewItem::paintCell( p, _cg, column, width, alignment );
+
+ _cg.setColor( QColorGroup::Text, c );
+}
+
+QString KUserViewItem::text(int num) const
+{
+ switch(num)
+ {
+ case 0: return mUser->getCaps() & KU::KUser::Cap_POSIX ?
+ QString::number( mUser->getUID() ) : QString::null;
+ case 1: return mUser->getName();
+ case 2: return mUser->getFullName();
+ case 3: return mUser->getHomeDir();
+ case 4: return mUser->getShell();
+ case 5: return mUser->getSID().getDOM();
+ case 6: return mUser->getCaps() & KU::KUser::Cap_Samba ?
+ QString::number( mUser->getSID().getRID() ) : QString::null;
+ case 7: return mUser->getLoginScript();
+ case 8: return mUser->getProfilePath();
+ case 9: return mUser->getHomeDrive();
+ case 10: return mUser->getHomePath();
+ }
+
+ return QString::null;
+}
+
+KUserView::KUserView(QWidget *parent, const char *name)
+ : KListView( parent, name )
+{
+ setSelectionMode( QListView::Extended );
+}
+
+KUserView::~KUserView()
+{
+}
+
+void KUserView::insertItem(KU::KUser *aku) {
+ KUserViewItem *userItem = new KUserViewItem(this, aku);
+ KListView::insertItem(userItem);
+}
+
+void KUserView::removeItem(KU::KUser *aku) {
+ KUserViewItem *userItem = (KUserViewItem *)firstChild();
+
+ while(userItem)
+ {
+ if (userItem->user() == aku)
+ {
+ delete userItem;
+ return;
+ }
+ userItem = (KUserViewItem*) userItem->nextSibling();
+ }
+}
+
+void KUserView::init()
+{
+ while ( columns() > 5 ) {
+ removeColumn( 5 );
+ }
+
+ setAllColumnsShowFocus(true);
+ if ( columns() < 5 ) {
+ addColumn(i18n("UID"));
+ setColumnAlignment(0, AlignRight);
+ addColumn(i18n("User Login"));
+ addColumn(i18n("Full Name"));
+ addColumn(i18n("Home Directory"));
+ addColumn(i18n("Login Shell"));
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ addColumn(i18n("Domain SID"));
+ addColumn(i18n("RID"));
+ addColumn(i18n("Samba Login Script"));
+ addColumn(i18n("Samba Profile Path"));
+ addColumn(i18n("Samba Home Drive"));
+ addColumn(i18n("Samba Home Path"));
+ }
+}
+
+KU::KUser *KUserView::getCurrentUser() {
+ KUserViewItem *userItem = (KUserViewItem *)currentItem();
+ if (!userItem) return 0;
+
+ return userItem->user();
+}
+
+#include "kuservw.moc"
diff --git a/kuser/kuservw.h b/kuser/kuservw.h
new file mode 100644
index 0000000..3f28948
--- /dev/null
+++ b/kuser/kuservw.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_USERVW_H_
+#define _KU_USERVW_H_
+
+#include <qwidget.h>
+
+#include <klistview.h>
+
+#include "kuser.h"
+
+class KUserViewItem : public KListViewItem
+{
+public:
+ KUserViewItem(KListView *parent, KU::KUser *aku);
+ KU::KUser *user() { return mUser; }
+private:
+ virtual QString text ( int ) const;
+ virtual void paintCell( QPainter *p, const QColorGroup &cg,
+ int column, int width, int alignment );
+ virtual int compare( QListViewItem *i, int col, bool ascending ) const;
+ KU::KUser *mUser;
+};
+
+class KUserView : public KListView
+{
+ Q_OBJECT
+
+public:
+ KUserView( QWidget* parent = 0, const char* name = 0 );
+
+ virtual ~KUserView();
+
+ void insertItem(KU::KUser *aku);
+ void removeItem(KU::KUser *aku);
+ KU::KUser *getCurrentUser();
+ void init();
+};
+
+#endif // _KU_USERVW_H_
diff --git a/kuser/ldapsamba.ui b/kuser/ldapsamba.ui
new file mode 100644
index 0000000..b705cf7
--- /dev/null
+++ b/kuser/ldapsamba.ui
@@ -0,0 +1,366 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>LdapSamba</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>LdapSamba</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>465</width>
+ <height>281</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Samba</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ldapsam</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Manage Samba user accounts/groups</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_samloginscript</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Default login script:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_samloginscript</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel4_2_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Home drive:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_samhomedrive</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3_2_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Profile path template:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_samprofilepath</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel5_2_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="acceptDrops">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Home path template:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_samhomepath</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_samhomepath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_samprofilepath</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_samhomedrive</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_lanmanhash</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Store LanManager hashed password</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Domain name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_samdomain</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>kcfg_samdomain</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>domQuery</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Query Server</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Domain SID (you can obtain with 'net getlocalsid domain_name'):</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_samdomsid</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>kcfg_samdomsid</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxLength">
+ <number>41</number>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Algorithmic RID base:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_samridbase</cstring>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>kcfg_samridbase</cstring>
+ </property>
+ <property name="maxValue">
+ <number>9999999</number>
+ </property>
+ <property name="minValue">
+ <number>1000</number>
+ </property>
+ <property name="lineStep">
+ <number>2</number>
+ </property>
+ <property name="value">
+ <number>1000</number>
+ </property>
+ </widget>
+ <spacer>
+ <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>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </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>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_samloginscript</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_samdomsid</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_samhomedrive</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_samhomepath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_samprofilepath</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_samdomain</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_lanmanhash</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ldapsam</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>domQuery</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>kcfg_ldapsam</tabstop>
+ <tabstop>kcfg_samloginscript</tabstop>
+ <tabstop>kcfg_samprofilepath</tabstop>
+ <tabstop>kcfg_samhomedrive</tabstop>
+ <tabstop>kcfg_samhomepath</tabstop>
+ <tabstop>kcfg_lanmanhash</tabstop>
+ <tabstop>kcfg_samdomain</tabstop>
+ <tabstop>kcfg_samdomsid</tabstop>
+ <tabstop>domQuery</tabstop>
+</tabstops>
+<slots>
+ <slot>kcfg_ldapsam_toggled( bool )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kuser/ldapsettings.ui b/kuser/ldapsettings.ui
new file mode 100644
index 0000000..6bdd35b
--- /dev/null
+++ b/kuser/ldapsettings.ui
@@ -0,0 +1,278 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>LdapSettings</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>LdapSettings</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>394</width>
+ <height>227</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit" row="1" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kcfg_ldapuserfilter</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="3">
+ <item>
+ <property name="text">
+ <string>cn</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>gidNumber</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_ldapgrouprdn</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_ldapgroupbase</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="4" column="1">
+ <item>
+ <property name="text">
+ <string>Plain Text</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>CRYPT</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>MD5</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>SMD5</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>SHA</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>SSHA</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_ldappasswordhash</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>User base:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldapuserbase</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_4_2</cstring>
+ </property>
+ <property name="text">
+ <string>Group filter:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldapgroupfilter</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="2">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>Structural objectclass:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldapstructural</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>User filter:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldapuserfilter</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_ldapuserbase</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>kcfg_ldapgroupfilter</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="4" column="3">
+ <item>
+ <property name="text">
+ <string>account</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>inetOrgPerson</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_ldapstructural</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Group RDN prefix:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldapgrouprdn</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="3">
+ <item>
+ <property name="text">
+ <string>uid</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>uidNumber</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>cn</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_ldapuserrdn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Group base:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldapgroupbase</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>User RDN prefix:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldapuserrdn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Password hash:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_ldappasswordhash</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ldapshadow</cstring>
+ </property>
+ <property name="text">
+ <string>Manage shadowAccount objectclass</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ldapcnfullname</cstring>
+ </property>
+ <property name="text">
+ <string>Store the user's full name in the cn attribute</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ldapgecos</cstring>
+ </property>
+ <property name="text">
+ <string>Update the gecos attribute</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>kcfg_ldapuserbase</tabstop>
+ <tabstop>kcfg_ldapuserrdn</tabstop>
+ <tabstop>kcfg_ldapuserfilter</tabstop>
+ <tabstop>kcfg_ldapgroupbase</tabstop>
+ <tabstop>kcfg_ldapgrouprdn</tabstop>
+ <tabstop>kcfg_ldapgroupfilter</tabstop>
+ <tabstop>kcfg_ldappasswordhash</tabstop>
+ <tabstop>kcfg_ldapstructural</tabstop>
+ <tabstop>kcfg_ldapshadow</tabstop>
+ <tabstop>kcfg_ldapcnfullname</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kuser/main.cpp b/kuser/main.cpp
new file mode 100644
index 0000000..d6b4bfb
--- /dev/null
+++ b/kuser/main.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <qfont.h>
+
+#include <kiconloader.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include "kglobal_.h"
+#include "misc.h"
+#include "mainWidget.h"
+
+static const char *description =
+ I18N_NOOP("KDE User Editor");
+
+KUserGlobals *kug = 0;
+
+int main(int argc, char **argv)
+{
+
+ KAboutData aboutData("kuser", I18N_NOOP("KUser"),
+ _KU_VERSION, description, KAboutData::License_GPL,
+ "(c) 1997-2000, Denis Perchine\n(c) 2004, Szombathelyi György");
+ aboutData.addAuthor("Denis Perchine", I18N_NOOP("kuser author"),
+ "dyp@perchine.com", "http://www.perchine.com/dyp/");
+ aboutData.addAuthor("Szombathelyi György", I18N_NOOP("kuser author"),
+ "gyurco@freemail.hu");
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ mainWidget *mw = 0;
+
+ KApplication a;
+
+ kapp->sharedConfig()->setGroup( "general" );
+ kug = new KUserGlobals();
+ kug->initCfg( kapp->sharedConfig()->readEntry( "connection", "default" ) );
+
+ mw = new mainWidget("kuser");
+ a.setMainWidget(mw);
+ mw->setCaption(i18n("KDE User Manager"));
+ mw->show();
+
+ a.exec();
+
+ kug->kcfg()->writeConfig();
+ delete kug;
+
+}
diff --git a/kuser/mainView.cpp b/kuser/mainView.cpp
new file mode 100644
index 0000000..4f4e388
--- /dev/null
+++ b/kuser/mainView.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "mainView.h"
+
+#include <stdio.h>
+
+#include <qtooltip.h>
+#include <qfile.h>
+
+#include <kinputdialog.h>
+#include <ktoolbar.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include "misc.h"
+#include "kglobal_.h"
+#include "propdlg.h"
+#include "addUser.h"
+#include "delUser.h"
+#include "pwddlg.h"
+#include "editGroup.h"
+
+mainView::mainView(QWidget *parent) : QTabWidget(parent)
+{
+ init();
+}
+
+void mainView::init() {
+
+ lbusers = new KUserView( this, "lbusers" );
+ addTab( lbusers, i18n("Users") );
+
+ lbgroups = new KGroupView( this, "lbgroups" );
+ addTab( lbgroups, i18n("Groups"));
+
+ connect(lbusers, SIGNAL(doubleClicked(QListViewItem *)), this, SLOT(userSelected()));
+ connect(lbusers, SIGNAL(returnPressed(QListViewItem *)), this, SLOT(userSelected()));
+
+ connect(lbgroups, SIGNAL(doubleClicked(QListViewItem *)), this, SLOT(groupSelected()));
+ connect(lbgroups, SIGNAL(returnPressed(QListViewItem *)), this, SLOT(groupSelected()));
+
+ connect(this, SIGNAL(currentChanged(QWidget *)), this, SLOT(slotTabChanged()));
+}
+
+mainView::~mainView()
+{
+}
+
+void mainView::slotTabChanged()
+{
+ if (currentPage() == lbusers)
+ {
+ emit userSelected(true);
+ emit groupSelected(false);
+ }
+ else
+ {
+ emit userSelected(false);
+ emit groupSelected(true);
+ }
+}
+
+void mainView::clearUsers()
+{
+ lbusers->clear();
+}
+
+void mainView::clearGroups()
+{
+ lbgroups->clear();
+}
+
+void mainView::reloadUsers()
+{
+ KU::KUser *ku;
+
+ lbusers->clear();
+ lbusers->init();
+ uid_t uid = kug->kcfg()->firstUID();
+
+ ku = kug->getUsers().first();
+ while ( ku ) {
+ if ( ku->getUID() >= uid || mShowSys ) lbusers->insertItem( ku );
+ ku = kug->getUsers().next();
+ }
+ if (lbusers->firstChild())
+ lbusers->setSelected(lbusers->firstChild(), true);
+}
+
+void mainView::reloadGroups()
+{
+ KU::KGroup *kg;
+
+ lbgroups->clear();
+ lbgroups->init();
+ gid_t gid = kug->kcfg()->firstGID();
+
+ kg = kug->getGroups().first();
+ while ( kg ) {
+ if ( kg->getGID() >= gid || mShowSys ) lbgroups->insertItem(kg);
+ kg = kug->getGroups().next();
+ }
+}
+
+void mainView::useredit()
+{
+ userSelected();
+}
+
+void mainView::userdel()
+{
+ KU::KUser *user = lbusers->getCurrentUser();
+ if (!user)
+ return;
+
+ QString username = user->getName();
+ gid_t gid = user->getGID();
+ delUser dlg(user, this);
+
+ if ( dlg.exec() == QDialog::Rejected )
+ return;
+
+ user->setDeleteHome( dlg.getDeleteHomeDir() );
+ user->setDeleteMailBox( dlg.getDeleteMailBox() );
+
+ kug->getUsers().del( user );
+ if ( !updateUsers() ) return;
+
+ KU::KGroup *group = 0;
+ group = kug->getGroups().first();
+ while ( group ) {
+ kdDebug() << "group: " << group->getName() << endl;
+ if ( group->lookup_user( username ) ) {
+ kdDebug() << "group: " << group->getName() << " found user: " << username << endl;
+ KU::KGroup newgroup( group );
+ newgroup.removeUser( username );
+ kug->getGroups().mod( group, newgroup );
+ }
+ group = kug->getGroups().next();
+ }
+
+ if ( kug->kcfg()->userPrivateGroup() ) {
+
+ group = kug->getGroups().lookup( gid );
+
+ if ( group &&
+ KMessageBox::questionYesNo( 0, i18n("You are using private groups.\n"
+ "Do you want to delete the user's private group '%1'?")
+ .arg(group->getName()), QString::null,
+ KStdGuiItem::del(), i18n("Do Not Delete")) == KMessageBox::Yes) {
+ kdDebug() << "del private group" << endl;
+ kug->getGroups().del( group );
+ }
+ }
+ kdDebug() << "update groups" << endl;
+ updateGroups();
+}
+
+void mainView::useradd()
+{
+ KU::KUser *tk;
+
+ showPage(lbusers);
+
+ uid_t uid, rid = 0;
+ bool samba = kug->getUsers().getCaps() & KU::KUsers::Cap_Samba;
+
+ if ((uid = kug->getUsers().first_free()) == KU::KUsers::NO_FREE) {
+ KMessageBox::sorry( 0, i18n("You have run out of uid space.") );
+ return;
+ }
+/*
+ if ( samba && (rid = kug->getUsers().first_free_sam()) == 0) {
+ KMessageBox::sorry( 0, i18n("You have run out of user RID space.") );
+ return;
+ }
+*/
+ if ( samba ) rid = SID::uid2rid( uid );
+ bool ok;
+ QString name = KInputDialog::getText( QString::null,
+ i18n("Please type the name of the new user:"),
+ QString::null, &ok );
+
+ if ( !ok ) return;
+
+ if ( kug->getUsers().lookup( name ) ) {
+ KMessageBox::sorry( 0, i18n("User with name %1 already exists.").arg( name ) );
+ return;
+ }
+
+ tk = new KU::KUser();
+ tk->setCaps( samba ? KU::KUser::Cap_POSIX | KU::KUser::Cap_Samba : KU::KUser::Cap_POSIX );
+ tk->setUID( uid );
+ tk->setName( name );
+
+ if ( samba ) {
+ SID sid;
+ sid.setDOM( kug->getUsers().getDOMSID() );
+ sid.setRID( rid );
+ tk->setSID( sid );
+ tk->setProfilePath( kug->kcfg()->samprofilepath().replace( "%U",name ) );
+ tk->setHomePath( kug->kcfg()->samhomepath().replace( "%U", name ) );
+ tk->setHomeDrive( kug->kcfg()->samhomedrive() );
+ tk->setLoginScript( kug->kcfg()->samloginscript() );
+ tk->setDomain( kug->kcfg()->samdomain() );
+ }
+
+ tk->setShell( kug->kcfg()->shell() );
+ tk->setHomeDir( kug->kcfg()->homepath().replace( "%U", name ) );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow || samba ) {
+ tk->setLastChange( now() );
+ }
+
+ tk->setMin( kug->kcfg()->smin() );
+ tk->setMax( kug->kcfg()->smax() );
+ tk->setWarn( kug->kcfg()->swarn() );
+ tk->setInactive( kug->kcfg()->sinact() );
+ tk->setExpire( kug->kcfg()->sneverexpire() ? (uint) -1 :
+ (kug->kcfg()->sexpire()).toTime_t() );
+
+ bool privgroup = kug->kcfg()->userPrivateGroup();
+
+ if ( !privgroup ) tk->setGID( kug->kcfg()->defaultgroup() );
+
+ addUser au( tk, privgroup, this );
+
+ au.setCreateHomeDir( kug->kcfg()->createHomeDir() );
+ au.setCopySkel( kug->kcfg()->copySkel() );
+
+ if ( au.exec() == QDialog::Rejected ) {
+ delete tk;
+ return;
+ }
+ if ( privgroup ) {
+ KU::KGroup *tg;
+
+ if ((tg = kug->getGroups().lookup(tk->getName())) == 0) {
+ gid_t gid;
+ if ( kug->getGroups().lookup( tk->getUID() ) == 0 ) {
+ gid = tk->getUID();
+ } else {
+ gid = kug->getGroups().first_free();
+ }
+ kdDebug() << "private group GID: " << gid << endl;
+ uid_t rid = 0;
+// if ( samba ) rid = kug->getGroups().first_free_sam();
+ if ( samba ) rid = SID::gid2rid( gid );
+ if ( gid == KU::KGroups::NO_FREE || ( samba && rid == 0 ) ) {
+ kug->getGroups().cancelMods();
+ delete tk;
+ return;
+ }
+ tg = new KU::KGroup();
+ tg->setGID( gid );
+ if ( samba && ( tk->getCaps() & KU::KUser::Cap_Samba ) ) {
+ SID sid;
+ sid.setDOM( kug->getGroups().getDOMSID() );
+ sid.setRID( rid );
+ tg->setSID( sid );
+ tg->setDisplayName( tk->getName() );
+ tg->setCaps( KU::KGroup::Cap_Samba );
+ }
+ tg->setName( tk->getName() );
+ kug->getGroups().add( tg );
+ }
+ tk->setGID( tg->getGID() );
+ tk->setPGSID( tg->getSID() );
+ }
+ kug->getUsers().add( tk );
+ if ( !updateUsers() ) {
+ kug->getGroups().cancelMods();
+ return;
+ }
+ updateGroups();
+}
+
+bool mainView::queryClose()
+{
+ return true;
+}
+
+void mainView::setpwd()
+{
+ int count = lbusers->selectedItems().count();
+ if ( count == 0 ) return;
+ if ( count > 1 ) {
+ if ( KMessageBox::questionYesNo( 0,
+ i18n("You have selected %1 users. Do you really want to change the password for all the selected users?")
+ .arg( count ), QString::null, i18n("Change"), i18n("Do Not Change") ) == KMessageBox::No ) return;
+ }
+ pwddlg d( this );
+ if ( d.exec() != QDialog::Accepted ) return;
+
+ KU::KUser newuser, *user;
+ QListViewItem *item;
+
+ item = lbusers->firstChild();
+ while ( item ) {
+ if ( item->isSelected() ) {
+ user = ((KUserViewItem*) item)->user();
+ newuser.copy( user );
+ kug->getUsers().createPassword( &newuser, d.getPassword() );
+ newuser.setLastChange( now() );
+ newuser.setDisabled( false );
+ kug->getUsers().mod( user, newuser );
+ }
+ item = item->nextSibling();
+ }
+ updateUsers();
+}
+
+void mainView::groupSelected()
+{
+ bool samba = kug->getGroups().getCaps() & KU::KGroups::Cap_Samba;
+ KU::KGroup *tmpKG = lbgroups->getCurrentGroup();
+ if ( !tmpKG ) return;
+ KU::KGroup newGroup( tmpKG );
+
+ kdDebug() << "The SID for group " << newGroup.getName() << " is: '" << newGroup.getSID().getSID() << "'" << endl;
+ if ( samba && ( newGroup.getCaps() & KU::KGroup::Cap_Samba ) &&
+ newGroup.getSID().isEmpty() ) {
+ SID sid;
+ sid.setDOM( kug->getGroups().getDOMSID() );
+// sid.setRID( kug->getGroups().first_free_sam() );
+ sid.setRID( SID::gid2rid( newGroup.getGID() ) );
+ newGroup.setSID( sid );
+ kdDebug() << "The new SID for group " << newGroup.getName() << " is: " << sid.getSID() << endl;
+ }
+ editGroup egdlg( &newGroup, samba, false );
+
+ if ( egdlg.exec() == QDialog::Accepted ) {
+ kug->getGroups().mod( tmpKG, newGroup );
+ updateGroups();
+ }
+}
+
+void mainView::userSelected()
+{
+ QListViewItem *item;
+ QPtrList<KU::KUser> ulist;
+
+ item = lbusers->firstChild();
+ while ( item ) {
+ if ( item->isSelected() ) {
+ ulist.append( ((KUserViewItem*) item)->user() );
+ }
+ item = item->nextSibling();
+ }
+ if ( ulist.isEmpty() ) return;
+
+ propdlg editUser( ulist, this );
+ if ( editUser.exec() == QDialog::Rejected ) return;
+
+ KU::KUser *user, newuser;
+ user = ulist.first();
+ while ( user ) {
+ editUser.mergeUser( user, &newuser );
+ kug->getUsers().mod( user, newuser );
+ user = ulist.next();
+ }
+ updateUsers();
+ updateGroups();
+}
+
+void mainView::grpadd()
+{
+ showPage(lbgroups);
+
+ gid_t gid;
+ uid_t rid = 0;
+ bool samba;
+
+ samba = kug->getGroups().getCaps() & KU::KGroups::Cap_Samba;
+
+ if ( (gid = kug->getGroups().first_free()) == KU::KGroups::NO_FREE )
+ {
+ KMessageBox::sorry( 0, i18n("You have run out of gid space.") );
+ return;
+ }
+/*
+ if ( samba && (rid = kug->getGroups().first_free_sam()) == 0 )
+ {
+ KMessageBox::sorry( 0, i18n("You have run out of group RID space.") );
+ return;
+ }
+*/
+ if ( samba ) rid = SID::gid2rid( gid );
+
+ KU::KGroup *tk = new KU::KGroup();
+ tk->setGID(gid);
+ if ( samba ) {
+ SID sid;
+ sid.setRID( rid );
+ sid.setDOM( kug->getGroups().getDOMSID() );
+ tk->setSID( sid );
+ }
+ editGroup egdlg( tk, samba, true );
+
+ if ( egdlg.exec() == QDialog::Rejected ) {
+ delete tk;
+ return;
+ }
+ kug->getGroups().add(tk);
+ updateGroups();
+}
+
+void mainView::grpedit()
+{
+ groupSelected();
+}
+
+void mainView::grpdel()
+{
+ QListViewItem *item;
+ KU::KGroup *group = NULL;
+ int selected = 0;
+
+ item = lbgroups->firstChild();
+ while ( item ) {
+ if ( item->isSelected() ) {
+
+ selected++;
+ group = ((KGroupViewItem*) item)->group();
+
+ KU::KUser *user = kug->getUsers().first();
+ while ( user ) {
+ if ( user->getGID() == group->getGID() ) {
+ KMessageBox::error( 0, i18n( "The group '%1' is the primary group of one or more users (such as '%2'); it cannot be deleted." ).arg( group->getName() ).arg( user->getName() ) );
+ return;
+ }
+ user = kug->getUsers().next();
+ }
+ }
+ item = item->nextSibling();
+ }
+
+ switch ( selected ) {
+ case 0: return;
+ case 1:
+ if (KMessageBox::warningContinueCancel( 0,
+ i18n("Do you really want to delete the group '%1'?").arg(group->getName()),
+ QString::null, KStdGuiItem::del()) != KMessageBox::Continue) return;
+ break;
+ default:
+ if (KMessageBox::warningContinueCancel( 0,
+ i18n("Do you really want to delete the %1 selected groups?").arg(selected),
+ QString::null, KStdGuiItem::del()) != KMessageBox::Continue) return;
+ }
+
+ item = lbgroups->firstChild();
+ while ( item ) {
+ if ( item->isSelected() ) {
+ group = ((KGroupViewItem*) item)->group();
+ kug->getGroups().del( group );
+ }
+ item = item->nextSibling();
+ }
+ updateGroups();
+}
+
+bool mainView::updateGroups()
+{
+ bool ret;
+ kdDebug() << "updateGroups() " << endl;
+ ret = kug->getGroups().dbcommit();
+
+ KU::KGroup *group;
+ KU::KGroups::DelIt dit( kug->getGroups().mDelSucc );
+ KU::KGroups::AddIt ait( kug->getGroups().mAddSucc );
+
+ while ( (group = dit.current()) != 0 ) {
+ ++dit;
+ lbgroups->removeItem( group );
+ }
+ while ( (group = ait.current()) != 0 ) {
+ ++ait;
+ lbgroups->insertItem( group );
+ }
+ kdDebug() << "commit groups" << endl;
+ kug->getGroups().commit();
+ return ret;
+}
+
+bool mainView::updateUsers()
+{
+ bool ret;
+ kdDebug() << "updateUsers() " << endl;
+ ret = kug->getUsers().dbcommit();
+
+ KU::KUser *user;
+ KU::KUsers::DelIt dit( kug->getUsers().mDelSucc );
+ KU::KUsers::AddIt ait( kug->getUsers().mAddSucc );
+
+ while ( (user = dit.current()) != 0 ) {
+ ++dit;
+ lbusers->removeItem( user );
+ }
+ while ( (user = ait.current()) != 0 ) {
+ ++ait;
+ lbusers->insertItem( user );
+ }
+ kug->getUsers().commit();
+ return ret;
+}
+
+
+#include "mainView.moc"
diff --git a/kuser/mainView.h b/kuser/mainView.h
new file mode 100644
index 0000000..5304ea3
--- /dev/null
+++ b/kuser/mainView.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_MAINVIEW_H_
+#define _KU_MAINVIEW_H_
+
+#include <stdlib.h>
+
+#include <qevent.h>
+#include <qptrlist.h>
+#include <qpushbutton.h>
+#include <qpixmap.h>
+#include <qtabwidget.h>
+
+#include "kuservw.h"
+#include "kgroupvw.h"
+
+class mainView : public QTabWidget {
+Q_OBJECT
+public:
+ mainView(QWidget *parent = 0);
+ ~mainView();
+
+ void init();
+ void setShowSys( bool b ) { mShowSys = b; }
+
+ bool queryClose();
+
+ void clearUsers();
+ void clearGroups();
+ void reloadUsers();
+ void reloadGroups();
+
+public slots:
+ void slotTabChanged();
+
+ void userSelected();
+ void groupSelected();
+
+ void useradd();
+ void useredit();
+ void userdel();
+
+ void grpadd();
+ void grpedit();
+ void grpdel();
+
+ void setpwd();
+
+signals:
+ void userSelected(bool);
+ void groupSelected(bool);
+
+protected:
+ bool updateUsers();
+ bool updateGroups();
+
+ KUserView *lbusers;
+ KGroupView *lbgroups;
+ bool mShowSys;
+};
+
+#endif // _KU_MAINVIEW_H_
diff --git a/kuser/mainWidget.cpp b/kuser/mainWidget.cpp
new file mode 100644
index 0000000..91b5862
--- /dev/null
+++ b/kuser/mainWidget.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <qtooltip.h>
+#include <qtimer.h>
+
+#include <ktoolbar.h>
+#include <kiconloader.h>
+#include <kaction.h>
+#include <klocale.h>
+#include <kstdaction.h>
+
+#include <kdebug.h>
+#include <kaction.h>
+#include <kstatusbar.h>
+#include <kedittoolbar.h>
+
+#include "kglobal_.h"
+#include "editDefaults.h"
+#include "mainWidget.h"
+#include "selectconn.h"
+#include "mainView.h"
+
+mainWidget::mainWidget(const char *name) : KMainWindow(0,name)
+{
+ md = new mainView(this);
+
+ setupActions();
+ md->setShowSys( mShowSys->isChecked() );
+ init();
+ md->slotTabChanged();
+
+ statusBar()->insertItem(i18n("Reading configuration"), 0);
+
+ setCentralWidget(md);
+
+ setupGUI();
+
+ statusBar()->changeItem(i18n("Ready"), 0);
+}
+
+mainWidget::~mainWidget()
+{
+ delete md;
+}
+
+bool mainWidget::queryClose()
+{
+ return md->queryClose();
+}
+
+void mainWidget::setupActions()
+{
+ KStdAction::quit(this, SLOT(close()), actionCollection());
+ KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection());
+
+ KStdAction::preferences(this, SLOT(properties()), actionCollection());
+
+#define BarIconC(x) BarIcon(QString::fromLatin1(x))
+
+ (void) new KAction(i18n("&Add..."), QIconSet(BarIconC("add_user")), 0, md,
+ SLOT(useradd()), actionCollection(), "add_user");
+
+ (void) new KAction(i18n("&Edit..."), QIconSet(BarIconC("edit_user")), 0, md,
+ SLOT(useredit()), actionCollection(), "edit_user");
+
+ (void) new KAction(i18n("&Delete..."), QIconSet(BarIconC("delete_user")), 0, md,
+ SLOT(userdel()), actionCollection(), "delete_user");
+
+ (void) new KAction(i18n("&Set Password..."),
+ 0, md, SLOT(setpwd()), actionCollection(), "set_password_user");
+
+ (void) new KAction(i18n("&Add..."), QIconSet(BarIconC("add_group")), 0, md,
+ SLOT(grpadd()), actionCollection(), "add_group");
+
+ (void) new KAction(i18n("&Edit..."), QIconSet(BarIconC("edit_group")), 0, md,
+ SLOT(grpedit()), actionCollection(), "edit_group");
+
+ (void) new KAction(i18n("&Delete"), QIconSet(BarIconC("delete_group")), 0, md,
+ SLOT(grpdel()), actionCollection(), "delete_group");
+
+ (void) new KAction(i18n("&Reload"), QIconSet(BarIconC("reload")), 0, this,
+ SLOT(reload()), actionCollection(), "reload");
+
+#undef BarIconC
+
+ (void) new KAction(i18n("&Select Connection..."),
+ 0, this,
+ SLOT(selectconn()), actionCollection(), "select_conn");
+
+ mShowSys = new KToggleAction(i18n("Show System Users/Groups"),
+ 0, 0, this,
+ SLOT(showSys()), actionCollection(), "show_sys");
+ mShowSys->setCheckedState(i18n("Hide System Users/Groups"));
+ mShowSys->setChecked( kug->kcfg()->showsys() );
+}
+
+void mainWidget::showSys()
+{
+ kug->kcfg()->setShowsys( mShowSys->isChecked() );
+ md->setShowSys( mShowSys->isChecked() );
+ md->reloadUsers();
+ md->reloadGroups();
+}
+
+void mainWidget::properties()
+{
+ editDefaults *eddlg = new editDefaults( kug->kcfg(), this );
+ connect(eddlg, SIGNAL(settingsChanged()), this, SLOT(slotApplySettings()));
+
+ eddlg->show();
+}
+
+void mainWidget::reload()
+{
+ init();
+}
+
+void mainWidget::init()
+{
+ bool rw;
+
+ md->clearUsers();
+ md->clearGroups();
+ kug->init();
+ rw = ! ( kug->getUsers().getCaps() & KU::KUsers::Cap_ReadOnly );
+ kdDebug() << "Users rw()" << rw << endl;
+ actionCollection()->action("add_user")->setEnabled( rw );
+ actionCollection()->action("edit_user")->setEnabled( rw );
+ actionCollection()->action("delete_user")->setEnabled( rw );
+ actionCollection()->action("set_password_user")->setEnabled( rw );
+ if ( rw ) {
+ connect( md, SIGNAL(userSelected(bool)),
+ actionCollection()->action("edit_user"), SLOT(setEnabled(bool)) );
+ connect( md, SIGNAL(userSelected(bool)),
+ actionCollection()->action("delete_user"), SLOT(setEnabled(bool)) );
+ connect( md, SIGNAL(userSelected(bool)),
+ actionCollection()->action("set_password_user"), SLOT(setEnabled(bool)) );
+ } else {
+ disconnect( md, SIGNAL(userSelected(bool)), 0, 0 );
+ }
+
+ rw = ! ( kug->getGroups().getCaps() & KU::KGroups::Cap_ReadOnly );
+ kdDebug() << "Groups rw()" << rw << endl;
+ actionCollection()->action("add_group")->setEnabled( rw );
+ actionCollection()->action("edit_group")->setEnabled( rw );
+ actionCollection()->action("delete_group")->setEnabled( rw );
+ if ( rw ) {
+ connect( md, SIGNAL(groupSelected(bool)),
+ actionCollection()->action("edit_group"), SLOT(setEnabled(bool)) );
+ connect( md, SIGNAL(groupSelected(bool)),
+ actionCollection()->action("delete_group"), SLOT(setEnabled(bool)) );
+ } else {
+ disconnect( md, SIGNAL(groupSelected(bool)), 0, 0 );
+ }
+ md->reloadUsers();
+ md->reloadGroups();
+ QTimer::singleShot( 0, md, SLOT(slotTabChanged()) );
+}
+
+void mainWidget::slotApplySettings()
+{
+ kdDebug() << "settings changed!" << endl;
+ init();
+}
+
+void mainWidget::slotApplyConnection()
+{
+ kdDebug() << "slotApplyConnection()" << endl;
+ QString conn = sc->connSelected();
+ kug->kcfg()->setConnection( conn );
+ kug->initCfg( conn );
+ slotApplySettings();
+}
+
+void mainWidget::selectconn()
+{
+ sc = new SelectConn( kug->kcfg()->connection(), this, "selectconn" );
+ connect( sc, SIGNAL(applyClicked()), SLOT(slotApplyConnection()) );
+ connect( sc, SIGNAL(okClicked()), SLOT(slotApplyConnection()) );
+ sc->show();
+}
+
+#include "mainWidget.moc"
diff --git a/kuser/mainWidget.h b/kuser/mainWidget.h
new file mode 100644
index 0000000..840ca01
--- /dev/null
+++ b/kuser/mainWidget.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_MAINWIDGET_H_
+#define _KU_MAINWIDGET_H_
+
+#include <kmainwindow.h>
+
+class SelectConn;
+class mainView;
+class KToggleAction;
+
+class mainWidget : public KMainWindow {
+Q_OBJECT
+public:
+ mainWidget(const char *name = 0);
+ ~mainWidget();
+ bool queryClose();
+
+protected:
+ void init();
+ void setupActions();
+
+protected slots:
+ void showSys();
+ void properties();
+ void slotApplySettings();
+ void slotApplyConnection();
+ void selectconn();
+ void reload();
+
+private:
+ KToggleAction *mShowSys;
+ mainView *md;
+ SelectConn *sc;
+
+};
+
+#endif // _KU_MAINWIDGET_H_
diff --git a/kuser/misc.cpp b/kuser/misc.cpp
new file mode 100644
index 0000000..4215c40
--- /dev/null
+++ b/kuser/misc.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "globals.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+#include <qfile.h>
+
+#include <kmessagebox.h>
+
+#include "misc.h"
+#include "kglobal_.h"
+
+bool backup(const QString & name)
+{
+ QString tmp = name + QString::fromLatin1(KU_BACKUP_EXT);
+ QFile::remove( tmp );
+
+ if (copyFile(QFile::encodeName(name), QFile::encodeName(tmp)) == -1)
+ {
+ QString str;
+ KMessageBox::error( 0, i18n("Can't create backup file for %1").arg(name) );
+ return false;
+ }
+ return true;
+}
+
+time_t now() {
+ struct timeval tv;
+
+ gettimeofday( &tv, NULL );
+ return ( tv.tv_sec );
+}
+
+#define BLOCK_SIZE 65536
+
+int copyFile(const QString & from, const QString & to)
+{
+ QFile fi;
+ QFile fo;
+ char buf[BLOCK_SIZE];
+
+ fi.setName(from);
+ fo.setName(to);
+
+ if (!fi.exists()) {
+ KMessageBox::error( 0, i18n("File %1 does not exist.").arg(from) );
+ return (-1);
+ }
+
+ if (!fi.open(IO_ReadOnly)) {
+ KMessageBox::error( 0, i18n("Cannot open file %1 for reading.").arg(from) );
+ return (-1);
+ }
+
+ if (!fo.open(IO_Raw | IO_WriteOnly | IO_Truncate)) {
+ KMessageBox::error( 0, i18n("Cannot open file %1 for writing.").arg(to) );
+ return (-1);
+ }
+
+ while (!fi.atEnd()) {
+ int len = fi.readBlock(buf, BLOCK_SIZE);
+ if (len <= 0)
+ break;
+ fo.writeBlock(buf, len);
+ }
+
+ fi.close();
+ fo.close();
+
+ return (0);
+}
+
+QStringList readShells()
+{
+ QStringList shells;
+
+ FILE *f = fopen(SHELL_FILE,"r");
+ if (f) {
+ while (!feof(f)) {
+ char s[200];
+
+ fgets(s, 200, f);
+ if (feof(f))
+ break;
+
+ s[strlen(s)-1]=0;
+ if ((s[0])&&(s[0]!='#'))
+ shells.append(QFile::decodeName(s));
+ }
+ fclose(f);
+ }
+ return shells;
+}
+
+void addShell(const QString &shell)
+{
+ QStringList shells = readShells();
+ if (shells.contains(shell))
+ return;
+
+ FILE *f = fopen(SHELL_FILE,"a");
+ if (f)
+ {
+ fputs(QFile::encodeName(shell).data(), f);
+ fputc('\n', f);
+ }
+ fclose(f);
+}
+
+QCString genSalt( int len )
+{
+ QCString salt( len + 1 );
+ const char * set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+ salt[0] = set[getpid() % strlen(set)];
+ for( int i = 1; i < len; i++ ) {
+ salt[i] = set[kapp->random() % strlen(set)];
+ }
+ return salt;
+}
+
+QString encryptPass( const QString &pass, bool md5 )
+{
+ QCString salt;
+ char tmp[128];
+
+ if ( md5 ) {
+ salt = "$1$";
+ salt += genSalt( 8 );
+ salt += '$';
+
+ } else {
+ salt = genSalt( 2 );
+ }
+ strcpy( tmp, crypt( QFile::encodeName( pass ), salt ) );
+ return QString::fromLocal8Bit( tmp );
+}
+
+int timeToDays(time_t time)
+{
+ return time < 0 ? -1 : time/(24*60*60);
+}
+
+time_t daysToTime(int days)
+{
+ return days*24*60*60;
+}
diff --git a/kuser/misc.h b/kuser/misc.h
new file mode 100644
index 0000000..87485e6
--- /dev/null
+++ b/kuser/misc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_MISC_H_
+#define _KU_MISC_H_
+
+#include <sys/time.h>
+
+#include <klocale.h>
+#include <kapplication.h>
+#include <qstring.h>
+#include <qwidget.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+
+class KUser;
+
+bool backup(const QString & name);
+QCString genSalt( int len );
+QString encryptPass( const QString &pass, bool md5 );
+time_t now();
+int copyFile(const QString & from, const QString & to);
+QStringList readShells();
+void addShell(const QString &shell);
+int timeToDays(time_t time);
+time_t daysToTime(int days);
+
+#endif // _KU_MISC_H_
diff --git a/kuser/passwordpolicy.ui b/kuser/passwordpolicy.ui
new file mode 100644
index 0000000..03318d4
--- /dev/null
+++ b/kuser/passwordpolicy.ui
@@ -0,0 +1,244 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>PasswordPolicy</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PasswordPolicy</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>479</width>
+ <height>157</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Time before password expires to issue an expire warning:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_swarn</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Time when password expires after last password change:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_smax</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Time when account will be disabled after expiration of password:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_sinact</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_smax</cstring>
+ </property>
+ <property name="suffix">
+ <string> days</string>
+ </property>
+ <property name="specialValueText">
+ <string>Never</string>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="1">
+ <property name="name">
+ <cstring>kcfg_sinact</cstring>
+ </property>
+ <property name="suffix">
+ <string> days</string>
+ </property>
+ <property name="specialValueText">
+ <string>Never</string>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Time before password may not be changed after last password change:</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_smin</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="2" column="1">
+ <property name="name">
+ <cstring>kcfg_swarn</cstring>
+ </property>
+ <property name="suffix">
+ <string> days</string>
+ </property>
+ <property name="specialValueText">
+ <string>Never</string>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_smin</cstring>
+ </property>
+ <property name="suffix">
+ <string> days</string>
+ </property>
+ <property name="specialValueText">
+ <string></string>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Account will expire on:</string>
+ </property>
+ </widget>
+ <widget class="KDateTimeWidget">
+ <property name="name">
+ <cstring>kcfg_sexpire</cstring>
+ </property>
+ <property name="dateTime">
+ <datetime>
+ <year>2000</year>
+ <month>1</month>
+ <day>1</day>
+ <hour>0</hour>
+ <minute>0</minute>
+ <second>0</second>
+ </datetime>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_sneverexpire</cstring>
+ </property>
+ <property name="text">
+ <string>Never</string>
+ </property>
+ </widget>
+ </hbox>
+ </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>40</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>kcfg_sneverexpire</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_sexpire</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>kcfg_smin</tabstop>
+ <tabstop>kcfg_smax</tabstop>
+ <tabstop>kcfg_swarn</tabstop>
+ <tabstop>kcfg_sinact</tabstop>
+ <tabstop>kcfg_sneverexpire</tabstop>
+</tabstops>
+<slots>
+ <slot>kcfg_sneverexpire_toggled( bool )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kdatetimewidget.h</includehint>
+ <includehint>kdatewidget.h</includehint>
+ <includehint>ktimewidget.h</includehint>
+</includehints>
+</UI>
diff --git a/kuser/pic/Makefile.am b/kuser/pic/Makefile.am
new file mode 100644
index 0000000..38d815a
--- /dev/null
+++ b/kuser/pic/Makefile.am
@@ -0,0 +1,9 @@
+
+# add here all files
+pics_DATA = group.png user.png
+
+# this is the directory, where all datas are installed
+# you have given the datas in data_DATA
+picsdir = $(kde_datadir)/kuser/pics/
+
+EXTRA_DIST = $(pics_DATA)
diff --git a/kuser/pic/group.png b/kuser/pic/group.png
new file mode 100644
index 0000000..e0985dc
--- /dev/null
+++ b/kuser/pic/group.png
Binary files differ
diff --git a/kuser/pic/user.png b/kuser/pic/user.png
new file mode 100644
index 0000000..ceac8d1
--- /dev/null
+++ b/kuser/pic/user.png
Binary files differ
diff --git a/kuser/propdlg.cpp b/kuser/propdlg.cpp
new file mode 100644
index 0000000..726cec1
--- /dev/null
+++ b/kuser/propdlg.cpp
@@ -0,0 +1,991 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qdatetime.h>
+#include <qwhatsthis.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qfile.h>
+
+#include <kseparator.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include <qvalidator.h>
+
+#include "propdlg.h"
+#include "pwddlg.h"
+#include "kglobal_.h"
+#include "misc.h"
+
+void propdlg::addRow(QWidget *parent, QGridLayout *layout, int row,
+ QWidget *widget, const QString &label, const QString &what,
+ bool two_column, bool nochange)
+{
+ QLabel *lab = new QLabel(widget, label, parent);
+ lab->setMinimumSize(lab->sizeHint());
+ widget->setMinimumSize(widget->sizeHint());
+ layout->addWidget(lab, row, 0);
+ if (!what.isEmpty())
+ {
+ QWhatsThis::add(lab, what);
+ QWhatsThis::add(widget, what);
+ }
+ if (two_column)
+ layout->addMultiCellWidget(widget, row, row, 1, 2);
+ else
+ layout->addWidget(widget, row, 1);
+
+ if ( !nochange || ro ) return;
+ QCheckBox *nc = new QCheckBox( i18n("Do not change"), parent );
+ layout->addWidget( nc, row, 3 );
+ nc->hide();
+ mNoChanges[ widget ] = nc;
+}
+
+KIntSpinBox *propdlg::addDaysGroup(QWidget *parent, QGridLayout *layout, int row,
+ const QString &title, bool never)
+{
+ KIntSpinBox *days;
+
+ QLabel *label = new QLabel( title, parent );
+ layout->addMultiCellWidget( label, row, row, 0, 1, AlignRight );
+
+ days = new KIntSpinBox( parent );
+ label->setBuddy( days );
+ days->setSuffix( i18n(" days") );
+ days->setMaxValue( 99999 );
+ if (never)
+ {
+ days->setMinValue( -1 );
+ days->setSpecialValueText(i18n("Never"));
+ }
+ else
+ {
+ days->setMinValue( 0 );
+ }
+ layout->addWidget( days, row, 2 );
+
+ connect(days, SIGNAL(valueChanged(int)), this, SLOT(changed()));
+
+ QCheckBox *nc = new QCheckBox( i18n("Do not change"), parent );
+ layout->addWidget( nc, row, 3 );
+ nc->hide();
+ mNoChanges[ days ] = nc;
+
+ return days;
+}
+
+void propdlg::initDlg()
+{
+ ro = kug->getUsers().getCaps() & KU::KUsers::Cap_ReadOnly;
+
+ QString whatstr;
+
+ // Tab 1: User Info
+ {
+ QFrame *frame = addPage(i18n("User Info"));
+ QGridLayout *layout = new QGridLayout(frame, 20, 4, marginHint(), spacingHint());
+ int row = 0;
+
+ frontpage = frame;
+ frontlayout = layout;
+
+ lbuser = new QLabel(frame);
+// whatstr = i18n("WHAT IS THIS: User login");
+ addRow(frame, layout, row++, lbuser, i18n("User login:"), whatstr, false, false);
+
+ leid = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: User Id");
+ leid->setValidator(new QIntValidator(frame));
+ addRow(frame, layout, row++, leid, i18n("&User ID:"), whatstr);
+ connect(leid, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ if ( !ro ) {
+ pbsetpwd = new QPushButton(i18n("Set &Password..."), frame);
+ layout->addWidget(pbsetpwd, 0, 2);
+ connect(pbsetpwd, SIGNAL(clicked()), this, SLOT(setpwd()));
+ }
+
+
+ lefname = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Full Name");
+ addRow(frame, layout, row++, lefname, i18n("Full &name:"), whatstr);
+ connect(lefname, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+ lefname->setFocus();
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_InetOrg ) {
+ lesurname = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Surname");
+ addRow(frame, layout, row++, lesurname, i18n("Surname:"), whatstr);
+ connect(lesurname, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ lemail = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Email");
+ addRow(frame, layout, row++, lemail, i18n("Email address:"), whatstr);
+ connect(lemail, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+ }
+
+ leshell = new KComboBox(true, frame);
+ leshell->clear();
+ leshell->insertItem(i18n("<Empty>"));
+
+ QStringList shells = readShells();
+ shells.sort();
+ leshell->insertStringList(shells);
+ connect(leshell, SIGNAL(activated(const QString &)), this, SLOT(changed()));
+ connect(leshell, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Login Shell");
+ addRow(frame, layout, row++, leshell, i18n("&Login shell:"), whatstr);
+
+ lehome = new KLineEdit(frame);
+ connect(lehome, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Home Directory");
+ addRow(frame, layout, row++, lehome, i18n("&Home folder:"), whatstr);
+
+ // FreeBSD appears to use the comma separated fields in the GECOS entry
+ // differently than Linux.
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_BSD ) {
+ leoffice = new KLineEdit(frame);
+ connect(leoffice, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Office");
+ addRow(frame, layout, row++, leoffice, i18n("&Office:"), whatstr);
+
+ leophone = new KLineEdit(frame);
+ connect(leophone, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Office Phone");
+ addRow(frame, layout, row++, leophone, i18n("Offi&ce Phone:"), whatstr);
+
+ lehphone = new KLineEdit(frame);
+ connect(lehphone, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Home Phone");
+ addRow(frame, layout, row++, lehphone, i18n("Ho&me Phone:"), whatstr);
+
+ leclass = new KLineEdit(frame);
+ connect(leclass, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Login class");
+ addRow(frame, layout, row++, leclass, i18n("Login class:"), whatstr, true);
+ } else {
+ leoffice1 = new KLineEdit(frame);
+ connect(leoffice1, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Office1");
+ addRow(frame, layout, row++, leoffice1, i18n("&Office #1:"), whatstr);
+
+ leoffice2 = new KLineEdit(frame);
+ connect(leoffice2, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Office2");
+ addRow(frame, layout, row++, leoffice2, i18n("O&ffice #2:"), whatstr);
+
+ leaddress = new KLineEdit(frame);
+ connect(leaddress, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+// whatstr = i18n("WHAT IS THIS: Address");
+ addRow(frame, layout, row++, leaddress, i18n("&Address:"), whatstr);
+ }
+ cbdisabled = new QCheckBox(frame);
+ connect(cbdisabled, SIGNAL(stateChanged(int)), this, SLOT(changed()));
+ addRow(frame, layout, row++, cbdisabled, i18n("Account &disabled"), whatstr);
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Disable_POSIX ) {
+ cbposix = new QCheckBox(frame);
+ connect(cbposix, SIGNAL(stateChanged(int)), this, SLOT(changed()));
+ connect(cbposix, SIGNAL(stateChanged(int)), this, SLOT(cbposixChanged()));
+ addRow(frame, layout, row++, cbposix, i18n("Disable &POSIX account information"), whatstr);
+ } else {
+ cbposix = 0;
+ }
+ frontrow = row;
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_BSD ) {
+
+ // Tab 2 : Password Management
+ QFrame *frame = addPage(i18n("Password Management"));
+ QGridLayout *layout = new QGridLayout(frame, 20, 4, marginHint(), spacingHint());
+ int row = 0;
+
+ QDateTime time;
+ leslstchg = new QLabel(frame);
+ addRow(frame, layout, row++, leslstchg, i18n("Last password change:"), QString::null, true);
+
+ layout->addMultiCellWidget(new KSeparator(KSeparator::HLine, frame), row, row, 0, 3);
+ row++;
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ) {
+ layout->addWidget( new QLabel( i18n("POSIX parameters:"), frame ), row++, 0 );
+ lesmin = addDaysGroup(frame, layout, row++, i18n("Time before password may &not be changed after last password change:"), false);
+ lesmax = addDaysGroup(frame, layout, row++, i18n("Time when password &expires after last password change:") );
+ leswarn = addDaysGroup(frame, layout, row++, i18n("Time before password expires to &issue an expire warning:"));
+ lesinact = addDaysGroup(frame, layout, row++, i18n("Time when account will be &disabled after expiration of password:"));
+ layout->addMultiCellWidget(new KSeparator(KSeparator::HLine, frame), row, row, 0, 3);
+ row++;
+ }
+ /*
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ layout->addWidget( new QLabel( "SAMBA parameters:", frame ), row++, 0 );
+ layout->addMultiCellWidget(new KSeparator(KSeparator::HLine, frame), row, row, 0, 3);
+ row++;
+ }
+ */
+ QLabel *label = new QLabel( i18n("&Account will expire on:"), frame );
+ layout->addWidget( label, row, 0 );
+ lesexpire = new KDateTimeWidget( frame );
+ label->setBuddy( lesexpire );
+ layout->addMultiCellWidget( lesexpire, row, row, 1, 2);
+
+ cbexpire = new QCheckBox( i18n("Never"), frame );
+ layout->addWidget( cbexpire, row++, 3 );
+
+ connect( lesexpire, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(changed()) );
+ connect( cbexpire, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
+ connect( cbexpire, SIGNAL(toggled(bool)), lesexpire, SLOT(setDisabled(bool)) );
+ }
+
+ // Tab 3: Samba
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ QFrame *frame = addPage(i18n("Samba"));
+ QGridLayout *layout = new QGridLayout(frame, 10, 4, marginHint(), spacingHint());
+ int row = 0;
+
+ lerid = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Rid");
+ lerid->setValidator(new QIntValidator(frame));
+ addRow(frame, layout, row++, lerid, i18n("RID:"), whatstr);
+ connect(lerid, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ leliscript = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Login script");
+ addRow(frame, layout, row++, leliscript, i18n("Login script:"), whatstr);
+ connect(leliscript, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ leprofile = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Login script");
+ addRow(frame, layout, row++, leprofile, i18n("Profile path:"), whatstr);
+ connect(leprofile, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ lehomedrive = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Login script");
+ addRow(frame, layout, row++, lehomedrive, i18n("Home drive:"), whatstr);
+ connect(lehomedrive, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ lehomepath = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Login script");
+ addRow(frame, layout, row++, lehomepath, i18n("Home path:"), whatstr);
+ connect(lehomepath, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ leworkstations = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Login script");
+ addRow(frame, layout, row++, leworkstations, i18n("User workstations:"), whatstr);
+ connect(leworkstations, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ ledomain = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Login script");
+ addRow(frame, layout, row++, ledomain, i18n("Domain name:"), whatstr);
+ connect(ledomain, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ ledomsid = new KLineEdit(frame);
+// whatstr = i18n("WHAT IS THIS: Login script");
+ addRow(frame, layout, row++, ledomsid, i18n("Domain SID:"), whatstr);
+ connect(ledomsid, SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
+
+ cbsamba = new QCheckBox(frame);
+ connect(cbsamba, SIGNAL(stateChanged(int)), this, SLOT(changed()));
+ connect(cbsamba, SIGNAL(stateChanged(int)), this, SLOT(cbsambaChanged()));
+ addRow(frame, layout, row++, cbsamba, i18n("Disable &Samba account information"), whatstr);
+ }
+
+ // Tab 4: Groups
+ {
+ QFrame *frame = addPage(i18n("Groups"));
+ QGridLayout *layout = new QGridLayout(frame, 2, 2, marginHint(), spacingHint());
+
+ lstgrp = new KListView(frame);
+ lstgrp->setFullWidth(true); // Single column, full widget width.
+ lstgrp->addColumn( i18n("Groups") );
+ if ( ro ) lstgrp->setSelectionMode( QListView::NoSelection );
+// QString whatstr = i18n("Select the groups that this user belongs to.");
+ QWhatsThis::add(lstgrp, whatstr);
+ layout->addMultiCellWidget(lstgrp, 0, 0, 0, 1);
+ leprigr = new QLabel( i18n("Primary group: "), frame );
+ layout->addWidget( leprigr, 1, 0 );
+ if ( !ro ) {
+ pbprigr = new QPushButton( i18n("Set as Primary"), frame );
+ layout->addWidget( pbprigr, 1, 1 );
+ connect( pbprigr, SIGNAL(clicked()), this, SLOT(setpgroup()) );
+ }
+ connect( lstgrp, SIGNAL(clicked(QListViewItem *)), this, SLOT(gchanged()) );
+ }
+
+}
+
+propdlg::propdlg( const QPtrList<KU::KUser> &users,
+ QWidget *parent, const char *name ) :
+ KDialogBase(Tabbed, i18n("User Properties"), Ok | Cancel, Ok, parent, name, true)
+
+{
+ mUsers = users;
+ if ( mUsers.getFirst() != mUsers.getLast() )
+ setCaption( i18n("User Properties - %1 Selected Users").arg( mUsers.count() ) );
+ initDlg();
+ loadgroups( false );
+ selectuser();
+ ischanged = false;
+ isgchanged = false;
+}
+
+propdlg::propdlg( KU::KUser *AUser, bool fixedprivgroup,
+ QWidget *parent, const char *name ) :
+ KDialogBase(Tabbed, i18n("User Properties"), Ok | Cancel, Ok, parent, name, true)
+
+{
+ mUsers.append( AUser );
+ initDlg();
+ loadgroups( fixedprivgroup );
+ selectuser();
+ ischanged = false;
+ isgchanged = false;
+}
+
+propdlg::~propdlg()
+{
+}
+
+void propdlg::cbposixChanged()
+{
+ bool posix = !( cbposix->state() == QButton::On );
+ leid->setEnabled( posix & ( mUsers.getFirst() == mUsers.getLast() ) );
+ leshell->setEnabled( posix );
+ lehome->setEnabled( posix );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ) {
+ lesmin->setEnabled( posix );
+ lesmax->setEnabled( posix );
+ leswarn->setEnabled( posix );
+ lesinact->setEnabled( posix );
+ }
+}
+
+void propdlg::cbsambaChanged()
+{
+ bool samba = !( cbsamba->state() == QButton::On );
+ lerid->setEnabled( samba & ( mUsers.getFirst() == mUsers.getLast() ) );
+ leliscript->setEnabled( samba );
+ leprofile->setEnabled( samba );
+ lehomedrive->setEnabled( samba );
+ lehomepath->setEnabled( samba );
+ leworkstations->setEnabled( samba );
+ ledomain->setEnabled( samba );
+ ledomsid->setEnabled( samba );
+}
+
+void propdlg::setLE( KLineEdit *le, const QString &val, bool first )
+{
+ if ( first ) {
+ le->setText( val );
+ if ( ro ) le->setReadOnly( true );
+ return;
+ }
+ if ( val.isEmpty() && le->text().isEmpty() ) return;
+ if ( le->text() != val ) {
+ le->setText( "" );
+ if ( !ro && mNoChanges.contains( le ) ) {
+ mNoChanges[ le ]->show();
+ mNoChanges[ le ]->setChecked( true );
+ }
+ }
+}
+
+void propdlg::setCB( QCheckBox *cb, bool val, bool first )
+{
+ if ( first ) {
+ cb->setChecked( val );
+ if ( ro ) cb->setEnabled( false );
+ return;
+ }
+ if ( cb->isChecked() != val ) {
+ cb->setTristate();
+ cb->setNoChange();
+ }
+}
+
+void propdlg::setSB( KIntSpinBox *sb, int val, bool first )
+{
+ if ( first ) {
+ sb->setValue( val );
+ if ( ro ) sb->setEnabled( false );
+ return;
+ }
+ if ( sb->value() != val ) {
+ sb->setValue( 0 );
+ if ( !ro && mNoChanges.contains( sb ) ) {
+ mNoChanges[ sb ]->show();
+ mNoChanges[ sb ]->setChecked( true );
+ }
+ }
+}
+
+void propdlg::selectuser()
+{
+ KU::KUser *user;
+ bool first = true, one = ( mUsers.getFirst() == mUsers.getLast() );
+
+ ismoreshells = false;
+ user = mUsers.first();
+ olduid = user->getUID();
+ oldrid = user->getSID().getRID();
+ oldshell = user->getShell();
+ lstchg = user->getLastChange();
+ QDateTime datetime;
+ datetime.setTime_t( lstchg );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_BSD ) {
+
+ leslstchg->setText( KGlobal::locale()->formatDateTime( datetime, false ) );
+ }
+
+ if ( one ) {
+ lbuser->setText( user->getName() );
+ leid->setText( QString::number( user->getUID() ) );
+ if ( ro ) leid->setReadOnly( true );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ lerid->setText( QString::number( user->getSID().getRID() ) );
+ if ( ro ) lerid->setReadOnly( true );
+ }
+ } else {
+ leid->setEnabled( false );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ lerid->setEnabled( false );
+ }
+ }
+ if ( ro ) leshell->setEditable( false );
+
+ while ( user ) {
+
+ setLE( lefname, user->getFullName(), first );
+ QString home;
+ home = user->getHomeDir();
+ if ( !one ) home.replace( user->getName(), "%U" );
+ setLE( lehome, home, first );
+
+ QString shell = user->getShell();
+ if ( first ) {
+ if ( !shell.isEmpty() ) {
+ bool tested = false;
+ for ( int i=0; i<leshell->count(); i++ )
+ if ( leshell->text(i) == shell ) {
+ tested = true;
+ leshell->setCurrentItem(i);
+ break;
+ }
+ if ( !tested ) {
+ leshell->insertItem( shell );
+ leshell->setCurrentItem( leshell->count()-1 );
+ }
+ } else
+ leshell->setCurrentItem(0);
+ } else {
+ if ( leshell->currentText() != shell ) {
+ if ( !ismoreshells ) {
+ leshell->insertItem( i18n("Do Not Change"), 0 );
+ ismoreshells = true;
+ }
+ leshell->setCurrentItem( 0 );
+ }
+ }
+
+ setCB( cbdisabled, user->getDisabled(), first );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Disable_POSIX ) {
+ setCB( cbposix, !(user->getCaps() & KU::KUser::Cap_POSIX), first );
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ setLE( leliscript, user->getLoginScript(), first );
+ QString profile;
+ profile = user->getProfilePath();
+ if ( !one ) profile.replace( user->getName(), "%U" );
+ setLE( leprofile, profile, first );
+ setLE( lehomedrive, user->getHomeDrive(), first );
+ home = user->getHomePath();
+ if ( !one ) home.replace( user->getName(), "%U" );
+ setLE( lehomepath, home, first );
+ setLE( leworkstations, user->getWorkstations(), first );
+ setLE( ledomain, user->getDomain(), first );
+ setLE( ledomsid, user->getSID().getDOM(), first );
+ setCB( cbsamba, !(user->getCaps() & KU::KUser::Cap_Samba), first );
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_BSD ) {
+
+ if ( user->getLastChange() != lstchg ) {
+ leslstchg->setText( "" );
+ lstchg = 0;
+ }
+
+ QDateTime expire;
+ expire.setTime_t( user->getExpire() );
+ kdDebug() << "expiration: " << user->getExpire() << endl;
+ setCB( cbexpire, (int) expire.toTime_t() == -1, first );
+ if ( (int) expire.toTime_t() == -1 ) expire.setTime_t( 0 );
+ if ( first ) {
+ lesexpire->setDateTime( expire );
+ } else {
+ if ( lesexpire->dateTime() != expire ) {
+ expire.setTime_t( 0 );
+ lesexpire->setDateTime( expire );
+ }
+ }
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ) {
+ setSB( lesmin, user->getMin(), first );
+ setSB( lesmax, user->getMax(), first );
+ setSB( leswarn, user->getWarn(), first );
+ setSB( lesinact, user->getInactive(), first );
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_InetOrg ) {
+ setLE( lesurname, user->getSurname(), first );
+ setLE( lemail, user->getEmail(), first );
+ }
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_BSD ) {
+ setLE( leoffice, user->getOffice(), first );
+ setLE( leophone, user->getWorkPhone(), first );
+ setLE( lehphone, user->getHomePhone(), first );
+ setLE( leclass, user->getClass(), first );
+ } else {
+ setLE( leoffice1, user->getOffice1(), first );
+ setLE( leoffice2, user->getOffice2(), first );
+ setLE( leaddress, user->getAddress(), first );
+ }
+
+ first = false;
+ user = mUsers.next();
+ }
+}
+
+void propdlg::loadgroups( bool fixedprivgroup )
+{
+ bool wasprivgr = false;
+
+ primaryGroupWasOn = false;
+
+ KU::KGroup *group = kug->getGroups().first();
+ while ( group ) {
+ QString groupName = group->getName();
+ QCheckListItem *item = new QCheckListItem(lstgrp, groupName, QCheckListItem::CheckBox);
+ KU::KUser *user = mUsers.first();
+ while ( user ) {
+ bool prigr =
+ ( !fixedprivgroup && group->getGID() == user->getGID() ) ||
+ ( fixedprivgroup && groupName == user->getName() );
+ bool on = group->lookup_user( user->getName() ) || prigr;
+
+ if ( prigr ) {
+ item->setEnabled( false );
+ if ( !wasprivgr )
+ primaryGroup = groupName;
+ else
+ if ( primaryGroup != groupName ) primaryGroup = "";
+// primaryGroupWasOn = group->lookup_user(user->getName());
+ wasprivgr = true;
+ }
+
+ if ( mUsers.getFirst() == user )
+ item->setOn( on );
+ else
+ if ( item->isOn() != on ) {
+ item->setTristate( true );
+ item->setState( QCheckListItem::NoChange );
+ }
+ user = mUsers.next();
+ }
+ group = kug->getGroups().next();
+ }
+
+ if ( fixedprivgroup ) {
+ KU::KUser *user = mUsers.first();
+ kdDebug() << "privgroup: " << user->getName() << endl;
+ if ( !wasprivgr ) {
+ QCheckListItem *item = new QCheckListItem(lstgrp, user->getName(), QCheckListItem::CheckBox);
+ item->setOn(true);
+ item->setEnabled(false);
+ primaryGroup = user->getName();
+ }
+ }
+ leprigr->setText( i18n("Primary group: ") + primaryGroup );
+}
+
+void propdlg::setpgroup()
+{
+ isgchanged = true;
+ QCheckListItem *item;
+ item = (QCheckListItem *) lstgrp->selectedItem();
+ if ( item == 0 || item->text() == primaryGroup )
+ return;
+
+ bool prevPrimaryGroupWasOn = primaryGroupWasOn;
+ primaryGroup = ((QCheckListItem *) lstgrp->selectedItem())->text();
+
+ item = (QCheckListItem *) lstgrp->firstChild();
+
+ while(item)
+ {
+ QString groupName = item->text();
+ if ( !item->isEnabled() )
+ {
+ item->setEnabled(true);
+ item->setOn(prevPrimaryGroupWasOn);
+ item->repaint();
+ }
+ if ( groupName == primaryGroup )
+ {
+ primaryGroupWasOn = item->isOn();
+ item->setEnabled(false);
+ item->setOn(true);
+ item->repaint();
+ }
+
+ item = (QCheckListItem *) item->nextSibling();
+ }
+ leprigr->setText( i18n("Primary group: ") + primaryGroup );
+}
+
+void propdlg::changed()
+{
+ QWidget *widget = (QWidget*) sender();
+ if ( mNoChanges.contains( widget ) ) mNoChanges[ widget ]->setChecked( false );
+ ischanged = true;
+ kdDebug() << "changed" << endl;
+}
+
+void propdlg::gchanged()
+{
+ isgchanged = true;
+}
+
+QString propdlg::mergeLE( KLineEdit *le, const QString &val, bool one )
+{
+ QCheckBox *cb = 0;
+ if ( mNoChanges.contains( le ) ) cb = mNoChanges[ le ];
+ return ( one || ( cb && !cb->isChecked() ) ) ? le->text() : val;
+}
+
+int propdlg::mergeSB( KIntSpinBox *sb, int val, bool one )
+{
+ QCheckBox *cb = 0;
+ if ( mNoChanges.contains( sb ) ) cb = mNoChanges[ sb ];
+ return ( one || ( cb && !cb->isChecked() ) ) ? sb->value() : val;
+}
+
+void propdlg::mergeUser( KU::KUser *user, KU::KUser *newuser )
+{
+ QDateTime epoch ;
+ epoch.setTime_t(0);
+ bool one = ( mUsers.getFirst() == mUsers.getLast() );
+ bool posix, samba = false;
+
+ newuser->copy( user );
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Disable_POSIX && cbposix->state() != QButton::NoChange ) {
+ if ( cbposix->isChecked() )
+ newuser->setCaps( newuser->getCaps() & ~KU::KUser::Cap_POSIX );
+ else
+ newuser->setCaps( newuser->getCaps() | KU::KUser::Cap_POSIX );
+ }
+ posix = newuser->getCaps() & KU::KUser::Cap_POSIX;
+ kdDebug() << "posix: " << posix << endl;
+ if ( one ) {
+// newuser->setName( leuser->text() );
+ newuser->setUID( posix ? leid->text().toInt() : 0 );
+ }
+ if ( !newpass.isNull() ) {
+ kug->getUsers().createPassword( newuser, newpass );
+ newuser->setLastChange( lstchg );
+ }
+ newuser->setFullName( mergeLE( lefname, user->getFullName(), one ) );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ if ( cbsamba->state() != QButton::NoChange ) {
+ if ( cbsamba->isChecked() )
+ newuser->setCaps( newuser->getCaps() & ~KU::KUser::Cap_Samba );
+ else
+ newuser->setCaps( newuser->getCaps() | KU::KUser::Cap_Samba );
+ }
+ samba = newuser->getCaps() & KU::KUser::Cap_Samba;
+ kdDebug() << "user : " << newuser->getName() << " caps: " << newuser->getCaps() << " samba: " << samba << endl;
+
+ SID sid;
+ if ( samba ) {
+ sid.setRID( one ? lerid->text().toUInt() : user->getSID().getRID() );
+ sid.setDOM( mergeLE( ledomsid, user->getSID().getDOM(), one ) );
+ }
+ newuser->setSID( sid );
+ newuser->setLoginScript( samba ?
+ mergeLE( leliscript, user->getLoginScript(), one ) : QString::null );
+ newuser->setProfilePath( samba ?
+ mergeLE( leprofile, user->getProfilePath(), one ).replace( "%U", newuser->getName() ) : QString::null );
+ newuser->setHomeDrive( samba ?
+ mergeLE( lehomedrive, user->getHomeDrive(), one ) : QString::null );
+ newuser->setHomePath( samba ?
+ mergeLE( lehomepath, user->getHomePath(), one ).replace( "%U", newuser->getName() ) : QString::null );
+ newuser->setWorkstations( samba ?
+ mergeLE( leworkstations, user->getWorkstations(), one ) : QString::null );
+ newuser->setDomain( samba ?
+ mergeLE( ledomain, user->getDomain(), one ) : QString::null );
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_BSD ) {
+ newuser->setOffice( mergeLE( leoffice, user->getOffice(), one ) );
+ newuser->setWorkPhone( mergeLE( leophone, user->getWorkPhone(), one ) );
+ newuser->setHomePhone( mergeLE( lehphone, user->getHomePhone(), one ) );
+ newuser->setClass( mergeLE( leclass, user->getClass(), one ) );
+ } else {
+ newuser->setOffice1( mergeLE( leoffice1, user->getOffice1(), one ) );
+ newuser->setOffice2( mergeLE( leoffice2, user->getOffice2(), one ) );
+ newuser->setAddress( mergeLE( leaddress, user->getAddress(), one ) );
+ }
+
+ newuser->setHomeDir( posix ?
+ mergeLE( lehome, user->getHomeDir(), one ).replace( "%U", newuser->getName() ) :
+ QString::null );
+ if ( posix ) {
+ if ( leshell->currentItem() == 0 && ismoreshells ) {
+ newuser->setShell( user->getShell() );
+ } else if (
+ ( leshell->currentItem() == 0 && !ismoreshells ) ||
+ ( leshell->currentItem() == 1 && ismoreshells ) ) {
+
+ newuser->setShell( QString::null );
+ } else {
+ // TODO: Check shell.
+ newuser->setShell( leshell->currentText() );
+ }
+ } else
+ newuser->setShell( QString::null );
+
+ newuser->setDisabled( (cbdisabled->state() == QButton::NoChange) ? user->getDisabled() : cbdisabled->isChecked() );
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_InetOrg ) {
+ newuser->setSurname( mergeLE( lesurname, user->getSurname(), one ) );
+ newuser->setEmail( mergeLE( lemail, user->getEmail(), one ) );
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ) {
+ newuser->setMin( posix ? mergeSB( lesmin, user->getMin(), one ) : 0 );
+ newuser->setMax( posix ? mergeSB( lesmax, user->getMax(), one ) : 0 );
+ newuser->setWarn( posix ? mergeSB( leswarn, user->getWarn(), one ) : 0 );
+ newuser->setInactive( posix ? mergeSB( lesinact, user->getInactive(), one ) : 0 );
+ }
+
+ if ( ( (kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow) && posix ) ||
+ ( (kug->getUsers().getCaps() & KU::KUsers::Cap_Samba) && samba ) ||
+ ( (kug->getUsers().getCaps() & KU::KUsers::Cap_BSD) && posix ) ) {
+
+ switch ( cbexpire->state() ) {
+ case QButton::NoChange:
+ newuser->setExpire( user->getExpire() );
+ break;
+ case QButton::On:
+ newuser->setExpire( -1 );
+ break;
+ case QButton::Off:
+ newuser->setExpire( !one && lesexpire->dateTime().toTime_t() == 0 ?
+ user->getExpire() : lesexpire->dateTime().toTime_t() );
+ break;
+ }
+ } else {
+ newuser->setExpire( -1 );
+ }
+
+ if ( !primaryGroup.isEmpty() ) {
+ KU::KGroup *group = kug->getGroups().lookup( primaryGroup );
+ if ( group ) {
+ newuser->setGID( group->getGID() );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ newuser->setPGSID( group->getSID() );
+ }
+ }
+ }
+}
+
+bool propdlg::saveg()
+{
+ if ( !isgchanged ) return true;
+
+ QCheckListItem *item = (QCheckListItem *) lstgrp->firstChild();
+ KU::KGroup *group;
+
+ while(item)
+ {
+ kdDebug() << "saveg: group name: " << item->text() << endl;
+ group = kug->getGroups().lookup(item->text());
+ if ( group && item->state() != QCheckListItem::NoChange ) {
+
+ KU::KGroup newgroup( group );
+ bool mod = false;
+ bool on = item->isOn();
+ KU::KUser *user = mUsers.first();
+
+ while ( user ) {
+ if ( on && (( !primaryGroup.isEmpty() && primaryGroup != group->getName() ) ||
+ ( primaryGroup.isEmpty() && user->getGID() != group->getGID() )) ) {
+ if ( newgroup.addUser( user->getName() ) ) mod = true;
+ } else {
+ if ( newgroup.removeUser( user->getName() ) ) mod = true;
+ }
+ user = mUsers.next();
+ }
+
+ if ( mod ) kug->getGroups().mod( group, newgroup );
+ }
+ item = (QCheckListItem *) item->nextSibling();
+ }
+ return true;
+}
+
+bool propdlg::checkShell(const QString &shell)
+{
+ if (shell.isEmpty())
+ return true;
+ QStringList shells = readShells();
+ return shells.contains(shell);
+}
+
+bool propdlg::check()
+{
+ bool one = ( mUsers.getFirst() == mUsers.getLast() );
+ bool posix = !( kug->getUsers().getCaps() & KU::KUsers::Cap_Disable_POSIX ) || !( cbposix->isChecked() );
+
+ if ( one && posix && leid->text().isEmpty() ) {
+ KMessageBox::sorry( 0, i18n("You need to specify an UID.") );
+ return false;
+ }
+
+ if ( one && posix && lehome->text().isEmpty() ) {
+ KMessageBox::sorry( 0, i18n("You must specify a home directory.") );
+ return false;
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_InetOrg ) {
+ if ( one && lesurname->text().isEmpty() ) {
+ KMessageBox::sorry( 0, i18n("You must fill the surname field.") );
+ return false;
+ }
+ }
+
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) {
+ if ( one && lerid->text().isEmpty() && !( cbsamba->isChecked() ) ) {
+ KMessageBox::sorry( 0, i18n("You need to specify a samba RID.") );
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void propdlg::setpwd()
+{
+ pwddlg pd( this );
+
+ if ( pd.exec() == QDialog::Accepted ) {
+ ischanged = true;
+ newpass = pd.getPassword();
+ lstchg = now();
+ QDateTime datetime;
+ datetime.setTime_t( lstchg );
+ if ( kug->getUsers().getCaps() & KU::KUsers::Cap_Shadow ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ||
+ kug->getUsers().getCaps() & KU::KUsers::Cap_BSD ) {
+
+ leslstchg->setText( KGlobal::locale()->formatDateTime( datetime, false ) );
+ }
+ cbdisabled->setChecked( false );
+ }
+}
+
+void propdlg::slotOk()
+{
+ if ( ro ) {
+ reject();
+ return;
+ }
+
+ bool one = ( mUsers.getFirst() == mUsers.getLast() );
+
+ uid_t newuid = leid->text().toULong();
+
+ if ( one && ( !( kug->getUsers().getCaps() & KU::KUsers::Cap_Disable_POSIX ) || !cbposix->isChecked() )
+ && olduid != newuid )
+ {
+ if (kug->getUsers().lookup(newuid)) {
+ KMessageBox::sorry( 0,
+ i18n("User with UID %1 already exists").arg(newuid) );
+ return;
+ }
+ }
+
+ if ( one && ( kug->getUsers().getCaps() & KU::KUsers::Cap_Samba ) && !cbsamba->isChecked() ) {
+ uint newrid = lerid->text().toInt();
+ if ( oldrid != newrid ) {
+ if (kug->getUsers().lookup_sam(newrid)) {
+ KMessageBox::sorry( 0,
+ i18n("User with RID %1 already exists").arg(newrid) );
+ return;
+ }
+ }
+ }
+
+ QString newshell;
+ if (leshell->currentItem() != 0)
+ newshell = leshell->currentText();
+
+ if (oldshell != newshell)
+ {
+ if (!checkShell(newshell)) {
+ int result = KMessageBox::warningYesNoCancel( 0,
+ i18n("<p>The shell %1 is not yet listed in the file %2. "
+ "In order to use this shell you must add it to "
+ "this file first."
+ "<p>Do you want to add it now?").arg(newshell).arg(QFile::decodeName(SHELL_FILE)),
+ i18n("Unlisted Shell"),
+ i18n("&Add Shell"),
+ i18n("Do &Not Add"));
+ if (result == KMessageBox::Cancel)
+ return;
+
+ if (result == KMessageBox::Yes)
+ addShell(newshell);
+ }
+ }
+
+ if ( !ischanged && !isgchanged ) {
+ reject();
+ } else if ( check() ) {
+ saveg();
+ accept();
+ }
+}
+
+#include "propdlg.moc"
diff --git a/kuser/propdlg.h b/kuser/propdlg.h
new file mode 100644
index 0000000..2832574
--- /dev/null
+++ b/kuser/propdlg.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_PROPDLG_H_
+#define _KU_PROPDLG_H_
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qwidget.h>
+#include <qlistbox.h>
+#include <qtooltip.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qmap.h>
+
+#include <klineedit.h>
+#include <kdatetimewidget.h>
+#include <knuminput.h>
+#include <kdialogbase.h>
+#include <klistview.h>
+#include <kcombobox.h>
+
+#include "kuser.h"
+
+class propdlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ propdlg( const QPtrList<KU::KUser> &users,
+ QWidget *parent = 0, const char *name = 0 );
+ propdlg( KU::KUser *AUser, bool fixedprivgroup,
+ QWidget *parent = 0, const char *name = 0 );
+ ~propdlg();
+
+ void mergeUser( KU::KUser *user, KU::KUser *newuser );
+
+protected slots:
+ virtual void slotOk();
+ void setpwd();
+ void changed(); // Change to misc settings
+ void cbposixChanged(); // Change to diaable POSIX account info
+ void cbsambaChanged(); // Change to diaable POSIX account info
+ void gchanged(); // Change to group settings
+ void setpgroup(); // Change in primary group
+
+protected:
+ void initDlg();
+ void selectuser();
+ void save();
+ bool saveg();
+ bool check();
+ void loadgroups( bool fixedprivgroup );
+ bool checkShell(const QString &shell);
+ void addRow( QWidget *parent, QGridLayout *layout, int row,
+ QWidget *widget, const QString &label, const QString &what,
+ bool two_column=true, bool nochange=true );
+ void setLE( KLineEdit *le, const QString &val, bool first );
+ void setCB( QCheckBox *cb, bool val, bool first );
+ void setSB( KIntSpinBox *sb, int val, bool first );
+ QString mergeLE( KLineEdit *le, const QString &val, bool one );
+ int mergeSB( KIntSpinBox *sb, int val, bool one );
+
+ KIntSpinBox *addDaysGroup( QWidget *parent, QGridLayout *layout, int row,
+ const QString &title, bool never=true );
+
+ QFrame *frontpage;
+ QGridLayout *frontlayout;
+ int frontrow;
+
+ QPtrList<KU::KUser> mUsers;
+ QMap<QWidget*, QCheckBox*> mNoChanges;
+ bool ismoreshells;
+ bool ischanged;
+ bool isgchanged;
+ uid_t olduid;
+ uint oldrid;
+ QString oldshell;
+ QString primaryGroup;
+ bool primaryGroupWasOn;
+ bool ro;
+
+ QString newpass;
+ time_t lstchg;
+
+ KListView *lstgrp;
+
+ QPushButton *pbsetpwd;
+
+ QLabel *lbuser;
+ KLineEdit *leid;
+ KLineEdit *lefname;
+ KLineEdit *lesurname;
+ KLineEdit *lemail;
+
+ KComboBox *leshell;
+ KLineEdit *lehome;
+
+ KLineEdit *leoffice;
+ KLineEdit *leophone;
+ KLineEdit *lehphone;
+ KLineEdit *leclass;
+
+ KLineEdit *leoffice1;
+ KLineEdit *leoffice2;
+ KLineEdit *leaddress;
+
+ QCheckBox *cbdisabled;
+ QCheckBox *cbposix;
+ QCheckBox *cbsamba;
+ QLabel *leprigr;
+ QPushButton *pbprigr;
+
+ QLabel *leslstchg;
+ KIntSpinBox *lesmin;
+ KIntSpinBox *lesmax;
+ KIntSpinBox *leswarn;
+ KIntSpinBox *lesinact;
+ KDateTimeWidget *lesexpire;
+ QCheckBox *cbexpire;
+
+//samba specific:
+ KLineEdit *lerid;
+ KLineEdit *leliscript;
+ KLineEdit *leprofile;
+ KLineEdit *lehomedrive;
+ KLineEdit *lehomepath;
+ KLineEdit *leworkstations;
+ KLineEdit *ledomain;
+ KLineEdit *ledomsid;
+};
+
+#endif // _KU_PROPDLG_H_
+
diff --git a/kuser/pwddlg.cpp b/kuser/pwddlg.cpp
new file mode 100644
index 0000000..3c8f9cd
--- /dev/null
+++ b/kuser/pwddlg.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Former maintainer: Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <qgrid.h>
+
+#include <kmessagebox.h>
+
+#include "pwddlg.h"
+#include "misc.h"
+
+pwddlg::pwddlg( QWidget* parent, const char* name )
+ : KDialogBase(parent, name, true, i18n("Enter Password"), Ok | Cancel, Ok, true)
+{
+ QGrid *page = makeGridMainWidget(2, QGrid::Horizontal);
+
+ QLabel* lb1 = new QLabel(page, "lb1");
+ lb1->setText(i18n("Password:"));
+ lb1->setMinimumSize(lb1->sizeHint());
+ lb1->setAlignment(AlignRight|AlignVCenter);
+
+ lepw1 = new KLineEdit(page, "LineEdit_1");
+
+ // ensure it fits at least 12 characters
+ lepw1->setText( "XXXXXXXXXXXX" );
+ lepw1->setMinimumSize(lepw1->sizeHint());
+
+ // clear text
+ lepw1->clear();
+ lepw1->setFocus();
+ lepw1->setEchoMode(KLineEdit::Password);
+
+ QLabel* lb2 = new QLabel(page, "lb2");
+ lb2->setText(i18n("Verify:"));
+ lb2->setMinimumSize(lb2->sizeHint());
+ lb2->setAlignment(AlignRight|AlignVCenter);
+
+ lepw2 = new KLineEdit(page, "LineEdit_2");
+
+ // ensure it fits at least 12 characters
+ lepw2->setText( "XXXXXXXXXXXX" );
+ lepw2->setMinimumSize(lepw2->sizeHint());
+
+ // clear text
+ lepw2->clear();
+ lepw2->setEchoMode(KLineEdit::Password);
+}
+
+pwddlg::~pwddlg()
+{
+ delete lepw1;
+ delete lepw2;
+}
+
+void pwddlg::slotOk()
+{
+ if ( lepw1->text() != lepw2->text() ) {
+ KMessageBox::sorry( 0, i18n("Passwords are not identical.\nTry again.") );
+ lepw1->clear();
+ lepw2->clear();
+ lepw1->setFocus();
+ } else {
+ accept();
+ }
+}
+
+QString pwddlg::getPassword() const
+{
+ return lepw1->text();
+}
+
+#include "pwddlg.moc"
diff --git a/kuser/pwddlg.h b/kuser/pwddlg.h
new file mode 100644
index 0000000..485a806
--- /dev/null
+++ b/kuser/pwddlg.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ * Maintained by Adriaan de Groot <groot@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_PWDDLG_H_
+#define _KU_PWDDLG_H_
+
+#include <qstring.h>
+#include <klineedit.h>
+#include <kdialogbase.h>
+
+class pwddlg : public KDialogBase {
+ Q_OBJECT
+
+public:
+ pwddlg( QWidget* parent = NULL, const char* name = NULL );
+ ~pwddlg();
+
+ QString getPassword() const;
+protected slots:
+ void slotOk();
+
+private:
+ KLineEdit *lepw1;
+ KLineEdit *lepw2;
+};
+
+#endif // _KU_PWDDLG_H_
diff --git a/kuser/selectconn.cpp b/kuser/selectconn.cpp
new file mode 100644
index 0000000..f5a6385
--- /dev/null
+++ b/kuser/selectconn.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <qpixmap.h>
+#include <qlayout.h>
+
+#include <qlabel.h>
+#include <qgrid.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kinputdialog.h>
+
+#include "kglobal_.h"
+#include "selectconn.h"
+#include "editDefaults.h"
+
+SelectConn::SelectConn(const QString &selected, QWidget* parent, const char * name) :
+ KDialogBase( Plain, WStyle_DialogBorder, parent, name, true,
+ i18n("Connection Selection"), Ok | Apply | Cancel | User1 | User2 | User3 )
+{
+ QStringList conns;
+
+ setButtonText( User3, i18n("&New...") );
+ setButtonText( User2, i18n("&Edit") );
+ setButtonText( User1, i18n("&Delete") );
+
+ QFrame *page = plainPage();
+ QVBoxLayout *topLayout = new QVBoxLayout( page, 0, KDialog::spacingHint() );
+ QLabel *label = new QLabel( i18n("Defined connections:"), page );
+ mCombo = new KComboBox( page );
+ mSelected = selected;
+ kdDebug() << "selected item: " << mSelected << endl;
+
+ conns = kapp->sharedConfig()->groupList();
+ QStringList::iterator it = conns.begin();
+ int i = 0, sel = 0;
+ while ( it != conns.end() ) {
+ if ( (*it).startsWith( "connection-" ) ) {
+ (*it).remove( QRegExp("^connection-") );
+ if ( (*it) == mSelected ) sel = i;
+ i++;
+ it++;
+ } else
+ it = conns.remove( it );
+ }
+ mCombo->insertStringList( conns );
+ if ( mCombo->count() == 0 ) mCombo->insertItem( "default" );
+ mCombo->setCurrentItem( sel );
+ mSelected = connSelected();
+ topLayout->addWidget( label );
+ topLayout->addWidget( mCombo );
+}
+
+QString SelectConn::connSelected()
+{
+ return mCombo->currentText();
+}
+
+void SelectConn::slotUser3()
+{
+ newconn = KInputDialog::getText( QString::null,
+ i18n("Please type the name of the new connection:") );
+ if ( newconn.isEmpty() ) return;
+ if ( kapp->sharedConfig()->groupList().contains( "connection-" + newconn ) ) {
+ KMessageBox::sorry( 0, i18n("A connection with this name already exists.") );
+ return;
+ }
+
+ KUserPrefsBase kcfg( kapp->sharedConfig(), newconn );
+
+ editDefaults eddlg( &kcfg, this );
+ connect(&eddlg, SIGNAL(settingsChanged()), this, SLOT(slotNewApplySettings()));
+ eddlg.exec();
+
+ if ( newconn.isEmpty() )
+ emit( applyClicked() );
+}
+
+void SelectConn::slotNewApplySettings()
+{
+ if ( !newconn.isEmpty() ) {
+ mCombo->insertItem( newconn );
+ mCombo->setCurrentItem( mCombo->count()-1 );
+ mSelected = newconn;
+ }
+}
+
+void SelectConn::slotUser2()
+{
+ kdDebug() << "slotUser2: " << connSelected() << endl;
+ KUserPrefsBase kcfg( kapp->sharedConfig(), connSelected() );
+ kcfg.readConfig();
+
+ editDefaults eddlg( &kcfg, this );
+ connect( &eddlg, SIGNAL(settingsChanged()), this, SLOT(slotApplySettings()) );
+
+ eddlg.exec();
+}
+
+void SelectConn::slotUser1()
+{
+ QString conn = connSelected();
+ if ( KMessageBox::warningContinueCancel( 0, i18n("Do you really want to delete the connection '%1'?").
+ arg( conn ),i18n("Delete Connection"),KStdGuiItem::del() ) == KMessageBox::Cancel ) return;
+
+ kapp->sharedConfig()->deleteGroup( "connection-" + conn, true );
+ kapp->sharedConfig()->sync();
+ mCombo->removeItem( mCombo->currentItem() );
+ if ( mCombo->count() == 0 ) {
+ mCombo->insertItem( "default" );
+ mCombo->setCurrentItem( 0 );
+ }
+ kdDebug() << "slotUser1: " << conn << " " << mSelected << endl;
+ if ( mSelected == conn )
+ emit( applyClicked() );
+}
+
+void SelectConn::slotApply()
+{
+ kdDebug() << "slotApply()" << endl;
+ if ( connSelected() != mSelected ) {
+ mSelected = connSelected();
+ emit( applyClicked() );
+ }
+}
+
+void SelectConn::slotApplySettings()
+{
+ kdDebug() << "slotApplySettings()" << endl;
+ if ( connSelected() == mSelected )
+ emit( applyClicked() );
+}
+
+#include "selectconn.moc"
diff --git a/kuser/selectconn.h b/kuser/selectconn.h
new file mode 100644
index 0000000..674e148
--- /dev/null
+++ b/kuser/selectconn.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _KU_SELECTCONN_H_
+#define _KU_SELECTCONN_H_
+
+#include <kdialogbase.h>
+#include <kcombobox.h>
+
+class SelectConn : public KDialogBase {
+ Q_OBJECT
+public:
+ SelectConn( const QString &selected, QWidget* parent, const char * name);
+ QString connSelected();
+protected slots:
+ void slotUser1();
+ void slotUser2();
+ void slotUser3();
+ void slotNewApplySettings();
+ void slotApplySettings();
+ void slotApply();
+
+protected:
+ KComboBox *mCombo;
+ QString conn, newconn, mSelected;
+};
+
+#endif // _KU_SELECTCONN_H_
diff --git a/kuser/sha1.cpp b/kuser/sha1.cpp
new file mode 100644
index 0000000..6d8a1f0
--- /dev/null
+++ b/kuser/sha1.cpp
@@ -0,0 +1,179 @@
+/*
+ * Cryptographic API.
+ *
+ * SHA1 Secure Hash Algorithm.
+ *
+ * Derived from cryptoapi implementation, adapted for in-place
+ * scatterlist interface. Originally based on the public domain
+ * implementation written by Steve Reid.
+ *
+ * Copyright (c) Alan Smithee.
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "sha1.h"
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_HMAC_BLOCK_SIZE 64
+
+static inline Q_UINT32 rol(Q_UINT32 value, Q_UINT32 bits)
+{
+ return (((value) << (bits)) | ((value) >> (32 - (bits))));
+}
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+# define blk0(i) block32[i]
+
+#define blk(i) (block32[i&15] = rol(block32[(i+13)&15]^block32[(i+8)&15] \
+ ^block32[(i+2)&15]^block32[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5); \
+ w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5); \
+ w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5); \
+ w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+static void sha1_transform(Q_UINT32 *state, const Q_UINT8 *in)
+{
+ Q_UINT32 a, b, c, d, e;
+ Q_UINT32 block32[16];
+
+ /* convert/copy data to workspace */
+ for (a = 0; a < sizeof(block32)/sizeof(Q_UINT32); a++)
+#ifdef WORDS_BIGENDIAN
+ block32[a] = ((const Q_UINT32 *)in)[a];
+#else
+ block32[a] = ((const Q_UINT32 *)in)[a] >> 24 |
+ (((const Q_UINT32 *)in)[a] >> 8 & 0x0000ff00) |
+ (((const Q_UINT32 *)in)[a] << 8 & 0x00ff0000) |
+ (((const Q_UINT32 *)in)[a] << 24);
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variabes */
+ a = b = c = d = e = 0;
+ memset (block32, 0x00, sizeof block32);
+}
+
+void sha1_init(void *ctx)
+{
+ struct sha1_ctx *sctx = (sha1_ctx*) ctx;
+ static const struct sha1_ctx initstate = {
+ 0,
+ { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 },
+ { 0, }
+ };
+
+ *sctx = initstate;
+}
+
+void sha1_update(void *ctx, const Q_UINT8 *data, unsigned int len)
+{
+ struct sha1_ctx *sctx = (sha1_ctx*) ctx;
+ unsigned int i, j;
+
+ j = (sctx->count >> 3) & 0x3f;
+ sctx->count += len << 3;
+
+ if ((j + len) > 63) {
+ memcpy(&sctx->buffer[j], data, (i = 64-j));
+ sha1_transform(sctx->state, sctx->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ sha1_transform(sctx->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&sctx->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+void sha1_final(void* ctx, Q_UINT8 *out)
+{
+ struct sha1_ctx *sctx = (sha1_ctx*) ctx;
+ Q_UINT32 i, j, index, padlen;
+ Q_UINT64 t;
+ Q_UINT8 bits[8] = { 0, };
+ static const Q_UINT8 padding[64] = { 0x80, };
+
+ t = sctx->count;
+ bits[7] = 0xff & t; t>>=8;
+ bits[6] = 0xff & t; t>>=8;
+ bits[5] = 0xff & t; t>>=8;
+ bits[4] = 0xff & t; t>>=8;
+ bits[3] = 0xff & t; t>>=8;
+ bits[2] = 0xff & t; t>>=8;
+ bits[1] = 0xff & t; t>>=8;
+ bits[0] = 0xff & t;
+
+ /* Pad out to 56 mod 64 */
+ index = (sctx->count >> 3) & 0x3f;
+ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+ sha1_update(sctx, padding, padlen);
+
+ /* Append length */
+ sha1_update(sctx, bits, sizeof bits);
+
+ /* Store state in digest */
+ for (i = j = 0; i < 5; i++, j += 4) {
+ Q_UINT32 t2 = sctx->state[i];
+ out[j+3] = t2 & 0xff; t2>>=8;
+ out[j+2] = t2 & 0xff; t2>>=8;
+ out[j+1] = t2 & 0xff; t2>>=8;
+ out[j ] = t2 & 0xff;
+ }
+
+ /* Wipe context */
+ memset(sctx, 0, sizeof *sctx);
+}
+
diff --git a/kuser/sha1.h b/kuser/sha1.h
new file mode 100644
index 0000000..d6b62ad
--- /dev/null
+++ b/kuser/sha1.h
@@ -0,0 +1,36 @@
+/*
+ * Cryptographic API.
+ *
+ * SHA1 Secure Hash Algorithm.
+ *
+ * Derived from cryptoapi implementation, adapted for in-place
+ * scatterlist interface. Originally based on the public domain
+ * implementation written by Steve Reid.
+ *
+ * Copyright (c) Alan Smithee.
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+#include <qglobal.h>
+
+struct sha1_ctx {
+ Q_UINT64 count;
+ Q_UINT32 state[5];
+ Q_UINT8 buffer[64];
+};
+
+void sha1_init(void *ctx);
+void sha1_update(void *ctx, const Q_UINT8 *data, unsigned int len);
+void sha1_final(void* ctx, Q_UINT8 *out);
+
+#endif
diff --git a/kuser/sid.cpp b/kuser/sid.cpp
new file mode 100644
index 0000000..e1080c6
--- /dev/null
+++ b/kuser/sid.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2004 Szombathelyi Gyrgy <gyurco@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "sid.h"
+#include <kdebug.h>
+//From Samba
+/* Take the bottom bit. */
+#define RID_MULTIPLIER 2
+
+/* The two common types. */
+#define USER_RID_TYPE 0
+#define GROUP_RID_TYPE 1
+
+uint SID::mAlgRidBase = 1000;
+
+SID::SID()
+{
+ mRid = 0; mSid = QString::null; mDom = QString::null;
+}
+
+SID::SID( const SID &sid )
+{
+ setSID( sid.getSID() );
+}
+
+SID::SID( const QString &sid )
+{
+ setSID( sid );
+}
+
+SID::~SID()
+{
+}
+
+uint SID::uid2rid( uint uid )
+{
+ return( (( uid*RID_MULTIPLIER ) + mAlgRidBase ) | USER_RID_TYPE );
+}
+
+uint SID::gid2rid( uint gid )
+{
+ return( (( gid*RID_MULTIPLIER ) + mAlgRidBase ) | GROUP_RID_TYPE );
+}
+
+bool SID::operator == ( const SID &sid ) const
+{
+ return ( mSid == sid.mSid && mDom == sid.mDom );
+}
+
+bool SID::operator != ( const SID&sid ) const
+{
+ return ( mSid != sid.mSid || mDom != sid.mDom );
+}
+
+bool SID::isEmpty() const
+{
+ return ( ( mSid.isEmpty() || mRid == 0 ) && mDom.isEmpty() );
+}
+
+void SID::updateSID()
+{
+ mSid = mDom + QString::fromLatin1("-") + QString::number( mRid );
+}
+
+void SID::setSID( const QString &sid )
+{
+ int pos;
+ QString rid;
+
+ mSid = sid;
+ pos = sid.findRev( '-' );
+ mDom = sid.left( pos );
+ rid = sid.right( sid.length() - pos - 1 );
+ mRid = rid.toUInt();
+}
+
+void SID::setRID( const QString &rid )
+{
+ mRid = rid.toUInt();
+ updateSID();
+}
+
+void SID::setRID( uint rid )
+{
+ mRid = rid;
+ updateSID();
+}
+
+void SID::setDOM( const QString &dom )
+{
+ mDom = dom;
+ updateSID();
+}
+
+const QString& SID::getSID() const
+{
+ return mSid;
+}
+
+uint SID::getRID() const
+{
+ return mRid;
+}
+
+const QString& SID::getDOM() const
+{
+ return mDom;
+}
diff --git a/kuser/sid.h b/kuser/sid.h
new file mode 100644
index 0000000..e856b77
--- /dev/null
+++ b/kuser/sid.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2004 Szombathelyi Gyrgy <gyurco@freemail.hu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef _SID_H_
+#define _SID_H_
+
+#include <qstring.h>
+
+class SID {
+
+public:
+ SID();
+ SID( const QString &sid );
+ SID( const SID &sid );
+ ~SID();
+
+ bool operator== ( const SID &sid ) const;
+ bool operator!= ( const SID &sid ) const;
+ bool isEmpty() const;
+ void setSID( const QString &sid );
+ void setRID( const QString &rid );
+ void setRID( uint rid );
+ void setDOM( const QString &dom );
+ const QString &getSID() const;
+ uint getRID() const ;
+ const QString &getDOM() const;
+
+ static uint uid2rid( uint uid );
+ static uint gid2rid( uint gid );
+ static void setAlgRidBase( uint base ) { mAlgRidBase = base; };
+ static uint getAlgRidBase() { return mAlgRidBase; };
+private:
+ void updateSID();
+ QString mSid, mDom;
+ uint mRid;
+ static uint mAlgRidBase;
+};
+
+#endif //_SID_H_
diff --git a/kuser/stamp-h.in b/kuser/stamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/kuser/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/kuser/toolbar/Makefile.am b/kuser/toolbar/Makefile.am
new file mode 100644
index 0000000..acee0fe
--- /dev/null
+++ b/kuser/toolbar/Makefile.am
@@ -0,0 +1,2 @@
+kusericonsdir = $(kde_datadir)/kuser/icons
+kusericons_ICON = AUTO
diff --git a/kuser/toolbar/cr22-action-add_group.png b/kuser/toolbar/cr22-action-add_group.png
new file mode 100644
index 0000000..8260a89
--- /dev/null
+++ b/kuser/toolbar/cr22-action-add_group.png
Binary files differ
diff --git a/kuser/toolbar/cr22-action-add_user.png b/kuser/toolbar/cr22-action-add_user.png
new file mode 100644
index 0000000..ec800f4
--- /dev/null
+++ b/kuser/toolbar/cr22-action-add_user.png
Binary files differ
diff --git a/kuser/toolbar/cr22-action-delete_group.png b/kuser/toolbar/cr22-action-delete_group.png
new file mode 100644
index 0000000..41984a9
--- /dev/null
+++ b/kuser/toolbar/cr22-action-delete_group.png
Binary files differ
diff --git a/kuser/toolbar/cr22-action-delete_user.png b/kuser/toolbar/cr22-action-delete_user.png
new file mode 100644
index 0000000..73fb036
--- /dev/null
+++ b/kuser/toolbar/cr22-action-delete_user.png
Binary files differ
diff --git a/kuser/toolbar/cr22-action-edit_group.png b/kuser/toolbar/cr22-action-edit_group.png
new file mode 100644
index 0000000..490404c
--- /dev/null
+++ b/kuser/toolbar/cr22-action-edit_group.png
Binary files differ
diff --git a/kuser/toolbar/cr22-action-edit_user.png b/kuser/toolbar/cr22-action-edit_user.png
new file mode 100644
index 0000000..5c9e727
--- /dev/null
+++ b/kuser/toolbar/cr22-action-edit_user.png
Binary files differ
diff --git a/lilo-config/COPYING b/lilo-config/COPYING
new file mode 100644
index 0000000..8c1e969
--- /dev/null
+++ b/lilo-config/COPYING
@@ -0,0 +1,346 @@
+NOTE: The GPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to are copyrighted by the author(s) who
+actually wrote it.
+
+---------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/lilo-config/Makefile.am b/lilo-config/Makefile.am
new file mode 100644
index 0000000..2a20143
--- /dev/null
+++ b/lilo-config/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = common kde-qt-common kde
+
+messages:
+ $(XGETTEXT) -k_ */*.cpp -o $(podir)/kcmlilo.pot
+
diff --git a/lilo-config/README b/lilo-config/README
new file mode 100644
index 0000000..db83406
--- /dev/null
+++ b/lilo-config/README
@@ -0,0 +1,9 @@
+lilo-config is a kcontrol plugin for configuring LILO, the most commonly
+used Linux boot loader.
+
+Parts of the code (basically all the code that does the real work) are designed
+to be UI independent (if I ever have the time, there will be a textmode
+frontend), which is why I'm using "String"s rather than "QString"s throughout
+the code. Please don't change this.
+
+Send comments/suggestions to kde-devel@kde.org.
diff --git a/lilo-config/common/Config.cc b/lilo-config/common/Config.cc
new file mode 100644
index 0000000..37921ba
--- /dev/null
+++ b/lilo-config/common/Config.cc
@@ -0,0 +1,66 @@
+/* Config.cc
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "Config.h"
+void ConfigFile::set(String const &key, String const &value, bool const &quote, bool const &removeIfEmpty, String const &prefix)
+{
+ String re="[ \t]*" + key + "[ \t]*=";
+ String s=grep(re);
+ if(value.empty() && removeIfEmpty) {
+ if(!s.empty())
+ remove(s);
+ } else if(s.empty()) {
+ if(quote)
+ insert(end(), prefix + key + "=\"" + value + "\"");
+ else
+ insert(end(), prefix + key + "=" + value);
+ } else {
+ for(iterator it=begin(); it!=end(); it++)
+ if(!(*it).regex(re).empty()) {
+ if(quote)
+ (*it)=prefix + key + "=\"" + value +"\"";
+ else
+ (*it)=prefix + key + "=" + value;
+ break;
+ }
+ }
+}
+String const ConfigFile::get(String const &key, String const &dflt, bool const &unquote)
+{
+ String s=grep("[ \t]*" + key + "[ \t]*=").simplifyWhiteSpace();
+ if(s.empty())
+ return dflt;
+ s=s.mid(s.locate("=")+2).simplifyWhiteSpace();
+ if(unquote) {
+ if(s.chr(0)=='"')
+ s=s.mid(2);
+ if(s.chr(s.size()-1)=='"')
+ s=s.left(s.size()-1);
+ }
+ return s.simplifyWhiteSpace();
+}
diff --git a/lilo-config/common/Config.h b/lilo-config/common/Config.h
new file mode 100644
index 0000000..6ac6334
--- /dev/null
+++ b/lilo-config/common/Config.h
@@ -0,0 +1,40 @@
+/* Config.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _CONFIGFILE_H_
+#define _CONFIGFILE_H_ 1
+
+#include "String.h"
+class ConfigFile:public StringList
+{
+public:
+ void set(String const &key, String const &value, bool const &quote=true, bool const &removeIfEmpty=true, String const &prefix="");
+ String const get(String const &key, String const &dflt="", bool const &unquote=true);
+};
+
+#endif
diff --git a/lilo-config/common/Disks.cc b/lilo-config/common/Disks.cc
new file mode 100644
index 0000000..b4a417d
--- /dev/null
+++ b/lilo-config/common/Disks.cc
@@ -0,0 +1,294 @@
+/* Disks.cc
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "Disks.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+StringList ptable::disklist()
+{
+ /* The basics behind scanning for a disk are simple: If it can be *
+ * opened, it exists. *
+ * Using access() is not sufficient - that's successful if the device *
+ * node exists but there's no actual device. *
+ * Checking /proc/devices would work, but it wouldn't autoload modules*
+ * so chances are we'd be missing something. */
+ StringList dsk;
+ int fd;
+ bool finished=false;
+ #define CHECK_DEV(d) if((fd=open(d, O_RDONLY))<0) { \
+ finished=true; \
+ continue; \
+ } \
+ close(fd); \
+ dsk+=d
+ String dev="/dev/hd"; // IDE devices: /dev/hd[a-t]
+ for(char a='a'; a<='t'; a++) {
+ // We can't use finished for IDE drives - it's perfectly OK
+ // to have a /dev/hdc but no /dev/hdb.
+ CHECK_DEV(dev+a);
+ }
+ finished=false;
+ dev="/dev/sd"; // SCSI disks 0-25
+ for(char a='a'; a<='z' && !finished; a++) {
+ CHECK_DEV(dev+a);
+ }
+ for(char prefix='a'; prefix <='d' && !finished; prefix++) {
+ dev="/dev/sd" + prefix; // SCSI disks 26-127
+ for(char a='a'; (a<='x' || (a<='z' && prefix<'d')) && !finished; a++) {
+ CHECK_DEV(dev+a);
+ }
+ }
+ finished=false;
+ dev="/dev/i2o/hd"; // I2O disks 0-25: /dev/i2o/hd[a-z]
+ for(char a='a'; a<='z' && !finished; a++) {
+ CHECK_DEV(dev+a);
+ }
+ for(char prefix='a'; prefix <='d' && !finished; prefix++) {
+ dev="/dev/i2o/hd" + prefix; // I2O disks 26-127
+ for(char a='a'; (a<='x' || (a<='z' && prefix<'d')) && !finished; a++) {
+ CHECK_DEV(dev+a);
+ }
+ }
+ finished=false;
+ dev="/dev/pd"; // Parallel port disks: /dev/pd[a-d]
+ for(char a='a'; a<='d' && !finished; a++) {
+ CHECK_DEV(dev+a);
+ }
+ finished=false;
+ for(unsigned int i=0; i<=31 && !finished; i++) { // Software RAID
+ String device;
+ device.sprintf("/dev/md%u", i);
+ CHECK_DEV(device);
+ }
+ finished=false;
+ for(unsigned int i=0; i<=7; i++) { //Compaq Smart Array
+ for(unsigned int j=0; j<=15 && !finished; j++) {
+ String device;
+ device.sprintf("/dev/ida/c%ud%u", i, j);
+ CHECK_DEV(device);
+ }
+ }
+ finished=false;
+ for(unsigned int i=0; i<=7; i++) { // Mylex DAC960
+ for(unsigned int j=0; j<=31 && !finished; j++) {
+ String device;
+ device.sprintf("/dev/rd/c%ud%u", i, j);
+ CHECK_DEV(device);
+ }
+ }
+ finished=false;
+ dev="/dev/ed"; // MCA ESDI harddisks: /dev/ed[ab]
+ for(char a='a'; a<='b' && !finished; a++) {
+ CHECK_DEV(dev+a);
+ }
+ finished=false;
+ dev="/dev/xd"; // XT (8-bit) harddisks: /dev/xd[ab]
+ for(char a='a'; a<='b' && !finished; a++) {
+ CHECK_DEV(dev+a);
+ }
+ return dsk;
+}
+StringList ptable::partlist()
+{
+ StringList s;
+ StringList d=disklist();
+ for(StringList::const_iterator it=d.begin(); it!=d.end(); it++) {
+ for(int i=1; i<32; i++) {
+ String drive;
+ drive.sprintf("%s%u", (*it).cstr(), i);
+ int fd=open(drive, O_RDONLY);
+ if(fd>=0) {
+ char test;
+ if(read(fd, &test, 1)>0)
+ s += drive;
+ close(fd);
+ } else
+ break;
+ }
+ }
+ return s;
+}
+ptable::ptable(StringList const &disks)
+{
+ partition.clear();
+ id.clear();
+ mountpt.clear();
+ for(StringList::const_iterator it=disks.begin(); it!=disks.end(); it++)
+ scandisk(*it);
+}
+ptable::ptable(String const &disk)
+{
+ partition.clear();
+ id.clear();
+ mountpt.clear();
+ scandisk(disk);
+}
+void ptable::scandisk(String const &disk)
+{
+ String cmd;
+ cmd.sprintf("fdisk -l %s 2>&1", (char*)disk);
+ FILE *fdisk=popen(cmd, "r");
+ char *buf=(char *) malloc(1024);
+ String dev;
+ while(fgets(buf, 1024, fdisk)) {
+ if(strncmp("/dev/", buf, 5)==0) { // Partition entry
+ // We don't care about active vs. non-active partitions.
+ // Remove the sign.
+ while(strchr(buf, '*')) *strchr(buf, '*')=' ';
+ // blanks are blanks...
+ while(strchr(buf, '\t')) *strchr(buf, '\t')=' ';
+ // Get the device
+ *strchr(buf, ' ')=0;
+ dev=buf;
+ partition += buf;
+ // And figure out where/if it's mounted
+ mountpt[dev]=mountpoint(dev);
+ // Lastly, get the partition type.
+ strcpy(buf, buf+strlen(buf)+1);
+ while(isspace(*buf)) strcpy(buf, buf+1);
+ strcpy(buf, strchr(buf, ' ')); // skip Start
+ while(isspace(*buf)) strcpy(buf, buf+1);
+ strcpy(buf, strchr(buf, ' ')); // skip End
+ while(isspace(*buf)) strcpy(buf, buf+1);
+ strcpy(buf, strchr(buf, ' ')); // skip Blocks
+ while(isspace(*buf)) strcpy(buf, buf+1);
+ id[dev]=strtol(buf, NULL, 16);
+ }
+ }
+ pclose(fdisk);
+ free(buf);
+}
+String ptable::mountpoint(String const &device, bool fstab_fallback)
+{
+ char *buf=new char[1024];
+ FILE *f=fopen("/etc/mtab", "r");
+ String mp="";
+ while(fgets(buf, 1024, f)) {
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ if(device.cmp(buf)) {
+ strcpy(buf, buf+strlen(buf)+1);
+ while(isspace(*buf))
+ strcpy(buf, buf+1);
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ mp=buf;
+ mp=mp.simplifyWhiteSpace();
+ break;
+ }
+ }
+ fclose(f);
+ if(mp.empty() && fstab_fallback) {
+ f=fopen("/etc/fstab", "r");
+ while(fgets(buf, 1024, f)) {
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ if(device.cmp(buf)) {
+ strcpy(buf, buf+strlen(buf)+1);
+ while(isspace(*buf))
+ strcpy(buf, buf+1);
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ mp=buf;
+ mp=mp.simplifyWhiteSpace();
+ break;
+ }
+ }
+ fclose(f);
+ }
+ delete buf;
+ return mp;
+}
+String ptable::device(String const &mountpt, bool fstab_fallback)
+{
+ char *buf=new char[1024];
+ FILE *f=fopen("/etc/mtab", "r");
+ String dev="";
+ while(fgets(buf, 1024, f)) {
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ String device=buf;
+ strcpy(buf, buf+strlen(buf)+1);
+ while(isspace(*buf))
+ strcpy(buf, buf+1);
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ String mp=buf;
+ mp=mp.simplifyWhiteSpace();
+ if(mp==mountpt) {
+ dev=device;
+ break;
+ }
+ }
+ fclose(f);
+
+ if(dev.empty() && fstab_fallback) {
+ // The FS is not mounted - maybe it could be, though.
+ f=fopen("/etc/fstab", "r");
+ while(fgets(buf, 1024, f)) {
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ String device=buf;
+ strcpy(buf, buf+strlen(buf)+1);
+ while(isspace(*buf))
+ strcpy(buf, buf+1);
+ if(strchr(buf,' '))
+ *strchr(buf, ' ')=0;
+ if(strchr(buf,'\t'))
+ *strchr(buf, '\t')=0;
+ String mp=buf;
+ mp=mp.simplifyWhiteSpace();
+ if(mp==mountpt) {
+ dev=device;
+ break;
+ }
+ }
+ fclose(f);
+ }
+ delete buf;
+ return dev;
+}
diff --git a/lilo-config/common/Disks.h b/lilo-config/common/Disks.h
new file mode 100644
index 0000000..8965694
--- /dev/null
+++ b/lilo-config/common/Disks.h
@@ -0,0 +1,49 @@
+/* Disks.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _DISKS_H_
+#define _DISKS_H_ 1
+#include "String.h"
+#include <list>
+#include <map>
+class ptable {
+public:
+ ptable(StringList const &disks=disklist());
+ ptable(String const &disk);
+ static StringList disklist();
+ static StringList partlist();
+ static String mountpoint(String const &device, bool fstab_fallback=false);
+ static String device(String const &mountpt, bool fstab_fallback=false);
+protected:
+ void scandisk(String const &disk);
+public:
+ StringList partition;
+ std::map<String,int> id;
+ std::map<String,String> mountpt;
+};
+#endif
diff --git a/lilo-config/common/Files.cc b/lilo-config/common/Files.cc
new file mode 100644
index 0000000..19af29d
--- /dev/null
+++ b/lilo-config/common/Files.cc
@@ -0,0 +1,70 @@
+/* Files.cc
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "Files.h"
+#include <glob.h>
+#include <sys/stat.h>
+#define ISSET(x,y) ((x&y)==y)
+StringList &Files::glob(String name, enum Types types, bool dotfiles, bool braces)
+{
+ glob_t gl;
+ int flags=0;
+ StringList *result;
+ if(dotfiles)
+ flags |= GLOB_PERIOD;
+ if(braces)
+ flags |= GLOB_BRACE;
+ ::glob(name, flags, NULL, &gl);
+ if(types==Any)
+ result=new StringList(gl.gl_pathv, gl.gl_pathc);
+ else {
+ struct stat s;
+ result=new StringList;
+ for(unsigned int i=0; i<gl.gl_pathc; i++) {
+ if(!lstat(gl.gl_pathv[i], &s)) {
+ if(S_ISLNK(s.st_mode) && !ISSET(types,Link))
+ continue;
+ if(S_ISREG(s.st_mode) && !ISSET(types,File))
+ continue;
+ if(S_ISDIR(s.st_mode) && !ISSET(types,Dir))
+ continue;
+ if(S_ISCHR(s.st_mode) && !ISSET(types,CharDevice))
+ continue;
+ if(S_ISBLK(s.st_mode) && !ISSET(types,BlockDevice))
+ continue;
+ if(S_ISFIFO(s.st_mode) && !ISSET(types,Fifo))
+ continue;
+ if(S_ISSOCK(s.st_mode) && !ISSET(types,Socket))
+ continue;
+ result->insert(result->end(), gl.gl_pathv[i]);
+ }
+ }
+ }
+ globfree(&gl);
+ return *result;
+}
diff --git a/lilo-config/common/Files.h b/lilo-config/common/Files.h
new file mode 100644
index 0000000..ad1fa3b
--- /dev/null
+++ b/lilo-config/common/Files.h
@@ -0,0 +1,47 @@
+/* Files.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _FILES_H_
+#define _FILES_H_ 1
+#include "String.h"
+class Files {
+public:
+ enum Types { File = 0x1,
+ Dir = 0x2,
+ Link = 0x4,
+ CharDevice = 0x8,
+ BlockDevice= 0x10,
+ Device = CharDevice | BlockDevice,
+ Fifo = 0x20,
+ Socket = 0x40,
+ All = File | Dir | Link | Device | Fifo | Socket,
+ Any = All
+ };
+ static StringList &glob(String name, enum Types types=All, bool dotfiles=true, bool braces=true);
+};
+#endif
diff --git a/lilo-config/common/Makefile.am b/lilo-config/common/Makefile.am
new file mode 100644
index 0000000..37b44eb
--- /dev/null
+++ b/lilo-config/common/Makefile.am
@@ -0,0 +1,11 @@
+# SUBDIRS = tests
+
+noinst_LTLIBRARIES = libcommon.la
+INCLUDES = $(all_includes)
+
+noinst_HEADERS = \
+ String.h Files.h Disks.h Config.h lilo.h
+
+libcommon_la_SOURCES = \
+ String.cc Files.cc Disks.cc Config.cc lilo.cc
+
diff --git a/lilo-config/common/String.cc b/lilo-config/common/String.cc
new file mode 100644
index 0000000..f8a0e35
--- /dev/null
+++ b/lilo-config/common/String.cc
@@ -0,0 +1,437 @@
+/* String.cc
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#define _GNU_SOURCE 1
+#include <features.h>
+#include <string.h>
+#include <string>
+#include "String.h"
+#include <stdio.h>
+#include <regex.h>
+#include <stdlib.h>
+
+using namespace std;
+
+void String::sprintf(const char *format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ char *buf=0;
+ int size=vsnprintf(buf, 0, format, arg);
+ if(size==-1) { /* ARGH!!! */
+ cerr << "WARNING: Your C library (libc) does not conform to the ISO C99 standard!" << endl << "Consider upgrading to glibc 2.1 or higher!" << endl;
+ int bufsiz=1024;
+ while(size==-1) {
+ buf=(char *) malloc(bufsiz);
+ size=vsnprintf(buf, 0, format, arg);
+ bufsiz+=1024;
+ free(buf);
+ }
+ }
+ buf=(char *) malloc(size+1);
+ vsnprintf(buf, size+1, format, arg);
+ string str=buf;
+ *this=buf;
+ va_end(arg);
+ free(buf);
+ return;
+}
+bool String::readfile(String filename)
+{
+ FILE *f=fopen(filename, "r");
+ if(!f)
+ return false;
+
+ string str="";
+ char *buf=(char *) malloc(1024);
+ while(!feof(f) && !ferror(f)) {
+ if(!fgets(buf, 1024, f))
+ continue;
+ str += buf;
+ };
+ *this=buf;
+ free(buf);
+ fclose(f);
+ return true;
+}
+char *String::cstr() const
+{
+ char *a=new char[size()+1];
+ a[size()]=0;
+ strncpy(a, data(), size());
+ return a;
+}
+bool String::cmp(char const * const s) const
+{
+ if(size() != strlen(s))
+ return false;
+ return (strncmp(data(), s, size())==0);
+}
+bool String::casecmp(char const * const s) const
+{
+ if(size() != strlen(s))
+ return false;
+ return (strncasecmp(data(), s, size())==0);
+}
+bool String::contains(String const &s, bool cs) const
+{
+ if(cs)
+ if(strstr(cstr(), s.cstr()))
+ return true;
+ else
+ return false;
+ else
+ if(strcasestr(cstr(), s.cstr()))
+ return true;
+ else
+ return false;
+}
+int String::locate(String const &s, bool cs, unsigned int startat) const
+{
+ if(startat>=size())
+ return -1;
+
+ char *s0=cstr(), *s1=s.cstr(), *s2;
+ int r;
+ if(cs)
+ s2=strstr(s0+startat, s1);
+ else
+ s2=strcasestr(s0+startat, s1);
+ if(s2==NULL) {
+ delete [] s0;
+ delete [] s1;
+ return -1;
+ }
+ r=(s2-s0);
+ if(startat>0) r++;
+ delete [] s0;
+ delete [] s1;
+ return r;
+}
+String const String::operator +(char const &s) {
+ char a[2];
+ a[0]=s;
+ a[1]=0;
+ String st=cstr();
+ st+=a;
+ return st;
+}
+String const String::operator +(char const * const s) {
+ String st=cstr();
+ st += s;
+ return st;
+}
+bool String::operator ==(char s) {
+ if(size()==1 && cstr()[0]==s)
+ return true;
+ else
+ return false;
+}
+bool String::operator !=(char s) {
+ if(size()!=1 || cstr()[0]!=s)
+ return true;
+ else
+ return false;
+}
+String String::simplifyWhiteSpace() const {
+ char *s=cstr();
+ for(unsigned int i=0; i<size(); i++)
+ if(isspace(s[i]))
+ s[i]=' ';
+ while(*s==' ')
+ strcpy(s, s+1);
+ int l = strlen(s);
+ while(l && (s[l-1]==' '))
+ s[--l]=0;
+
+ while(strstr(s, " "))
+ strcpy(strstr(s, " "), strstr(s, " ")+1);
+ return s;
+}
+String String::left(unsigned int num) const
+{
+ if(num==0) return "";
+ char *s=cstr();
+ if(size()<=num)
+ return s;
+ s[num]=0;
+ return s;
+}
+String String::right(unsigned int num) const
+{
+ if(num==0) return "";
+ char *s=cstr();
+ if(size()<=num)
+ return s;
+ strcpy(s, s+strlen(s)-num);
+ return s;
+}
+String String::mid(unsigned int start, unsigned int num) const
+{
+ if(start>=size())
+ return "";
+ char *s=cstr();
+ start--;
+ if(start>0)
+ strcpy(s, s+start);
+ if(num>0 && num<=strlen(s))
+ s[num]=0;
+ return s;
+}
+String &String::regex(String const &expr, bool cs) const
+{
+ regex_t regexp;
+ int err;
+ regmatch_t reg[1];
+ String *ret=new String("");
+ if((err=regcomp(&regexp, expr, cs?REG_EXTENDED:REG_EXTENDED|REG_ICASE))) {
+ regfree(&regexp);
+ return *ret;
+ }
+ err=regexec(&regexp, cstr(), 1, reg, 0);
+ regfree(&regexp);
+ if(err)
+ return *ret;
+ if(reg[0].rm_so!=-1) {
+ char *s=strdup(cstr()+reg[0].rm_so);
+ s[reg[0].rm_eo-reg[0].rm_so]=0;
+ delete ret;
+ ret=new String(s);
+ free(s);
+ }
+ return *ret;
+}
+String &String::replace(String const &what, String const &with, bool all) const
+{
+ String *result;
+ if(!contains(what)) {
+ result=new String(*this);
+ return *result;
+ }
+ result=new String;
+ *result=left(locate(what));
+ *result+=with;
+ if(!all) {
+ *result+=right(size()-locate(what)-what.size());
+ } else {
+ unsigned int start=locate(what)+what.size()+1;
+ int loc;
+ while((loc=locate(what, true, start+1))!=-1) {
+ *result+=mid(start, loc-start);
+ *result+=with;
+ start=locate(what, true, start)+what.size();
+ }
+ if(size()>start)
+ *result+=right(size()-start+1);
+ }
+ return *result;
+}
+String String::escapeForRegExp(String const &s)
+{
+ static const char meta[] = "$()*+.?[\\]^{|}";
+ String quoted = s;
+ int i = 0;
+
+ while ( i < (int) quoted.length() ) {
+ if ( strchr(meta, quoted.at(i)) != 0 )
+ quoted.insert( i++, "\\" );
+ i++;
+ }
+ return quoted;
+}
+StringList::StringList(String const &s)
+{
+ clear();
+ char *st=strdup((char const * const)s);
+ char *tok;
+ char *line=strtok_r(st, "\n", &tok);
+ while(line) {
+ if(line[strlen(line)-1]=='\r') // Handle sucking OSes
+ line[strlen(line)-1]=0;
+ insert(end(), line);
+ line=strtok_r(NULL, "\n", &tok);
+ }
+ free(st);
+}
+
+StringList::StringList(char **strs, int num)
+{
+ clear();
+ if(num>=0) {
+ for(int i=0; i<num; i++)
+ insert(end(), strs[i]);
+ } else {
+ for(int i=0; strs[i]!=NULL; i++)
+ insert(end(), strs[i]);
+ }
+}
+
+bool StringList::readfile(String const &filename)
+{
+ clear();
+ FILE *f=fopen(filename, "r");
+ if(!f)
+ return false;
+ char *buf=(char *) malloc(1024);
+ while(!feof(f) && !ferror(f)) {
+ if(!fgets(buf, 1024, f))
+ continue;
+ while(strlen(buf) && (buf[strlen(buf)-1]=='\n' || buf[strlen(buf)-1]=='\r'))
+ buf[strlen(buf)-1]=0;
+ insert(end(), buf);
+ };
+ free(buf);
+ fclose(f);
+ return true;
+}
+bool StringList::writefile(String const &filename) const
+{
+ FILE *f=fopen(filename, "w");
+ if(!f)
+ return false;
+ for(const_iterator it=begin(); it!=end(); it++) {
+ fputs(*it, f);
+ fputs("\n", f);
+ }
+ fclose(f);
+ return true;
+}
+void StringList::operator +=(StringList const &s)
+{
+ for(const_iterator it=s.begin(); it!=s.end(); it++)
+ insert(end(), *it);
+}
+void StringList::operator +=(StringList const * const s)
+{
+ for(const_iterator it=s->begin(); it!=s->end(); it++)
+ insert(end(), *it);
+}
+bool StringList::contains(String const &s) const
+{
+ for(const_iterator it=begin(); it!=end(); it++)
+ if(*it == s)
+ return true;
+ return false;
+}
+void StringList::remove(String const &s)
+{
+ bool done=false;
+ for(iterator it=begin(); !done && it!=end(); it++)
+ if(*it==s) {
+ erase(it);
+ done=true;
+ }
+}
+String const &StringList::grep(String const &s) const
+{
+ for(const_iterator it=begin(); it!=end(); it++)
+ if(!(*it).regex(s).empty())
+ return *it;
+ String *r=new String;
+ return *r;
+}
+int __stringlist_compare(const void *a, const void *b)
+{
+ if(a==0 && b==0)
+ return 0;
+ else if(a==0)
+ return 1;
+ else if(b==0)
+ return -1;
+ else
+ return strcmp((const char *)a,(const char *)b);
+}
+int __stringlist_compare_noncs(const void *a, const void *b)
+{
+ if(a==0 && b==0)
+ return 0;
+ else if(a==0)
+ return 1;
+ else if(b==0)
+ return -1;
+ else
+ return strcasecmp((const char *)a,(const char *)b);
+}
+void StringList::sort(bool cs)
+{
+ unsigned int i=0, s=size();
+ char **strings=new char*[s];
+ for(const_iterator it=begin(); it!=end(); it++)
+ strings[i++]=(*it).cstr();
+ if(cs)
+ qsort(strings, s, sizeof(char*), __stringlist_compare);
+ else
+ qsort(strings, s, sizeof(char*), __stringlist_compare_noncs);
+ clear();
+ for(i=0; i<s; i++) {
+ insert(end(), strings[i]);
+ delete [] strings[i];
+ }
+ delete [] strings;
+}
+StringList::operator String() const
+{
+ String s="";
+ for(const_iterator it=begin(); it!=end(); it++) {
+ s+=(*it);
+ if(s.right()!=String("\n") && s.right()!=String("\r"))
+ s+="\n";
+ }
+ return s;
+}
+
+ostream &operator <<(ostream &os, String const &s)
+{
+ if(!s.empty())
+ os << (char const * const) s;
+ return os;
+}
+ostream &operator <<(ostream &os, String const *s)
+{
+ if(!s->empty())
+ os << (char const * const) *s;
+ return os;
+}
+ostream &operator <<(ostream &os, StringList const &s)
+{
+ for(StringList::const_iterator it=s.begin(); it!=s.end(); it++) {
+ os << *it;
+ if((*it).right()!=String("\n") && (*it).right()!=String("\r"))
+ os << endl;
+ }
+ return os;
+}
+ostream &operator <<(ostream &os, StringList const *s)
+{
+ for(StringList::const_iterator it=s->begin(); it!=s->end(); it++) {
+ os << *it;
+ if((*it).right()!=String("\n") && (*it).right()!=String("\r"))
+ os << endl;
+ }
+ return os;
+}
diff --git a/lilo-config/common/String.h b/lilo-config/common/String.h
new file mode 100644
index 0000000..7b12af5
--- /dev/null
+++ b/lilo-config/common/String.h
@@ -0,0 +1,96 @@
+/* String.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+/* Somewhat more sane string handling functions... *
+ * Should be portable, therefore we aren't simply using QString. */
+
+#ifndef _STRING_H_
+#define _STRING_H_ 1
+#include <string>
+#include <list>
+#include <iostream>
+#include <stdarg.h>
+
+class String;
+class StringList;
+
+typedef std::list<String> strlist;
+
+class String:public std::string {
+public:
+ String():std::string("") { }
+ String(char const * const &s):std::string(s) { }
+ String(std::string const &s):std::string(s) { }
+ String const operator +(char const &s);
+ String const operator +(char const * const s);
+ bool operator ==(char s);
+ bool operator !=(char s);
+ operator char * () const { return cstr(); }
+ char * cstr() const;
+ bool cmp(char const * const s) const;
+ bool casecmp(char const * const s) const;
+ bool contains(String const &s, bool cs=true) const;
+ int locate(String const &s, bool cs=true, unsigned int startat=0) const;
+ void sprintf(const char *format, ...);
+ bool readfile(String filename);
+ String simplifyWhiteSpace() const;
+ String left(unsigned int num=1) const;
+ String right(unsigned int num=1) const;
+ String mid(unsigned int start, unsigned int num=0) const;
+ String &regex(String const &expr, bool cs=true) const;
+ String &replace(String const &what, String const &with, bool all=true) const;
+ static String escapeForRegExp(String const &s);
+ char chr(unsigned int index) const { if(index>=size()) return 0; else return data()[index]; }
+ int length() const { return size(); } // For compatibility with QString
+ char const *latin1() const { return cstr(); } // For compatibility with QString
+};
+
+class StringList:public strlist {
+public:
+ StringList() { clear(); }
+ StringList(String const &s);
+ StringList(char **strs, int num=-1);
+ bool readfile(String const &filename);
+ bool writefile(String const &filename) const;
+ void operator +=(String const &s) { insert(end(), s); }
+ void operator +=(char const * const &s) { insert(end(), s); }
+ void operator +=(StringList const &s);
+ void operator +=(StringList const * const s);
+ operator String() const;
+ bool contains(String const &s) const;
+ void remove(String const &s);
+ void add(String const &s) { insert(end(), s); }
+ String const &grep(String const &s) const;
+ void sort(bool cs=true);
+};
+
+std::ostream &operator <<(std::ostream &os, String const &s);
+std::ostream &operator <<(std::ostream &os, String const *s);
+std::ostream &operator <<(std::ostream &os, StringList const &s);
+std::ostream &operator <<(std::ostream &os, StringList const *s);
+#endif
diff --git a/lilo-config/common/lilo.cc b/lilo-config/common/lilo.cc
new file mode 100644
index 0000000..6625f0d
--- /dev/null
+++ b/lilo-config/common/lilo.cc
@@ -0,0 +1,585 @@
+/* lilo.cc
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "lilo.h"
+#include "Disks.h"
+#include "Files.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <fstream>
+#include <string.h>
+
+using namespace std;
+
+bool liloimage::isLinux() const {
+ const_iterator it=begin();
+ if((*it).contains("image"))
+ return true;
+ else
+ return false;
+}
+
+liloimage *liloimages::find(String const &s) const
+{
+ String t = String::escapeForRegExp(s);
+
+ String regex="^[ \t]*label[ \t]*=[ \t]*\"?" + t + "\"?[ \t]*";
+ for(const_iterator it=begin(); it!=end(); it++) {
+ if(!(*it).grep(regex).empty())
+ return (liloimage*)&(*it);
+ }
+ return 0;
+}
+void liloimages::remove(String const &s)
+{
+ liloimage *i=find(s);
+ for(iterator it=begin(); it!=end(); it++)
+ if(*it==*i) {
+ erase(it);
+ break;
+ }
+}
+
+liloconf::liloconf(String const &filename)
+{
+ checked=false;
+ defaults.clear();
+ images.clear();
+ if(filename.empty()) {
+ probe();
+ } else {
+ StringList s;
+ if(s.readfile(filename))
+ set(s);
+ else
+ probe();
+ }
+}
+void liloconf::set(StringList const &s)
+{
+ defaults.clear();
+ images.clear();
+ checked=false;
+ bool inHeader=true;
+ bool start;
+ liloimage *image=0;
+ for(StringList::const_iterator it=s.begin(); it!=s.end(); it++) {
+ String s=*it;
+ start=false;
+ s=s.simplifyWhiteSpace();
+ if(s.empty())
+ continue;
+ if(s.left(5)==(String)"other" && (s.mid(6, 1)==' ' || s.mid(6, 1)=='=')) {
+ inHeader=false;
+ start=true;
+ }
+ if(s.left(5)==(String)"image" && (s.mid(6, 1)==' ' || s.mid(6, 1)=='=')) {
+ inHeader=false;
+ start=true;
+ }
+ if(inHeader) {
+ defaults+=*it;
+ } else if(start) {
+ if(image)
+ images.insert(images.end(), *image);
+ image=new liloimage;
+ *image += *it;
+ } else {
+ *image += *it;
+ }
+ }
+ if(image)
+ images.insert(images.end(), *image);
+}
+void liloconf::set(String const &s)
+{
+ set((StringList)s);
+}
+void liloconf::writeFile(String const &filename)
+{
+ ofstream f;
+ f.open(filename, ios::out);
+ f << *this << endl;
+ f.close();
+ chmod(filename, 0600);
+}
+bool liloconf::install(bool probeonly)
+{
+ char *lilotmp=strdup("/tmp/liloXXXXXX");
+ String command;
+ int fd=mkstemp(lilotmp);
+ // Unfortunately, gcc 3.1 and higher don't have ofstream::attach
+ // anymore. Pity, used to be immensely useful.
+ // f.attach(fd);
+ close(fd);
+ ofstream f(lilotmp, ios::out);
+ f << defaults << endl;
+ for(liloimages::iterator it=images.begin(); it!=images.end(); it++) {
+ f << *it << endl;
+ }
+ f.close();
+
+ if(probeonly)
+ command.sprintf("/sbin/lilo -v -t -C %s 2>&1", (char const * const)lilotmp);
+ else
+ command.sprintf("/sbin/lilo -v -C %s 2>&1", (char const * const)lilotmp);
+ output="";
+ FILE *lilo=popen(command, "r");
+ char *buf=(char *) malloc(1024);
+ while(fgets(buf, 1024, lilo))
+ output += buf;
+ free(buf);
+ ok=(pclose(lilo)==0);
+ unlink(lilotmp);
+ free(lilotmp);
+ checked=true;
+ return ok;
+}
+bool const liloconf::isOk()
+{
+ if(!checked)
+ check();
+ return ok;
+}
+String const liloconf::liloOut()
+{
+ if(!checked)
+ check();
+ return output;
+}
+bool liloconf::probe()
+{
+ ptable p;
+ StringList drives=p.disklist();
+ String const root=p.device("/", true);
+ checked=false;
+ defaults.clear();
+ images.clear();
+ /* Set some reasonable defaults... */
+ // Try to figure out the boot device first...
+ if(drives.contains("/dev/hda")) {
+ defaults += "boot=/dev/hda"; // 1st IDE/ATAPI harddisk
+ defaults += "lba32"; // otherwise it is assumed
+ }
+ else if(drives.contains("/dev/sda")) {
+ defaults += "boot=/dev/sda"; // 1st SCSI harddisk
+ defaults += "linear"; // some SCSI disks need this
+ } else if(drives.contains("/dev/i2o/hda"))
+ defaults += "boot=/dev/i2o/hda"; // 1st I2O harddisk
+ else if(drives.contains("/dev/eda"))
+ defaults += "boot=/dev/eda"; // 1st MCA ESDI harddisk
+ else if(drives.contains("/dev/pda"))
+ defaults += "boot=/dev/pda"; // 1st Parallel port IDE disk
+ else
+ defaults += "boot=Insert_your_boot_device_here"; // shouldn't happen
+ defaults += "prompt";
+ defaults += "timeout=50";
+ if(!access("/boot/message", F_OK))
+ defaults += "message=/boot/message";
+ defaults += "root=" + root;
+
+ /* Scan for available operating systems...
+ * The list of what to do for each partition type is based on my
+ * best guess. I don't have anything but Linux (Red Hat Linux 7.0),
+ * FreeBSD (5.0-CURRENT), OpenBSD (2.6), FreeDOS (some CVS snapshot)
+ * and DR-DOS (7.03), so anything else might be wrong.
+ * If you have any additions or corrections, please send them to
+ * bero@redhat.com.
+ */
+ // Scan for Linux kernels in the currently running system
+ // The following may or may not be specific to Red Hat Linux and
+ // similar distributions... If you're using a distribution that does
+ // things differently, tell me how it should be done there.
+ StringList files=Files::glob("/boot/*", Files::File);
+ for(StringList::iterator it=files.begin(); it!=files.end(); it++) {
+ struct stat s;
+ if(lstat(*it, &s)) // If we can't stat it, it can't be a kernel
+ continue;
+ if(s.st_size<131072) // if you managed to compile a kernel at less than 128k, you're cheating. ;)
+ continue;
+ if((*it).contains("System.map") || (*it).contains("initrd")) // definitely not a kernel
+ continue;
+ if((*it).contains("vmlinux")) {
+ // If the kernel exists both in compressed and in
+ // uncompressed form, ignore the uncompressed one.
+ String compr=(*it).replace("vmlinux", "vmlinuz");
+ if(!access(compr, F_OK))
+ continue;
+ }
+ String version=(*it).regex("(test-?|pre-?)?([0-9]\\.[0-9]\\.[0-9]+)(-?[0-9A-Za-z]+)*");
+ String label=version;
+ if(version.empty()) // not a recognized kernel
+ version="linux";
+
+ if (label.empty())
+ {
+ label = (*it);
+ if (label.find('/') != string::npos)
+ label = label.right(label.length()-1-label.rfind('/'));
+ }
+ // Check if we have an initial ramdisk (initrd) for this kernel...
+ String initrd1; // first guess
+ String initrd2; // second guess
+ if((*it).contains("vmlinuz")) {
+ initrd1=(*it).replace("vmlinux", "initrd")+".img";
+ initrd2=(*it).replace("vmlinuz", "initrd.img");
+ }
+ else if((*it).contains("vmlinux")) {
+ initrd1=(*it).replace("vmlinux", "initrd")+".img";
+ initrd2=(*it).replace("vmlinuz", "initrd.img");
+ }
+ else if((*it).contains("kernel")) {
+ initrd1=(*it).replace("kernel", "initrd")+".img";
+ initrd2=(*it).replace("vmlinuz", "initrd.img");
+ }
+ else if((*it).contains("linux")) {
+ initrd1=(*it).replace("linux", "initrd")+".img";
+ initrd2=(*it).replace("vmlinuz", "initrd.img");
+ }
+ else {
+ initrd1="/boot/initrd-"+version+".img";
+ initrd2="/boot/initrd.img-"+version;
+ }
+
+ String initrd = "";
+ if(!access(initrd1, F_OK))
+ initrd = initrd1;
+ else if(!access(initrd2, F_OK))
+ initrd = initrd2;
+
+ if(label.size()>15) // LILO can't handle this
+ if(label.contains("enterprise"))
+ label=label.replace("enterprise", "E");
+ if(label.size()>15)
+ label=label.left(15);
+
+ // label, kernel, root, initrd, optional, append, vga, readonly,
+ // literal, ramdisk
+ addLinux(label, *it, root, initrd);
+ }
+ addLinux("Linux_Compiled", "/usr/src/linux/arch/i386/boot/bzImage", root, "", true); // User-compiled kernel that wasn't moved...
+
+ // Scan for other OSes... and Linux kernels on other partitions.
+ for(StringList::iterator it=p.partition.begin(); it!=p.partition.end(); it++) {
+ switch(p.id[*it]) {
+ case 0x01: // FAT12... Might be some really really old DOS.
+ case 0x04: // FAT16 < 32 M... Probably another old DOS.
+ case 0x06: // FAT16
+ case 0x0b: // FAT32
+ case 0x0c: // FAT32 (LBA)
+ case 0x0e: // FAT16 (LBA)
+ case 0x14: // Hidden FAT16 < 32 M...
+ case 0x16: // Hidden FAT16
+ case 0x1b: // Hidden FAT32
+ case 0x1c: // Hidden FAT32 (LBA)
+ case 0x1e: // Hidden FAT16 (LBA)
+ case 0x24: // NEC DOS
+ case 0x55: // EZ-Drive... I think this was some DOS tool
+ // to see "large" disks ages ago, so it may be
+ // a DOS partition... Not sure about this one.
+ case 0xc1: // DRDOS/sec
+ case 0xc4: // DRDOS/sec
+ case 0xc6: // DRDOS/sec
+ {
+ // Try to determine which type of DOS we're using
+ String mp=p.mountpt[*it];
+ String lbl="DOS";
+ if(mp.empty()) {
+ char *tmp=tmpnam(NULL);
+ tmp=tmpnam(NULL);
+ mkdir(tmp, 0700);
+ if(!mount(*it, tmp, "msdos", MS_MGC_VAL|MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL))
+ mp=tmp;
+ else if(!mount(*it, mp, "vfat", MS_MGC_VAL|MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL))
+ mp=tmp;
+ }
+ if(!mp.empty()) {
+ struct stat s;
+ if(stat(mp+"/ibmbio.com", &s) && stat(mp+"/io.sys", &s) && stat(mp+"/ntldr", &s)) // Doesn't look like a bootable DOS partition, ignore it
+ break;
+ if(!stat(mp+"/drdos.386", &s))
+ lbl="DR-DOS";
+ else if(!stat(mp+"/ntldr", &s))
+ lbl="NT";
+ else if(!stat(mp+"/msdos.sys", &s)) {
+ if(s.st_size < 4096)
+ /* msdos.sys is actual code in DOS, it's a config file in SuckOS */
+ if(!stat(mp+"/windows/system/sfc.exe", &s)) /* This is (supposed to be?) a component of Suck98 but not Suck95 */
+ lbl="Windows98";
+ else
+ lbl="Windows95";
+ }
+ if(p.mountpt[*it].empty()) {
+ umount(mp);
+ sync();
+ rmdir(mp);
+ }
+ }
+ addOther(lbl, *it);
+ break;
+ }
+ case 0x02: // Xenix root... Does Xenix actually boot this way?
+ addOther("Xenix", *it);
+ break;
+ case 0x07: // HPFS or NTFS... Is there any way to check which?
+ // (without trying to mount them... many kernels
+ // support neither)
+ case 0x17: // Hidden HPFS or NTFS
+ addOther("NT", *it);
+ break;
+ case 0x09: // AIX
+ addOther("AIX", *it);
+ break;
+ case 0x83: // My favorite :)
+ case 0xfd: // Linux RAID
+ // TODO: scan other FSes for kernels...
+ break;
+ case 0x84:
+ {
+ // CLASH: SystemSoft MobilePRO BIOS and
+ // various Dell BIOSes use the same
+ // ID (0x84) for its hibernation partitions
+ // as OS/2 does for hidden C: drives.
+ // Fortunately, hibernation partitions are easy to
+ // recognize...
+ int fd=open(*it, O_RDONLY);
+ char *header=(char *) malloc(20);
+ read(fd, header, 20);
+ close(fd);
+ if(strncmp(header, "SystemSoft", 10)==0) // It's a hibernation partition
+ break;
+ else if(strncmp(header+3, "Dell Suspend", 12)==0) { // It's a Dell hibernation partition
+ // Dell BIOSes are ultimately buggy: They don't do resume-from-disk
+ // properly.
+ // Hibernation partitions are bootable and need to be loaded by the
+ // boot manager instead.
+ addOther("SuspendToDisk", *it);
+ break;
+ }
+ addOther("OS2", *it, false, "/boot/os2_d.b");
+ }
+ case 0x0a: // OS/2 Boot Manager
+ addOther("OS2", *it, false, "/boot/os2_d.b");
+ break;
+ case 0x10: // OPUS... (what is that?)
+ addOther("OPUS", *it);
+ break;
+ case 0x3c: // Partition Magic
+ addOther("PartitionMagic", *it);
+ break;
+ case 0x40: // Venix 80286
+ addOther("Venix", *it);
+ break;
+ case 0x4d: // QNX
+ addOther("QNX", *it);
+ break;
+ case 0x52: // CP/M (does anyone dual-boot between CP/M and
+ // Linux? Would be interesting to see. ;) )
+ case 0xdb: // CP/M/CTOS
+ addOther("CPM", *it);
+ break;
+ case 0x63: // GNU/Hurd
+ addOther("GNU_Hurd", *it);
+ break;
+ case 0x64: // Novell Netware
+ case 0x65: // Novell Netware
+ addOther("Netware", *it);
+ break;
+ case 0x75: // PC/IX (what is that?)
+ addOther("PCIX", *it);
+ break;
+ case 0x80: // Old Minix
+ case 0x81: // Minix and some VERY old Linux kernels
+ addOther("Minix", *it);
+ break;
+ case 0x9f: // BSD/OS
+ case 0xb7: // BSDI
+ addOther("BSD_OS", *it);
+ break;
+ case 0xa5: // Some BSDs... Is there any way to determine which
+ // one?
+ addOther("BSD", *it);
+ break;
+ case 0xa6: // OpenBSD
+ addOther("OpenBSD", *it);
+ break;
+ case 0xa7: // NeXTSTEP
+ addOther("NeXT", *it);
+ break;
+ case 0xc7: // Syrinx (what is that?)
+ addOther("Syrinx", *it);
+ break;
+ case 0xeb: // BeOS
+ addOther("BeOS", *it);
+ break;
+ case 0xfe: // LANstep (what is that?)
+ addOther("LANstep", *it);
+ break;
+ case 0xff: // BBT (what is that?)
+ addOther("BBT", *it);
+ break;
+ }
+ }
+ // addOther("floppy", "/dev/fd0", true);
+ //Would be nice, but LILO can't handle an optional
+ //other=nonexistantdevice entry ATM.
+ return true;
+}
+void liloconf::addLinux(String const &label, String const &kernel, String const &root, String const &initrd, bool optional, String const &append, String const &vga, bool readonly, String const &literal, String const &ramdisk)
+{
+ liloimage *lx_image=new liloimage;
+ *lx_image += "image="+kernel;
+ *lx_image += "\tlabel=\""+label+"\"";
+ if(!root.empty())
+ *lx_image += "\troot="+root;
+ if(readonly)
+ *lx_image += "\tread-only";
+ else
+ *lx_image += "\tread-write";
+ if(!initrd.empty())
+ *lx_image += "\tinitrd=\""+initrd+"\"";
+ if(!append.empty())
+ *lx_image += "\tappend=\""+append+"\"";
+ if(!vga.empty())
+ *lx_image += "\tvga=\""+vga+"\"";
+ if(!literal.empty())
+ *lx_image += "\tliteral=\""+literal+"\"";
+ if(!ramdisk.empty())
+ *lx_image += "\tramdisk=\""+ramdisk+"\"";
+ if(optional)
+ *lx_image += "\toptional";
+ images.insert(images.end(), *lx_image);
+}
+void liloconf::addOther(String const &name, String const &partition, bool const &optional, String const &chain)
+{
+ liloimage *other=new liloimage;
+ *other += "other="+partition;
+ *other += "\tlabel=\""+name+"\"";
+ if(optional)
+ *other += "\toptional";
+ if(!chain.empty())
+ *other += "\tloader="+chain+"\"";
+ images.insert(images.end(), *other);
+}
+void liloconf::remove(String const &label)
+{
+ String t = String::escapeForRegExp(label);
+
+ String regex="[ \t]*label[ \t]*=[ \t]*\"?"+t+"\"?[ \t]*";
+ for(liloimages::iterator it=images.begin(); it!=images.end(); it++) {
+ if(!(*it).grep(regex).empty()) {
+ images.erase(it);
+ break;
+ }
+ }
+}
+void liloconf::removeKernel(String const &kernel)
+{
+ String t = String::escapeForRegExp(kernel);
+
+ String regex="[ \t]*(image|other)[ \t]*=[ \t]*\"?"+t+"\"?[ \t]*";
+ for(liloimages::iterator it=images.begin(); it!=images.end(); it++) {
+ if(!(*it).grep(regex).empty()) {
+ images.erase(it);
+ break;
+ }
+ }
+}
+StringList const &liloconf::entries() const
+{
+ StringList *s=new StringList;
+ for(liloimages::const_iterator it=images.begin(); it!=images.end(); it++) {
+ String lbl=(*it).grep("[ \t]*label[ \t]*=.*");
+ lbl=lbl.mid(lbl.locate("label")+6);
+ while(isspace(lbl.chr(0)) || lbl.chr(0)=='=' || lbl.chr(0)=='\"')
+ lbl=lbl.mid(2);
+ while(isspace(lbl.right().chr(0)) || lbl.right()==(String)"\"")
+ lbl=lbl.left(lbl.size()-1);
+ s->add(lbl);
+ }
+ return *s;
+}
+String const liloconf::dflt() const
+{
+ String dflt="";
+ for(StringList::const_iterator it=defaults.begin(); it!=defaults.end() && dflt.empty(); it++)
+ if(!((*it).regex("^[ \t]*default[ \t]*=")).empty())
+ dflt=(*it).simplifyWhiteSpace();
+ if(dflt.empty()) {
+ liloimages::const_iterator it=images.begin();
+ if (it != images.end())
+ dflt=(*it).grep("^[ \t]*label[ \t]*=").simplifyWhiteSpace();
+ }
+ if(!dflt.empty()) {
+ dflt=dflt.mid(dflt.locate("=")+2).simplifyWhiteSpace();
+ if(dflt.left()==(String)"\"")
+ dflt=dflt.mid(2).simplifyWhiteSpace();
+ if(dflt.right()==(String)"\"")
+ dflt=dflt.left(dflt.size()-1).simplifyWhiteSpace();
+ }
+ return dflt;
+}
+void liloconf::setDefault(String const &dflt)
+{
+ bool ready=false;
+ for(StringList::const_iterator it=defaults.begin(); !ready && it!=defaults.end(); it++)
+ if(!((*it).regex("^[ \t]*default[ \t]*=")).empty()) {
+ defaults.remove(*it);
+ ready=true;
+ }
+ defaults+="default=" + dflt;
+}
+liloconf::operator String() const
+{
+ String s=defaults;
+ s+="\n";
+ for(liloimages::const_iterator it=images.begin(); it!=images.end(); it++) {
+ s+=*it;
+ s+="\n";
+ }
+ return s;
+}
+
+ostream &operator <<(ostream &os, liloconf const &l)
+{
+ os << l.defaults << endl;
+ for(liloimages::const_iterator it=l.images.begin(); it!=l.images.end(); it++)
+ os << *it << endl;
+ return os;
+}
+ostream &operator <<(ostream &os, liloconf const *l)
+{
+ os << l->defaults << endl;
+ for(liloimages::const_iterator it=l->images.begin(); it!=l->images.end(); it++)
+ os << *it << endl;
+ return os;
+}
diff --git a/lilo-config/common/lilo.h b/lilo-config/common/lilo.h
new file mode 100644
index 0000000..c992df0
--- /dev/null
+++ b/lilo-config/common/lilo.h
@@ -0,0 +1,77 @@
+/* lilo.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by A. Seigo and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _LILO_H_
+#define _LILO_H_ 1
+#include "Config.h"
+#include <iostream>
+
+class liloimage:public ConfigFile {
+public:
+ bool isLinux() const;
+};
+
+class liloimages:public std::list<liloimage> {
+public:
+ void remove(String const &s);
+ liloimage *find(String const &s) const;
+ liloimage *operator[](String const &s) const { return find(s); }
+};
+
+class liloconf {
+ friend std::ostream &operator <<(std::ostream &os, liloconf const &l);
+ friend std::ostream &operator <<(std::ostream &os, liloconf const *l);
+public:
+ liloconf(String const &filename="/etc/lilo.conf");
+ void set(StringList const &s);
+ void set(String const &s);
+ void writeFile(String const &filename);
+ bool const isOk();
+ String const liloOut();
+ bool install(bool probeonly=false);
+ bool probe();
+ void addLinux(String const &label, String const &kernel, String const &root="", String const &initrd="", bool optional=false, String const &append="", String const &vga="", bool readonly=true, String const &literal="", String const &ramdisk="");
+ void addOther(String const &name, String const &partition, bool const &optional=false, String const &chain="");
+ void remove(String const &label);
+ void removeKernel(String const &kernel);
+ StringList const &entries() const;
+ String const dflt() const;
+ void setDefault(String const &dflt);
+ operator String() const;
+protected:
+ void check() { install(true); }
+ bool ok;
+ String output;
+public:
+ bool checked;
+ ConfigFile defaults;
+ liloimages images;
+};
+std::ostream &operator <<(std::ostream &os, liloconf const &l);
+std::ostream &operator <<(std::ostream &os, liloconf const *l);
+#endif
diff --git a/lilo-config/common/tests/Makefile.am b/lilo-config/common/tests/Makefile.am
new file mode 100644
index 0000000..8059a44
--- /dev/null
+++ b/lilo-config/common/tests/Makefile.am
@@ -0,0 +1,9 @@
+String_LDADD = ../.libs/libcommon.a
+noinst_PROGRAMS = String
+INCLUDES = -I.. $(all_includes)
+
+String_SOURCES = \
+ String.cc
+
+messages:
+
diff --git a/lilo-config/common/tests/String.cc b/lilo-config/common/tests/String.cc
new file mode 100644
index 0000000..7b0b60e
--- /dev/null
+++ b/lilo-config/common/tests/String.cc
@@ -0,0 +1,77 @@
+/*
+**
+** Copyright (C) 2000 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+using namespace std;
+
+#include <String.h>
+int main(int argc, char **argv)
+{
+ int bugs=0;
+ String s="Microsoft sucks! Red Hat doesn't suck!";
+ String t="Microsoft sucks! Destroy Microsoft! Microsoft must die!";
+ String u="Microsoft sucks!";
+ if(s.left(16)!="Microsoft sucks!") {
+ cerr << "left() seems to be broken." << endl;
+ bugs++;
+ }
+ if(s.right(21) != "Red Hat doesn't suck!") {
+ cerr << "right() seems to be broken." << endl;
+ bugs++;
+ }
+ if(s.mid(18) != 'R') {
+ cerr << "mid() with one parameter seems to be broken." << endl;
+ bugs++;
+ }
+ if(s.mid(18, 7) != "Red Hat") {
+ cerr << "mid() with 2 parameters seems to be broken." << endl;
+ bugs++;
+ }
+ if(s.regex("Red ?[Hh]at|RED ?HAT")!="Red Hat") {
+ cerr << "regex() seems to be broken." << endl;
+ bugs++;
+ }
+ if(!s.contains("Red Hat")) {
+ cerr << "contains() seems to be broken." << endl;
+ bugs++;
+ }
+ if(t.replace("Microsoft", "Windows", false) != "Windows sucks! Destroy Microsoft! Microsoft must die!") {
+ cerr << "replace() [once] seems to be broken." << endl;
+ bugs++;
+ }
+ if(t.replace("Microsoft", "Windows") != "Windows sucks! Destroy Windows! Windows must die!") {
+ cerr << "replace() [all] seems to be broken." << endl;
+ bugs++;
+ }
+ if(u.replace("Microsoft", "Windows") != "Windows sucks!") {
+ cerr << "replace() [all, test case 2] seems to be broken." << endl;
+ bugs++;
+ }
+
+ if(bugs==0)
+ cout << "No bugs in String class detected." << endl;
+ return bugs;
+}
diff --git a/lilo-config/configure.in.in b/lilo-config/configure.in.in
new file mode 100644
index 0000000..6f608f7
--- /dev/null
+++ b/lilo-config/configure.in.in
@@ -0,0 +1,5 @@
+KDE_FIND_PATH(lilo, LILO, [/sbin /usr/sbin /usr/local/sbin /opt/lilo],
+[
+ DO_NOT_COMPILE="$DO_NOT_COMPILE lilo-config"
+])
+
diff --git a/lilo-config/kde-qt-common/EditWidget.cpp b/lilo-config/kde-qt-common/EditWidget.cpp
new file mode 100644
index 0000000..fad957a
--- /dev/null
+++ b/lilo-config/kde-qt-common/EditWidget.cpp
@@ -0,0 +1,81 @@
+/* EditWidget.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "EditWidget.moc"
+#include "ui.h"
+EditWidget::EditWidget(QString const label, QString const text, bool isFile, QWidget *parent, const char *name, WFlags f, bool allowLines):QHBox(allowLines, parent, name, f)
+{
+ setMargin(SPACE_MARGIN);
+ setSpacing(SPACE_INSIDE);
+ lbl=new QLabel(label, this);
+ setStretchFactor(lbl, 0);
+ line=new QLineEdit(text, this);
+ setStretchFactor(line, 1);
+ connect(line, SIGNAL(textChanged(const QString &)), SIGNAL(textChanged(const QString &)));
+ connect(line, SIGNAL(returnPressed()), SIGNAL(returnPressed()));
+ lbl->setBuddy(line);
+ if(isFile) {
+ select=new QPushButton(_("Select..."), this);
+ connect(select, SIGNAL(clicked()), SLOT(selectFileClicked()));
+ select->resize(select->minimumSizeHint());
+ setStretchFactor(select, 0);
+ } else
+ select=0;
+}
+void EditWidget::selectFileClicked()
+{
+ QString filename=FileDlg::getOpenFileName(QString::null, QString::null, this);
+ if(!filename.isEmpty())
+ line->setText(filename);
+}
+QSize EditWidget::sizeHint() const
+{
+ int w=2*SPACE_MARGIN+lbl->sizeHint().width()+SPACE_INSIDE+line->sizeHint().width();
+ int h=lbl->sizeHint().height();
+ if(h<line->sizeHint().height())
+ h=line->sizeHint().height();
+ if(select!=0) {
+ w+=SPACE_INSIDE+select->sizeHint().width();
+ if(h<select->sizeHint().height())
+ h=select->sizeHint().height();
+ }
+ return QSize(w, h);
+}
+QSize EditWidget::minimumSizeHint() const
+{
+ int w=2*SPACE_MARGIN+lbl->minimumSizeHint().width()+SPACE_INSIDE+line->minimumSizeHint().width();
+ int h=lbl->minimumSizeHint().height();
+ if(h<line->minimumSizeHint().height())
+ h=line->minimumSizeHint().height();
+ if(select!=0) {
+ w+=SPACE_INSIDE+select->minimumSizeHint().width();
+ if(h<select->minimumSizeHint().height())
+ h=select->minimumSizeHint().height();
+ }
+ return QSize(w, h);
+}
diff --git a/lilo-config/kde-qt-common/EditWidget.h b/lilo-config/kde-qt-common/EditWidget.h
new file mode 100644
index 0000000..515c65e
--- /dev/null
+++ b/lilo-config/kde-qt-common/EditWidget.h
@@ -0,0 +1,92 @@
+/* EditWidget.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _EDITWIDGET_H_
+#define _EDITWIDGET_H_ 1
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+class EditWidget:public QHBox
+{
+ Q_OBJECT
+public:
+ EditWidget(QString const label="", QString const text="", bool isFile=false, QWidget *parent=0, const char *name=0, WFlags f=0, bool allowLines=true);
+ void setLabel(QString const &label) { lbl->setText(label); };
+ QString text() const { return line->text(); };
+ QString displayText() const { return line->displayText(); };
+ int maxLength() const { return line->maxLength(); };
+ virtual void setMaxLength(int l) { line->setMaxLength(l); };
+ virtual void setFrame(bool b) { line->setFrame(b); };
+ bool frame() const { return line->frame(); };
+ virtual void setEchoMode(QLineEdit::EchoMode e) { line->setEchoMode(e); };
+ QLineEdit::EchoMode echoMode() const { return line->echoMode(); };
+ void setReadOnly(bool b) const { line->setReadOnly(b); };
+ bool isReadOnly() const { return line->isReadOnly(); };
+ virtual void setValidator(const QValidator *v) { line->setValidator(v); };
+ const QValidator *validator() const { return line->validator(); };
+ virtual void setSelection(int s, int e) { line->setSelection(s, e); };
+ virtual void setCursorPosition(int p) { line->setCursorPosition(p); };
+ int cursorPosition() const { return line->cursorPosition(); };
+ bool validateAndSet(const QString &s, int a, int b, int c) { return line->validateAndSet(s, a, b, c); };
+ void cut() { line->cut(); };
+ void copy() const { line->copy(); };
+ void paste() { line->paste(); };
+ void setAlignment(int flag) { line->setAlignment(flag); };
+ int alignment() const { return line->alignment(); };
+ void cursorLeft(bool mark, int steps=1) { line->cursorLeft(mark, steps); };
+ void cursorRight(bool mark, int steps=1) { line->cursorRight(mark, steps); };
+ void cursorWordForward(bool mark) { line->cursorWordForward(mark); };
+ void cursorWordBackward(bool mark) { line->cursorWordBackward(mark); };
+ void backspace() { line->backspace(); };
+ void del() { line->del(); };
+ void home(bool mark) { line->home(mark); };
+ void end(bool mark) { line->end(mark); };
+ void setEdited(bool e) { line->setEdited(e); };
+ bool edited() const { return line->edited(); };
+ bool hasMarkedText() const { return line->hasMarkedText(); };
+ QString markedText() const { return line->markedText(); };
+ virtual QSize sizeHint() const;
+ virtual QSize minimumSizeHint() const;
+public slots:
+ virtual void setText(const QString &text) { line->setText(text); };
+ void selectAll() { line->selectAll(); };
+ void deselect() { line->deselect(); };
+ void clearValidator() { line->clearValidator(); };
+ void insert(const QString &s) { line->insert(s); };
+ void clear() { line->clear(); };
+ void selectFileClicked();
+signals:
+ void textChanged(const QString &);
+ void returnPressed();
+private:
+ QLabel *lbl;
+ QLineEdit *line;
+ QPushButton *select;
+};
+#endif
diff --git a/lilo-config/kde-qt-common/Makefile.am b/lilo-config/kde-qt-common/Makefile.am
new file mode 100644
index 0000000..f5b57eb
--- /dev/null
+++ b/lilo-config/kde-qt-common/Makefile.am
@@ -0,0 +1,14 @@
+AM_CXXFLAGS = -DUSE_KDE
+INCLUDES= -I$(srcdir)/../common -I$(srcdir)/.. -I. $(all_includes)
+
+noinst_LTLIBRARIES=libwidgets.la
+
+libwidgets_la_SOURCES = \
+ mainwidget.cpp general.cpp images.cpp expert.cpp \
+ EditWidget.cpp
+libwidgets_la_LIBADD = $(LIB_QT) ../common/libcommon.la
+libwidgets_la_METASOURCES = AUTO
+
+noinst_HEADERS = \
+ mainwidget.h ui.h general.h images.h expert.h \
+ EditWidget.h
diff --git a/lilo-config/kde-qt-common/expert.cpp b/lilo-config/kde-qt-common/expert.cpp
new file mode 100644
index 0000000..dea58e9
--- /dev/null
+++ b/lilo-config/kde-qt-common/expert.cpp
@@ -0,0 +1,63 @@
+/* expert.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "expert.moc"
+#include <ui.h>
+#include <qwhatsthis.h>
+#include <String.h>
+#include <strstream>
+Expert::Expert(liloconf *l, QWidget *parent, const char *name):QWidget(parent, name)
+{
+ lilo=l;
+ layout=new QHBoxLayout(this);
+ edit=new QMultiLineEdit(this);
+ layout->addWidget(edit);
+ connect(edit, SIGNAL(textChanged()), SIGNAL(configChanged()));
+ QWhatsThis::add(edit, _("You can edit the lilo.conf file directly here. All changes you make here are automatically transferred to the graphical interface."));
+ update();
+}
+Expert::~Expert()
+{
+ delete edit;
+}
+void Expert::update()
+{
+ bool blocked = signalsBlocked();
+ blockSignals(true);
+ edit->setText(((String)*lilo).cstr());
+ blockSignals(blocked);
+}
+void Expert::saveChanges()
+{
+ lilo->set(edit->text().latin1());
+}
+
+void Expert::makeReadOnly()
+{
+ edit->setEnabled( false );
+}
diff --git a/lilo-config/kde-qt-common/expert.h b/lilo-config/kde-qt-common/expert.h
new file mode 100644
index 0000000..d9d6afb
--- /dev/null
+++ b/lilo-config/kde-qt-common/expert.h
@@ -0,0 +1,53 @@
+/* expert.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _EXPERT_H_
+#define _EXPERT_H_ 1
+#include <lilo.h>
+#include <qwidget.h>
+#include <qmultilineedit.h>
+#include <qlayout.h>
+class Expert:public QWidget
+{
+ Q_OBJECT
+public:
+ Expert(liloconf *l=0, QWidget *parent=0, const char *name=0);
+ ~Expert();
+ void setCfg(liloconf *l) { lilo=l; };
+ void makeReadOnly();
+public slots:
+ void update();
+ void saveChanges();
+signals:
+ void configChanged();
+private:
+ liloconf *lilo;
+ QHBoxLayout *layout;
+ QMultiLineEdit *edit;
+};
+#endif
diff --git a/lilo-config/kde-qt-common/general.cpp b/lilo-config/kde-qt-common/general.cpp
new file mode 100644
index 0000000..7944409
--- /dev/null
+++ b/lilo-config/kde-qt-common/general.cpp
@@ -0,0 +1,229 @@
+/* general.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "general.moc"
+#include "EditWidget.h"
+#include <Disks.h>
+#include <qlayout.h>
+#include <ui.h>
+#include <qwhatsthis.h>
+
+#include <stdlib.h>
+
+General::General(liloconf *l, QWidget *parent, const char *name):QWidget(parent, name)
+{
+ lilo=l;
+ QVBoxLayout *layout=new QVBoxLayout(this);
+ layout->setMargin(SPACE_MARGIN);
+ layout->setSpacing(SPACE_INSIDE);
+ QHBox *drv=new QHBox(this);
+ QLabel *drive_lbl=new QLabel(_("Install &boot record to drive/partition:"), drv);
+ drive=new QComboBox(false, drv);
+ drive_lbl->setBuddy(drive);
+ StringList p=ptable::disklist();
+ p+=ptable::partlist();
+ p.sort();
+ for(StringList::const_iterator it=p.begin(); it!=p.end(); it++)
+ drive->insertItem((*it).cstr());
+ connect(drive, SIGNAL(activated(int)), SIGNAL(configChanged()));
+ layout->addWidget(drv);
+ QWhatsThis::add(drv, _("Select the drive or partition you want to install the LILO boot loader to here. Unless you intend to use other boot managers in addition to LILO, this should be the MBR (master boot record) of your boot drive.<br>In this case, you should probably select <i>/dev/hda</i> if your boot drive is an IDE drive or <i>/dev/sda</i> if your boot drive is SCSI."));
+
+ QHBox *to=new QHBox(this);
+ QLabel *to_lbl=new QLabel(_("Boot the default kernel/OS &after:"), to);
+ timeout=new QSpinBox(0, 1000000, 1, to);
+ timeout->setSuffix(_("/10 seconds"));
+ connect(timeout, SIGNAL(valueChanged(int)), SIGNAL(configChanged()));
+ to_lbl->setBuddy(timeout);
+ layout->addWidget(to);
+ QWhatsThis::add(to, _("LILO will wait the amount of time specified here before booting the kernel (or OS) marked as <i>default</i> in the <b>Images</b> tab."));
+
+ QHBox *modes=new QHBox(this);
+ linear=new QCheckBox(_("Use &linear mode"), modes);
+ connect(linear, SIGNAL(clicked()), SIGNAL(configChanged()));
+ QWhatsThis::add(linear, _("Check this box if you want to use the linear mode.<br>Linear mode tells the boot loader the location of kernels in linear addressing rather than sector/head/cylinder.<br>linear mode is required for some SCSI drives, and shouldn't hurt unless you're planning to create a boot disk to be used with a different computer.<br>See the lilo.conf man page for details."));
+ compact=new QCheckBox(_("Use &compact mode"), modes);
+ connect(compact, SIGNAL(clicked()), SIGNAL(configChanged()));
+ QWhatsThis::add(compact, _("Check this box if you want to use the compact mode.<br>The compact mode tries to merge read requests for adjacent sectors into a single read request. This reduces load time and keeps the boot map smaller, but will not work on all systems."));
+ layout->addWidget(modes);
+
+ QHBox *opts=new QHBox(this);
+ lock=new QCheckBox(_("&Record boot command lines for defaults"), opts);
+ connect(lock, SIGNAL(clicked()), SIGNAL(configChanged()));
+ QWhatsThis::add(lock, "<qt>"+_("Checking this box enables automatic recording of boot command lines as the defaults for the following boots. This way, lilo \"locks\" on a choice until it is manually overridden.\nThis sets the <b>lock</b> option in lilo.conf."));
+ restricted=new QCheckBox(_("R&estrict parameters"), opts);
+ connect(restricted, SIGNAL(clicked()), SIGNAL(configChanged()));
+ connect(restricted, SIGNAL(clicked()), SLOT(check_pw()));
+ QWhatsThis::add(restricted, _("If this box is checked, a password (entered below) is required only if any parameters are changed (i.e. the user can boot <i>linux</i>, but not <i>linux single</i> or <i>linux init=/bin/sh</i>).\nThis sets the <b>restricted</b> option in lilo.conf.<br>This sets a default for all Linux kernels you want to boot. If you need a per-kernel setting, go to the <i>Operating systems</i> tab and select <i>Details</i>."));
+ layout->addWidget(opts);
+
+ QHBox *pw=new QHBox(this);
+ use_password=new QCheckBox(_("Require &password:"), pw);
+ connect(use_password, SIGNAL(clicked()), SIGNAL(configChanged()));
+ connect(use_password, SIGNAL(clicked()), SLOT(check_pw()));
+ password=new QLineEdit(pw);
+ password->setMaxLength(15);
+ password->setEchoMode(QLineEdit::Password);
+ connect(password, SIGNAL(textChanged(const QString &)), SIGNAL(configChanged()));
+ QWhatsThis::add(pw, _("Enter the password required for bootup (if any) here. If <i>restricted</i> above is checked, the password is required for additional parameters only.<br><b>WARNING:</b> The password is stored in clear text in /etc/lilo.conf. You'll want to make sure nobody untrusted can read this file. Also, you probably don't want to use your normal/root password here.<br>This sets a default for all Linux kernels you want to boot. If you need a per-kernel setting, go to the <i>Operating systems</i> tab and select <i>Details</i>."));
+ layout->addWidget(pw);
+
+ QHBox *vgab=new QHBox(this);
+ QLabel *vlbl=new QLabel(_("&Default graphics mode on text console:"), vgab);
+ vga=new QComboBox(false, vgab);
+ vlbl->setBuddy(vga);
+ QWhatsThis::add(vgab, _("You can select the default graphics mode here.<br>If you intend to use a VGA graphics mode, you must compile the kernel with support for framebuffer devices. The <i>ask</i> setting brings up a prompt at boot time.<br>This sets a default for all Linux kernels you want to boot. If you need a per-kernel setting, go to the <i>Operating systems</i> tab and select <i>Details</i>."));
+ vga->insertItem(_("default"));
+ vga->insertItem(_("ask"));
+ vga->insertItem(_("text 80x25 (0)"));
+ vga->insertItem(_("text 80x50 (1)"));
+ vga->insertItem(_("text 80x43 (2)"));
+ vga->insertItem(_("text 80x28 (3)"));
+ vga->insertItem(_("text 80x30 (4)"));
+ vga->insertItem(_("text 80x34 (5)"));
+ vga->insertItem(_("text 80x60 (6)"));
+ vga->insertItem(_("text 40x25 (7)"));
+ vga->insertItem(_("VGA 640x480, 256 colors (769)"));
+ vga->insertItem(_("VGA 640x480, 32767 colors (784)"));
+ vga->insertItem(_("VGA 640x480, 65536 colors (785)"));
+ vga->insertItem(_("VGA 640x480, 16.7M colors (786)"));
+ vga->insertItem(_("VGA 800x600, 256 colors (771)"));
+ vga->insertItem(_("VGA 800x600, 32767 colors (787)"));
+ vga->insertItem(_("VGA 800x600, 65536 colors (788)"));
+ vga->insertItem(_("VGA 800x600, 16.7M colors (789)"));
+ vga->insertItem(_("VGA 1024x768, 256 colors (773)"));
+ vga->insertItem(_("VGA 1024x768, 32767 colors (790)"));
+ vga->insertItem(_("VGA 1024x768, 65536 colors (791)"));
+ vga->insertItem(_("VGA 1024x768, 16.7M colors (792)"));
+ vga->insertItem(_("VGA 1280x1024, 256 colors (775)"));
+ vga->insertItem(_("VGA 1280x1024, 32767 colors (793)"));
+ vga->insertItem(_("VGA 1280x1024, 65536 colors (794)"));
+ vga->insertItem(_("VGA 1280x1024, 16.7M colors (795)"));
+ connect( vga, SIGNAL(activated ( int )), SIGNAL(configChanged()));
+ layout->addWidget(vgab);
+
+ prompt=new QCheckBox(_("Enter LILO &prompt automatically"), this);
+ QWhatsThis::add(prompt, _("If this box is checked, LILO goes to the LILO prompt whether or not a key is pressed. If it is turned off, LILO boots the default operating system unless shift is pressed (in that case, it goes to the LILO prompt).<br>This sets the <i>prompt</i> option in lilo.conf."));
+ connect(prompt, SIGNAL(clicked()), SIGNAL(configChanged()));
+
+ layout->addWidget(prompt);
+
+ update();
+}
+void General::saveChanges()
+{
+ QString to;
+ to.sprintf("%u", timeout->value());
+ QString boot = drive->currentText();
+ lilo->defaults.set("boot", boot.isEmpty() ? "" : boot.latin1());
+ lilo->defaults.set("timeout", to.latin1());
+ if(compact->isChecked() && lilo->defaults.grep("^[ \t]*compact[ \t]*$").empty())
+ lilo->defaults += "compact";
+ else if(!compact->isChecked() && !lilo->defaults.grep("^[ \t]*compact[ \t]*$").empty())
+ lilo->defaults.remove(lilo->defaults.grep("^[ \t]*compact[ \t]*$"));
+ if(linear->isChecked() && lilo->defaults.grep("^[ \t]*linear[ \t]*$").empty())
+ lilo->defaults += "linear";
+ else if(!linear->isChecked() && !lilo->defaults.grep("^[ \t]*linear[ \t]*$").empty())
+ lilo->defaults.remove(lilo->defaults.grep("^[ \t]*linear[ \t]*$"));
+ if(lock->isChecked() && lilo->defaults.grep("^[ \t]*lock[ \t]*$").empty())
+ lilo->defaults += "lock";
+ else if(!lock->isChecked() && !lilo->defaults.grep("^[ \t]*lock[ \t]*$").empty())
+ lilo->defaults.remove(lilo->defaults.grep("^[ \t]*lock[ \t]*$"));
+ if(restricted->isChecked() && lilo->defaults.grep("^[ \t]*restricted[ \t]*$").empty())
+ lilo->defaults += "restricted";
+ else if(!restricted->isChecked() && !lilo->defaults.grep("^[ \t]*restricted[ \t]*$").empty())
+ lilo->defaults.remove(lilo->defaults.grep("^[ \t]*restricted[ \t]*$"));
+ if(restricted->isChecked() || use_password->isChecked())
+ lilo->defaults.set("password", password->text().latin1());
+ else
+ lilo->defaults.remove(lilo->defaults.grep("^[ \t]*password[ \t]*=.*"));
+ if(vga->currentText()=="default") {
+ if(!lilo->defaults.grep("[ \t]*vga[ \t]*=").empty())
+ lilo->defaults.remove(lilo->defaults.grep("[ \t]*vga[ \t]*="));
+ } else {
+ QString mode=vga->currentText();
+ if(mode!="ask") {
+ mode=mode.mid(mode.find('(')+1);
+ mode=mode.left(mode.length()-1);
+ }
+ lilo->defaults.set("vga", mode.latin1());
+ }
+ if(prompt->isChecked() && lilo->defaults.grep("^[ \t]*prompt[ \t]*$").empty())
+ lilo->defaults += "prompt";
+ else if(!prompt->isChecked() && !lilo->defaults.grep("^[ \t]*prompt[ \t]*$").empty())
+ lilo->defaults.remove(lilo->defaults.grep("^[ \t]*prompt[ \t]*$"));
+}
+void General::update()
+{
+ QString boot=lilo->defaults.get("boot").cstr();
+ for(int i=0; i<drive->count(); i++)
+ if(drive->text(i)==boot)
+ drive->setCurrentItem(i);
+ timeout->setValue(atoi(lilo->defaults.get("timeout")));
+ compact->setChecked(!lilo->defaults.grep("^[ \t]*compact[ \t]*$").empty());
+ linear->setChecked(!lilo->defaults.grep("^[ \t]*linear[ \t]*$").empty());
+ lock->setChecked(!lilo->defaults.grep("^[ \t]*lock[ \t]*$").empty());
+ restricted->setChecked(!lilo->defaults.grep("^[ \t]*restricted[ \t]*$").empty());
+ String pw=lilo->defaults.grep("^[ \t]*password[ \t]*=.*");
+ use_password->setChecked(!pw.empty());
+ if(!pw.empty())
+ password->setText(lilo->defaults.get("password").cstr());
+ check_pw();
+ QString mode=lilo->defaults.get("vga", "").cstr();
+ if(mode.isEmpty())
+ vga->setCurrentItem(0);
+ else if(mode=="ask")
+ vga->setCurrentItem(1);
+ else
+ for(int i=0; i<vga->count(); i++) {
+ if(vga->text(i).contains("(" + mode + ")")) {
+ vga->setCurrentItem(i);
+ break;
+ }
+ }
+ prompt->setChecked(!lilo->defaults.grep("^[ \t]*prompt[ \t]*$").empty());
+}
+void General::check_pw()
+{
+ password->setEnabled(restricted->isChecked() || use_password->isChecked());
+}
+
+void General::makeReadOnly()
+{
+ drive->setEnabled( false );
+ timeout->setEnabled( false );
+ linear->setEnabled( false );
+ compact->setEnabled( false );
+ lock->setEnabled( false );
+ restricted->setEnabled( false );
+ use_password->setEnabled( false );
+ password->setEnabled( false );
+ vga->setEnabled( false );
+ prompt->setEnabled( false );
+
+}
diff --git a/lilo-config/kde-qt-common/general.h b/lilo-config/kde-qt-common/general.h
new file mode 100644
index 0000000..7e88a90
--- /dev/null
+++ b/lilo-config/kde-qt-common/general.h
@@ -0,0 +1,62 @@
+/* general.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _GENERAL_H_
+#define _GENERAL_H_ 1
+#include <lilo.h>
+#include <qwidget.h>
+#include <qcombobox.h>
+#include <qspinbox.h>
+#include <qcheckbox.h>
+class General:public QWidget
+{
+ Q_OBJECT
+public:
+ General(liloconf *l=0, QWidget *parent=0, const char *name=0);
+ void makeReadOnly();
+signals:
+ void configChanged();
+public slots:
+ void saveChanges();
+ void update();
+private slots:
+ void check_pw();
+private:
+ liloconf *lilo;
+ QComboBox *drive;
+ QSpinBox *timeout;
+ QCheckBox *linear;
+ QCheckBox *compact;
+ QCheckBox *lock;
+ QCheckBox *restricted;
+ QCheckBox *use_password;
+ QLineEdit *password;
+ QComboBox *vga;
+ QCheckBox *prompt;
+};
+#endif
diff --git a/lilo-config/kde-qt-common/images.cpp b/lilo-config/kde-qt-common/images.cpp
new file mode 100644
index 0000000..98dd1cb
--- /dev/null
+++ b/lilo-config/kde-qt-common/images.cpp
@@ -0,0 +1,334 @@
+/* images.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "images.moc"
+#include <ui.h>
+#include <qwhatsthis.h>
+#include <qregexp.h>
+#include <qstring.h>
+
+#ifdef USE_KDE
+#include "kde/InputBox.h"
+#include "kde/Details.h"
+#else
+#include "qt/InputBox.h"
+#include "qt/Details.h"
+#endif
+
+Images::Images(liloconf *l, QWidget *parent, const char *name):QWidget(parent, name)
+{
+ current=""; previous=""; // Using QString::null gives problems!
+ lilo=l;
+ layout=new QHBoxLayout(this);
+ layout->setMargin(SPACE_MARGIN);
+ layout->setSpacing(SPACE_INSIDE);
+ images=new QListBox(this);
+ layout->addWidget(images, 1);
+ connect(images, SIGNAL(highlighted(const QString &)), SLOT(imageSelected(const QString &)));
+ QWhatsThis::add(images, _("This is the list of kernels and operating systems you can currently boot. Select which one you want to edit here."));
+
+ parameters=new QVBox(this);
+ parameters->setMargin(SPACE_MARGIN);
+ parameters->setSpacing(SPACE_INSIDE);
+ layout->addWidget(parameters, 2);
+ image=new EditWidget(_("&Kernel:"), "", true, parameters);
+ QWhatsThis::add(image, _("Enter the filename of the kernel you want to boot here."));
+ connect(image, SIGNAL(textChanged(const QString &)), this, SIGNAL(configChanged()));
+ label=new EditWidget(_("&Label:"), "", false, parameters);
+ QWhatsThis::add(label, _("Enter the label (name) of the kernel you want to boot here."));
+ connect(label, SIGNAL(textChanged(const QString &)), this, SIGNAL(configChanged()));
+ root=new EditWidget(_("&Root filesystem:"), "", true, parameters);
+ QWhatsThis::add(root, _("Enter the root filesystem (i.e. the partition that will be mounted as / at boot time) for the kernel you want to boot here."));
+ connect(root, SIGNAL(textChanged(const QString &)), this, SIGNAL(configChanged()));
+ initrd=new EditWidget(_("&Initial ramdisk:"), "", true, parameters);
+ QWhatsThis::add(initrd, _("If you want to use an initial ramdisk (initrd) for this kernel, enter its filename here. Leave this field blank if you don't intend to use an initial ramdisk for this kernel."));
+ connect(initrd, SIGNAL(textChanged(const QString &)), this, SIGNAL(configChanged()));
+ append=new EditWidget(_("E&xtra parameters:"), "", false, parameters);
+ QWhatsThis::add(append, _("Enter any extra parameters you wish to pass to the kernel here. Usually, this can be left blank.<br>This sets the <i>append</i> option in lilo.conf."));
+ connect(append, SIGNAL(textChanged(const QString &)), this, SIGNAL(configChanged()));
+
+ actions=new QVBox(this);
+ actions->setMargin(SPACE_MARGIN);
+ actions->setSpacing(SPACE_INSIDE);
+ layout->addWidget(actions);
+ dflt=new QPushButton(_("Set &Default"), actions);
+ QWhatsThis::add(dflt, _("Boot this kernel/OS if the user doesn't make a different choice"));
+ connect(dflt, SIGNAL(clicked()), SLOT(dfltClicked()));
+ details=new QPushButton(_("De&tails"), actions);
+ QWhatsThis::add(details, _("This button brings up a dialog box with further, less commonly used, options."));
+ connect(details, SIGNAL(clicked()), SLOT(detailsClicked()));
+ probe=new QPushButton(_("&Probe"), actions);
+ connect(probe, SIGNAL(clicked()), SLOT(probeClicked()));
+ QWhatsThis::add(probe, _("Automatically generate a (hopefully) reasonable lilo.conf for your system"));
+ check=new QPushButton(_("&Check Configuration"), actions);
+ connect(check, SIGNAL(clicked()), SLOT(checkClicked()));
+ QWhatsThis::add(check, _("Run LILO in test mode to see if the configuration is ok"));
+ addKrnl=new QPushButton(_("Add &Kernel..."), actions);
+ connect(addKrnl, SIGNAL(clicked()), SLOT(addKrnlClicked()));
+ QWhatsThis::add(addKrnl, _("Add a new Linux kernel to the boot menu"));
+ addOS=new QPushButton(_("Add Other &OS..."), actions);
+ connect(addOS, SIGNAL(clicked()), SLOT(addOSClicked()));
+ QWhatsThis::add(addOS, _("Add a non-Linux OS to the boot menu"));
+ remove=new QPushButton(_("&Remove Entry"), actions);
+ connect(remove, SIGNAL(clicked()), SLOT(removeClicked()));
+ QWhatsThis::add(remove, _("Remove entry from the boot menu"));
+ update();
+}
+Images::~Images()
+{
+ delete probe;
+}
+void Images::update() // SLOT
+{
+ int selection=images->currentItem();
+ if(selection==-1) selection=0;
+ String dflt=lilo->dflt();
+ String entry;
+ StringList imgs=lilo->entries();
+ images->clear();
+ for(StringList::const_iterator it=imgs.begin(); it!=imgs.end(); it++) {
+ if(*it==dflt)
+ entry=*it + " (default)";
+ else
+ entry=*it;
+ images->insertItem(entry.cstr());
+ }
+ if((unsigned int)selection>images->count()) selection=images->count();
+ images->setSelected(selection, true);
+ imageSelected(images->text(selection));
+}
+void Images::probeClicked() // SLOT
+{
+ lilo->probe();
+ update();
+ emit configChanged();
+}
+void Images::dfltClicked() // SLOT
+{
+ if (images->currentItem() < 0) return;
+ lilo->setDefault(images->currentText().replace(QRegExp(" (default)", true, true), "").latin1());
+ update();
+ emit configChanged();
+}
+void Images::detailsClicked() // SLOT
+{
+ liloimage *l=lilo->images[current.latin1()];
+ Details *d = new Details(l, this);
+ if(d->exec()==QDialog::Accepted) {
+ String tmp;
+ tmp=l->grep("^[ \t]*read-only[ \t]*");
+ if(d->isReadOnly() && tmp.empty())
+ l->insert(l->end(), "\tread-only");
+ else if(!d->isReadOnly() && !tmp.empty())
+ l->remove(tmp);
+ l->set("vga", d->vgaMode().latin1(), true, true, "\t");
+ tmp=l->grep("^[ \t]*unsafe[ \t]*");
+ if(d->isUnsafe() && tmp.empty())
+ l->insert(l->end(), "\tunsafe");
+ else if(!d->isUnsafe() && !tmp.empty())
+ l->remove(tmp);
+ tmp=l->grep("^[ \t]*lock[ \t]*");
+ if(d->isLocked() && tmp.empty())
+ l->insert(l->end(), "\tlock");
+ else if(!d->isLocked() && !tmp.empty())
+ l->remove(tmp);
+ tmp=l->grep("^[ \t]*restricted[ \t]*");
+ if(d->isRestricted() && tmp.empty())
+ l->insert(l->end(), "\trestricted");
+ else if(!d->isRestricted() && !tmp.empty())
+ l->remove(tmp);
+ if(d->isRestricted() || d->usePassword())
+ l->set("password", d->Password().latin1(), true, true, "\t");
+
+ l->set("password", d->Password().latin1(), true, true, "\t");
+ emit configChanged();
+ }
+ delete d;
+}
+void Images::checkClicked() // SLOT
+{
+ QString LiloOut=lilo->liloOut().cstr();
+ if(lilo->isOk()) {
+ LiloOut=_("Configuration ok. LILO said:\n")+LiloOut;
+ InformationOK(this, LiloOut, _("Configuration OK"), "lilo-config.confOK");
+ } else {
+ LiloOut=_("Configuration NOT ok. LILO said:\n")+LiloOut;
+ ErrorOK(this, _("Configuration NOT ok"), LiloOut);
+ }
+}
+void Images::addKrnlClicked() // SLOT
+{
+ InputBox::entries e;
+ InputBox::entry l0={ _("&Kernel filename:"), "", true, _("Enter the filename of the kernel you want to boot here.") };
+ InputBox::entry l1={ _("&Label:"), "", false, _("Enter the label (name) of the kernel you want to boot here.") };
+ InputBox::entry l2={ _("&Root filesystem:"), "", true, _("Enter the root filesystem (i.e. the partition that will be mounted as / at boot time) for the kernel you want to boot here.") };
+ InputBox::entry l3={ _("&Initial ramdisk:"), "", true, _("If you want to use an initial ramdisk (initrd) for this kernel, enter its filename here. Leave this field blank if you don't intend to use an initial ramdisk for this kernel.") };
+ e.insert(e.end(), l0);
+ e.insert(e.end(), l1);
+ e.insert(e.end(), l2);
+ e.insert(e.end(), l3);
+ InputBox *label=new InputBox(e, this);
+ if(label->exec()==QDialog::Accepted) {
+ QStringList s=label->text();
+ QStringList::Iterator it=s.begin();
+ String kernel=(*it).latin1();
+ it++;
+ String label=(*it).latin1();
+ it++;
+ String root=(*it).latin1();
+ it++;
+ String initrd=(*it).latin1();
+ lilo->addLinux(label, kernel, root, initrd);
+ update();
+ emit configChanged();
+ }
+ delete label;
+}
+void Images::addOSClicked() // SLOT
+{
+ InputBox::entries e;
+ InputBox::entry l0={_("Boot from dis&k:"), "", true, _("Enter the partition containing the operating system you'd like to boot here.") };
+ InputBox::entry l1={_("&Label:"), "", false, _("Enter the label (name) of the operating system here.") };
+ e.insert(e.end(), l0);
+ e.insert(e.end(), l1);
+ InputBox *label=new InputBox(e, this);
+ if(label->exec()==QDialog::Accepted) {
+ QStringList s=label->text();
+ QStringList::Iterator it=s.begin();
+ String disk=(*it).latin1();
+ it++;
+ String label=(*it).latin1();
+ lilo->addOther(label, disk);
+ update();
+ emit configChanged();
+ }
+ delete label;
+}
+void Images::removeClicked() // SLOT
+{
+ if(images->currentItem()==-1)
+ return;
+ QString s=images->currentText();
+ if(s.right(10)==" (default)")
+ s=s.left(s.length()-10);
+ if (s.isNull())
+ s = "";
+ lilo->images.remove(s.latin1());
+ previous=""; current="";
+ update();
+ emit configChanged();
+}
+
+QString value(QString const &s)
+{
+ QString r=s.mid(s.find('=')+1).simplifyWhiteSpace();
+ if(r.left(1)=="\"")
+ r=r.mid(1);
+ if(r.right(1)=="\"")
+ r=r.left(r.length()-1);
+ if (r.isNull())
+ r = "";
+ return r;
+}
+
+void Images::imageSelected(const QString &i) // SLOT
+{
+ bool blocked = signalsBlocked();
+ blockSignals(true);
+ QString s=i;
+ if(s.right(10)==" (default)")
+ s=s.left(s.length()-10);
+ if(previous!=s && !previous.isEmpty()) {
+ previous=s;
+ saveChanges();
+ } else if(previous.isEmpty())
+ previous=s;
+
+ if (s.isNull())
+ s = "";
+ current=s;
+ liloimage *l=lilo->images[s.latin1()];
+ if(l) {
+ QString img=value(l->grep("^[ \t]*(image|other)[ \t]*=").cstr());
+ image->setText(img);
+ label->setText(s);
+ if(l->isLinux()) {
+ image->setLabel(_("&Kernel:"));
+ String rt=l->grep("^[ \t]*root[ \t]*=");
+ if(!rt.empty())
+ root->setText(value(rt.cstr()));
+ else
+ root->setText("");
+ String rd=l->grep("^[ \t]*initrd[ \t]*=");
+ if(!rd.empty())
+ initrd->setText(value(rd.cstr()));
+ else
+ initrd->setText("");
+ append->setText(l->get("append").cstr());
+ root->show();
+ initrd->show();
+ append->show();
+ } else {
+ image->setLabel(_("Dis&k:"));
+ root->hide();
+ initrd->hide();
+ append->hide();
+ }
+ }
+ blockSignals(blocked);
+}
+void Images::saveChanges() // SLOT
+{
+ if(!current.isEmpty()) {
+ liloimage *l=lilo->images[current.latin1()];
+ if(l) {
+ l->set("image", image->text().latin1(), true, true);
+ l->set("label", label->text().latin1(), true, true, "\t");
+ l->set("root", root->text().latin1(), true, true, "\t");
+ l->set("initrd", initrd->text().latin1(), true, true, "\t");
+ l->set("append", append->text().latin1(), true, true, "\t");
+ }
+ }
+}
+
+void Images::makeReadOnly()
+{
+ images->setEnabled( false );
+ image->setEnabled( false );
+ label->setEnabled( false );
+ root->setEnabled( false );
+ initrd->setEnabled( false );
+ append->setEnabled( false );
+ dflt->setEnabled( false );
+ details->setEnabled( false );
+ probe->setEnabled( false );
+ check->setEnabled( false );
+ addKrnl->setEnabled( false );
+ addOS->setEnabled( false );
+ remove->setEnabled( false );
+}
diff --git a/lilo-config/kde-qt-common/images.h b/lilo-config/kde-qt-common/images.h
new file mode 100644
index 0000000..62c6124
--- /dev/null
+++ b/lilo-config/kde-qt-common/images.h
@@ -0,0 +1,82 @@
+/* images.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _IMAGES_H_
+#define _IMAGES_H_ 1
+#include <lilo.h>
+#include <qwidget.h>
+#include <qmultilineedit.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qlistbox.h>
+#include <qvbox.h>
+#include "EditWidget.h"
+class Images:public QWidget
+{
+ Q_OBJECT
+public:
+ Images(liloconf *l=0, QWidget *parent=0, const char *name=0);
+ ~Images();
+ void setCfg(liloconf *l) { lilo=l; };
+ void makeReadOnly();
+public slots:
+ void update();
+ void saveChanges();
+private slots:
+ void probeClicked();
+ void dfltClicked();
+ void detailsClicked();
+ void checkClicked();
+ void addKrnlClicked();
+ void addOSClicked();
+ void removeClicked();
+ void imageSelected(const QString &i);
+signals:
+ void configChanged();
+private:
+ liloconf *lilo;
+ QString previous;
+ QString current;
+ QHBoxLayout *layout;
+ QListBox *images;
+ QVBox *parameters;
+ EditWidget *image;
+ EditWidget *label;
+ EditWidget *root;
+ EditWidget *initrd;
+ EditWidget *append;
+ QVBox *actions;
+ QPushButton *dflt;
+ QPushButton *details;
+ QPushButton *probe;
+ QPushButton *check;
+ QPushButton *addKrnl;
+ QPushButton *addOS;
+ QPushButton *remove;
+};
+#endif
diff --git a/lilo-config/kde-qt-common/mainwidget.cpp b/lilo-config/kde-qt-common/mainwidget.cpp
new file mode 100644
index 0000000..6d76dc5
--- /dev/null
+++ b/lilo-config/kde-qt-common/mainwidget.cpp
@@ -0,0 +1,107 @@
+/* mainwidget.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "mainwidget.moc"
+#include "ui.h"
+
+MainWidget::MainWidget(QWidget *parent, const char *name)
+ : QTabWidget(parent, name)
+{
+ l=new liloconf();
+ general=new General(l, this);
+ connect(general, SIGNAL(configChanged()), SIGNAL(configChanged()));
+ images=new Images(l, this);
+ connect(images, SIGNAL(configChanged()), SIGNAL(configChanged()));
+ expert=new Expert(l, this);
+ connect(expert, SIGNAL(configChanged()), SIGNAL(configChanged()));
+ connect(expert, SIGNAL(configChanged()), images, SLOT(update()));
+ addTab(general, _("&General Options"));
+ addTab(images, _("&Operating Systems"));
+ addTab(expert, _("&Expert"));
+ connect(this, SIGNAL(selected(const QString &)), SLOT(tabChanged(const QString &)));
+ load();
+ arrangeWidgets();
+}
+
+void MainWidget::makeReadOnly()
+{
+ general->makeReadOnly();
+ images->makeReadOnly();
+ expert->makeReadOnly();
+}
+
+void MainWidget::load()
+{
+ defaults();
+}
+
+void MainWidget::save()
+{
+ if(previous==_("&Expert"))
+ expert->saveChanges();
+ else {
+ general->saveChanges();
+ images->saveChanges();
+ }
+ l->checked=false;
+ if(!l->isOk()) {
+ if(WarningYesNo(this, "About to write a faulty lilo.conf", "WARNING: the config file is currently NOT ok.\nDo you really want to override /etc/lilo.conf?\n\nIf you aren't sure, select \"no\" and click the \"Check configuration\" button to see the details.\nIf you don't know what's wrong, try clicking the \"Probe\" button to auto-generate a working lilo.conf.\nIf you're getting this message after using the \"Probe\" button, please send a full bug report,\nincluding the output of \"Check configuration\" and the generated lilo.conf (displayed in the \"Expert\" tab),\nto bero@kde.org.")!=IDYES)
+ return;
+ }
+ l->writeFile("/etc/lilo.conf");
+ l->install();
+}
+
+void MainWidget::defaults()
+{
+}
+
+void MainWidget::reset()
+{
+ load();
+}
+
+void MainWidget::arrangeWidgets()
+{
+}
+void MainWidget::tabChanged(QString const &lbl) // SLOT
+{
+ if(previous==_("&Expert"))
+ expert->saveChanges();
+ else if(previous==_("&General options"))
+ general->saveChanges();
+ else if(previous==_("&Operating systems"))
+ images->saveChanges();
+ if(lbl==_("&Expert"))
+ expert->update();
+ else if(lbl==_("&Operating systems"))
+ images->update();
+ else if(lbl==_("&General options"))
+ general->update();
+ previous=lbl;
+}
diff --git a/lilo-config/kde-qt-common/mainwidget.h b/lilo-config/kde-qt-common/mainwidget.h
new file mode 100644
index 0000000..46696e8
--- /dev/null
+++ b/lilo-config/kde-qt-common/mainwidget.h
@@ -0,0 +1,60 @@
+/* mainwidget.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _MAINWIDGET_H_
+#define _MAINWIDGET_H_ 1
+#include <qwidget.h>
+#include <qlistbox.h>
+#include <qtabwidget.h>
+#include <qevent.h>
+#include "general.h"
+#include "images.h"
+#include "expert.h"
+
+class MainWidget: public QTabWidget {
+ Q_OBJECT
+public:
+ MainWidget(QWidget *parent, const char *name=0);
+ void arrangeWidgets();
+ void makeReadOnly();
+public slots:
+ void load();
+ void save();
+ void reset();
+ void defaults();
+ void tabChanged(const QString &lbl);
+signals:
+ void configChanged();
+private:
+ QString previous;
+ General *general;
+ Images *images;
+ Expert *expert;
+ liloconf *l;
+};
+#endif
diff --git a/lilo-config/kde-qt-common/ui.h b/lilo-config/kde-qt-common/ui.h
new file mode 100644
index 0000000..e672847
--- /dev/null
+++ b/lilo-config/kde-qt-common/ui.h
@@ -0,0 +1,77 @@
+/* ui.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+/* UI definitions... Coding these things twice (with and without KDE)
+ * wouldn't make sense... */
+
+#ifndef _UI_H
+#define _UI_H
+
+#ifdef USE_KDE
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <ktabctl.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+#define _(x) i18n(x)
+#define WarningYesNo(parent, caption, text) \
+ KMessageBox::warningYesNo(parent, text, caption)
+#define ErrorOK(parent, caption, text) \
+ KMessageBox::sorry(parent, text, caption)
+#define InformationOK(parent, text, caption, dontShowAgainName) \
+ KMessageBox::information(parent, text, caption, dontShowAgainName)
+#define CriticalErrorOK(parent, text, caption) \
+ KMessageBox::error(parent, text, caption)
+#define TabBar KTabCtl
+#define FileDlg KFileDialog
+#define SPACE_MARGIN KDialog::marginHint()
+#define SPACE_INSIDE KDialog::spacingHint()
+#else
+#include <qmessagebox.h>
+#include <qtabwidget.h>
+#include <qdialog.h>
+#include <qfiledialog.h>
+#define _(x) tr(x)
+#define WarningYesNo(parent, caption, text) \
+ QMessageBox::warning(parent, caption, text, QMessageBox::Yes, QMessageBox::No)
+#define ErrorOK(parent, caption, text) \
+ QMessageBox::information(parent, caption, text)
+#define InformationOK(parent, text, caption, dontShowAgainName) \
+ QMessageBox::information(parent, caption, text)
+#define CriticalErrorOK(parent, text, caption) \
+ QMessageBox::critical(parent, caption, text)
+#define TabBar QTabWidget
+#define FileDlg QFileDialog
+#define SPACE_MARGIN 5
+#define SPACE_INSIDE 5
+#endif
+#define IDYES 3
+#define IDNO 4
+
+#endif
+
diff --git a/lilo-config/kde/Details.cpp b/lilo-config/kde/Details.cpp
new file mode 100644
index 0000000..4e19b14
--- /dev/null
+++ b/lilo-config/kde/Details.cpp
@@ -0,0 +1,134 @@
+/* Details.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "Details.moc"
+
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+#include <ui.h>
+
+Details::Details(liloimage *lilo, QWidget *parent, const char *name, WFlags /* f */)
+ : KDialogBase(parent, name, true, QString::null, Ok|Cancel, Ok, true)
+{
+ l=lilo;
+
+ QVBox *page = makeVBoxMainWidget();
+
+ QHBox *vgab=new QHBox(page);
+ QLabel *vlbl=new QLabel(_("&Graphics mode on text console:"), vgab);
+ vga=new QComboBox(false, vgab);
+ vlbl->setBuddy(vga);
+ QWhatsThis::add(vgab, _("You can select the graphics mode for this kernel here.<br>If you intend to use a VGA graphics mode, you must compile the kernel with support for framebuffer devices. The <i>ask</i> setting brings up a prompt at boot time."));
+ vga->insertItem(_("default"));
+ vga->insertItem(_("ask"));
+ vga->insertItem(_("text 80x25 (0)"));
+ vga->insertItem(_("text 80x50 (1)"));
+ vga->insertItem(_("text 80x43 (2)"));
+ vga->insertItem(_("text 80x28 (3)"));
+ vga->insertItem(_("text 80x30 (4)"));
+ vga->insertItem(_("text 80x34 (5)"));
+ vga->insertItem(_("text 80x60 (6)"));
+ vga->insertItem(_("text 40x25 (7)"));
+ vga->insertItem(_("VGA 640x480, 256 colors (769)"));
+ vga->insertItem(_("VGA 640x480, 32767 colors (784)"));
+ vga->insertItem(_("VGA 640x480, 65536 colors (785)"));
+ vga->insertItem(_("VGA 640x480, 16.7M colors (786)"));
+ vga->insertItem(_("VGA 800x600, 256 colors (771)"));
+ vga->insertItem(_("VGA 800x600, 32767 colors (787)"));
+ vga->insertItem(_("VGA 800x600, 65536 colors (788)"));
+ vga->insertItem(_("VGA 800x600, 16.7M colors (789)"));
+ vga->insertItem(_("VGA 1024x768, 256 colors (773)"));
+ vga->insertItem(_("VGA 1024x768, 32767 colors (790)"));
+ vga->insertItem(_("VGA 1024x768, 65536 colors (791)"));
+ vga->insertItem(_("VGA 1024x768, 16.7M colors (792)"));
+ vga->insertItem(_("VGA 1280x1024, 256 colors (775)"));
+ vga->insertItem(_("VGA 1280x1024, 32767 colors (793)"));
+ vga->insertItem(_("VGA 1280x1024, 65536 colors (794)"));
+ vga->insertItem(_("VGA 1280x1024, 16.7M colors (795)"));
+
+ readonly=new QCheckBox(_("Mount root filesystem &read-only"), page);
+ QWhatsThis::add(readonly, _("Mount the root filesystem for this kernel read-only. Since the init scripts normally take care of remounting the root filesystem in read-write mode after running some checks, this should always be turned on.<br>Don't turn this off unless you know what you're doing."));
+
+ unsafe=new QCheckBox(_("Do not check &partition table"), page);
+ QWhatsThis::add(unsafe, _("This turns off some sanity checks while writing the configuration. This should not be used under \"normal\" circumstances, but it can be useful, for example, by providing the capability of booting from a floppy disk, without having a floppy in the drive every time you run lilo.<br>This sets the <i>unsafe</i> keyword in lilo.conf."));
+
+ QHBox *opts=new QHBox(page);
+ lock=new QCheckBox(_("&Record boot command lines for defaults"), opts);
+ QWhatsThis::add(lock, "<qt>" + _("Checking this box enables automatic recording of boot command lines as the default for the following bootups. This way, lilo \"locks\" on a choice until it is manually overridden.<br>This sets the <b>lock</b> option in lilo.conf"));
+ restricted=new QCheckBox(_("R&estrict parameters"), opts);
+ connect(restricted, SIGNAL(clicked()), SLOT(check_pw()));
+ QWhatsThis::add(restricted, _("If this box is checked, a password (entered below) is required only if any parameters are changed (i.e. the user can boot <i>linux</i>, but not <i>linux single</i> or <i>linux init=/bin/sh</i>).\nThis sets the <b>restricted</b> option in lilo.conf."));
+
+ QHBox *pw=new QHBox(page);
+ use_password=new QCheckBox(_("Require &password:"), pw);
+ connect(use_password, SIGNAL(clicked()), SLOT(check_pw()));
+ password=new QLineEdit(pw);
+ password->setMaxLength(15);
+ password->setEchoMode(QLineEdit::Password);
+ QWhatsThis::add(pw, _("Enter the password required for bootup (if any) here. If <i>restricted</i> above is checked, the password is required for additional parameters only.<br><b>WARNING:</b> The password is stored in clear text in /etc/lilo.conf. You'll want to make sure nobody untrusted can read this file. Also, you probably don't want to use your normal/root password here."));
+
+ if(l) {
+ QString mode=l->get("vga", "").cstr();
+ if(mode.isEmpty())
+ vga->setCurrentItem(0);
+ else if(mode=="ask")
+ vga->setCurrentItem(1);
+ else
+ for(int i=0; i<vga->count(); i++) {
+ if(vga->text(i).contains("(" + mode + ")")) {
+ vga->setCurrentItem(i);
+ break;
+ }
+ }
+ readonly->setChecked(!l->grep("[ \t]*read-only[ \t]*").empty());
+ unsafe->setChecked(!l->grep("[ \t]*unsafe[ \t]*").empty());
+ lock->setChecked(!l->grep("[ \t]*lock[ \t]*").empty());
+ restricted->setChecked(!l->grep("[ \t]*restricted[ \t]*").empty());
+ password->setText(l->get("password").cstr());
+ }
+
+ check_pw();
+}
+
+void Details::check_pw()
+{
+ password->setEnabled(restricted->isChecked() || use_password->isChecked());
+}
+
+QString Details::vgaMode() const
+{
+ QString s=vga->currentText();
+ if(s=="default")
+ return "";
+ else if(s!="ask") {
+ s=s.mid(s.find('(')+1);
+ s=s.left(s.length()-1);
+ }
+ return s;
+}
diff --git a/lilo-config/kde/Details.h b/lilo-config/kde/Details.h
new file mode 100644
index 0000000..e752f0b
--- /dev/null
+++ b/lilo-config/kde/Details.h
@@ -0,0 +1,61 @@
+/* Details.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef _DETAILS_H_
+#define _DETAILS_H_ 1
+
+#include <lilo.h>
+#include <kdialogbase.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+
+class Details:public KDialogBase
+{
+ Q_OBJECT
+public:
+ Details(liloimage *lilo, QWidget *parent=0, const char *name=0, WFlags f=0);
+ bool isReadOnly() const { return readonly->isChecked(); };
+ QString vgaMode() const;
+ bool isUnsafe() const { return unsafe->isChecked(); };
+ bool isLocked() const { return lock->isChecked(); };
+ bool isRestricted() const { return restricted->isChecked(); };
+ bool usePassword() const { return use_password->isChecked(); };
+ QString Password() const { return password->text(); };
+private slots:
+ void check_pw();
+private:
+ liloimage *l;
+ QCheckBox *readonly;
+ QComboBox *vga;
+ QCheckBox *unsafe;
+ QCheckBox *lock;
+ QCheckBox *restricted;
+ QCheckBox *use_password;
+ QLineEdit *password;
+};
+#endif
diff --git a/lilo-config/kde/InputBox.cpp b/lilo-config/kde/InputBox.cpp
new file mode 100644
index 0000000..a338c20
--- /dev/null
+++ b/lilo-config/kde/InputBox.cpp
@@ -0,0 +1,43 @@
+/* InputBox.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "InputBox.moc"
+#include <qvbox.h>
+#include <qwhatsthis.h>
+#include <ui.h>
+
+InputBox::InputBox(entries e, QWidget *parent, const char *name, bool hasCancel, WFlags f)
+ : KDialogBase(parent, name, true, QString::null, hasCancel ? Ok | Cancel : Ok, Ok, true )
+{
+ QVBox *page = makeVBoxMainWidget();
+ for(entries::iterator it=e.begin(); it!=e.end(); it++) {
+ EditWidget *ed=new EditWidget((*it).label, (*it).dflt, (*it).isFile, page);
+ QWhatsThis::add(ed, (*it).help);
+ edit.insert(edit.end(), ed);
+ }
+}
diff --git a/lilo-config/kde/InputBox.h b/lilo-config/kde/InputBox.h
new file mode 100644
index 0000000..d263161
--- /dev/null
+++ b/lilo-config/kde/InputBox.h
@@ -0,0 +1,50 @@
+/* InputBox.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _INPUTBOX_H_
+#define _INPUTBOX_H_ 1
+
+#include <kdialogbase.h>
+
+#include <qlabel.h>
+#include <qlineedit.h>
+
+#include "EditWidget.h"
+#include <list>
+class InputBox:public KDialogBase
+{
+ Q_OBJECT
+public:
+ typedef struct { QString label; QString dflt; bool isFile; QString help; } entry;
+ typedef std::list<entry> entries;
+ InputBox(entries e, QWidget *parent=0, const char *name=0, bool hasCancel=true, WFlags f=0);
+ QStringList const text() const { QStringList s; for(std::list<EditWidget*>::const_iterator it=edit.begin(); it!=edit.end(); it++) s << (*it)->text(); return s; };
+private:
+ std::list<EditWidget*> edit;
+};
+#endif
diff --git a/lilo-config/kde/Makefile.am b/lilo-config/kde/Makefile.am
new file mode 100644
index 0000000..08c52b8
--- /dev/null
+++ b/lilo-config/kde/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES= -I$(srcdir)/../common -I$(srcdir)/../kde-qt-common $(all_includes)
+
+kde_module_LTLIBRARIES = kcm_lilo.la
+
+kcm_lilo_la_SOURCES = kcontrol.cpp Details.cpp InputBox.cpp
+kcm_lilo_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+kcm_lilo_la_LIBADD = ../kde-qt-common/libwidgets.la $(LIB_KIO)
+kcm_lilo_la_METASOURCES = AUTO
+AM_CXXFLAGS = -DUSE_KDE
+
+noinst_HEADERS = Details.h InputBox.h
+
+xdg_apps_DATA = lilo.desktop
diff --git a/lilo-config/kde/kcontrol.cpp b/lilo-config/kde/kcontrol.cpp
new file mode 100644
index 0000000..2db98af
--- /dev/null
+++ b/lilo-config/kde/kcontrol.cpp
@@ -0,0 +1,87 @@
+/* kcontrol.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include "kcontrol.moc"
+#include <mainwidget.h>
+#include <ui.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <qlayout.h>
+#include <kaboutdata.h>
+#include <unistd.h>
+
+KControl::KControl(QWidget *parent, const char *name)
+ : KCModule(parent, name)
+{
+ QVBoxLayout *layout=new QVBoxLayout(this);
+ m=new MainWidget(this, name);
+ layout->addWidget(m);
+ connect(m, SIGNAL(configChanged()), SLOT(configChanged()));
+ if (getuid() != 0) {
+ m->makeReadOnly();
+ }
+ KAboutData *about = new KAboutData(I18N_NOOP("kcmlilo"), I18N_NOOP("LILO Configuration"),
+ 0, 0, KAboutData::License_GPL,
+ I18N_NOOP("(c) 2000, Bernhard Rosenkraenzer"));
+ about->addAuthor("Bernhard \"Bero\" Rosenkraenzer", 0, "bero@redhat.com");
+ setAboutData(about);
+}
+
+void KControl::load()
+{
+ m->load();
+}
+
+void KControl::save()
+{
+ m->save();
+}
+
+void KControl::defaults()
+{
+ m->defaults();
+}
+
+void KControl::reset()
+{
+ m->reset();
+}
+
+void KControl::configChanged() // SLOT
+{
+ emit changed(true);
+}
+
+extern "C"
+{
+ KDE_EXPORT KCModule *create_lilo(QWidget *parent, const char *name)
+ {
+ return new KControl(parent, "kcmlilo");
+ }
+}
+
diff --git a/lilo-config/kde/kcontrol.h b/lilo-config/kde/kcontrol.h
new file mode 100644
index 0000000..d06d834
--- /dev/null
+++ b/lilo-config/kde/kcontrol.h
@@ -0,0 +1,54 @@
+/* kcontrol.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+** Contributions by M. Laurent and W. Bastian.
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+#ifndef _KCONTROL_H_
+#define _KCONTROL_H_
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#include <qwidget.h>
+#include <qevent.h>
+#include <kcmodule.h>
+#include "mainwidget.h"
+
+class KAboutData;
+
+class KControl: public KCModule {
+ Q_OBJECT
+public:
+ KControl(QWidget *parent, const char *name);
+ void load();
+ void save();
+ void defaults();
+ void reset();
+public slots:
+ void configChanged();
+private:
+ MainWidget *m;
+};
+
+#endif
+
diff --git a/lilo-config/kde/lilo.desktop b/lilo-config/kde/lilo.desktop
new file mode 100644
index 0000000..cd1c7ba
--- /dev/null
+++ b/lilo-config/kde/lilo.desktop
@@ -0,0 +1,212 @@
+[Desktop Entry]
+Exec=kcmshell lilo
+Icon=hdd_unmount
+Type=Application
+
+X-KDE-ModuleType=Library
+X-KDE-Library=lilo
+X-KDE-RootOnly=true
+X-KDE-HasReadOnlyMode=false
+
+Name=Boot Manager (LILO)
+Name[af]=Boot Bestuurder (Lilo)
+Name[ar]=مدير إنطلاق النظام (LILO)
+Name[az]=Açılış İdarəçisi (LILO)
+Name[be]=Кіраўнік загрузкі LILO
+Name[bg]=Стартиране
+Name[bn]=বুট ম্যানেজার (LILO)
+Name[br]=C'Harger loc'hañ (LILO)
+Name[ca]=Gestor d'arrencada (LILO)
+Name[cs]=Správce spuštění (LILO)
+Name[cy]=Rheolydd Cychwyn (LILO)
+Name[da]=Boothåndtering (LILO)
+Name[de]=Bootmanager (Lilo)
+Name[el]=Διαχειριστής Εκκίνησης (LILO)
+Name[eo]=Linukslanĉilo (LILO)
+Name[es]=Administrador de arranque (LILO)
+Name[et]=Alglaadur (LILO)
+Name[eu]=Letra-tipoen kudeatzailea
+Name[fa]=مدیر راه‌اندازی (LILO)
+Name[fi]=Käynnistyksenhallinta (LILO)
+Name[fo]=Sjálvbyrjarahandfarari (LILO)
+Name[fr]=Gestionnaire de démarrage (LILO)
+Name[ga]=Bainisteoir Tosaithe (LILO)
+Name[gl]=Xestor de Arranque (LILO)
+Name[he]=מנהל האתחול (LILO)
+Name[hi]=बूट प्रबंधक (लिलो)
+Name[hr]=Upravljanje pokretanjem (LILO)
+Name[hu]=Rendszerindító (LILO)
+Name[id]=Manajer Boot (LILO)
+Name[is]=Ræsistjóri (LILO)
+Name[it]=Gestore di avvio (LILO)
+Name[ja]=ブートマネージャ (LILO)
+Name[ka]=ჩატვირთვის მმართველი (LILO)
+Name[kk]=Жүктеуіш (LILO)
+Name[km]=កម្មវិធី​គ្រប់គ្រង​ការ​ចាប់ផ្ដើម​ឡើង​វិញ (LILO)
+Name[ko]=부트 관리자 (LILO)
+Name[lt]=Užkrovos tvarkyklė (LILO)
+Name[lv]=Sāknēšanas Menedžeris (LILO)
+Name[mn]=Бүүт Менежер (Лило)
+Name[ms]=Pengurus Boot (LILO)
+Name[nb]=Oppstartsbehandler (LILO)
+Name[nds]=Systeemstart-Pleger (LILO)
+Name[ne]=बुट प्रबन्धक (एलआईएलओ)
+Name[nl]=Opstartbeheerder (LILO)
+Name[nn]=Oppstartshandsamar (LILO)
+Name[pa]=ਬੂਟ ਪਰਬੰਧਕ (LILO)
+Name[pl]=Uruchamianie systemu (LILO)
+Name[pt]=Gestor de Arranque (LILO)
+Name[pt_BR]=Gerenciador de Inicialização (LILO)
+Name[ro]=Manager de boot-are (LILO)
+Name[ru]=Загрузчик LILO
+Name[se]=Vuolggahangieđahalli (LILO)
+Name[sk]=Správca bootovania (LILO)
+Name[sl]=Upravljalnik zagona (LILO)
+Name[sr]=Бут менаџер (LILO)
+Name[sr@Latn]=But menadžer (LILO)
+Name[sv]=Starthanterare (Lilo)
+Name[ta]=ஆரம்ப இயக்க மேலாளர்(LILO)
+Name[tg]=Роҳбари Пурборкардан (LILO)
+Name[th]=จัดการการบูต (LILO)
+Name[tr]=Açılış Yöneticisi (LILO)
+Name[uk]=Менеджер завантаження (LILO)
+Name[ven]=Muranga phanda wa Butu (LILO)
+Name[vi]=Bộ quản lý khởi động (LILO)
+Name[wa]=Apontiaedje del enondrece (LILO)
+Name[xh]=Umphathi wesiNgxobo (LILO)
+Name[zh_CN]=启动管理器(LILO)
+Name[zh_HK]=開機管理員(LILO)
+Name[zh_TW]=開機啟動管理程式(LILO)
+Name[zu]=Umphathi Wesingxobo (LILO)
+Comment=Configure LILO (the Linux boot manager)
+Comment[af]=Konfigureer Lilo (die Linux boot bestuurder)
+Comment[ar]=إعدادات LILO (مدير إنطلاق نظام لينكس)
+Comment[az]=LILO Qurğuları (Linuks açılış idarəçisi)
+Comment[be]=Наставіць LILO (кіраўнік загрузкі Linux)
+Comment[bg]=Графично настройване на първоначалното зареждането на Линукс
+Comment[bn]=LILO (লিনাক্স বুট ম্যানেজার) কনফিগার করে
+Comment[br]=Kefluniañ LILO (ar c'harger loc'hañ evit Linux)
+Comment[bs]=Podesi LILO (Linux boot manager)
+Comment[ca]=Aquí podreu configurar el LILO (el gestor d'arrencada de Linux)
+Comment[cs]=Zde je možné nastavit LILO (LInux LOader)
+Comment[cy]=Ffurfweddu LILO (rheolydd cychwyn Linux)
+Comment[da]=Indstil LILO (Linux-boothåndtering)
+Comment[de]=Hier können Sie Lilo (den Bootmanager von Linux) einrichten
+Comment[el]=Ρύθμιση LILO (Ο διαχειριστής εκκίνησης του Linux)
+Comment[eo]=Agordu LILOn (la Linukslanĉilon)
+Comment[es]=Configurar LILO (el administrador de arranque de Linux)
+Comment[et]=Linuxi alglaaduri LILO seadistamine
+Comment[eu]=LILO konfiguratu (Linuxen abikoko kudeatzailea)
+Comment[fa]=پیکربندی LILO (مدیر راه‌اندازی لینوکس)
+Comment[fi]=Aseta LILO:a (Linuxin käynnistysmanageri)
+Comment[fr]=Configuration de LILO (le gestionnaire de démarrage de Linux)
+Comment[ga]=Cumraigh LILO (bainisteoir tosaithe Linux)
+Comment[gl]=Configurar LILO (O xestor de arranque de linux)
+Comment[he]=שינוי הגדרות LILO (מנהל האתחול של לינוקס)
+Comment[hi]=लिलो कॉन्फ़िगर करें (लिनक्स बूट प्रबंधक)
+Comment[hr]=Konfigurirajte LILO (Linux upravitelj pokretanja sustava)
+Comment[hu]=a LILO beállításai
+Comment[is]=Stilla LILO (Linux ræsistjórann)
+Comment[it]=Configura LILO (il gestore dell'avvio di Linux)
+Comment[ja]=LILO (Linux ブートマネージャ) の設定
+Comment[ka]=LILO-ს კონფიგურაცია (ლინუქსის ჩატვირთვის მმართველი)
+Comment[kk]=LILO (Linux жүктеуішін) баптауы
+Comment[km]=កំណត់​រចនា​សម្ព័ន្ធ LILO (កម្មវិធី​គ្រប់គ្រង​ការ​ចាប់ផ្ដើម​ឡើង​វិញ​លីនុច)
+Comment[ko]=LILO(리눅스 부트 관리자) 설정
+Comment[lt]=Konfigūruoti LILO (Linux užkrovos tvarkyklę)
+Comment[mk]=Конфигурирајте го LILO (менаџерот за подигање на Линукс)
+Comment[mn]=Лило (Линүкс эхлүүлэгч менежер) Тохируулах
+Comment[ms]=Selaraskan LILO (pengurus boot Linux)
+Comment[mt]=Ikkonfigura l-LILO (Linux Loader)
+Comment[nb]=Her kan du sette opp LILO (Linux oppstartssystem)
+Comment[nds]=LILO (Systeemstart-Pleger vun Linux) instellen
+Comment[ne]=एलआईएलओ कन्फिगर गर्नुहोस् (लिनक्स बुट प्रबन्धक)
+Comment[nl]=Lilo (Linux Opstartmanager) instellen
+Comment[nn]=LILO-oppsett (Linux-oppstartssystemet)
+Comment[pa]=LILO ਸੰਰਚਨਾ(ਲੀਨਕਸ ਬੂਟ ਪਰਬੰਧਕ)
+Comment[pl]=Konfiguracja LILO (menedżera rozruchu systemu w Linuksie)
+Comment[pt]=Configuração do LILO (o gestor de arranque do Linux)
+Comment[pt_BR]=Configura o LILO (o gerenciador de boot do Linux)
+Comment[ro]=Configurează managerul de boot-are LILO
+Comment[ru]=Утилита настройки LILO (менеджера загрузки Linux)
+Comment[se]=Heivet LILO (Linux-vuolggahanvuogádaga)
+Comment[sk]=Nastavenie LILO (správca bootovania pre Linux)
+Comment[sl]=Nastavitve LILO (zagonski upravljalnik za Linux)
+Comment[sr]=Подесите LILO (Линукс бут менаџер)
+Comment[sr@Latn]=Podesite LILO (Linuks but menadžer)
+Comment[sv]=Anpassa Lilo (starthanterare för Linux)
+Comment[ta]=வடிவமை LILO(லினக்ஸ் இயக்க மேலாளர்)
+Comment[tg]=Танзимоти LILO (Роҳбари Пурборкунии Линукс)
+Comment[th]=ปรับแต่ง LILO (เครื่องมือจัดการการบูตของลินุกซ์)
+Comment[tr]=LILO'yu Yapılandır
+Comment[uk]=Налаштувати LILO (менеджер завантаження Linux)
+Comment[ven]=Dzudzanyani LILO (mulanguli wa boot ya Linux)
+Comment[vi]=Cấu hình LILO (bộ quản lý khởi động Linux)
+Comment[wa]=Chal vos ploz apontyî LILO (l' enondrece Linux)
+Comment[xh]=Qwalalsela LILO (umphathi we boot ye Linux)
+Comment[zh_CN]=配置 LILO (Linux 启动管理程序)
+Comment[zh_HK]=設定 LILO (Linux 的開機管理員)
+Comment[zh_TW]=你可在此設定 LILO (Linux 的開機管理程式)
+
+Keywords=lilo,boot,bootup,boot manager,linux,Other OS,MBR,startup,start
+Keywords[ar]=lilo,boot,bootup,مسيير الإقلاع,لينكس,أنظمة التشغيل الأخرى,MBR,بدء التشغيل,إبدء
+Keywords[az]=lilo,açılış,başlanğıc,açılış idarəçisi,linuks,digər əməliyyat sistemləri, MBR
+Keywords[bg]=зареждане, стартиране, сектор, запис, Линукс, ядро, мениджър, lilo, boot, bootup, boot manager, linux, Other OS, MBR, startup, start
+Keywords[bn]= lilo,boot,bootup,boot manager,linux,Other OS,MBR,startup,start
+Keywords[ca]=lilo,arrencada,gestor d'arrencada,linux,d'altres SO,MBR
+Keywords[cs]=Lilo,Boot,Bootup,Boot manager,Linux,Jiný OS,MBR,Startup,Start,Spuštění
+Keywords[cy]=lilo,cychwyn, rheolydd cychwyn, linux, CG Arall, MBR, dechrau
+Keywords[da]=lilo,boot,bootup,boothåndtering,linux,Andet OS,MBR,opstart,start
+Keywords[de]=Lilo,Booten,Linux,MBR,Start,Systemstart,Bootmanager,andere OS
+Keywords[el]=lilo,εκκίνηση,διαδικασία εκκίνησης,διαχειριστής εκκίνησης,linux,Άλλο ΛΣ,MBRδιαδικασία εκκίνησης,εκκίνηση
+Keywords[eo]=lilo,lanĉo,lanĉadministrilo,Linukso,alia operaciumo,MBR,rulo
+Keywords[es]=lilo,arranque,administrador de arranque,linux,Otro SO,MBR,inicio
+Keywords[et]=lilo,boot,bootup,alglaadimine,linux,teine OS,MBR,käivitamine,start
+Keywords[fa]=lilo، راه‌اندازی، راه‌اندازی، مدیر راه‌اندازی، لینوکس، سیستم عامل دیگر، MBR، راه‌اندازی، آغاز
+Keywords[fi]=lilo,boot,bootup,käynnistyksenhallinta,linux,MBR,käynnistys,käynnistä
+Keywords[fo]=lilo,sjálvbyrja,byrja,handfarari,Linux,annað stýrikervi,MBR
+Keywords[fr]=lilo, boot, démarrage, gestionnaire de démarrage, linux, autre OS, MBR
+Keywords[ga]=lilo,tosaigh,tosú,bainisteoir tosaithe,linux,CO eile,MBR,tosú,tús
+Keywords[he]=הפעלה,התחלה,MBR,אתחול,מנהל אתחול,לינוקס,מערכות הפעלה אחרות,רשומת אתחול ראשית,lilo
+Keywords[hi]=लिलो, बूट, बूटअप,बूट प्रबंधक, लिनक्स, अन्य ओएस, एमबीआर, प्रारंभ में, प्रारंभ, शुरू
+Keywords[hr]=lilo,boot,bootup,boot manager,linux,Other OS,MBR,startup,start,pokretanje,početak,počinjanje,ostali OS,upravitelj pokretanjem
+Keywords[hu]=lilo,boot,rendszerindítás,rendszerindítás-kezelő,Linux,más operációs rendszerek,MBR,indulás,start
+Keywords[id]=lilo,boot,bootup,manajer boot,linux,OS Lainnya,MBR,startup,start
+Keywords[is]=lilo,boot,bootup,boot manager,linux,Other OS,MBR,startup,start,ræsa
+Keywords[it]=lilo,boot,boot manager,linux,altri sistemi operativi,MBR,avvio,gestore avvio
+Keywords[ja]=lilo,ブート,ブートマネージャ,linux,他のOS,MBR,起動,開始
+Keywords[ka]=lilo,ჩატვირთვა,ჩატვირთვის მმართველი,linux,სხვა ოს,MBR,შესრულება,დაწყება
+Keywords[km]=lilo,ចាប់ផ្ដើម​ឡើង​វិញ,bootup,កម្មវិធី​គ្រប់គ្រង​ការ​ចាប់ផ្ដើម​ឡើង​វិញ,លីនុច,OS ផ្សេង​ទៀត,MBR,ចាប់ផ្ដើម​ឡើង​វិញ,ចាប់ផ្ដើម
+Keywords[ko]=lilo,부팅,부트로더,리눅스,MBR,시작
+Keywords[lt]=lilo,boot,bootup,boot manager,linux,Other OS,MBR,startup,start,užkrova,krovimasis,kitos OS
+Keywords[lv]=lilo,sāknēt,sāknēšana,sāknēšanas menedžeris,linux,Citas OS,MBR,startēšana,startēt
+Keywords[mk]=lilo,boot,bootup,boot manager,linux,Other OS,MBR,startup,start,подигање,менаџер,линукс,старт
+Keywords[mn]=лило,бүүт,бүүт хийх,бүүт менежер,линүкс,Өөр ҮС,МБР,эхлүүлэх,эхлэл
+Keywords[ms]=lilo,boot,bootup,pengurus boot,linux,OS lain,MBR,startup,mula
+Keywords[nb]=lilo,boot,oppstart,linux,andre operativsystem,MBR,start
+Keywords[nds]=lilo,Systeemstart,boot,hoochfohren,boot manager,Systeemstart-Pleger,linux,Anner BS,MBR,starten,start
+Keywords[ne]=लिलो, बुट, बुटअप, बुट प्रबन्धक, लिनक्स, अन्य ओएस, एमबीआर, सुरुआत, सुरु
+Keywords[nl]=lilo,boot,bootup,boot manager,beheerder,linux,mbr,startup,start, ander besturingssysteem,opstarten,Windows,OS\2,BeOS
+Keywords[nn]=lilo,boot,oppstart,linux,andre operativsystem,MBR,start
+Keywords[pa]=ਲੀਲੋ, ਬੂਟ, ਬੂਟਅੱਪ, ਬੂਟ ਪਰਬੰਧਕ,ਲੀਨਕਸ, ਹੋਰ OS,MBR,ਸ਼ੁਰੂਆਤੀ, ਸ਼ੁਰੂ
+Keywords[pl]=lilo,boot,menedżer,uruchamianie systemu,linux,linuks,inne systemy,MBR,start
+Keywords[pt]=lilo,arranque,gestor de arranque,linux,outro SO,MBR,iniciar,início
+Keywords[pt_BR]=lilo,boot,bootup,gerenciador de boot,linux,outro SO,MBR,inicialização,iniciar
+Keywords[ro]=lilo,boot,boot-are,bootare,manager de boot-are,linux,alte S.O.,MBR,pornire,start
+Keywords[ru]=lilo,boot,bootup,boot manager,linux,Other OS,MBR,загрузка,start
+Keywords[se]=lilo,boot,vuolggaheapmi,linux,eará operatiivavuogádagat,MBR,álggaheapmi
+Keywords[sk]=lilo,boot,bootup,správca bootu,linux,Iný OS,MBR,startup,štart
+Keywords[sl]=lilo,boot,bootup,boot manager,linux,drugi OS,MBR,zagon
+Keywords[sv]=lilo,boot,bootning,bootväljare,linux,Annat OS,MBR,uppstart,start
+Keywords[ta]= லிலோ,துவக்கம்,மேலே துவக்கு,துவக்க மேலாளர்,லினக்ஸ்,மற்ற OS,MBR,துவக்கம்,துவக்கு
+Keywords[th]=lilo,บูต,bootup,เครื่องมือจัดการการบูต,ลินุกซ์,ระบบปฏิบัตการอื่น ๆ,MBR,การเริ่มระบบ,เริ่ม
+Keywords[tr]=lilo,açılış,başlangıç,açılış yöneticisi,linux,diğer işletim sistemleri
+Keywords[uk]=lilo,boot,завантаження,менеджер завантаження,linux,інші ОС,MBR,запуск
+Keywords[ven]=lilo,boot,bootup,boot manager,linux,Other Os,MBR,Mathomoni,Thoma
+Keywords[vi]=lilo,boot,khởi động,bootup,mở máy,quản lý khởi động,boot manager,linux,Other OS,hệ điều hành,HĐH,MBR,khởi chạy,startup,start
+Keywords[wa]=LILO,boot,bootup,linux,Ôtes SO,MBR,startup,start,enondrece,enondaedje
+Keywords[xh]=lilo,isingxobo,faka isingxobo, uphathi wesingxobo,linux,Ezinye OS,MBR,faka isiqalo,qala
+Keywords[zh_CN]=lilo,boot,bootup,boot manager,linux,Other OS,MBR,startup,start,启动,启动管理器,其它操作系统
+Keywords[zu]=lilo,isingxobo,faka isingxobo umphathi wesingxobo,linux,Ezinye OS,MBR,faka isiqalo,qala
+
+Categories=Qt;KDE;Settings;X-KDE-settings-system;
diff --git a/lilo-config/qt/Details.cpp b/lilo-config/qt/Details.cpp
new file mode 100644
index 0000000..eae3ed5
--- /dev/null
+++ b/lilo-config/qt/Details.cpp
@@ -0,0 +1,144 @@
+/* Details.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "Details.moc"
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+#include <ui.h>
+
+Details::Details(liloimage *lilo, QWidget *parent, const char *name, WFlags f):QDialog(parent, name, true, f)
+{
+ l=lilo;
+
+ QVBoxLayout *layout=new QVBoxLayout(this);
+ layout->setMargin(SPACE_MARGIN);
+ layout->setSpacing(SPACE_INSIDE);
+
+ QHBox *vgab=new QHBox(this);
+ QLabel *vlbl=new QLabel(_("&Graphics mode on text console:"), vgab);
+ vga=new QComboBox(false, vgab);
+ vlbl->setBuddy(vga);
+ QWhatsThis::add(vgab, _("You can select the graphics mode for this kernel here.<br>If you intend to use a VGA graphics mode, you must compile the kernel with support for framebuffer devices. The <i>ask</i> setting brings up a prompt at boot time."));
+ vga->insertItem(_("default"));
+ vga->insertItem(_("ask"));
+ vga->insertItem(_("text 80x25 (0)"));
+ vga->insertItem(_("text 80x50 (1)"));
+ vga->insertItem(_("text 80x43 (2)"));
+ vga->insertItem(_("text 80x28 (3)"));
+ vga->insertItem(_("text 80x30 (4)"));
+ vga->insertItem(_("text 80x34 (5)"));
+ vga->insertItem(_("text 80x60 (6)"));
+ vga->insertItem(_("text 40x25 (7)"));
+ vga->insertItem(_("VGA 640x480, 256 colors (769)"));
+ vga->insertItem(_("VGA 640x480, 32767 colors (784)"));
+ vga->insertItem(_("VGA 640x480, 65536 colors (785)"));
+ vga->insertItem(_("VGA 640x480, 16.7M colors (786)"));
+ vga->insertItem(_("VGA 800x600, 256 colors (771)"));
+ vga->insertItem(_("VGA 800x600, 32767 colors (787)"));
+ vga->insertItem(_("VGA 800x600, 65536 colors (788)"));
+ vga->insertItem(_("VGA 800x600, 16.7M colors (789)"));
+ vga->insertItem(_("VGA 1024x768, 256 colors (773)"));
+ vga->insertItem(_("VGA 1024x768, 32767 colors (790)"));
+ vga->insertItem(_("VGA 1024x768, 65536 colors (791)"));
+ vga->insertItem(_("VGA 1024x768, 16.7M colors (792)"));
+ vga->insertItem(_("VGA 1280x1024, 256 colors (775)"));
+ vga->insertItem(_("VGA 1280x1024, 32767 colors (793)"));
+ vga->insertItem(_("VGA 1280x1024, 65536 colors (794)"));
+ vga->insertItem(_("VGA 1280x1024, 16.7M colors (795)"));
+ layout->addWidget(vgab);
+
+ readonly=new QCheckBox(_("Mount root filesystem &read-only"), this);
+ QWhatsThis::add(readonly, _("Mount the root filesystem for this kernel read-only. Since the init scripts normally take care of remounting the root filesystem in read-write mode after running some checks, this should always be turned on.<br>Don't turn this off unless you know what you're doing."));
+ layout->addWidget(readonly);
+
+ unsafe=new QCheckBox(_("Do not check &partition table"), this);
+ QWhatsThis::add(unsafe, _("This turns off some sanity checks while writing the configuration. This shouldn't be used under \"normal\" circumstances, but it's useful, for example, for installing the possibility to boot from a floppy disk without having a floppy in the drive every time you run lilo.<br>This sets the <i>unsafe</i> keyword in lilo.conf."));
+ layout->addWidget(unsafe);
+
+ QHBox *opts=new QHBox(this);
+ lock=new QCheckBox(_("&Record boot command lines for defaults"), opts);
+ QWhatsThis::add(lock, "<qt>"+_("Checking this box enables automatic recording of boot command lines as the default for the following bootups. This way, lilo \"locks\" on a choice until it is manually overridden.<br>This sets the <b>lock</b> option in lilo.conf"));
+ restricted=new QCheckBox(_("R&estrict parameters"), opts);
+ connect(restricted, SIGNAL(clicked()), SLOT(check_pw()));
+ QWhatsThis::add(restricted, _("If this box is checked, a password (entered below) is required only if any parameters are changed (i.e. the user can boot <i>linux</i>, but not <i>linux single</i> or <i>linux init=/bin/sh</i>).\nThis sets the <b>restricted</b> option in lilo.conf."));
+ layout->addWidget(opts);
+
+ QHBox *pw=new QHBox(this);
+ use_password=new QCheckBox(_("Require &password:"), pw);
+ connect(use_password, SIGNAL(clicked()), SLOT(check_pw()));
+ password=new QLineEdit(pw);
+ password->setMaxLength(15);
+ password->setEchoMode(QLineEdit::Password);
+ QWhatsThis::add(pw, _("Enter the password required for bootup (if any) here. If <i>restricted</i> above is checked, the password is required for additional parameters only.<br><b>WARNING:</b> The password is stored in clear text in /etc/lilo.conf. You'll want to make sure nobody untrusted can read this file. Also, you probably don't want to use your normal/root password here."));
+ layout->addWidget(pw);
+
+ QHBox *btns=new QHBox(this);
+ ok=new QPushButton(_("&OK"), btns);
+ cancel=new QPushButton(_("&Cancel"), btns);
+ layout->addWidget(btns);
+ connect(cancel, SIGNAL(clicked()), SLOT(reject()));
+ connect(ok, SIGNAL(clicked()), SLOT(accept()));
+
+ if(l) {
+ QString mode=l->get("vga", "").cstr();
+ if(mode.isEmpty())
+ vga->setCurrentItem(0);
+ else if(mode=="ask")
+ vga->setCurrentItem(1);
+ else
+ for(int i=0; i<vga->count(); i++) {
+ if(vga->text(i).contains("(" + mode + ")")) {
+ vga->setCurrentItem(i);
+ break;
+ }
+ }
+ readonly->setChecked(!l->grep("[ \t]*read-only[ \t]*").empty());
+ unsafe->setChecked(!l->grep("[ \t]*unsafe[ \t]*").empty());
+ lock->setChecked(!l->grep("[ \t]*lock[ \t]*").empty());
+ restricted->setChecked(!l->grep("[ \t]*restricted[ \t]*").empty());
+ password->setText(l->get("password").cstr());
+ }
+
+ check_pw();
+}
+void Details::check_pw()
+{
+ password->setEnabled(restricted->isChecked() || use_password->isChecked());
+}
+QString Details::vgaMode() const
+{
+ QString s=vga->currentText();
+ if(s=="default")
+ return "";
+ else if(s!="ask") {
+ s=s.mid(s.find('(')+1);
+ s=s.left(s.length()-1);
+ }
+ return s;
+}
diff --git a/lilo-config/qt/Details.h b/lilo-config/qt/Details.h
new file mode 100644
index 0000000..f189430
--- /dev/null
+++ b/lilo-config/qt/Details.h
@@ -0,0 +1,61 @@
+/* Details.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+#ifndef _DETAILS_H_
+#define _DETAILS_H_ 1
+#include <lilo.h>
+#include <qdialog.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+class Details:public QDialog
+{
+ Q_OBJECT
+public:
+ Details(liloimage *lilo, QWidget *parent=0, const char *name=0, WFlags f=0);
+ bool isReadOnly() const { return readonly->isChecked(); };
+ QString vgaMode() const;
+ bool isUnsafe() const { return unsafe->isChecked(); };
+ bool isLocked() const { return lock->isChecked(); };
+ bool isRestricted() const { return restricted->isChecked(); };
+ bool usePassword() const { return use_password->isChecked(); };
+ QString Password() const { return password->text(); };
+private slots:
+ void check_pw();
+private:
+ liloimage *l;
+ QCheckBox *readonly;
+ QComboBox *vga;
+ QCheckBox *unsafe;
+ QCheckBox *lock;
+ QCheckBox *restricted;
+ QCheckBox *use_password;
+ QLineEdit *password;
+ QPushButton *ok;
+ QPushButton *cancel;
+};
+#endif
diff --git a/lilo-config/qt/InputBox.cpp b/lilo-config/qt/InputBox.cpp
new file mode 100644
index 0000000..f95989b
--- /dev/null
+++ b/lilo-config/qt/InputBox.cpp
@@ -0,0 +1,56 @@
+/* InputBox.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include "InputBox.moc"
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qwhatsthis.h>
+#include <ui.h>
+
+InputBox::InputBox(entries e, QWidget *parent, const char *name, bool hasCancel, WFlags f):QDialog(parent, name, true, f)
+{
+ QVBoxLayout *layout=new QVBoxLayout(this);
+ layout->setMargin(SPACE_MARGIN);
+ layout->setSpacing(SPACE_INSIDE);
+ for(entries::iterator it=e.begin(); it!=e.end(); it++) {
+ EditWidget *ed=new EditWidget((*it).label, (*it).dflt, (*it).isFile, this);
+ QWhatsThis::add(ed, (*it).help);
+ layout->addWidget(ed);
+ edit.insert(edit.end(), ed);
+ }
+ if(hasCancel) {
+ QHBox *btns=new QHBox(this);
+ ok=new QPushButton(_("&OK"), btns);
+ cancel=new QPushButton(_("&Cancel"), btns);
+ layout->addWidget(btns);
+ connect(cancel, SIGNAL(clicked()), SLOT(reject()));
+ } else {
+ ok=new QPushButton(_("&OK"), this);
+ layout->addWidget(ok);
+ }
+ connect(ok, SIGNAL(clicked()), SLOT(accept()));
+}
diff --git a/lilo-config/qt/InputBox.h b/lilo-config/qt/InputBox.h
new file mode 100644
index 0000000..da2371b
--- /dev/null
+++ b/lilo-config/qt/InputBox.h
@@ -0,0 +1,49 @@
+/* InputBox.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef _INPUTBOX_H_
+#define _INPUTBOX_H_ 1
+#include <qdialog.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include "EditWidget.h"
+#include <list>
+class InputBox:public QDialog
+{
+ Q_OBJECT
+public:
+ typedef struct { QString label; QString dflt; bool isFile; QString help; } entry;
+ typedef std::list<entry> entries;
+ InputBox(entries e, QWidget *parent=0, const char *name=0, bool hasCancel=true, WFlags f=0);
+ QStringList const text() const { QStringList s; for(std::list<EditWidget*>::const_iterator it=edit.begin(); it!=edit.end(); it++) s << (*it)->text(); return s; };
+private:
+ std::list<EditWidget*> edit;
+ QPushButton *ok;
+ QPushButton *cancel;
+};
+#endif
diff --git a/lilo-config/qt/Makefile.am b/lilo-config/qt/Makefile.am
new file mode 100644
index 0000000..fa0fd6c
--- /dev/null
+++ b/lilo-config/qt/Makefile.am
@@ -0,0 +1,21 @@
+libwidgets.a: ../kde-qt-common/*.cpp ../kde-qt-common/*.h
+ rm -f ../kde-qt-common/.COMPILED_KDE
+ if ! test -e ../kde-qt-common/.COMPILED_QT; then \
+ perl -pi -e "s,^AM_CXXFLAGS.*,AM_CXXFLAGS = -UUSE_KDE," ../kde-qt-common/Makefile.am; \
+ perl -pi -e "s,libwidgets_la_LIBADD.*,libwidgets_la_LIBADD = -lqt ../common/libcommon.la," ../kde-qt-common/Makefile.am; \
+ make -C ../kde-qt-common clean; fi
+ make -C ../kde-qt-common
+ install -c -m755 ../kde-qt-common/.libs/libwidgets.a .
+ touch ../kde-qt-common/.COMPILED_QT
+
+INCLUDES= -I../common -I../kde-qt-common $(all_includes)
+
+bin_PROGRAMS = lilo-config
+
+lilo_config_SOURCES = standalone.cpp Details.cpp InputBox.cpp
+lilo_config_LDFLAGS = $(all_libraries)
+lilo_config_LDADD = $(LIB_QT) libwidgets.a
+lilo_config_METASOURCES = AUTO
+AM_CXXFLAGS = -UUSE_KDE
+
+KDE_OPTIONS = qtonly
diff --git a/lilo-config/qt/configure.in.in b/lilo-config/qt/configure.in.in
new file mode 100644
index 0000000..db37557
--- /dev/null
+++ b/lilo-config/qt/configure.in.in
@@ -0,0 +1,4 @@
+# There's no point in compiling the Qt-only frontend inside a KDE package...
+# Leaving it out, but there's not much of a point in removing the code (it still
+# has its uses), and it's quite short, so...
+DO_NOT_COMPILE="$DO_NOT_COMPILE qt"
diff --git a/lilo-config/qt/standalone.cpp b/lilo-config/qt/standalone.cpp
new file mode 100644
index 0000000..268ad21
--- /dev/null
+++ b/lilo-config/qt/standalone.cpp
@@ -0,0 +1,126 @@
+/* standalone.cpp
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#include <qapplication.h>
+#include <qobject.h>
+#include <qwhatsthis.h>
+#include <qwindowsstyle.h>
+#include <mainwidget.h>
+#include <ui.h>
+#include "standalone.moc"
+
+Standalone::Standalone(QWidget *parent, const char *name):QWidget(parent,name)
+{
+ m=new MainWidget(this);
+ connect(m, SIGNAL(configChanged()), SLOT(configChanged()));
+ actions=new QHButtonGroup(this);
+ _whatsthis=new QPushButton(_("&What's This?"), actions);
+ _whatsthis->setAccel(SHIFT+Key_F1);
+ QWhatsThis::add(_whatsthis, _("The <i>What's This?</i> button is part of this program's help system. Click on the What's This? button then on any widget in the window to get information (like this) on it."));
+ connect(_whatsthis, SIGNAL(clicked()), SLOT(whatsthis()));
+ _help=new QPushButton(_("&Help"), actions);
+ _help->setAccel(Key_F1);
+ QWhatsThis::add(_help, _("This button calls up the program's online help system. If it does nothing, no help file has been written (yet); in that case, use the <i>What's This</i> button on the left."));
+ connect(_help, SIGNAL(clicked()), this, SLOT(help()));
+ _deflt=new QPushButton(_("&Default"), actions);
+ QWhatsThis::add(_deflt, _("This button resets all parameters to some (hopefully sane) default values."));
+ connect(_deflt, SIGNAL(clicked()), this, SLOT(defaults()));
+ _reset=new QPushButton(_("&Reset"), actions);
+ QWhatsThis::add(_reset, _("This button resets all parameters to what they were before you started the program."));
+ connect(_reset, SIGNAL(clicked()), this, SLOT(reset()));
+ _apply=new QPushButton(_("&Apply"), actions);
+ QWhatsThis::add(_apply, _("This button saves all your changes without exiting."));
+ connect(_apply, SIGNAL(clicked()), this, SLOT(apply()));
+ _ok=new QPushButton(_("&OK"), actions);
+ QWhatsThis::add(_ok, _("This button saves all your changes and exits the program."));
+ connect(_ok, SIGNAL(clicked()), this, SLOT(ok()));
+ _cancel=new QPushButton(_("&Cancel"), actions);
+ QWhatsThis::add(_cancel, _("This button exits the program without saving your changes."));
+ connect(_cancel, SIGNAL(clicked()), this, SLOT(cancel()));
+ _apply->setEnabled(false);
+ setMinimumWidth(actions->sizeHint().width()+10);
+ arrangeWidgets();
+}
+
+void Standalone::arrangeWidgets()
+{
+ m->setGeometry(SPACE_MARGIN, SPACE_MARGIN, width()-2*SPACE_MARGIN, height()-actions->sizeHint().height()-SPACE_MARGIN-SPACE_INSIDE);
+ actions->setGeometry(SPACE_MARGIN, height()-actions->sizeHint().height()-SPACE_MARGIN, width()-2*SPACE_MARGIN, actions->sizeHint().height());
+}
+
+void Standalone::resizeEvent(QResizeEvent *e)
+{
+ QWidget::resizeEvent(e);
+ arrangeWidgets();
+}
+
+void Standalone::whatsthis()
+{
+ QWhatsThis::enterWhatsThisMode();
+}
+void Standalone::help()
+{
+}
+void Standalone::defaults()
+{
+ m->defaults();
+}
+void Standalone::reset()
+{
+ m->reset();
+}
+void Standalone::apply()
+{
+ m->save();
+}
+void Standalone::ok()
+{
+ m->save();
+ emit done();
+}
+void Standalone::cancel()
+{
+ emit done();
+}
+
+void Standalone::configChanged() // SLOT
+{
+ _apply->setEnabled(true);
+}
+
+int main(int argc, char **argv) {
+ QApplication a(argc, argv);
+ Standalone *s=new Standalone(0);
+ int ret;
+ a.setStyle(new QWindowsStyle());
+ a.setMainWidget(s);
+ QObject::connect(s, SIGNAL(done()), &a, SLOT(quit()));
+ s->show();
+ ret=a.exec();
+ delete s;
+ return ret;
+}
diff --git a/lilo-config/qt/standalone.h b/lilo-config/qt/standalone.h
new file mode 100644
index 0000000..8b0fa16
--- /dev/null
+++ b/lilo-config/qt/standalone.h
@@ -0,0 +1,64 @@
+/* standalone.h
+**
+** Copyright (C) 2000,2001 by Bernhard Rosenkraenzer
+**
+*/
+
+/*
+** This program is free software; you can redistribute it and/or modify
+** it under 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.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program in a file called COPYING; if not, write to
+** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+** MA 02110-1301, USA.
+*/
+
+/*
+** Bug reports and questions can be sent to kde-devel@kde.org
+*/
+
+#ifndef _STANDALONE_H_
+#define _STANDALONE_H_ 1
+#include <qwidget.h>
+#include <qpushbutton.h>
+#include <qhbuttongroup.h>
+#include <qevent.h>
+#include "mainwidget.h"
+class Standalone: public QWidget
+{
+ Q_OBJECT
+public:
+ Standalone(QWidget *parent=0, const char *name=0);
+ void resizeEvent(QResizeEvent *e);
+public slots:
+ void whatsthis();
+ void help();
+ void defaults();
+ void reset();
+ void apply();
+ void ok();
+ void cancel();
+ void configChanged();
+signals:
+ void done();
+private:
+ void arrangeWidgets();
+ MainWidget *m;
+ QHButtonGroup *actions;
+ QPushButton *_whatsthis;
+ QPushButton *_help;
+ QPushButton *_deflt;
+ QPushButton *_reset;
+ QPushButton *_apply;
+ QPushButton *_ok;
+ QPushButton *_cancel;
+};
+#endif
diff --git a/secpolicy/Makefile.am b/secpolicy/Makefile.am
new file mode 100644
index 0000000..0d221bc
--- /dev/null
+++ b/secpolicy/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES= $(all_includes)
+METASOURCES = AUTO
+
+bin_PROGRAMS = secpolicy
+secpolicy_SOURCES = main.cpp secpolicywin.cpp pamview.cpp ppitem.cpp
+secpolicy_LDADD = $(LIB_KIO)
+secpolicy_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+noinst_HEADERS = secpolicywin.h pamview.h ppitem.h
+
+EXTRA_DIST =
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/secpolicy.pot
diff --git a/secpolicy/main.cpp b/secpolicy/main.cpp
new file mode 100644
index 0000000..6060405
--- /dev/null
+++ b/secpolicy/main.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1999 by Preston Brown <pbrown@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <kuniqueapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <stdlib.h>
+
+#include "secpolicywin.h"
+
+static const char description[] =
+ I18N_NOOP("Display PAM security policies");
+
+static const char version[] = "v0.0.1";
+
+
+int main(int argc, char **argv)
+{
+ KCmdLineArgs::init(argc, argv, "secpolicy", description, version);
+
+ if (!KUniqueApplication::start())
+ exit(0);
+
+ KUniqueApplication app;
+ SecPolicyWin *spWin = new SecPolicyWin();
+
+ app.setMainWidget(spWin);
+ return app.exec();
+}
diff --git a/secpolicy/pamview.cpp b/secpolicy/pamview.cpp
new file mode 100644
index 0000000..f16ac4d
--- /dev/null
+++ b/secpolicy/pamview.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1999 by Preston Brown <pbrown@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <qlayout.h>
+#include <qlistbox.h>
+#include <qlistview.h>
+#include <qlabel.h>
+#include <qdir.h>
+#include <qtextstream.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "ppitem.h"
+#include "pamview.h"
+
+#include <stdlib.h>
+
+PamView::PamView(QWidget *parent, const char *name)
+ : QWidget(parent, name)
+{
+ QHBoxLayout *topl = new QHBoxLayout(this);
+
+ QVBoxLayout *leftl = new QVBoxLayout;
+ topl->addLayout(leftl);
+
+ QLabel *label = new QLabel(i18n("Available services:"), this);
+ leftl->addWidget(label);
+
+ servicesLB = new QListBox(this);
+ leftl->addWidget(servicesLB);
+
+ propertiesLV = new QListView(this);
+ propertiesLV->addColumn(i18n("Category"));
+ propertiesLV->addColumn(i18n("Level"));
+ propertiesLV->addColumn(i18n("Module"));
+ topl->addWidget(propertiesLV);
+
+ init();
+}
+
+PamView::~PamView()
+{
+}
+
+void PamView::init()
+{
+ initServices();
+}
+
+void PamView::initServices()
+{
+
+ QDir d("/etc/pam.d");
+ d.setFilter(QDir::Files|QDir::Readable);
+
+ if (!d.exists()) {
+ KMessageBox::error(this, i18n("/etc/pam.d folder does not exist.\n"
+ "Either your system does not have PAM support "
+ "or there is some other configuration problem."));
+ exit(1);
+ }
+
+ const QFileInfoList *list = d.entryInfoList();
+ QFileInfoListIterator it(*list);
+ QFileInfo *fi;
+ while ((fi = it.current()) != 0) {
+ servicesLB->insertItem(fi->fileName());
+ QFile f(fi->filePath());
+ if (f.open(IO_ReadOnly)) {
+ QTextStream t(&f);
+ QString s;
+ while (!t.eof()) {
+ s = t.readLine().stripWhiteSpace();
+ if (s.isEmpty() || (s[0] == '#'))
+ continue;
+
+ PamPropertiesItem *item = new PamPropertiesItem(fi->filePath(),
+ QStringList::split(QRegExp("\\s"), s),
+ propertiesLV);
+ propertiesLV->insertItem(item);
+ }
+ f.close();
+ }
+ ++it;
+ }
+}
+
+#include "pamview.moc"
diff --git a/secpolicy/pamview.h b/secpolicy/pamview.h
new file mode 100644
index 0000000..ea41634
--- /dev/null
+++ b/secpolicy/pamview.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1999 by Preston Brown <pbrown@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PAMVIEW_H
+#define _PAMVIEW_H
+
+#include <qwidget.h>
+
+class QListBox;
+class QListView;
+
+class PamView : public QWidget
+{
+ Q_OBJECT
+public:
+ PamView(QWidget *parent = 0, const char *name = 0);
+ virtual ~PamView();
+
+protected:
+ void init();
+ void initServices();
+
+private:
+ QListBox *servicesLB;
+ QListView *propertiesLV;
+};
+
+#endif
diff --git a/secpolicy/ppitem.cpp b/secpolicy/ppitem.cpp
new file mode 100644
index 0000000..05fb358
--- /dev/null
+++ b/secpolicy/ppitem.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1999 by Preston Brown <pbrown@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <qstringlist.h>
+#include "ppitem.h"
+
+PamPropertiesItem::PamPropertiesItem(QString fileName,
+ QStringList properties,
+ QListView *parent)
+ : QListViewItem(parent)
+{
+ int i = properties.count();
+ if (i > 0)
+ category = properties[0];
+ if (i > 1)
+ level = properties[1];
+ if (i > 2)
+ lib = properties[2];
+
+ setText(0, category);
+ setText(1, level);
+ setText(2, lib);
+}
diff --git a/secpolicy/ppitem.h b/secpolicy/ppitem.h
new file mode 100644
index 0000000..591d729
--- /dev/null
+++ b/secpolicy/ppitem.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1999 by Preston Brown <pbrown@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PPITEM_H
+#define _PPITEM_H
+
+#include <qlistview.h>
+
+class PamPropertiesItem : public QListViewItem
+{
+ public:
+ PamPropertiesItem(QString fileName, QStringList properties,
+ QListView *parent);
+
+ private:
+ QString category, level, lib;
+};
+
+#endif
diff --git a/secpolicy/secpolicywin.cpp b/secpolicy/secpolicywin.cpp
new file mode 100644
index 0000000..64a454d
--- /dev/null
+++ b/secpolicy/secpolicywin.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1999 by Preston Brown <pbrown@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kmenubar.h>
+#include <kdialog.h>
+#include <dcopclient.h>
+#include <qpopupmenu.h>
+#include <kstdaccel.h>
+
+#include "pamview.h"
+#include "secpolicywin.h"
+
+SecPolicyWin::SecPolicyWin(const char *name)
+ : KMainWindow(0,name)
+{
+ view = new PamView(this);
+ setCentralWidget(view);
+
+ KMenuBar *mBar = menuBar();
+ QPopupMenu *fileMenu = new QPopupMenu(this);
+ fileMenu->insertItem(i18n("&Quit"), kapp, SLOT(closeAllWindows()), KStdAccel::shortcut(KStdAccel::Quit));
+ mBar->insertItem(i18n("&File"), fileMenu);
+
+ connect(kapp, SIGNAL(lastWindowClosed()), kapp, SLOT(quit()));
+
+ adjustSize();
+ // work around KTMainWindow sizing bug.
+ resize(sizeHint().width(), sizeHint().height() + mBar->height() +
+ KDialog::marginHint());
+ show();
+}
+
+SecPolicyWin::~SecPolicyWin()
+{
+}
+
+void SecPolicyWin::closeEvent(QCloseEvent *e)
+{
+ e->accept();
+}
diff --git a/secpolicy/secpolicywin.h b/secpolicy/secpolicywin.h
new file mode 100644
index 0000000..a58b8a6
--- /dev/null
+++ b/secpolicy/secpolicywin.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1999 by Preston Brown <pbrown@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _SECPOLICYWIN_H
+#define _SECPOLICYWIN_H
+
+#include <kmainwindow.h>
+
+class PamView;
+
+class SecPolicyWin : public KMainWindow
+{
+public:
+ SecPolicyWin(const char *name = 0);
+ ~SecPolicyWin();
+
+protected:
+ virtual void closeEvent(QCloseEvent *);
+
+private:
+ PamView *view;
+};
+
+#endif