summaryrefslogtreecommitdiff
path: root/kdecore
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
committerChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
commit43d35cfb36c924eede624f4a5c2fcb0dd7d698b6 (patch)
treeb7ac13bcf009d94cabb4c5afeee0825a4ce9da67 /kdecore
parentbf385f44f99d73263b1787daac7423599e69f024 (diff)
downloadlibcalendaring-43d35cfb36c924eede624f4a5c2fcb0dd7d698b6.tar.gz
kdecore import
commit 557c1267cbb5e352e1487c3dd468cd4a4cb63254 Merge: aed99b0 387e3c3 Author: David Faure <faure@kde.org> Date: Thu Jun 14 17:56:59 2012 +0200 Merge remote-tracking branch 'origin/KDE/4.8'
Diffstat (limited to 'kdecore')
-rw-r--r--kdecore/CMakeLists.txt679
-rw-r--r--kdecore/MAINTAINERS213
-rw-r--r--kdecore/Mainpage.dox45
-rw-r--r--kdecore/README4
-rw-r--r--kdecore/auth/AuthBackend.cpp70
-rw-r--r--kdecore/auth/AuthBackend.h74
-rw-r--r--kdecore/auth/BackendsConfig.h.cmake9
-rw-r--r--kdecore/auth/BackendsManager.cpp138
-rw-r--r--kdecore/auth/BackendsManager.h48
-rw-r--r--kdecore/auth/ConfigureChecks.cmake233
-rw-r--r--kdecore/auth/HelperProxy.cpp28
-rw-r--r--kdecore/auth/HelperProxy.h67
-rw-r--r--kdecore/auth/TODO6
-rw-r--r--kdecore/auth/backends/dbus/DBusHelperProxy.cpp405
-rw-r--r--kdecore/auth/backends/dbus/DBusHelperProxy.h80
-rw-r--r--kdecore/auth/backends/dbus/dbus_policy.stub11
-rw-r--r--kdecore/auth/backends/dbus/dbus_service.stub4
-rw-r--r--kdecore/auth/backends/dbus/org.kde.auth.conf13
-rw-r--r--kdecore/auth/backends/dbus/org.kde.auth.xml30
-rw-r--r--kdecore/auth/backends/fake/FakeBackend.cpp60
-rw-r--r--kdecore/auth/backends/fake/FakeBackend.h47
-rw-r--r--kdecore/auth/backends/fake/kauth-policy-gen-polkit.cpp77
-rw-r--r--kdecore/auth/backends/fakehelper/FakeHelperProxy.cpp97
-rw-r--r--kdecore/auth/backends/fakehelper/FakeHelperProxy.h50
-rw-r--r--kdecore/auth/backends/mac/AuthServicesBackend.cpp137
-rw-r--r--kdecore/auth/backends/mac/AuthServicesBackend.h46
-rw-r--r--kdecore/auth/backends/mac/kauth-policy-gen-mac.cpp61
-rw-r--r--kdecore/auth/backends/policykit/PolicyKitBackend.cpp104
-rw-r--r--kdecore/auth/backends/policykit/PolicyKitBackend.h54
-rw-r--r--kdecore/auth/backends/policykit/kauth-policy-gen-polkit.cpp119
-rw-r--r--kdecore/auth/backends/polkit-1/Polkit1Backend.cpp229
-rw-r--r--kdecore/auth/backends/polkit-1/Polkit1Backend.h82
-rw-r--r--kdecore/auth/backends/polkit-1/kauth-policy-gen-polkit1.cpp122
-rw-r--r--kdecore/auth/kauth.h29
-rw-r--r--kdecore/auth/kauthaction.cpp387
-rw-r--r--kdecore/auth/kauthaction.h506
-rw-r--r--kdecore/auth/kauthactionreply.cpp190
-rw-r--r--kdecore/auth/kauthactionreply.h608
-rw-r--r--kdecore/auth/kauthactionwatcher.cpp118
-rw-r--r--kdecore/auth/kauthactionwatcher.h154
-rw-r--r--kdecore/auth/kauthhelpersupport.cpp112
-rw-r--r--kdecore/auth/kauthhelpersupport.h106
-rw-r--r--kdecore/auth/policy-gen/policy-gen.cpp155
-rw-r--r--kdecore/auth/policy-gen/policy-gen.h42
-rw-r--r--kdecore/compression/ConfigureChecks.cmake12
-rw-r--r--kdecore/compression/config-compression.h.cmake8
-rw-r--r--kdecore/compression/karchive_export.h55
-rw-r--r--kdecore/compression/kbzip2filter.cpp195
-rw-r--r--kdecore/compression/kbzip2filter.h58
-rw-r--r--kdecore/compression/kfilterbase.cpp168
-rw-r--r--kdecore/compression/kfilterbase.h133
-rw-r--r--kdecore/compression/kfilterdev.cpp366
-rw-r--r--kdecore/compression/kfilterdev.h153
-rw-r--r--kdecore/compression/kgzipfilter.cpp385
-rw-r--r--kdecore/compression/kgzipfilter.h73
-rw-r--r--kdecore/compression/kxzfilter.cpp174
-rw-r--r--kdecore/compression/kxzfilter.h61
-rw-r--r--kdecore/config-kstandarddirs.h.cmake2
-rw-r--r--kdecore/config/DESIGN106
-rw-r--r--kdecore/config/TODO216
-rw-r--r--kdecore/config/bufferfragment_p.h181
-rw-r--r--kdecore/config/conversion_check.h120
-rw-r--r--kdecore/config/kconfig.cpp888
-rw-r--r--kdecore/config/kconfig.h412
-rw-r--r--kdecore/config/kconfig_p.h116
-rw-r--r--kdecore/config/kconfigbackend.cpp131
-rw-r--r--kdecore/config/kconfigbackend.desktop85
-rw-r--r--kdecore/config/kconfigbackend.h223
-rw-r--r--kdecore/config/kconfigbase.cpp112
-rw-r--r--kdecore/config/kconfigbase.h184
-rw-r--r--kdecore/config/kconfigbase_p.h30
-rw-r--r--kdecore/config/kconfigdata.h473
-rw-r--r--kdecore/config/kconfiggroup.cpp1251
-rw-r--r--kdecore/config/kconfiggroup.h769
-rw-r--r--kdecore/config/kconfiggroup_p.h42
-rw-r--r--kdecore/config/kconfigini.cpp752
-rw-r--r--kdecore/config/kconfigini_p.h79
-rw-r--r--kdecore/config/kcoreconfigskeleton.cpp1322
-rw-r--r--kdecore/config/kcoreconfigskeleton.h1418
-rw-r--r--kdecore/config/kcoreconfigskeleton_p.h64
-rw-r--r--kdecore/config/kdesktopfile.cpp402
-rw-r--r--kdecore/config/kdesktopfile.h258
-rw-r--r--kdecore/config/ksharedconfig.cpp86
-rw-r--r--kdecore/config/ksharedconfig.h112
-rw-r--r--kdecore/date/ConfigureChecks.cmake5
-rw-r--r--kdecore/date/Messages.sh2
-rw-r--r--kdecore/date/config-date.h.cmake9
-rw-r--r--kdecore/date/kcalendarera.cpp91
-rw-r--r--kdecore/date/kcalendarera_p.h77
-rw-r--r--kdecore/date/kcalendarsystem.cpp2506
-rw-r--r--kdecore/date/kcalendarsystem.h1693
-rw-r--r--kdecore/date/kcalendarsystemcoptic.cpp570
-rw-r--r--kdecore/date/kcalendarsystemcoptic_p.h78
-rw-r--r--kdecore/date/kcalendarsystemcopticprivate_p.h50
-rw-r--r--kdecore/date/kcalendarsystemethiopian.cpp418
-rw-r--r--kdecore/date/kcalendarsystemethiopian_p.h80
-rw-r--r--kdecore/date/kcalendarsystemgregorian.cpp566
-rw-r--r--kdecore/date/kcalendarsystemgregorian_p.h87
-rw-r--r--kdecore/date/kcalendarsystemgregorianprivate_p.h54
-rw-r--r--kdecore/date/kcalendarsystemhebrew.cpp1051
-rw-r--r--kdecore/date/kcalendarsystemhebrew_p.h87
-rw-r--r--kdecore/date/kcalendarsystemindiannational.cpp549
-rw-r--r--kdecore/date/kcalendarsystemindiannational_p.h83
-rw-r--r--kdecore/date/kcalendarsystemislamiccivil.cpp596
-rw-r--r--kdecore/date/kcalendarsystemislamiccivil_p.h85
-rw-r--r--kdecore/date/kcalendarsystemjalali.cpp626
-rw-r--r--kdecore/date/kcalendarsystemjalali_p.h74
-rw-r--r--kdecore/date/kcalendarsystemjapanese.cpp234
-rw-r--r--kdecore/date/kcalendarsystemjapanese_p.h82
-rw-r--r--kdecore/date/kcalendarsystemjulian.cpp569
-rw-r--r--kdecore/date/kcalendarsystemjulian_p.h83
-rw-r--r--kdecore/date/kcalendarsystemminguo.cpp200
-rw-r--r--kdecore/date/kcalendarsystemminguo_p.h80
-rw-r--r--kdecore/date/kcalendarsystemprivate_p.h111
-rw-r--r--kdecore/date/kcalendarsystemqdate.cpp561
-rw-r--r--kdecore/date/kcalendarsystemqdate_p.h93
-rw-r--r--kdecore/date/kcalendarsystemthai.cpp186
-rw-r--r--kdecore/date/kcalendarsystemthai_p.h74
-rw-r--r--kdecore/date/kdatetime.cpp3077
-rw-r--r--kdecore/date/kdatetime.h1641
-rw-r--r--kdecore/date/kdatetimeformatter.cpp795
-rw-r--r--kdecore/date/kdatetimeformatter_p.h98
-rw-r--r--kdecore/date/kdatetimeparser.cpp403
-rw-r--r--kdecore/date/kdatetimeparser_p.h80
-rw-r--r--kdecore/date/kdayperiod.cpp206
-rw-r--r--kdecore/date/kdayperiod_p.h175
-rw-r--r--kdecore/date/klocalizeddate.cpp616
-rw-r--r--kdecore/date/klocalizeddate.h1189
-rw-r--r--kdecore/date/ksystemtimezone.cpp892
-rw-r--r--kdecore/date/ksystemtimezone.h536
-rw-r--r--kdecore/date/ktimezone.cpp1392
-rw-r--r--kdecore/date/ktimezone.h1532
-rw-r--r--kdecore/date/ktimezone_win.cpp691
-rw-r--r--kdecore/date/ktimezone_win.h102
-rw-r--r--kdecore/date/ktzfiletimezone.cpp407
-rw-r--r--kdecore/date/ktzfiletimezone.h218
-rw-r--r--kdecore/doc/DESIGN.COLOR141
-rw-r--r--kdecore/doc/DESIGN.iconloading187
-rw-r--r--kdecore/doc/DESIGN.kconfig224
-rw-r--r--kdecore/doc/README.kiosk817
-rw-r--r--kdecore/doc/README.kstartupinfo279
-rw-r--r--kdecore/fakes.c667
-rw-r--r--kdecore/io/config-kdirwatch.h.cmake3
-rw-r--r--kdecore/io/kar.cpp183
-rw-r--r--kdecore/io/kar.h93
-rw-r--r--kdecore/io/karchive.cpp848
-rw-r--r--kdecore/io/karchive.h602
-rw-r--r--kdecore/io/kautosavefile.cpp234
-rw-r--r--kdecore/io/kautosavefile.h248
-rw-r--r--kdecore/io/kdebug.cpp924
-rw-r--r--kdecore/io/kdebug.h403
-rw-r--r--kdecore/io/kdebugdbusiface.cpp46
-rw-r--r--kdecore/io/kdebugdbusiface_p.h52
-rw-r--r--kdecore/io/kdirwatch.cpp1908
-rw-r--r--kdecore/io/kdirwatch.h309
-rw-r--r--kdecore/io/kdirwatch_p.h273
-rw-r--r--kdecore/io/kdirwatch_win.cpp77
-rw-r--r--kdecore/io/kfilesystemtype_p.cpp132
-rw-r--r--kdecore/io/kfilesystemtype_p.h40
-rw-r--r--kdecore/io/klimitediodevice.cpp80
-rw-r--r--kdecore/io/klimitediodevice_p.h64
-rw-r--r--kdecore/io/klockfile.h130
-rw-r--r--kdecore/io/klockfile_unix.cpp502
-rw-r--r--kdecore/io/klockfile_win.cpp147
-rw-r--r--kdecore/io/kmessage.cpp105
-rw-r--r--kdecore/io/kmessage.h129
-rw-r--r--kdecore/io/kmountpoint.cpp543
-rw-r--r--kdecore/io/kmountpoint.h162
-rw-r--r--kdecore/io/kprocess.cpp410
-rw-r--r--kdecore/io/kprocess.h341
-rw-r--r--kdecore/io/kprocess_p.h48
-rw-r--r--kdecore/io/ksavefile.cpp412
-rw-r--r--kdecore/io/ksavefile.h277
-rw-r--r--kdecore/io/ktar.cpp862
-rw-r--r--kdecore/io/ktar.h109
-rw-r--r--kdecore/io/ktempdir.cpp290
-rw-r--r--kdecore/io/ktempdir.h166
-rw-r--r--kdecore/io/ktemporaryfile.cpp78
-rw-r--r--kdecore/io/ktemporaryfile.h139
-rw-r--r--kdecore/io/kurl.cpp1917
-rw-r--r--kdecore/io/kurl.h1190
-rw-r--r--kdecore/io/kzip.cpp1382
-rw-r--r--kdecore/io/kzip.h223
-rw-r--r--kdecore/jobs/kcompositejob.cpp115
-rw-r--r--kdecore/jobs/kcompositejob.h114
-rw-r--r--kdecore/jobs/kcompositejob_p.h41
-rw-r--r--kdecore/jobs/kjob.cpp370
-rw-r--r--kdecore/jobs/kjob.h638
-rw-r--r--kdecore/jobs/kjob_p.h65
-rw-r--r--kdecore/jobs/kjobtrackerinterface.cpp150
-rw-r--r--kdecore/jobs/kjobtrackerinterface.h167
-rw-r--r--kdecore/jobs/kjobuidelegate.cpp120
-rw-r--r--kdecore/jobs/kjobuidelegate.h138
-rw-r--r--kdecore/kconfig_compiler/CMakeLists.txt31
-rw-r--r--kdecore/kconfig_compiler/README.dox446
-rw-r--r--kdecore/kconfig_compiler/TODO0
-rwxr-xr-xkdecore/kconfig_compiler/checkkcfg.pl83
-rw-r--r--kdecore/kconfig_compiler/kcfg.xsd234
-rw-r--r--kdecore/kconfig_compiler/kconfig_compiler.cpp2298
-rw-r--r--kdecore/kde-config.cpp268
-rw-r--r--kdecore/kdebug.areas753
-rw-r--r--kdecore/kdebugrc297
-rw-r--r--kdecore/kdecore.kdev43
-rw-r--r--kdecore/kdecore.pc.in12
-rw-r--r--kdecore/kdecore_export.h43
-rw-r--r--kdecore/kdefakes.h.cmake197
-rw-r--r--kdecore/kernel/kaboutdata.cpp950
-rw-r--r--kdecore/kernel/kaboutdata.h980
-rw-r--r--kdecore/kernel/kauthorized.cpp380
-rw-r--r--kdecore/kernel/kauthorized.h95
-rw-r--r--kdecore/kernel/kcmdlineargs.cpp1618
-rw-r--r--kdecore/kernel/kcmdlineargs.h692
-rw-r--r--kdecore/kernel/kcomponentdata.cpp239
-rw-r--r--kdecore/kernel/kcomponentdata.h192
-rw-r--r--kdecore/kernel/kcomponentdata_p.h99
-rw-r--r--kdecore/kernel/kglobal.cpp356
-rw-r--r--kdecore/kernel/kglobal.h580
-rw-r--r--kdecore/kernel/kglobal_p.h61
-rw-r--r--kdecore/kernel/kkernel_mac.cpp213
-rw-r--r--kdecore/kernel/kkernel_mac.h61
-rw-r--r--kdecore/kernel/kkernel_win.cpp539
-rw-r--r--kdecore/kernel/kkernel_win.h67
-rw-r--r--kdecore/kernel/kstandarddirs.cpp2159
-rw-r--r--kdecore/kernel/kstandarddirs.h810
-rw-r--r--kdecore/kernel/kstandarddirs_unix.cpp106
-rw-r--r--kdecore/kernel/kstandarddirs_win.cpp113
-rw-r--r--kdecore/kernel/ktoolinvocation.cpp396
-rw-r--r--kdecore/kernel/ktoolinvocation.h398
-rw-r--r--kdecore/kernel/ktoolinvocation_win.cpp85
-rw-r--r--kdecore/kernel/ktoolinvocation_x11.cpp422
-rw-r--r--kdecore/localization/all_languages.desktop18096
-rw-r--r--kdecore/localization/common_helpers.cpp106
-rw-r--r--kdecore/localization/common_helpers_p.h46
-rw-r--r--kdecore/localization/config-localization.h.cmake1
-rw-r--r--kdecore/localization/entry.desktop62
-rw-r--r--kdecore/localization/gettext.h265
-rw-r--r--kdecore/localization/guess_ja.cpp376
-rw-r--r--kdecore/localization/guess_ja_p.h129
-rw-r--r--kdecore/localization/kcatalog.cpp287
-rw-r--r--kdecore/localization/kcatalog_p.h213
-rw-r--r--kdecore/localization/kcatalogname_p.h36
-rw-r--r--kdecore/localization/kcharsets.cpp802
-rw-r--r--kdecore/localization/kcharsets.h181
-rw-r--r--kdecore/localization/kcurrencycode.cpp303
-rw-r--r--kdecore/localization/kcurrencycode.h341
-rw-r--r--kdecore/localization/kencodingdetector.cpp1257
-rw-r--r--kdecore/localization/kencodingdetector.h219
-rw-r--r--kdecore/localization/kencodingprober.cpp323
-rw-r--r--kdecore/localization/kencodingprober.h168
-rw-r--r--kdecore/localization/kentities.c835
-rw-r--r--kdecore/localization/kentities.gperf315
-rw-r--r--kdecore/localization/klocale.cpp787
-rw-r--r--kdecore/localization/klocale.h2143
-rw-r--r--kdecore/localization/klocale_kde.cpp3144
-rw-r--r--kdecore/localization/klocale_mac.cpp94
-rw-r--r--kdecore/localization/klocale_mac_p.h60
-rw-r--r--kdecore/localization/klocale_p.h1230
-rw-r--r--kdecore/localization/klocale_unix.cpp49
-rw-r--r--kdecore/localization/klocale_unix_p.h40
-rw-r--r--kdecore/localization/klocale_win.cpp129
-rw-r--r--kdecore/localization/klocale_win_p.h70
-rw-r--r--kdecore/localization/klocalizedstring.cpp1026
-rw-r--r--kdecore/localization/klocalizedstring.h1277
-rw-r--r--kdecore/localization/ktranscript.cpp1778
-rw-r--r--kdecore/localization/ktranscript_p.h90
-rw-r--r--kdecore/localization/kuitformats.cpp74
-rw-r--r--kdecore/localization/kuitformats_p.h53
-rw-r--r--kdecore/localization/kuitsemantics.cpp1628
-rw-r--r--kdecore/localization/kuitsemantics_p.h90
-rw-r--r--kdecore/localization/probers/CharDistribution.cpp98
-rw-r--r--kdecore/localization/probers/CharDistribution.h226
-rw-r--r--kdecore/localization/probers/ChineseGroupProber.cpp195
-rw-r--r--kdecore/localization/probers/ChineseGroupProber.h58
-rw-r--r--kdecore/localization/probers/JapaneseGroupProber.cpp195
-rw-r--r--kdecore/localization/probers/JapaneseGroupProber.h60
-rw-r--r--kdecore/localization/probers/JpCntx.cpp219
-rw-r--r--kdecore/localization/probers/JpCntx.h126
-rw-r--r--kdecore/localization/probers/LangBulgarianModel.cpp235
-rw-r--r--kdecore/localization/probers/LangCyrillicModel.cpp346
-rw-r--r--kdecore/localization/probers/LangGreekModel.cpp236
-rw-r--r--kdecore/localization/probers/LangHebrewModel.cpp208
-rw-r--r--kdecore/localization/probers/LangHungarianModel.cpp234
-rw-r--r--kdecore/localization/probers/LangThaiModel.cpp213
-rw-r--r--kdecore/localization/probers/UnicodeGroupProber.cpp156
-rw-r--r--kdecore/localization/probers/UnicodeGroupProber.h58
-rw-r--r--kdecore/localization/probers/ctype_test_p.h99
-rw-r--r--kdecore/localization/probers/nsBig5Prober.cpp84
-rw-r--r--kdecore/localization/probers/nsBig5Prober.h59
-rw-r--r--kdecore/localization/probers/nsCharSetProber.cpp117
-rw-r--r--kdecore/localization/probers/nsCharSetProber.h65
-rw-r--r--kdecore/localization/probers/nsCodingStateMachine.h116
-rw-r--r--kdecore/localization/probers/nsEUCJPProber.cpp97
-rw-r--r--kdecore/localization/probers/nsEUCJPProber.h63
-rw-r--r--kdecore/localization/probers/nsEUCKRProber.cpp87
-rw-r--r--kdecore/localization/probers/nsEUCKRProber.h59
-rw-r--r--kdecore/localization/probers/nsEUCTWProber.cpp87
-rw-r--r--kdecore/localization/probers/nsEUCTWProber.h59
-rw-r--r--kdecore/localization/probers/nsEscCharsetProber.cpp97
-rw-r--r--kdecore/localization/probers/nsEscCharsetProber.h55
-rw-r--r--kdecore/localization/probers/nsEscSM.cpp255
-rw-r--r--kdecore/localization/probers/nsGB2312Prober.cpp94
-rw-r--r--kdecore/localization/probers/nsGB2312Prober.h61
-rw-r--r--kdecore/localization/probers/nsHebrewProber.cpp186
-rw-r--r--kdecore/localization/probers/nsHebrewProber.h165
-rw-r--r--kdecore/localization/probers/nsLatin1Prober.cpp171
-rw-r--r--kdecore/localization/probers/nsLatin1Prober.h57
-rw-r--r--kdecore/localization/probers/nsMBCSGroupProber.cpp201
-rw-r--r--kdecore/localization/probers/nsMBCSGroupProber.h64
-rw-r--r--kdecore/localization/probers/nsMBCSSM.cpp618
-rw-r--r--kdecore/localization/probers/nsPkgInt.h77
-rw-r--r--kdecore/localization/probers/nsSBCSGroupProber.cpp217
-rw-r--r--kdecore/localization/probers/nsSBCSGroupProber.h72
-rw-r--r--kdecore/localization/probers/nsSBCharSetProber.cpp119
-rw-r--r--kdecore/localization/probers/nsSBCharSetProber.h113
-rw-r--r--kdecore/localization/probers/nsSJISProber.cpp96
-rw-r--r--kdecore/localization/probers/nsSJISProber.h77
-rw-r--r--kdecore/localization/probers/nsUniversalDetector.cpp249
-rw-r--r--kdecore/localization/probers/nsUniversalDetector.h67
-rw-r--r--kdecore/localization/probers/tables/Big5Freq.tab931
-rw-r--r--kdecore/localization/probers/tables/EUCKRFreq.tab602
-rw-r--r--kdecore/localization/probers/tables/EUCTWFreq.tab435
-rw-r--r--kdecore/localization/probers/tables/GB2312Freq.tab479
-rw-r--r--kdecore/localization/probers/tables/JISFreq.tab577
-rw-r--r--kdecore/network/ConfigureChecks.cmake62
-rw-r--r--kdecore/network/TODO22
-rw-r--r--kdecore/network/config-network.h.cmake53
-rw-r--r--kdecore/network/ipv6blacklist3
-rw-r--r--kdecore/network/k3bufferedsocket.cpp390
-rw-r--r--kdecore/network/k3bufferedsocket.h214
-rw-r--r--kdecore/network/k3clientsocketbase.cpp458
-rw-r--r--kdecore/network/k3clientsocketbase.h497
-rw-r--r--kdecore/network/k3datagramsocket.cpp301
-rw-r--r--kdecore/network/k3datagramsocket.h280
-rw-r--r--kdecore/network/k3httpproxysocketdevice.cpp285
-rw-r--r--kdecore/network/k3httpproxysocketdevice.h123
-rw-r--r--kdecore/network/k3iobuffer.h143
-rw-r--r--kdecore/network/k3resolver.cpp1063
-rw-r--r--kdecore/network/k3resolver.h960
-rw-r--r--kdecore/network/k3resolver_p.h352
-rw-r--r--kdecore/network/k3resolvermanager.cpp831
-rw-r--r--kdecore/network/k3resolverstandardworkers.cpp1046
-rw-r--r--kdecore/network/k3resolverstandardworkers_p.h113
-rw-r--r--kdecore/network/k3resolverworkerbase.cpp152
-rw-r--r--kdecore/network/k3resolverworkerbase.h323
-rw-r--r--kdecore/network/k3reverseresolver.cpp266
-rw-r--r--kdecore/network/k3reverseresolver.h197
-rw-r--r--kdecore/network/k3serversocket.cpp420
-rw-r--r--kdecore/network/k3serversocket.h428
-rw-r--r--kdecore/network/k3socketaddress.cpp955
-rw-r--r--kdecore/network/k3socketaddress.h905
-rw-r--r--kdecore/network/k3socketbase.cpp456
-rw-r--r--kdecore/network/k3socketbase.h853
-rw-r--r--kdecore/network/k3socketbuffer.cpp326
-rw-r--r--kdecore/network/k3socketbuffer_p.h176
-rw-r--r--kdecore/network/k3socketdevice.cpp922
-rw-r--r--kdecore/network/k3socketdevice.h417
-rw-r--r--kdecore/network/k3socks.cpp623
-rw-r--r--kdecore/network/k3socks.h206
-rw-r--r--kdecore/network/k3sockssocketdevice.cpp486
-rw-r--r--kdecore/network/k3sockssocketdevice.h147
-rw-r--r--kdecore/network/k3streamsocket.cpp384
-rw-r--r--kdecore/network/k3streamsocket.h251
-rw-r--r--kdecore/network/klocalsocket.cpp225
-rw-r--r--kdecore/network/klocalsocket.h319
-rw-r--r--kdecore/network/klocalsocket_p.h76
-rw-r--r--kdecore/network/klocalsocket_unix.cpp405
-rw-r--r--kdecore/network/klocalsocket_win.cpp53
-rw-r--r--kdecore/network/ksocketfactory.cpp151
-rw-r--r--kdecore/network/ksocketfactory.h204
-rw-r--r--kdecore/network/ksslcertificatemanager.cpp533
-rw-r--r--kdecore/network/ksslcertificatemanager.h99
-rw-r--r--kdecore/network/ksslcertificatemanager_p.h101
-rw-r--r--kdecore/network/kssld/CMakeLists.txt20
-rw-r--r--kdecore/network/kssld/kssld.cpp284
-rw-r--r--kdecore/network/kssld/kssld.desktop131
-rw-r--r--kdecore/network/kssld/kssld.h54
-rw-r--r--kdecore/network/kssld/kssld_adaptor.h64
-rw-r--r--kdecore/network/kssld/kssld_dbusmetatypes.h112
-rw-r--r--kdecore/network/kssld/kssld_interface.h99
-rw-r--r--kdecore/network/ktcpsocket.cpp1146
-rw-r--r--kdecore/network/ktcpsocket.h425
-rw-r--r--kdecore/network/ktcpsocket_p.h40
-rw-r--r--kdecore/network/netsupp.cpp1247
-rw-r--r--kdecore/network/netsupp.h333
-rw-r--r--kdecore/network/syssocket.h114
-rw-r--r--kdecore/services/kfoldermimetype.cpp143
-rw-r--r--kdecore/services/kfoldermimetype.h49
-rw-r--r--kdecore/services/kmimeglobsfileparser.cpp225
-rw-r--r--kdecore/services/kmimeglobsfileparser_p.h106
-rw-r--r--kdecore/services/kmimemagicrule.cpp190
-rw-r--r--kdecore/services/kmimemagicrule_p.h72
-rw-r--r--kdecore/services/kmimetype.cpp758
-rw-r--r--kdecore/services/kmimetype.h469
-rw-r--r--kdecore/services/kmimetype_p.h75
-rw-r--r--kdecore/services/kmimetypefactory.cpp164
-rw-r--r--kdecore/services/kmimetypefactory.h101
-rw-r--r--kdecore/services/kmimetyperepository.cpp774
-rw-r--r--kdecore/services/kmimetyperepository_p.h179
-rw-r--r--kdecore/services/kmimetypetrader.cpp175
-rw-r--r--kdecore/services/kmimetypetrader.h194
-rw-r--r--kdecore/services/kplugininfo.cpp418
-rw-r--r--kdecore/services/kplugininfo.desktop131
-rw-r--r--kdecore/services/kplugininfo.h360
-rw-r--r--kdecore/services/kservice.cpp987
-rw-r--r--kdecore/services/kservice.h688
-rw-r--r--kdecore/services/kservice_p.h99
-rw-r--r--kdecore/services/kserviceaction.cpp127
-rw-r--r--kdecore/services/kserviceaction.h120
-rw-r--r--kdecore/services/kservicefactory.cpp314
-rw-r--r--kdecore/services/kservicefactory.h126
-rw-r--r--kdecore/services/kservicegroup.cpp764
-rw-r--r--kdecore/services/kservicegroup.h287
-rw-r--r--kdecore/services/kservicegroup_p.h99
-rw-r--r--kdecore/services/kservicegroupfactory.cpp135
-rw-r--r--kdecore/services/kservicegroupfactory.h80
-rw-r--r--kdecore/services/kserviceoffer.cpp128
-rw-r--r--kdecore/services/kserviceoffer.h137
-rw-r--r--kdecore/services/kservicetype.cpp256
-rw-r--r--kdecore/services/kservicetype.h189
-rw-r--r--kdecore/services/kservicetype_p.h79
-rw-r--r--kdecore/services/kservicetypefactory.cpp137
-rw-r--r--kdecore/services/kservicetypefactory.h94
-rw-r--r--kdecore/services/kservicetypeprofile.cpp241
-rw-r--r--kdecore/services/kservicetypeprofile.h93
-rw-r--r--kdecore/services/kservicetypeprofile_p.h54
-rw-r--r--kdecore/services/kservicetypetrader.cpp173
-rw-r--r--kdecore/services/kservicetypetrader.h239
-rw-r--r--kdecore/services/ktraderparse.cpp179
-rw-r--r--kdecore/services/ktraderparse_p.h56
-rw-r--r--kdecore/services/ktraderparsetree.cpp704
-rw-r--r--kdecore/services/ktraderparsetree_p.h355
-rw-r--r--kdecore/services/lex.c2270
-rw-r--r--kdecore/services/lex.l168
-rw-r--r--kdecore/services/regen.sh9
-rw-r--r--kdecore/services/yacc.c2029
-rw-r--r--kdecore/services/yacc.h96
-rw-r--r--kdecore/services/yacc.y162
-rw-r--r--kdecore/sonnet/backgroundchecker.cpp171
-rw-r--r--kdecore/sonnet/backgroundchecker.h133
-rw-r--r--kdecore/sonnet/backgroundengine.cpp119
-rw-r--r--kdecore/sonnet/backgroundengine_p.h81
-rw-r--r--kdecore/sonnet/client.cpp33
-rw-r--r--kdecore/sonnet/client_p.h78
-rw-r--r--kdecore/sonnet/filter.cpp312
-rw-r--r--kdecore/sonnet/filter_p.h120
-rw-r--r--kdecore/sonnet/globals.cpp98
-rw-r--r--kdecore/sonnet/globals.h49
-rw-r--r--kdecore/sonnet/loader.cpp303
-rw-r--r--kdecore/sonnet/loader_p.h126
-rw-r--r--kdecore/sonnet/settings.cpp265
-rw-r--r--kdecore/sonnet/settings_p.h87
-rw-r--r--kdecore/sonnet/sonnetspeller.desktop88
-rw-r--r--kdecore/sonnet/speller.cpp302
-rw-r--r--kdecore/sonnet/speller.h153
-rw-r--r--kdecore/sonnet/spellerplugin.cpp62
-rw-r--r--kdecore/sonnet/spellerplugin_p.h101
-rw-r--r--kdecore/sonnet/tests/CMakeLists.txt27
-rw-r--r--kdecore/sonnet/tests/test.cpp97
-rw-r--r--kdecore/sonnet/tests/test_config.cpp40
-rw-r--r--kdecore/sonnet/tests/test_core.cpp172
-rw-r--r--kdecore/sonnet/tests/test_core.h32
-rw-r--r--kdecore/sonnet/tests/test_dialog.cpp67
-rw-r--r--kdecore/sonnet/tests/test_dialog.h42
-rw-r--r--kdecore/sonnet/tests/test_filter.cpp161
-rw-r--r--kdecore/sonnet/tests/test_filter.h34
-rw-r--r--kdecore/sycoca/.kprotocolinfofactory.cpp.kate-swpbin0 -> 63 bytes
-rw-r--r--kdecore/sycoca/kmemfile.cpp253
-rw-r--r--kdecore/sycoca/kmemfile.h100
-rw-r--r--kdecore/sycoca/kprotocolinfo.cpp462
-rw-r--r--kdecore/sycoca/kprotocolinfo.h378
-rw-r--r--kdecore/sycoca/kprotocolinfo_p.h65
-rw-r--r--kdecore/sycoca/kprotocolinfofactory.cpp122
-rw-r--r--kdecore/sycoca/kprotocolinfofactory.h99
-rw-r--r--kdecore/sycoca/ksycoca.cpp604
-rw-r--r--kdecore/sycoca/ksycoca.h235
-rw-r--r--kdecore/sycoca/ksycoca_p.h79
-rw-r--r--kdecore/sycoca/ksycocadevices_p.h125
-rw-r--r--kdecore/sycoca/ksycocadict.cpp562
-rw-r--r--kdecore/sycoca/ksycocadict_p.h135
-rw-r--r--kdecore/sycoca/ksycocaentry.cpp173
-rw-r--r--kdecore/sycoca/ksycocaentry.h157
-rw-r--r--kdecore/sycoca/ksycocaentry_p.h82
-rw-r--r--kdecore/sycoca/ksycocafactory.cpp248
-rw-r--r--kdecore/sycoca/ksycocafactory.h209
-rw-r--r--kdecore/sycoca/ksycocatype.h57
-rw-r--r--kdecore/tests/Berlinbin0 -> 2309 bytes
-rw-r--r--kdecore/tests/Berlin.zdump288
-rw-r--r--kdecore/tests/CMakeLists.txt177
-rw-r--r--kdecore/tests/Cairobin0 -> 955 bytes
-rw-r--r--kdecore/tests/Londonbin0 -> 1323 bytes
-rw-r--r--kdecore/tests/Los_Angelesbin0 -> 2819 bytes
-rw-r--r--kdecore/tests/Los_Angeles.zdump374
-rw-r--r--kdecore/tests/Parisbin0 -> 1082 bytes
-rw-r--r--kdecore/tests/cplusplustest.cpp48
-rw-r--r--kdecore/tests/dbuscalltest.cpp26
-rw-r--r--kdecore/tests/global_header_test.tar.bz2bin0 -> 242 bytes
-rw-r--r--kdecore/tests/globalcleanuptest.cpp45
-rw-r--r--kdecore/tests/kaboutdatatest.cpp252
-rw-r--r--kdecore/tests/kaboutdatatest.h38
-rw-r--r--kdecore/tests/karchivetest.cpp890
-rw-r--r--kdecore/tests/karchivetest.h67
-rw-r--r--kdecore/tests/kasciitest.cpp53
-rw-r--r--kdecore/tests/kasciitest.h32
-rw-r--r--kdecore/tests/kautosavefiletest.cpp114
-rw-r--r--kdecore/tests/kautosavefiletest.h42
-rw-r--r--kdecore/tests/kautostarttest.cpp169
-rw-r--r--kdecore/tests/kautostarttest.h41
-rw-r--r--kdecore/tests/kcalendartest.cpp3252
-rw-r--r--kdecore/tests/kcalendartest.h126
-rw-r--r--kdecore/tests/kcharsetstest.cpp34
-rw-r--r--kdecore/tests/kcmdlineargstest.cpp107
-rw-r--r--kdecore/tests/kconfigafterkglobaltest1.cpp65
-rw-r--r--kdecore/tests/kconfigafterkglobaltest2.cpp65
-rw-r--r--kdecore/tests/kconfigtest.cpp1569
-rw-r--r--kdecore/tests/kconfigtest.h89
-rw-r--r--kdecore/tests/kdatetimeformattertest.cpp376
-rw-r--r--kdecore/tests/kdatetimeformattertest.h45
-rw-r--r--kdecore/tests/kdatetimetest.cpp3985
-rw-r--r--kdecore/tests/kdatetimetest.h61
-rw-r--r--kdecore/tests/kdebug_qcoreapptest.cpp80
-rw-r--r--kdecore/tests/kdebug_unittest.cpp345
-rw-r--r--kdecore/tests/kdebug_unittest.h47
-rw-r--r--kdecore/tests/kdebugtest.cpp361
-rw-r--r--kdecore/tests/kdesktopfiletest.cpp126
-rw-r--r--kdecore/tests/kdesktopfiletest.h36
-rw-r--r--kdecore/tests/kdirwatch_unittest.cpp674
-rw-r--r--kdecore/tests/kdirwatchtest.cpp86
-rw-r--r--kdecore/tests/kdirwatchtest.h39
-rw-r--r--kdecore/tests/kdirwatchtest_gui.cpp152
-rw-r--r--kdecore/tests/kdirwatchtest_gui.h52
-rw-r--r--kdecore/tests/kencodingdetectortest.cpp89
-rw-r--r--kdecore/tests/kencodingdetectortest.h33
-rw-r--r--kdecore/tests/kentrymaptest.cpp202
-rw-r--r--kdecore/tests/kentrymaptest.h57
-rw-r--r--kdecore/tests/kfiltertest.cpp431
-rw-r--r--kdecore/tests/kfiltertest.h62
-rw-r--r--kdecore/tests/kglobalstatictest.cpp65
-rw-r--r--kdecore/tests/kglobaltest.cpp103
-rw-r--r--kdecore/tests/kjobtest.cpp419
-rw-r--r--kdecore/tests/kjobtest.h108
-rw-r--r--kdecore/tests/klibloadertest.cpp139
-rw-r--r--kdecore/tests/klibloadertest.h39
-rw-r--r--kdecore/tests/klibloadertest4_module.cpp37
-rw-r--r--kdecore/tests/klibloadertest4_module.h31
-rw-r--r--kdecore/tests/klibloadertest_module.cpp34
-rw-r--r--kdecore/tests/klibloadertest_module.h31
-rw-r--r--kdecore/tests/klimitediodevicetest.cpp79
-rw-r--r--kdecore/tests/klimitediodevicetest.h52
-rw-r--r--kdecore/tests/klocaletest.cpp1393
-rw-r--r--kdecore/tests/klocaletest.h51
-rw-r--r--kdecore/tests/klocaletimeformattest.cpp216
-rw-r--r--kdecore/tests/klocaletimeformattest.h56
-rw-r--r--kdecore/tests/klocalizedstringtest.cpp264
-rw-r--r--kdecore/tests/klocalizedstringtest.h42
-rw-r--r--kdecore/tests/klocalsocketservertest.cpp302
-rw-r--r--kdecore/tests/klocalsocketservertest.h51
-rw-r--r--kdecore/tests/klocalsockettest.cpp246
-rw-r--r--kdecore/tests/klocalsockettest.h48
-rw-r--r--kdecore/tests/klockfile_testlock.cpp42
-rw-r--r--kdecore/tests/klockfiletest.cpp158
-rw-r--r--kdecore/tests/klockfiletest.h38
-rw-r--r--kdecore/tests/kmacroexpandertest.cpp280
-rw-r--r--kdecore/tests/kmd5benchmark.cpp117
-rw-r--r--kdecore/tests/kmdcodectest.cpp392
-rw-r--r--kdecore/tests/kmemtest.cpp255
-rw-r--r--kdecore/tests/kmimeglobsfileparsertest.cpp275
-rw-r--r--kdecore/tests/kmimetype_nomimetypes.cpp75
-rw-r--r--kdecore/tests/kmimetypetest.cpp964
-rw-r--r--kdecore/tests/kmimetypetest.h71
-rw-r--r--kdecore/tests/kmountpointtest.cpp128
-rw-r--r--kdecore/tests/kmountpointtest.h35
-rw-r--r--kdecore/tests/kprocesstest.cpp112
-rw-r--r--kdecore/tests/krandomsequencetest.cpp96
-rw-r--r--kdecore/tests/ksavefiletest.cpp385
-rw-r--r--kdecore/tests/ksavefiletest.h41
-rw-r--r--kdecore/tests/kservicetest.cpp588
-rw-r--r--kdecore/tests/kservicetest.h59
-rw-r--r--kdecore/tests/kshareddatacachetest.cpp75
-rw-r--r--kdecore/tests/ksharedptrtest.cpp165
-rw-r--r--kdecore/tests/ksharedptrtest.h39
-rw-r--r--kdecore/tests/kshelltest.cpp217
-rw-r--r--kdecore/tests/ksortablelisttest.cpp32
-rw-r--r--kdecore/tests/kstandarddirstest.cpp477
-rw-r--r--kdecore/tests/kstandarddirstest.h52
-rw-r--r--kdecore/tests/kstringhandlertest.cpp252
-rw-r--r--kdecore/tests/kstringhandlertest.h23
-rw-r--r--kdecore/tests/ksycocadicttest.cpp150
-rw-r--r--kdecore/tests/ksycocathreadtest.cpp274
-rw-r--r--kdecore/tests/ktartest.cpp73
-rw-r--r--kdecore/tests/ktcpsockettest.cpp374
-rw-r--r--kdecore/tests/ktcpsockettest.h70
-rw-r--r--kdecore/tests/ktempdirtest.cpp74
-rw-r--r--kdecore/tests/ktempdirtest.h33
-rw-r--r--kdecore/tests/ktemporaryfiletest.cpp100
-rw-r--r--kdecore/tests/ktemporaryfiletest.h26
-rw-r--r--kdecore/tests/ktimezonestest.cpp669
-rw-r--r--kdecore/tests/ktimezonestest.h60
-rw-r--r--kdecore/tests/ktimezonestest_p.h110
-rw-r--r--kdecore/tests/kurlmimetest.cpp138
-rw-r--r--kdecore/tests/kurlmimetest.h36
-rw-r--r--kdecore/tests/kurltest.cpp2123
-rw-r--r--kdecore/tests/kurltest.h80
-rw-r--r--kdecore/tests/kziptest.cpp246
-rw-r--r--kdecore/tests/qcoreapptest.cpp46
-rw-r--r--kdecore/tests/startserviceby.cpp50
-rw-r--r--kdecore/tests/tar_directory_forgotten.tar.bz2bin0 -> 10723 bytes
-rw-r--r--kdecore/tests/tar_prefix_test.tar.bz2bin0 -> 10725 bytes
-rw-r--r--kdecore/text/kascii.cpp87
-rw-r--r--kdecore/text/kascii.h50
-rw-r--r--kdecore/text/kcodecs.cpp1117
-rw-r--r--kdecore/text/kcodecs.h488
-rw-r--r--kdecore/text/kstringhandler.cpp485
-rw-r--r--kdecore/text/kstringhandler.h233
-rw-r--r--kdecore/util/ConfigureChecks.cmake4
-rw-r--r--kdecore/util/config-util.h.cmake2
-rw-r--r--kdecore/util/kallocator.cpp292
-rw-r--r--kdecore/util/kallocator.h126
-rw-r--r--kdecore/util/kautostart.cpp359
-rw-r--r--kdecore/util/kautostart.h288
-rw-r--r--kdecore/util/kde_file.h229
-rw-r--r--kdecore/util/kde_file_win.cpp254
-rw-r--r--kdecore/util/kdedmodule.cpp101
-rw-r--r--kdecore/util/kdedmodule.h98
-rw-r--r--kdecore/util/kdeversion.cpp48
-rw-r--r--kdecore/util/kdeversion.h.cmake154
-rw-r--r--kdecore/util/kexportplugin.h76
-rw-r--r--kdecore/util/kgenericfactory.h362
-rw-r--r--kdecore/util/kgenericfactory.tcc277
-rw-r--r--kdecore/util/klauncher_iface.cpp28
-rw-r--r--kdecore/util/klauncher_iface.h198
-rw-r--r--kdecore/util/klibloader.cpp161
-rw-r--r--kdecore/util/klibloader.h298
-rw-r--r--kdecore/util/klibrary.cpp200
-rw-r--r--kdecore/util/klibrary.h84
-rw-r--r--kdecore/util/kmacroexpander.cpp357
-rw-r--r--kdecore/util/kmacroexpander.h408
-rw-r--r--kdecore/util/kmacroexpander_p.h34
-rw-r--r--kdecore/util/kmacroexpander_unix.cpp213
-rw-r--r--kdecore/util/kmacroexpander_win.cpp115
-rw-r--r--kdecore/util/kpluginfactory.cpp249
-rw-r--r--kdecore/util/kpluginfactory.h540
-rw-r--r--kdecore/util/kpluginfactory_p.h52
-rw-r--r--kdecore/util/kpluginloader.cpp283
-rw-r--r--kdecore/util/kpluginloader.h155
-rw-r--r--kdecore/util/krandom.cpp68
-rw-r--r--kdecore/util/krandom.h54
-rw-r--r--kdecore/util/krandomsequence.cpp220
-rw-r--r--kdecore/util/krandomsequence.h148
-rw-r--r--kdecore/util/kshareddatacache.cpp1774
-rw-r--r--kdecore/util/kshareddatacache.h222
-rw-r--r--kdecore/util/kshareddatacache_p.h440
-rw-r--r--kdecore/util/kshareddatacache_win.cpp119
-rw-r--r--kdecore/util/ksharedptr.h226
-rw-r--r--kdecore/util/kshell.cpp69
-rw-r--r--kdecore/util/kshell.h197
-rw-r--r--kdecore/util/kshell_p.h37
-rw-r--r--kdecore/util/kshell_unix.cpp295
-rw-r--r--kdecore/util/kshell_win.cpp254
-rw-r--r--kdecore/util/ksortablelist.h188
-rw-r--r--kdecore/util/ktypelist.h626
-rw-r--r--kdecore/util/ktypelistutils.h365
-rw-r--r--kdecore/util/ktypetraits.h293
-rw-r--r--kdecore/util/kuser.h389
-rw-r--r--kdecore/util/kuser_unix.cpp356
-rw-r--r--kdecore/util/kuser_win.cpp474
-rw-r--r--kdecore/util/kuser_wince.cpp238
-rw-r--r--kdecore/util/qtest_kde.cpp63
-rw-r--r--kdecore/util/qtest_kde.h155
668 files changed, 219124 insertions, 0 deletions
diff --git a/kdecore/CMakeLists.txt b/kdecore/CMakeLists.txt
new file mode 100644
index 0000000..1424b0e
--- /dev/null
+++ b/kdecore/CMakeLists.txt
@@ -0,0 +1,679 @@
+project(kdecore)
+
+# Generate config-kstandarddirs.h
+configure_file(config-kstandarddirs.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kstandarddirs.h )
+
+# Generate kdefakes.h
+configure_file(kdefakes.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdefakes.h )
+
+# Generate kdeversion.h
+configure_file(util/kdeversion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdeversion.h )
+
+# Configure checks for kdirwatch
+macro_optional_find_package(FAM)
+macro_bool_to_01(FAM_FOUND HAVE_FAM)
+
+check_include_files(sys/inotify.h SYS_INOTIFY_H_FOUND)
+macro_bool_to_01(SYS_INOTIFY_H_FOUND HAVE_SYS_INOTIFY_H)
+
+# Generate io/config-kdirwatch.h
+configure_file(io/config-kdirwatch.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/io/config-kdirwatch.h )
+
+# Configure checks for network/ but also for netsupp.*
+include(network/ConfigureChecks.cmake)
+configure_file(network/config-network.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/network/config-network.h )
+include_directories( ${CMAKE_CURRENT_BINARY_DIR}/network )
+
+# Configure checks for date/
+include(date/ConfigureChecks.cmake)
+configure_file(date/config-date.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/date/config-date.h)
+include_directories( ${CMAKE_CURRENT_BINARY_DIR}/date )
+
+# Configure checks for compression/
+include(compression/ConfigureChecks.cmake)
+configure_file(compression/config-compression.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/compression/config-compression.h)
+include_directories( ${CMAKE_CURRENT_BINARY_DIR}/compression )
+
+# This file handles all the logic for compiling KAuth's backends
+include(auth/ConfigureChecks.cmake)
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/auth/ )
+
+# Configure a small file to tell BackendsManager what to use
+configure_file(auth/BackendsConfig.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/BackendsConfig.h)
+
+# Configure checks for localization
+configure_file(localization/config-localization.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-localization.h)
+
+# Configure checks for util
+include(util/ConfigureChecks.cmake)
+configure_file(util/config-util.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-util.h)
+
+
+include_directories( ${KDE4_KDECORE_INCLUDES} )
+include_directories( ${ZLIB_INCLUDE_DIR} )
+include_directories( ${QT_INCLUDES} )
+
+if (KDE_PLATFORM_FEATURE_DISABLE_DEPRECATED)
+ set(KDECORE_NO_KDE3SUPPORT TRUE)
+endif(KDE_PLATFORM_FEATURE_DISABLE_DEPRECATED)
+
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/sonnet/ )
+
+# kdecore_OPTIONAL_SRCS is used to collect source files
+# which are not always compiled into kdecore
+# if it's used, *always* append to it
+set(kdecore_OPTIONAL_SRCS)
+# same for optional libs
+set(kdecore_OPTIONAL_LIBS)
+
+add_definitions(-DQT_NO_CAST_FROM_ASCII)
+
+if(WIN32)
+ set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${KDEWIN_LIBRARIES})
+endif(WIN32)
+
+# Needed for the kdatetime test in release mode
+if(KDE4_BUILD_TESTS)
+ add_definitions(-DCOMPILING_TESTS)
+endif(KDE4_BUILD_TESTS)
+
+# compile bzip2 support if available
+if(BZIP2_FOUND)
+ include_directories(${BZIP2_INCLUDE_DIR})
+ set(kdecore_OPTIONAL_SRCS ${kdecore_OPTIONAL_SRCS} compression/kbzip2filter.cpp )
+ set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${BZIP2_LIBRARIES})
+endif(BZIP2_FOUND)
+
+# compile lzma support if available
+if(LIBLZMA_FOUND)
+ include_directories(${LIBLZMA_INCLUDE_DIRS})
+ set(kdecore_OPTIONAL_SRCS ${kdecore_OPTIONAL_SRCS} compression/kxzfilter.cpp )
+ set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${LIBLZMA_LIBRARIES})
+endif(LIBLZMA_FOUND)
+
+# compile Gettext support if available
+if(LIBINTL_FOUND)
+ include_directories(${LIBINTL_INCLUDE_DIR})
+ set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${LIBINTL_LIBRARIES})
+endif(LIBINTL_FOUND)
+
+if (HAVE_RESOLV_LIBRARY)
+ set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} resolv)
+endif (HAVE_RESOLV_LIBRARY)
+
+if (APPLE)
+ set(kdecore_OPTIONAL_SRCS ${kdecore_OPTIONAL_SRCS}
+ kernel/kkernel_mac.cpp
+ localization/klocale_mac.cpp
+ )
+
+ set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${CARBON_LIBRARY})
+endif (APPLE)
+
+if (WIN32)
+ LIST(APPEND kdecore_OPTIONAL_SRCS
+ kernel/kkernel_win.cpp
+ kernel/ktoolinvocation_win.cpp
+ kernel/kstandarddirs_win.cpp
+ localization/klocale_win.cpp
+ network/klocalsocket_win.cpp
+ io/klockfile_win.cpp
+ util/kde_file_win.cpp
+ util/kmacroexpander_win.cpp
+ util/kshell_win.cpp
+ date/ktimezone_win.cpp
+ )
+ if(NOT WINCE)
+ LIST(APPEND kdecore_OPTIONAL_SRCS
+ util/kuser_win.cpp
+ )
+ else(NOT WINCE)
+ LIST(APPEND kdecore_OPTIONAL_SRCS
+ util/kuser_wince.cpp
+ )
+ endif(NOT WINCE)
+ if(NOT MSVC)
+ LIST(APPEND kdecore_OPTIONAL_SRCS
+ network/netsupp.cpp
+ )
+ endif(NOT MSVC)
+endif (WIN32)
+
+
+if (UNIX)
+ set(kdecore_OPTIONAL_SRCS ${kdecore_OPTIONAL_SRCS}
+ kernel/ktoolinvocation_x11.cpp
+ kernel/kstandarddirs_unix.cpp
+ localization/klocale_unix.cpp
+ network/klocalsocket_unix.cpp
+ network/netsupp.cpp
+ io/klockfile_unix.cpp
+ util/kshell_unix.cpp
+ util/kuser_unix.cpp
+ util/kmacroexpander_unix.cpp
+ fakes.c
+ )
+ if (NOT KDECORE_NO_KDE3SUPPORT)
+ set(kdecore_OPTIONAL_SRCS ${kdecore_OPTIONAL_SRCS}
+ network/k3httpproxysocketdevice.cpp
+ network/k3socks.cpp
+ network/k3sockssocketdevice.cpp
+ )
+ endif (NOT KDECORE_NO_KDE3SUPPORT)
+endif (UNIX)
+
+add_subdirectory( kconfig_compiler )
+add_subdirectory( tests )
+add_subdirectory( sonnet/tests )
+if ( NOT WINCE )
+ add_subdirectory( network/kssld )
+endif ( NOT WINCE )
+
+########### next target ###############
+
+if (UNIX)
+
+ kde4_add_library(kdefakes ${LIBRARY_TYPE} fakes.c)
+ set_target_properties(kdefakes PROPERTIES VERSION ${KDE_NON_GENERIC_LIB_VERSION} SOVERSION ${KDE_NON_GENERIC_LIB_SOVERSION})
+ if (NOT HAVE_TRUNC)
+ target_link_libraries(kdefakes m )
+ endif (NOT HAVE_TRUNC)
+ install(TARGETS kdefakes EXPORT kdelibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS} )
+
+endif (UNIX)
+
+
+
+########### next target ###############
+
+set(kdecore_LIB_SRCS
+ compression/kgzipfilter.cpp
+ compression/kfilterbase.cpp
+ compression/kfilterdev.cpp
+ config/kconfig.cpp
+ config/kconfigbase.cpp
+ config/kconfiggroup.cpp
+ config/kconfigbackend.cpp
+ config/kconfigini.cpp
+ config/kdesktopfile.cpp
+ config/ksharedconfig.cpp
+ config/kcoreconfigskeleton.cpp
+ date/kcalendarera.cpp
+ date/kcalendarsystem.cpp
+ date/kcalendarsystemcoptic.cpp
+ date/kcalendarsystemethiopian.cpp
+ date/kcalendarsystemqdate.cpp
+ date/kcalendarsystemgregorian.cpp
+ date/kcalendarsystemislamiccivil.cpp
+ date/kcalendarsystemhebrew.cpp
+ date/kcalendarsystemindiannational.cpp
+ date/kcalendarsystemjalali.cpp
+ date/kcalendarsystemjapanese.cpp
+ date/kcalendarsystemjulian.cpp
+ date/kcalendarsystemminguo.cpp
+ date/kcalendarsystemthai.cpp
+ date/kdatetime.cpp
+ date/kdatetimeformatter.cpp
+ date/kdatetimeparser.cpp
+ date/kdayperiod.cpp
+ date/klocalizeddate.cpp
+ date/ktimezone.cpp
+ date/ksystemtimezone.cpp
+ date/ktzfiletimezone.cpp
+ io/kar.cpp
+ io/karchive.cpp
+ io/kautosavefile.cpp
+ io/kdebug.cpp
+ io/kdebugdbusiface.cpp
+ io/kdirwatch.cpp
+ io/kfilesystemtype_p.cpp
+ io/klimitediodevice.cpp
+ io/kmessage.cpp
+ io/kmountpoint.cpp
+ io/kprocess.cpp
+ io/ksavefile.cpp
+ io/ktar.cpp
+ io/ktempdir.cpp
+ io/ktemporaryfile.cpp
+ io/kurl.cpp
+ io/kzip.cpp
+ jobs/kcompositejob.cpp
+ jobs/kjob.cpp
+ jobs/kjobuidelegate.cpp
+ jobs/kjobtrackerinterface.cpp
+ kernel/kauthorized.cpp
+ kernel/kaboutdata.cpp
+ kernel/kcmdlineargs.cpp
+ kernel/kglobal.cpp
+ kernel/kcomponentdata.cpp
+ kernel/kstandarddirs.cpp
+ kernel/ktoolinvocation.cpp
+ auth/kauthaction.cpp
+ auth/kauthactionreply.cpp
+ auth/kauthactionwatcher.cpp
+ auth/AuthBackend.cpp
+ auth/BackendsManager.cpp
+ auth/HelperProxy.cpp
+ auth/kauthhelpersupport.cpp
+ auth/backends/fake/FakeBackend.cpp
+ auth/backends/fakehelper/FakeHelperProxy.cpp
+ services/kfoldermimetype.cpp
+ services/kmimetypefactory.cpp
+ services/kmimemagicrule.cpp
+ services/kmimetypetrader.cpp
+ services/kmimetype.cpp
+ services/kmimeglobsfileparser.cpp
+ services/kmimetyperepository.cpp
+ services/kservice.cpp
+ services/kserviceaction.cpp
+ services/kservicefactory.cpp
+ services/kservicegroup.cpp
+ services/kservicegroupfactory.cpp
+ services/kserviceoffer.cpp
+ services/kservicetype.cpp
+ services/kservicetypefactory.cpp
+ services/kservicetypeprofile.cpp
+ services/kservicetypetrader.cpp
+ services/ktraderparse.cpp
+ services/ktraderparsetree.cpp
+ services/yacc.c
+ services/lex.c
+ services/kplugininfo.cpp
+ sonnet/loader.cpp
+ sonnet/client.cpp
+ sonnet/spellerplugin.cpp
+ sonnet/speller.cpp
+ sonnet/filter.cpp
+ sonnet/settings.cpp
+ sonnet/backgroundchecker.cpp
+ sonnet/backgroundengine.cpp
+ sonnet/globals.cpp
+)
+
+if (NOT KDECORE_NO_KDE3SUPPORT)
+ set(kdecore_LIB_SRCS ${kdecore_LIB_SRCS}
+ network/k3socketdevice.cpp # must be before the rest of network/, for enable-final
+ network/k3bufferedsocket.cpp
+ network/k3clientsocketbase.cpp
+ network/k3datagramsocket.cpp
+ network/k3resolver.cpp
+ network/k3resolvermanager.cpp
+ network/k3resolverworkerbase.cpp
+ network/k3resolverstandardworkers.cpp
+ network/k3reverseresolver.cpp
+ network/k3serversocket.cpp
+ network/k3socketaddress.cpp
+ network/k3socketbase.cpp
+ network/k3streamsocket.cpp
+ network/k3socketbuffer.cpp
+ )
+endif (NOT KDECORE_NO_KDE3SUPPORT)
+
+set(kdecore_LIB_SRCS ${kdecore_LIB_SRCS}
+ network/klocalsocket.cpp
+ network/ksocketfactory.cpp
+ network/ksslcertificatemanager.cpp
+ network/ktcpsocket.cpp
+ localization/kcatalog.cpp
+ localization/kcurrencycode.cpp
+ localization/kcharsets.cpp
+ localization/kencodingdetector.cpp
+ localization/guess_ja.cpp
+ localization/kencodingprober.cpp
+ localization/probers/CharDistribution.cpp
+ localization/probers/ChineseGroupProber.cpp
+ localization/probers/JapaneseGroupProber.cpp
+ localization/probers/JpCntx.cpp
+ localization/probers/LangBulgarianModel.cpp
+ localization/probers/LangCyrillicModel.cpp
+ localization/probers/LangGreekModel.cpp
+ localization/probers/LangHebrewModel.cpp
+ localization/probers/LangHungarianModel.cpp
+ localization/probers/LangThaiModel.cpp
+ localization/probers/UnicodeGroupProber.cpp
+ localization/probers/nsBig5Prober.cpp
+ localization/probers/nsCharSetProber.cpp
+ localization/probers/nsEUCJPProber.cpp
+ localization/probers/nsEUCKRProber.cpp
+ localization/probers/nsEUCTWProber.cpp
+ localization/probers/nsEscCharsetProber.cpp
+ localization/probers/nsEscSM.cpp
+ localization/probers/nsGB2312Prober.cpp
+ localization/probers/nsHebrewProber.cpp
+ localization/probers/nsLatin1Prober.cpp
+ localization/probers/nsMBCSGroupProber.cpp
+ localization/probers/nsMBCSSM.cpp
+ localization/probers/nsSBCSGroupProber.cpp
+ localization/probers/nsSBCharSetProber.cpp
+ localization/probers/nsSJISProber.cpp
+ localization/probers/nsUniversalDetector.cpp
+ localization/klocale.cpp
+ localization/klocale_kde.cpp
+ localization/klocalizedstring.cpp
+ localization/kuitsemantics.cpp
+ localization/kuitformats.cpp
+ localization/common_helpers.cpp
+ sycoca/ksycoca.cpp
+ sycoca/ksycocadict.cpp
+ sycoca/ksycocaentry.cpp
+ sycoca/ksycocafactory.cpp
+ sycoca/kprotocolinfo.cpp
+ sycoca/kprotocolinfofactory.cpp
+ sycoca/kmemfile.cpp
+ text/kascii.cpp
+ text/kcodecs.cpp
+ text/kstringhandler.cpp
+ util/kallocator.cpp
+ util/kautostart.cpp
+ util/kdedmodule.cpp
+ util/kdeversion.cpp
+ util/klauncher_iface.cpp
+ util/klibrary.cpp
+ util/kmacroexpander.cpp
+ util/kpluginfactory.cpp
+ util/kpluginloader.cpp
+ util/kshell.cpp
+ util/krandom.cpp
+ util/krandomsequence.cpp
+ util/qtest_kde.cpp
+ ${kdecore_OPTIONAL_SRCS}
+)
+
+if(NOT KDE_NO_DEPRECATED)
+ set(kdecore_LIB_SRCS ${kdecore_LIB_SRCS}
+ util/klibloader.cpp
+ )
+endif(NOT KDE_NO_DEPRECATED)
+
+if(NOT WIN32)
+ set(kdecore_LIB_SRCS ${kdecore_LIB_SRCS} util/kshareddatacache.cpp)
+ set(kdecore_OPTIONAL_LIBS ${kdecore_OPTIONAL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
+
+ set_source_files_properties(util/kshareddatacache.cpp
+ PROPERTIES COMPILE_FLAGS ${KDE4_ENABLE_EXCEPTIONS})
+else(NOT WIN32)
+ set(kdecore_LIB_SRCS ${kdecore_LIB_SRCS} util/kshareddatacache_win.cpp)
+ set(kdecore_LIB_SRCS ${kdecore_LIB_SRCS} io/kdirwatch_win.cpp)
+endif(NOT WIN32)
+
+if (NOT Q_WS_X11 AND NOT Q_WS_QWS)
+ add_definitions(-DNO_DISPLAY)
+endif (NOT Q_WS_X11 AND NOT Q_WS_QWS)
+
+kde4_add_library(kdecore ${LIBRARY_TYPE} ${kdecore_LIB_SRCS})
+
+target_link_libraries(kdecore ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTXML_LIBRARY} ${ZLIB_LIBRARY} ${kdecore_OPTIONAL_LIBS})
+
+if(WINCE)
+ target_link_libraries(kdecore ${WCECOMPAT_LIBRARIES} Ceshell.lib)
+endif(WINCE)
+
+set(SYS_INOTIFY_H_FOUND 0)
+if(SYS_INOTIFY_H_FOUND)
+ macro_log_feature(FAM_FOUND "FAM" "File alteration notification support via a separate service" "http://oss.sgi.com/projects/fam" FALSE "" "You have file alteration notification support built into your kernel, however you might consider installing FAM as it also supports NFS.")
+else(SYS_INOTIFY_H_FOUND)
+ macro_log_feature(FAM_FOUND "FAM" "File alteration notification support via a separate service" "http://oss.sgi.com/projects/fam" FALSE "" "Provides file alteration notification facilities using a separate service.")
+endif(SYS_INOTIFY_H_FOUND)
+
+if(FAM_FOUND)
+ include_directories(${FAM_INCLUDE_DIR})
+ target_link_libraries(kdecore ${FAM_LIBRARIES})
+endif(FAM_FOUND)
+
+if(WIN32)
+ set(kdecore_LINK_INTERFACE_LIBRARIES ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} ${KDEWIN_LIBRARIES})
+else(WIN32)
+ if(APPLE)
+ set(kdecore_LINK_INTERFACE_LIBRARIES ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} ${CARBON_LIBRARY})
+ else(APPLE)
+ set(kdecore_LINK_INTERFACE_LIBRARIES ${QT_QTDBUS_LIBRARY} ${QT_QTCORE_LIBRARY} )
+ endif(APPLE)
+endif(WIN32)
+
+target_link_libraries(kdecore LINK_INTERFACE_LIBRARIES ${kdecore_LINK_INTERFACE_LIBRARIES} )
+
+set_target_properties(kdecore PROPERTIES
+ VERSION ${KDE_NON_GENERIC_LIB_VERSION}
+ SOVERSION ${KDE_NON_GENERIC_LIB_SOVERSION}
+ )
+
+
+install(TARGETS kdecore EXPORT kdelibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS})
+
+########### next target ###############
+
+# KAuth policy generator executable
+
+# Compile only if fake backend has not been selected
+
+if (NOT "${KDE4_AUTH_BACKEND_NAME}" STREQUAL "FAKE")
+ # KAUTH_POLICY_GEN_SRCS has been generated from auth/ConfigureChecks.cmake
+ kde4_add_executable(kauth-policy-gen NOGUI ${KAUTH_POLICY_GEN_SRCS})
+
+ # KAUTH_POLICY_GEN_LIBRARIES has been generated from auth/ConfigureChecks.cmake
+ target_link_libraries( kauth-policy-gen ${KAUTH_POLICY_GEN_LIBRARIES} )
+
+ install( TARGETS kauth-policy-gen EXPORT kdelibsToolsTargets DESTINATION ${LIBEXEC_INSTALL_DIR})
+endif (NOT "${KDE4_AUTH_BACKEND_NAME}" STREQUAL "FAKE")
+
+if ( NOT WINCE )
+ ########### next target ###############
+
+ # KAuth backend plugin
+
+ if (NOT "${KDE4_AUTH_BACKEND_NAME}" STREQUAL "FAKE")
+ set(KAUTH_BACKEND_SRCS ${KAUTH_BACKEND_SRCS} auth/AuthBackend.cpp)
+ kde4_add_plugin(kauth_backend_plugin ${KAUTH_BACKEND_SRCS})
+ target_link_libraries(kauth_backend_plugin ${KAUTH_BACKEND_LIBS})
+ install(TARGETS kauth_backend_plugin
+ LIBRARY DESTINATION ${KAUTH_BACKEND_PLUGIN_DIR}
+ ARCHIVE DESTINATION ${KAUTH_BACKEND_PLUGIN_DIR}
+ RUNTIME DESTINATION ${KAUTH_BACKEND_PLUGIN_DIR}
+ )
+ endif (NOT "${KDE4_AUTH_BACKEND_NAME}" STREQUAL "FAKE")
+
+ ########### next target ###############
+
+ # KAuth helper plugin
+
+ if (NOT "${KDE4_AUTH_HELPER_BACKEND_NAME}" STREQUAL "FAKE")
+ kde4_add_plugin(kauth_helper_plugin ${KAUTH_HELPER_BACKEND_SRCS} auth/HelperProxy.cpp)
+ target_link_libraries(kauth_helper_plugin ${KAUTH_HELPER_BACKEND_LIBS})
+ install(TARGETS kauth_helper_plugin
+ LIBRARY DESTINATION ${KAUTH_HELPER_PLUGIN_DIR}
+ ARCHIVE DESTINATION ${KAUTH_HELPER_PLUGIN_DIR}
+ RUNTIME DESTINATION ${KAUTH_HELPER_PLUGIN_DIR}
+ )
+ endif (NOT "${KDE4_AUTH_HELPER_BACKEND_NAME}" STREQUAL "FAKE")
+endif ( NOT WINCE )
+
+########### next target ###############
+
+configure_file(localization/all_languages.desktop ${CMAKE_CURRENT_BINARY_DIR}/all_languages @ONLY)
+
+kde4_add_executable(kde4-config NOGUI kde-config.cpp )
+
+target_link_libraries(kde4-config ${KDE4_KDECORE_LIBS})
+
+install(TARGETS kde4-config ${INSTALL_TARGETS_DEFAULT_ARGS} )
+
+
+########### next target ###############
+
+if(NOT WINCE)
+ # kjs hash stuff for transcript plugin
+ set( CREATE_HASH_TABLE ${CMAKE_SOURCE_DIR}/kjs/create_hash_table )
+
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ktranscript.lut.h
+ COMMAND ${PERL_EXECUTABLE} ${CREATE_HASH_TABLE}
+ ${CMAKE_CURRENT_SOURCE_DIR}/localization/ktranscript.cpp
+ > ${CMAKE_CURRENT_BINARY_DIR}/ktranscript.lut.h
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/localization/ktranscript.cpp
+ )
+
+ # the transcript plugin
+ set( ktranscript_LIB_SRCS
+ localization/ktranscript.cpp
+ localization/common_helpers.cpp
+ )
+
+ kde4_add_plugin( ktranscript ${ktranscript_LIB_SRCS} )
+
+ target_link_libraries( ktranscript kjs ${QT_QTCORE_LIBRARY} )
+
+
+ if(KDE4_ENABLE_FINAL)
+ macro_add_file_dependencies(${CMAKE_CURRENT_BINARY_DIR}/ktranscript_final_cpp.cpp ${CMAKE_CURRENT_BINARY_DIR}/ktranscript.lut.h)
+ else(KDE4_ENABLE_FINAL)
+ macro_add_file_dependencies(${CMAKE_CURRENT_SOURCE_DIR}/localization/ktranscript.cpp ${CMAKE_CURRENT_BINARY_DIR}/ktranscript.lut.h)
+ endif(KDE4_ENABLE_FINAL)
+
+ install( TARGETS ktranscript DESTINATION ${PLUGIN_INSTALL_DIR} )
+
+endif(NOT WINCE)
+
+########### install files ###############
+install( FILES ${CMAKE_CURRENT_BINARY_DIR}/all_languages DESTINATION ${LOCALE_INSTALL_DIR} )
+install( FILES localization/entry.desktop DESTINATION ${LOCALE_INSTALL_DIR}/en_US )
+install( FILES kdebug.areas kdebugrc DESTINATION ${CONFIG_INSTALL_DIR} )
+install( FILES
+ kdecore_export.h
+ compression/kfilterbase.h
+ compression/karchive_export.h
+ compression/kfilterdev.h
+ config/conversion_check.h
+ config/kconfig.h
+ #config/kconfigbackend.h re-enable post-API review and implementation (4.2?)
+ config/kconfigbase.h
+ config/kconfiggroup.h
+ config/kdesktopfile.h
+ config/ksharedconfig.h
+ config/kcoreconfigskeleton.h
+ date/kcalendarsystem.h
+ date/kdatetime.h
+ date/klocalizeddate.h
+ date/ksystemtimezone.h
+ date/ktimezone.h
+ date/ktzfiletimezone.h
+ io/kar.h
+ io/karchive.h
+ io/kautosavefile.h
+ io/kdebug.h
+ io/kdirwatch.h
+ io/kmessage.h
+ io/kprocess.h
+ io/klockfile.h
+ io/kmountpoint.h
+ io/ksavefile.h
+ io/ktar.h
+ io/ktempdir.h
+ io/ktemporaryfile.h
+ io/kurl.h
+ io/kzip.h
+ jobs/kcompositejob.h
+ jobs/kjob.h
+ jobs/kjobuidelegate.h
+ jobs/kjobtrackerinterface.h
+ kernel/kaboutdata.h
+ kernel/kauthorized.h
+ kernel/kcmdlineargs.h
+ kernel/kglobal.h
+ kernel/kcomponentdata.h
+ kernel/kstandarddirs.h
+ kernel/ktoolinvocation.h
+ DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel
+)
+
+if (NOT KDECORE_NO_KDE3SUPPORT)
+ install(FILES
+ network/k3bufferedsocket.h
+ network/k3clientsocketbase.h
+ network/k3datagramsocket.h
+ network/k3httpproxysocketdevice.h
+ network/k3resolver.h
+ network/k3reverseresolver.h
+ network/k3serversocket.h
+ network/k3socketaddress.h
+ network/k3socketbase.h
+ network/k3socketdevice.h
+ network/k3socks.h
+ network/k3sockssocketdevice.h
+ network/k3streamsocket.h
+ DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel
+ )
+endif (NOT KDECORE_NO_KDE3SUPPORT)
+
+install(FILES
+ network/klocalsocket.h
+ network/ksocketfactory.h
+ network/ktcpsocket.h
+ auth/kauthaction.h
+ auth/kauthactionreply.h
+ auth/kauthactionwatcher.h
+ auth/kauthhelpersupport.h
+ auth/kauth.h
+ services/kmimetype.h
+ services/kmimetypetrader.h
+ services/kservice.h
+ services/kserviceaction.h
+ services/kservicegroup.h
+ #services/kservicefactory.h: do not install, internal API
+ services/kservicetype.h
+ #services/kservicetypefactory.h: do not install, internal API
+ services/kservicetypeprofile.h
+ services/kservicetypetrader.h
+ #services/kserviceoffer.h: do not install, internal API
+ services/kplugininfo.h
+ localization/kcharsets.h
+ localization/kcurrencycode.h
+ localization/kencodingdetector.h
+ localization/kencodingprober.h
+ localization/klocale.h
+ localization/klocalizedstring.h
+ sycoca/kprotocolinfo.h
+ sycoca/ksycoca.h
+ sycoca/ksycocaentry.h
+ sycoca/ksycocatype.h
+ text/kascii.h
+ text/kcodecs.h
+ text/kstringhandler.h
+ util/kallocator.h
+ util/kautostart.h
+ util/kde_file.h
+ util/kdedmodule.h
+ util/kgenericfactory.h
+ util/kgenericfactory.tcc
+ util/klauncher_iface.h
+ util/klibrary.h
+ util/klibloader.h
+ util/kmacroexpander.h
+ util/kexportplugin.h
+ util/kpluginfactory.h
+ util/kpluginloader.h
+ util/kshell.h
+ util/krandom.h
+ util/krandomsequence.h
+ util/kshareddatacache.h
+ util/ksharedptr.h
+ util/ksortablelist.h
+ util/ktypelist.h
+ util/ktypelistutils.h
+ util/ktypetraits.h
+ util/kuser.h
+ util/qtest_kde.h
+ ${CMAKE_CURRENT_BINARY_DIR}/kdefakes.h
+ ${CMAKE_CURRENT_BINARY_DIR}/kdeversion.h
+ DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel
+)
+
+install( FILES sonnet/backgroundchecker.h sonnet/speller.h sonnet/globals.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/sonnet COMPONENT Devel)
+
+install( FILES
+ config/kconfigbackend.desktop
+ services/kplugininfo.desktop
+ sonnet/sonnetspeller.desktop
+ DESTINATION ${SERVICETYPES_INSTALL_DIR}
+)
+
diff --git a/kdecore/MAINTAINERS b/kdecore/MAINTAINERS
new file mode 100644
index 0000000..b46b288
--- /dev/null
+++ b/kdecore/MAINTAINERS
@@ -0,0 +1,213 @@
+Here are the code maintainers for each part of this library. Any problems or
+suggested patches for a class should be directed to the responsible person for
+that class.
+
+compression/
+ kbzip2filter.cpp David Faure <faure@kde.org> (copyright)
+ kfilterbase.cpp David Faure <faure@kde.org> (copyright)
+ kfilterdev.cpp David Faure <faure@kde.org> (copyright)
+ kgzipfilter.cpp David Faure <faure@kde.org> (copyright)
+ kxzfilter.cpp Per Øyvind Karlsen <peroyvind@mandriva.org> (copyright)
+
+config/
+ kconfigbackend.cpp
+ kconfigbase.cpp
+ kconfig.cpp
+ kconfiggroup.cpp
+ kconfigini.cpp
+ kcoreconfigskeleton.cpp
+ kdesktopfile.cpp
+ ksharedconfig.cpp
+
+date/
+ kcalendarera.cpp John Layt <john@layt.net>
+ kcalendarsystem.cpp John Layt <john@layt.net>
+ kdatetimeformatter.cpp John Layt <john@layt.net>
+ kdatetimeparser.cpp John Layt <john@layt.net>
+ kdayperiod.cpp John Layt <john@layt.net>
+ klocalizeddate.cpp John Layt <john@layt.net>
+ kdatetime.cpp David Jarvie <djarvie@kde.org>
+ ksystemtimezone.cpp
+ ktimezone.cpp
+ ktzfiletimezone.cpp David Jarvie <djarvie@kde.org>
+
+io/
+ kautosavefile.cpp
+ kcmdwrapper.cpp
+ kdebug.cpp Stephan Kulow <coolo@kde.org>
+ kdebugdbusiface.cpp
+ klockfile_unix.cpp
+ klockfile_win.cpp
+ kmessage.cpp
+ kprocess.cpp
+ ksavefile.cpp
+ ktempdir.cpp Joseph Wenninger <jowenn@kde.org> (copyright)
+ ktemporaryfile.cpp Jaison Lee <lee.jaison@gmail.com>
+ kurl.cpp David Faure <faure@kde.org>
+
+jobs/
+ kcompositejob.cpp
+ kjob.cpp
+ kjobtrackerinterface.cpp
+ kjobuidelegate.cpp
+
+kconfig_compiler/
+ kconfig_compiler.cpp
+
+kernel/
+ kaboutdata.cpp David Faure <faure@kde.org>
+ kauthorized.cpp
+ kautostart.cpp
+ kcmdlineargs.cpp
+ kcomponentdata.cpp
+ kglobal.cpp Stephan Kulow <coolo@kde.org>
+ kkernel_mac.cpp
+ kkernel_win.cpp
+ kstandarddirs.cpp David Faure <faure@kde.org>
+ kstandarddirs_unix.cpp David Faure <faure@kde.org>
+ kstandarddirs_win.cpp
+ ktoolinvocation.cpp David Faure <faure@kde.org>
+ ktoolinvocation_win.cpp
+ ktoolinvocation_x11.cpp
+
+localization/
+ common_helpers.cpp
+ guess_ja.cpp
+ kcatalog.cpp Hans Petter Bieker <bieker@kde.org>
+ kcharsets.cpp
+ kencodingdetector.cpp
+ kencodingprober.cpp
+ kentities.c
+ klocale.cpp Hans Petter Bieker <bieker@kde.org>
+ klocalizedstring.cpp Chusslove Illich <caslav.ilic@gmx.net>
+ ktranscript.cpp Chusslove Illich <caslav.ilic@gmx.net>
+ kuitformats.cpp Chusslove Illich <caslav.ilic@gmx.net>
+ kuitsemantics.cpp Chusslove Illich <caslav.ilic@gmx.net>
+
+network/ Thiago Macieira <thiago@kde.org>
+ k3bufferedsocket.cpp
+ k3clientsocketbase.cpp
+ k3datagramsocket.cpp
+ k3httpproxysocketdevice.cpp
+ k3resolver.cpp
+ k3resolvermanager.cpp
+ k3resolverstandardworkers.cpp
+ k3resolverworkerbase.cpp
+ k3reverseresolver.cpp
+ k3serversocket.cpp
+ k3socketaddress.cpp
+ k3socketbase.cpp
+ k3socketbuffer.cpp
+ k3socketdevice.cpp
+ k3socks.cpp
+ k3sockssocketdevice.cpp
+ k3streamsocket.cpp
+ klocalsocket.cpp
+ klocalsocket_unix.cpp
+ klocalsocket_win.cpp
+ ksocketfactory.cpp
+ ksslcertificatemanager.cpp
+ ktcpsocket.cpp
+ netsupp.cpp
+network/kssld/
+ kssld.cpp
+
+services/ David Faure <faure@kde.org>
+ kfoldermimetype.cpp
+ kmimemagicrule.cpp
+ kmimetype.cpp
+ kmimetypefactory.cpp
+ kmimetypetrader.cpp
+ kplugininfo.cpp
+ kserviceaction.cpp
+ kservice.cpp
+ kservicefactory.cpp
+ kservicegroup.cpp
+ kservicegroupfactory.cpp
+ kserviceoffer.cpp
+ kservicetype.cpp
+ kservicetypefactory.cpp
+ kservicetypeprofile.cpp
+ kservicetypetrader.cpp
+ ktraderparse.cpp
+ ktraderparsetree.cpp
+
+sonnet/
+ backgroundchecker.cpp
+ backgroundengine.cpp
+ client.cpp
+ filter.cpp
+ globals.cpp
+ loader.cpp
+ settings.cpp
+ speller.cpp
+ spellerplugin.cpp
+
+sycoca/
+ kmemfile.cpp
+ kprotocolinfo.cpp David Faure <faure@kde.org>
+ kprotocolinfofactory.cpp David Faure <faure@kde.org>
+ ksycoca.cpp David Faure <faure@kde.org>
+ ksycocadict.cpp David Faure <faure@kde.org>
+ ksycocaentry.cpp David Faure <faure@kde.org>
+ ksycocafactory.cpp David Faure <faure@kde.org>
+
+text/
+ kascii.cpp
+ kcodecs.cpp
+ kstringhandler.cpp
+
+util/
+ kallocator.cpp
+ kdedmodule.cpp
+ kde_file_win.cpp
+ kdeversion.cpp
+ klauncher_iface.cpp
+ klibloader.cpp
+ klibrary.cpp
+ kmacroexpander.cpp
+ kmacroexpander_unix.cpp
+ kmacroexpander_win.cpp
+ kpluginfactory.cpp
+ kpluginloader.cpp
+ krandom.cpp
+ krandomsequence.cpp
+ kshell.cpp Oswald Buddenhagen <ossi@kde.org> (copyright)
+ kshell_unix.cpp
+ kshell_win.cpp
+ kuser_unix.cpp
+ kuser_win.cpp
+ qtest_kde.cpp
+
+
+Orphan Files
+============
+These are files listed with maintainers in the old version of this file that
+no longer exist in kdecore. It is likely these were moved or deleted for KDE4.
+If you know the fate of these files, please move or delete as appropriate.
+
+akasyncio.cpp Thiago Macieira <thiago@kde.org>
+kapplication_win.cpp Jaroslaw Staniek <staniek@kde.org> (copyright)
+kbufferedio.cpp Thiago Macieira <thiago@kde.org>
+kcharsets.cpp Lars Knoll <knoll@kde.org>
+kcheckaccelerators.cpp Matthias Kalle Dalheimer (kalle@kde.org) (copyright)
+kclipboard.cpp Carsten Pfeiffer <pfeiffer@kde.org> (copyright)
+kcompletion.cpp Carsten Pfeiffer <pfeiffer@kde.org>
+kdebugdcopiface.cpp Andreas Beckermann (b_mann@gmx.de) (copyright)
+kextsock.cpp Thiago Macieira <thiago@kde.org>
+kglobalaccel_win.cpp Ellis Whitehead <ellis@kde.org> (copyright)
+kglobalaccel_x11.cpp Ellis Whitehead <ellis@kde.org>
+kglobalaccel.cpp Ellis Whitehead <ellis@kde.org>
+kinstance.cpp Stephan Kulow <coolo@kde.org>
+kmountpoint.cpp David Faure <faure@kde.org>
+kmultipledrag.cpp David Faure <faure@kde.org>
+kpixmapprovider.cpp Carsten Pfeiffer <pfeiffer@kde.org>
+kprotocolinfo_kdecore.cpp David Faure <faure@kde.org>
+kshortcut.cpp Ellis Whitehead <ellis@kde.org>
+kshortcutmenu.cpp Ellis Whitehead <ellis@kde.org> (copyright)
+ksock.cpp Thiago Macieira <thiago@kde.org>
+ksockaddr.cpp Thiago Macieira <thiago@kde.org>
+kstaticdeleter.cpp Stephan Kulow <coolo@kde.org>
+kstdaccel.cpp Ellis Whitehead <ellis@kde.org>
+kuser.cpp Tim Jansen <tim@tjansen.de> (copyright)
+libintl.cpp Hans Petter Bieker <bieker@kde.org>
diff --git a/kdecore/Mainpage.dox b/kdecore/Mainpage.dox
new file mode 100644
index 0000000..c149473
--- /dev/null
+++ b/kdecore/Mainpage.dox
@@ -0,0 +1,45 @@
+/** \mainpage The KDE Core Library
+
+All KDE programs use this library to provide basic functionality such
+as the configuration system, IPC, internationalization and locale
+support, site-independent access to the filesystem and a large number
+of other (but no less important) things.
+<p>
+All KDE applications should link to the kdecore library. Also, using a
+KApplication derived class instead of QApplication is almost
+mandatory if you expect your application to behave nicely within the
+KDE environment.
+
+If you are unsure where to start, have a look at the
+<a href="http://techbase.kde.org/Development/Tutorials">tutorials on
+TechBase</a> to get you going.
+
+If you know what you are looking for, you should be able to find it in
+the <a href="annotated.html">class list</a> or the
+<a href="modules.html">modules list</a>.
+
+@authors
+Various: see copyrights on individual files for more information
+
+@maintainers
+See the
+<a href="http://websvn.kde.org/trunk/KDE/kdelibs/kdecore/MAINTAINERS?view=markup">MAINTAINERS</a>
+file.
+
+@licenses
+Library: @lgpl<br>
+Some helper utilities: @gpl
+
+*/
+
+/**
+
+\defgroup KDEMacros KDE Macros
+
+*/
+
+// DOXYGEN_EXCLUDE = malloc kde_file.h
+// DOXYGEN_SET_INPUT += @topdir@/kdemacros.h.cmake
+// DOXYGEN_SET_INPUT += @topdir@/kdecore/util/kdeversion.h.cmake
+// DOXYGEN_SET_PROJECT_NAME = KDECore
+// vim:ts=4:sw=4:expandtab:filetype=doxygen
diff --git a/kdecore/README b/kdecore/README
new file mode 100644
index 0000000..c8036dc
--- /dev/null
+++ b/kdecore/README
@@ -0,0 +1,4 @@
+This is the KDE "core" library. The kdecore library provides basic non user
+interface functionality. The classes in this library should not require linkage
+to QtGui or any other library that requires a graphical interface.
+
diff --git a/kdecore/auth/AuthBackend.cpp b/kdecore/auth/AuthBackend.cpp
new file mode 100644
index 0000000..0ea9de8
--- /dev/null
+++ b/kdecore/auth/AuthBackend.cpp
@@ -0,0 +1,70 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "AuthBackend.h"
+
+namespace KAuth
+{
+
+class AuthBackend::Private
+{
+public:
+ Private() {}
+ virtual ~Private() {}
+
+ Capabilities capabilities;
+};
+
+AuthBackend::AuthBackend()
+ : QObject(0)
+ , d(new Private)
+{
+
+}
+
+AuthBackend::~AuthBackend()
+{
+}
+
+AuthBackend::Capabilities AuthBackend::capabilities() const
+{
+ return d->capabilities;
+}
+
+void AuthBackend::setCapabilities(AuthBackend::Capabilities capabilities)
+{
+ d->capabilities = capabilities;
+}
+
+bool AuthBackend::actionExists(const QString& action)
+{
+ Q_UNUSED(action);
+ return false;
+}
+
+void AuthBackend::preAuthAction(const QString& action, QWidget* parent)
+{
+ Q_UNUSED(action)
+ Q_UNUSED(parent)
+}
+
+} //namespace KAuth
+
+#include "AuthBackend.moc"
diff --git a/kdecore/auth/AuthBackend.h b/kdecore/auth/AuthBackend.h
new file mode 100644
index 0000000..a86732e
--- /dev/null
+++ b/kdecore/auth/AuthBackend.h
@@ -0,0 +1,74 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 AUTH_BACKEND_H
+#define AUTH_BACKEND_H
+
+#include <QObject>
+
+#include "kauthaction.h"
+
+namespace KAuth
+{
+
+class AuthBackend : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(AuthBackend)
+
+public:
+ enum Capability {
+ NoCapability = 0,
+ AuthorizeFromClientCapability = 1,
+ AuthorizeFromHelperCapability = 2,
+ CheckActionExistenceCapability = 4,
+ PreAuthActionCapability = 8
+ };
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
+ AuthBackend();
+ virtual ~AuthBackend();
+ virtual void setupAction(const QString &action) = 0;
+ virtual void preAuthAction(const QString &action, QWidget *parent);
+ virtual Action::AuthStatus authorizeAction(const QString &action) = 0;
+ virtual Action::AuthStatus actionStatus(const QString &action) = 0;
+ virtual QByteArray callerID() const = 0;
+ virtual bool isCallerAuthorized(const QString &action, QByteArray callerID) = 0;
+ virtual bool actionExists(const QString &action);
+
+ Capabilities capabilities() const;
+
+protected:
+ void setCapabilities(Capabilities capabilities);
+
+Q_SIGNALS:
+ void actionStatusChanged(const QString &action, Action::AuthStatus status);
+
+private:
+ class Private;
+ Private * const d;
+};
+
+} // namespace Auth
+
+Q_DECLARE_INTERFACE(KAuth::AuthBackend, "org.kde.auth.AuthBackend/0.1")
+Q_DECLARE_OPERATORS_FOR_FLAGS(KAuth::AuthBackend::Capabilities)
+
+#endif
diff --git a/kdecore/auth/BackendsConfig.h.cmake b/kdecore/auth/BackendsConfig.h.cmake
new file mode 100644
index 0000000..6033f13
--- /dev/null
+++ b/kdecore/auth/BackendsConfig.h.cmake
@@ -0,0 +1,9 @@
+#cmakedefine KAUTH_COMPILING_OSX_BACKEND 1
+#cmakedefine KAUTH_COMPILING_POLKITQT_BACKEND 1
+#cmakedefine KAUTH_COMPILING_POLKITQT1_BACKEND 1
+#cmakedefine KAUTH_COMPILING_FAKE_BACKEND 1
+#cmakedefine KAUTH_COMPILING_DBUS_HELPER_BACKEND 1
+#cmakedefine KAUTH_COMPILING_FAKE_HELPER_BACKEND 1
+#define KAUTH_BACKEND_PLUGIN_DIR "${KAUTH_BACKEND_PLUGIN_DIR}"
+#define KAUTH_HELPER_PLUGIN_DIR "${KAUTH_HELPER_PLUGIN_DIR}"
+#define KAUTH_OTHER_PLUGIN_DIR "${KAUTH_OTHER_PLUGIN_DIR}"
diff --git a/kdecore/auth/BackendsManager.cpp b/kdecore/auth/BackendsManager.cpp
new file mode 100644
index 0000000..1d69c31
--- /dev/null
+++ b/kdecore/auth/BackendsManager.cpp
@@ -0,0 +1,138 @@
+/*
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "BackendsManager.h"
+
+#include "BackendsConfig.h"
+
+// Include fake backends
+#include "backends/fake/FakeBackend.h"
+#include "backends/fakehelper/FakeHelperProxy.h"
+
+#include <QPluginLoader>
+#include <QDir>
+
+#include <kdebug.h>
+
+namespace KAuth
+{
+
+AuthBackend *BackendsManager::auth = 0;
+HelperProxy *BackendsManager::helper = 0;
+
+BackendsManager::BackendsManager()
+{
+}
+
+QList< QObject* > BackendsManager::retrieveInstancesIn(const QString& path)
+{
+ QDir pluginPath(path);
+
+ if (!pluginPath.exists()) {
+ return QList< QObject* >();
+ }
+
+ const QFileInfoList entryList = pluginPath.entryInfoList(QDir::NoDotAndDotDot | QDir::Files);
+
+ if (entryList.isEmpty()) {
+ return QList< QObject* >();
+ }
+
+ QList< QObject* > retlist;
+
+ foreach(const QFileInfo &fi, entryList) {
+ QString filePath = fi.filePath(); // file name with path
+ QString fileName = fi.fileName(); // just file name
+
+ if(!QLibrary::isLibrary(filePath)) {
+ continue;
+ }
+
+ QString errstr;
+ QPluginLoader loader(filePath);
+ QObject *instance = loader.instance();
+ if (instance) {
+ retlist.append(instance);
+ }
+ }
+
+ return retlist;
+}
+
+void BackendsManager::init()
+{
+ // Backend plugin
+ const QList< QObject* > backends = retrieveInstancesIn(QFile::decodeName(KAUTH_BACKEND_PLUGIN_DIR));
+
+ foreach (QObject *instance, backends) {
+ auth = qobject_cast< KAuth::AuthBackend* >(instance);
+ if (auth) {
+ break;
+ }
+ }
+
+ // Helper plugin
+ const QList< QObject* > helpers = retrieveInstancesIn(QFile::decodeName(KAUTH_HELPER_PLUGIN_DIR));
+
+ foreach (QObject *instance, helpers) {
+ helper = qobject_cast< KAuth::HelperProxy* >(instance);
+ if (helper) {
+ break;
+ }
+ }
+
+ if (!auth) {
+ // Load the fake auth backend then
+ auth = new FakeBackend;
+#ifndef KAUTH_COMPILING_FAKE_BACKEND
+ // Spit a fat warning
+ kWarning() << "WARNING: KAuth was compiled with a working backend, but was unable to load it! Check your installation!";
+#endif
+ }
+
+ if (!helper) {
+ // Load the fake helper backend then
+ helper = new FakeHelperProxy;
+#ifndef KAUTH_COMPILING_FAKE_BACKEND
+ // Spit a fat warning
+ kWarning() << "WARNING: KAuth was compiled with a working helper backend, but was unable to load it! "
+ "Check your installation!";
+#endif
+ }
+}
+
+AuthBackend *BackendsManager::authBackend()
+{
+ if (!auth) {
+ init();
+ }
+
+ return auth;
+}
+
+HelperProxy *BackendsManager::helperProxy()
+{
+ if (!helper) {
+ init();
+ }
+
+ return helper;
+}
+
+} // namespace Auth
diff --git a/kdecore/auth/BackendsManager.h b/kdecore/auth/BackendsManager.h
new file mode 100644
index 0000000..0f4f291
--- /dev/null
+++ b/kdecore/auth/BackendsManager.h
@@ -0,0 +1,48 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 BACKENDS_MANAGER_H
+#define BACKENDS_MANAGER_H
+
+#include "AuthBackend.h"
+#include "HelperProxy.h"
+#include <kdecore_export.h>
+
+namespace KAuth
+{
+
+class KDECORE_EXPORT BackendsManager
+{
+ static AuthBackend *auth;
+ static HelperProxy *helper;
+
+ BackendsManager();
+public:
+ static AuthBackend *authBackend();
+ static HelperProxy *helperProxy();
+
+private:
+ static void init();
+ static QList<QObject*> retrieveInstancesIn(const QString &path);
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/ConfigureChecks.cmake b/kdecore/auth/ConfigureChecks.cmake
new file mode 100644
index 0000000..ff17ff0
--- /dev/null
+++ b/kdecore/auth/ConfigureChecks.cmake
@@ -0,0 +1,233 @@
+####### checks for kdecore/kauth ###############
+
+set(KDE4_AUTH_BACKEND_NAME "" CACHE STRING "Specifies the KAuth backend to build. Current available options are
+ PolkitQt, PolkitQt-1, Fake, Apple. Not setting this variable will build the most
+ appropriate backend for your system")
+
+set(KAUTH_BACKEND ${KDE4_AUTH_BACKEND_NAME})
+
+## Check if the user did not specify a backend to be built. If that is the case,
+## we check what is the best backend to build on this system.
+if(NOT KAUTH_BACKEND)
+ # Look for the most appropriate backend
+ message(STATUS "No backend for KAuth was explicitly specified: probing system to find the best one available")
+ if (APPLE)
+ set (KAUTH_BACKEND "OSX")
+ elseif (UNIX)
+ macro_optional_find_package(PolkitQt-1 0.99.0)
+
+ if (POLKITQT-1_FOUND)
+ set (KAUTH_BACKEND "PolkitQt-1")
+ macro_log_feature(POLKITQT-1_FOUND "PolkitQt-1" "Support for executing priviledged actions in a controlled way (KAuth)" "http://techbase.kde.org/Polkit-Qt-1"
+ FALSE "" "STRONGLY RECOMMENDED")
+ else (POLKITQT-1_FOUND)
+ macro_optional_find_package(PolkitQt)
+
+ if (POLKITQT_FOUND)
+ set (KAUTH_BACKEND "PolkitQt")
+ macro_log_feature(POLKITQT_FOUND "PolkitQt" "Support for executing priviledged actions in a controlled way (KAuth)" "http://api.kde.org/polkit-qt"
+ FALSE "" "STRONGLY RECOMMENDED")
+ else (POLKITQT_FOUND)
+ # Nothing was found: notify and log the missing features
+ macro_log_feature(POLKITQT-1_FOUND "PolkitQt-1" "Support for executing priviledged actions in a controlled way (KAuth)" "http://techbase.kde.org/Polkit-Qt-1"
+ FALSE "" "STRONGLY RECOMMENDED: Either this or PolkitQt is required to make KAuth work, and hence enable certain workspace functionalities")
+ macro_log_feature(POLKITQT_FOUND "PolkitQt" "Support for executing priviledged actions in a controlled way (KAuth)" "http://api.kde.org/polkit-qt"
+ FALSE "" "STRONGLY RECOMMENDED: Either this or PolkitQt-1 is required to make KAuth work, and hence enable certain workspace functionalities")
+ set (KAUTH_BACKEND "Fake")
+ endif (POLKITQT_FOUND)
+ endif (POLKITQT-1_FOUND)
+ else(UNIX)
+ set (KAUTH_BACKEND "Fake")
+ endif(APPLE)
+
+ # Case-insensitive
+ string(TOUPPER ${KAUTH_BACKEND} KAUTH_BACKEND_UPPER)
+ set (KAUTH_BACKEND ${KAUTH_BACKEND_UPPER})
+else(NOT KAUTH_BACKEND)
+ # Case-insensitive
+ string(TOUPPER ${KAUTH_BACKEND} KAUTH_BACKEND_UPPER)
+ set (KAUTH_BACKEND ${KAUTH_BACKEND_UPPER})
+
+ # Check if the specified backend is valid. If it is not, we fall back to the Fake one
+ if (NOT KAUTH_BACKEND STREQUAL "OSX" AND NOT KAUTH_BACKEND STREQUAL "POLKITQT" AND NOT KAUTH_BACKEND STREQUAL "POLKITQT-1" AND NOT KAUTH_BACKEND STREQUAL "FAKE")
+ message ("WARNING: The KAuth Backend ${KAUTH_BACKEND} you specified does not exist. Falling back to Fake backend")
+ set (KAUTH_BACKEND "FAKE")
+ endif (NOT KAUTH_BACKEND STREQUAL "OSX" AND NOT KAUTH_BACKEND STREQUAL "POLKITQT" AND NOT KAUTH_BACKEND STREQUAL "POLKITQT-1" AND NOT KAUTH_BACKEND STREQUAL "FAKE")
+
+ # Check requirements for each backend. If not, fall back to the fake one
+ if (KAUTH_BACKEND STREQUAL "OSX" AND NOT APPLE)
+ message ("WARNING: You chose the Apple KAuth backend but your system does not support it. Falling back to Fake backend")
+ set (KAUTH_BACKEND "FAKE")
+ endif (KAUTH_BACKEND STREQUAL "OSX" AND NOT APPLE)
+ if (KAUTH_BACKEND STREQUAL "POLKITQT")
+ macro_optional_find_package(PolkitQt)
+ macro_log_feature(POLKITQT_FOUND "PolkitQt" "Support for executing priviledged actions in a controlled way (KAuth)" "http://api.kde.org/polkit-qt"
+ FALSE "" "STRONGLY RECOMMENDED: Required to make KAuth work, and hence enable certain workspace functionalities")
+
+ if (NOT POLKITQT_FOUND)
+ message ("WARNING: You chose the PolkitQt KAuth backend but you don't have PolkitQt installed.
+ Falling back to Fake backend")
+ set (KAUTH_BACKEND "FAKE")
+ endif (NOT POLKITQT_FOUND)
+ endif (KAUTH_BACKEND STREQUAL "POLKITQT")
+ if (KAUTH_BACKEND STREQUAL "POLKITQT-1")
+ macro_optional_find_package(PolkitQt-1 0.99.0)
+ macro_log_feature(POLKITQT-1_FOUND "PolkitQt-1" "Support for executing priviledged actions in a controlled way (KAuth)" "http://techbase.kde.org/Polkit-Qt-1"
+ FALSE "" "STRONGLY RECOMMENDED: Required to make KAuth work, and hence enable certain workspace functionalities")
+
+ if (NOT POLKITQT-1_FOUND)
+ message ("WARNING: You chose the PolkitQt-1 KAuth backend but you don't have PolkitQt-1 installed.
+ Falling back to Fake backend")
+ set (KAUTH_BACKEND "FAKE")
+ endif (NOT POLKITQT-1_FOUND)
+ endif (KAUTH_BACKEND STREQUAL "POLKITQT-1")
+endif(NOT KAUTH_BACKEND)
+
+set(KDE4_AUTH_BACKEND_NAME ${KAUTH_BACKEND} CACHE STRING "Specifies the KAuth backend to build. Current available options are
+ PolkitQt, PolkitQt-1, Fake, Apple. Not setting this variable will build the most
+ appropriate backend for your system" FORCE)
+
+# Add the correct libraries depending on the backend, and eventually set the policy files install location
+if(KDE4_AUTH_BACKEND_NAME STREQUAL "OSX")
+ set (KAUTH_COMPILING_OSX_BACKEND TRUE)
+
+ find_library(CORE_FOUNDATION_LIBRARY CoreFoundation)
+ find_library(SECURITY_LIBRARY Security)
+
+ message(STATUS "Building Apple KAuth backend")
+
+ set(KAUTH_BACKEND_SRCS
+ auth/backends/mac/AuthServicesBackend.cpp
+ )
+
+ set(KAUTH_BACKEND_LIBS ${SECURITY_LIBRARY} ${QT_QTCORE_LIBRARY})
+elseif(KDE4_AUTH_BACKEND_NAME STREQUAL "POLKITQT")
+ set (KAUTH_COMPILING_POLKITQT_BACKEND TRUE)
+
+ message(STATUS "Building PolkitQt KAuth backend")
+
+ include_directories(${POLKITQT_INCLUDE_DIR})
+
+ set(KAUTH_BACKEND_SRCS
+ auth/backends/policykit/PolicyKitBackend.cpp
+ )
+
+ set(KAUTH_BACKEND_LIBS ${POLKITQT_CORE_LIBRARY} ${QT_QTCORE_LIBRARY})
+
+ set(KDE4_AUTH_POLICY_FILES_INSTALL_DIR ${POLKITQT_POLICY_FILES_INSTALL_DIR} CACHE STRING
+ "Where policy files generated by KAuth will be installed" FORCE)
+elseif(KDE4_AUTH_BACKEND_NAME STREQUAL "POLKITQT-1")
+ set (KAUTH_COMPILING_POLKITQT1_BACKEND TRUE)
+
+ message(STATUS "Building PolkitQt-1 KAuth backend")
+
+ include_directories(${POLKITQT-1_INCLUDE_DIR})
+
+ set(KAUTH_BACKEND_SRCS
+ auth/backends/polkit-1/Polkit1Backend.cpp
+ )
+
+ set(KAUTH_BACKEND_LIBS ${POLKITQT-1_CORE_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTGUI_LIBRARY} kdecore)
+
+ if (Q_WS_X11)
+ # QtGui as well
+ set(KAUTH_BACKEND_LIBS ${KAUTH_BACKEND_LIBS} ${QT_QTGUI_LIBRARY})
+ endif (Q_WS_X11)
+
+ # POLKITQT-1_POLICY_FILES_INSTALL_DIR has an absolute pathname, fix that.
+ string(REPLACE ${POLKITQT-1_INSTALL_DIR}
+ ${CMAKE_INSTALL_PREFIX} _KDE4_AUTH_POLICY_FILES_INSTALL_DIR
+ ${POLKITQT-1_POLICY_FILES_INSTALL_DIR})
+
+ set(KDE4_AUTH_POLICY_FILES_INSTALL_DIR ${_KDE4_AUTH_POLICY_FILES_INSTALL_DIR} CACHE STRING
+ "Where policy files generated by KAuth will be installed" FORCE)
+elseif(KDE4_AUTH_BACKEND_NAME STREQUAL "FAKE")
+ set (KAUTH_COMPILING_FAKE_BACKEND TRUE)
+
+ message(STATUS "Building Fake KAuth backend")
+ message("WARNING: No valid KAuth backends will be built. The library will not work properly unless compiled with
+ a working backend")
+endif()
+
+# KAuth policy generator executable source probing
+set(KAUTH_POLICY_GEN_SRCS
+ auth/policy-gen/policy-gen.cpp )
+set(KAUTH_POLICY_GEN_LIBRARIES ${QT_QTCORE_LIBRARY})
+
+if(KDE4_AUTH_BACKEND_NAME STREQUAL "OSX")
+ set(KAUTH_POLICY_GEN_SRCS ${KAUTH_POLICY_GEN_SRCS}
+ auth/backends/mac/kauth-policy-gen-mac.cpp)
+ set(KAUTH_POLICY_GEN_LIBRARIES ${KAUTH_POLICY_GEN_LIBRARIES} ${CORE_FOUNDATION_LIBRARY} ${SECURITY_LIBRARY})
+elseif(KDE4_AUTH_BACKEND_NAME STREQUAL "POLKITQT")
+ set(KAUTH_POLICY_GEN_SRCS ${KAUTH_POLICY_GEN_SRCS}
+ auth/backends/policykit/kauth-policy-gen-polkit.cpp )
+elseif(KDE4_AUTH_BACKEND_NAME STREQUAL "POLKITQT-1")
+ set(KAUTH_POLICY_GEN_SRCS ${KAUTH_POLICY_GEN_SRCS}
+ auth/backends/polkit-1/kauth-policy-gen-polkit1.cpp )
+endif()
+
+########################
+# Helper backend probing
+
+set(KDE4_AUTH_HELPER_BACKEND_NAME "" CACHE STRING "Specifies the KAuth helper backend to build. Current available options are
+ DBus, Fake. Not setting this variable will build the most appropriate backend for your system")
+
+set(KAUTH_HELPER_BACKEND ${KDE4_AUTH_HELPER_BACKEND_NAME})
+
+if(NOT KAUTH_HELPER_BACKEND)
+ # No checks needed, just set the dbus backend
+ set(KAUTH_HELPER_BACKEND "DBus")
+ string(TOUPPER ${KAUTH_HELPER_BACKEND} KAUTH_HELPER_BACKEND_UPPER)
+ set (KAUTH_HELPER_BACKEND ${KAUTH_HELPER_BACKEND_UPPER})
+else(NOT KAUTH_HELPER_BACKEND)
+ # No checks needed here either
+ string(TOUPPER ${KAUTH_HELPER_BACKEND} KAUTH_HELPER_BACKEND_UPPER)
+ set (KAUTH_HELPER_BACKEND ${KAUTH_HELPER_BACKEND_UPPER})
+endif(NOT KAUTH_HELPER_BACKEND)
+
+set(KDE4_AUTH_HELPER_BACKEND_NAME ${KAUTH_HELPER_BACKEND} CACHE STRING "Specifies the KAuth helper backend to build. Current
+ available options are DBus, Fake. Not setting this variable will
+ build the most appropriate backend for your system" FORCE)
+
+# Add the correct libraries/files depending on the backend
+if(KDE4_AUTH_HELPER_BACKEND_NAME STREQUAL "DBUS")
+ set (KAUTH_COMPILING_DBUS_HELPER_BACKEND TRUE)
+
+ qt4_add_dbus_adaptor(kauth_dbus_adaptor_SRCS
+ auth/backends/dbus/org.kde.auth.xml
+ auth/backends/dbus/DBusHelperProxy.h
+ KAuth::DBusHelperProxy)
+
+ set(KAUTH_HELPER_BACKEND_SRCS
+ auth/backends/dbus/DBusHelperProxy.cpp
+ ${kauth_dbus_adaptor_SRCS}
+ )
+
+ set(KAUTH_HELPER_BACKEND_LIBS kdecore)
+
+ # Install some files as well
+ install( FILES auth/backends/dbus/org.kde.auth.conf
+ DESTINATION ${SYSCONF_INSTALL_DIR}/dbus-1/system.d )
+
+ install( FILES auth/backends/dbus/dbus_policy.stub
+ auth/backends/dbus/dbus_service.stub
+ DESTINATION ${DATA_INSTALL_DIR}/kauth COMPONENT Devel)
+elseif(KDE4_AUTH_HELPER_BACKEND_NAME STREQUAL "FAKE")
+ set (KAUTH_COMPILING_FAKE_HELPER_BACKEND TRUE)
+
+ message("WARNING: No valid KAuth helper backends will be built. The library will not work properly unless compiled with
+ a working backend")
+endif()
+
+
+# Set directories for plugins
+if(NOT WIN32)
+_set_fancy(KAUTH_HELPER_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}/plugins/kauth/helper" "Where KAuth's helper plugin will be installed")
+_set_fancy(KAUTH_BACKEND_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}/plugins/kauth/backend" "Where KAuth's backend plugin will be installed")
+#set(KAUTH_OTHER_PLUGIN_DIR "${QT_PLUGINS_DIR}/kauth/plugins")
+else(NOT WIN32)
+set(KAUTH_HELPER_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}/plugins/kauth/helper")
+set(KAUTH_BACKEND_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}/plugins/kauth/backend")
+endif(NOT WIN32)
+
+## End
diff --git a/kdecore/auth/HelperProxy.cpp b/kdecore/auth/HelperProxy.cpp
new file mode 100644
index 0000000..ba7c934
--- /dev/null
+++ b/kdecore/auth/HelperProxy.cpp
@@ -0,0 +1,28 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "HelperProxy.h"
+
+namespace KAuth
+{
+
+HelperProxy::~HelperProxy() {}
+
+} // namespace KAuth
diff --git a/kdecore/auth/HelperProxy.h b/kdecore/auth/HelperProxy.h
new file mode 100644
index 0000000..eda2ba6
--- /dev/null
+++ b/kdecore/auth/HelperProxy.h
@@ -0,0 +1,67 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 HELPER_PROXY_H
+#define HELPER_PROXY_H
+
+#include <QObject>
+#include <QMap>
+#include <QString>
+#include <QVariant>
+
+#include "kauthaction.h"
+#include "kauthactionreply.h"
+#include "kauthactionwatcher.h"
+
+namespace KAuth
+{
+
+class HelperProxy : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual ~HelperProxy();
+
+ // Application-side methods
+ virtual bool executeActions(const QList<QPair<QString, QVariantMap> > &list, const QString &helperID) = 0;
+ virtual ActionReply executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments) = 0;
+ virtual Action::AuthStatus authorizeAction(const QString &action, const QString &helperID) = 0;
+ virtual void stopAction(const QString &action, const QString &helperID) = 0;
+
+ // Helper-side methods
+ virtual bool initHelper(const QString &name) = 0;
+ virtual void setHelperResponder(QObject *o) = 0;
+ virtual bool hasToStopAction() = 0;
+ virtual void sendDebugMessage(int level, const char *msg) = 0;
+ virtual void sendProgressStep(int step) = 0;
+ virtual void sendProgressStep(const QVariantMap &step) = 0;
+
+signals:
+ void actionStarted(const QString &action);
+ void actionPerformed(const QString &action, ActionReply reply);
+ void progressStep(const QString &action, int progress);
+ void progressStep(const QString &action, const QVariantMap &data);
+};
+
+} // namespace KAuth
+
+Q_DECLARE_INTERFACE(KAuth::HelperProxy, "org.kde.auth.HelperProxy/0.1")
+
+#endif
diff --git a/kdecore/auth/TODO b/kdecore/auth/TODO
new file mode 100644
index 0000000..1f9a21c
--- /dev/null
+++ b/kdecore/auth/TODO
@@ -0,0 +1,6 @@
+Todo list for libkauth:
+- Add vendor name and icon to actions.ini
+- Add an option (either on build-time or at invocation time) to enable/disable the helper quit timeout.
+ This is useful for debugging.
+- Check with others on k-c-d if it's needed to add strings with error descriptions.
+- Stop requests must be action-specific instead of global
diff --git a/kdecore/auth/backends/dbus/DBusHelperProxy.cpp b/kdecore/auth/backends/dbus/DBusHelperProxy.cpp
new file mode 100644
index 0000000..d40b7e4
--- /dev/null
+++ b/kdecore/auth/backends/dbus/DBusHelperProxy.cpp
@@ -0,0 +1,405 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "DBusHelperProxy.h"
+
+#include <QtCore/qplugin.h>
+#include <QObject>
+#include <QMap>
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusConnection>
+#include <QDebug>
+#include <QTimer>
+
+#include <klocalizedstring.h>
+
+#include <syslog.h>
+
+#include "BackendsManager.h"
+#include "authadaptor.h"
+
+Q_DECLARE_METATYPE(QTimer*)
+
+namespace KAuth
+{
+
+static void debugMessageReceived(int t, const QString &message);
+
+void DBusHelperProxy::stopAction(const QString &action, const QString &helperID)
+{
+ QDBusMessage message;
+ message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("stopAction"));
+
+ QList<QVariant> args;
+ args << action;
+ message.setArguments(args);
+
+ QDBusConnection::systemBus().asyncCall(message);
+}
+
+bool DBusHelperProxy::executeActions(const QList<QPair<QString, QVariantMap> > &list, const QString &helperID)
+{
+ QByteArray blob;
+ QDataStream stream(&blob, QIODevice::WriteOnly);
+
+ stream << list;
+
+ QDBusConnection::systemBus().interface()->startService(helperID);
+
+ if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int,QString,QByteArray)))) {
+ return false;
+ }
+
+ QDBusMessage message;
+ message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performActions"));
+
+ QList<QVariant> args;
+ args << blob << BackendsManager::authBackend()->callerID();
+ message.setArguments(args);
+
+ QDBusPendingCall reply = QDBusConnection::systemBus().asyncCall(message); // This is a NO_REPLY method
+ if (reply.reply().type() == QDBusMessage::ErrorMessage) {
+ return false;
+ }
+
+ return true;
+}
+
+ActionReply DBusHelperProxy::executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments)
+{
+ if (!m_actionsInProgress.isEmpty()) {
+ return ActionReply::HelperBusyReply;
+ }
+
+ QByteArray blob;
+ QDataStream stream(&blob, QIODevice::WriteOnly);
+
+ stream << arguments;
+
+ QDBusConnection::systemBus().interface()->startService(helperID);
+
+ if (!QDBusConnection::systemBus().connect(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("remoteSignal"), this, SLOT(remoteSignalReceived(int,QString,QByteArray)))) {
+ ActionReply errorReply = ActionReply::DBusErrorReply;
+ errorReply.setErrorDescription(i18n("DBus Backend error: connection to helper failed. %1",
+ QDBusConnection::systemBus().lastError().message()));
+ return errorReply;
+ }
+
+ QDBusMessage message;
+ message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("performAction"));
+
+ QList<QVariant> args;
+ args << action << BackendsManager::authBackend()->callerID() << blob;
+ message.setArguments(args);
+
+ m_actionsInProgress.push_back(action);
+
+ QEventLoop e;
+ QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message);
+ QDBusPendingCallWatcher watcher(pendingCall, this);
+ connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit()));
+ e.exec();
+
+ QDBusMessage reply = pendingCall.reply();
+
+ if (reply.type() == QDBusMessage::ErrorMessage) {
+ ActionReply r = ActionReply::DBusErrorReply;
+ r.setErrorDescription(i18n("DBus Backend error: could not contact the helper. "
+ "Connection error: %1. Message error: %2", QDBusConnection::systemBus().lastError().message(),
+ reply.errorMessage()));
+ qDebug() << reply.errorMessage();
+
+ // The remote signal will never arrive: so let's erase the action from the list ourselves
+ m_actionsInProgress.removeOne(action);
+
+ return r;
+ }
+
+ if (reply.arguments().size() != 1) {
+ ActionReply errorReply = ActionReply::DBusErrorReply;
+ errorReply.setErrorDescription(i18n("DBus Backend error: received corrupt data from helper %1 %2",
+ reply.arguments().size(), QDBusConnection::systemBus().lastError().message()));
+
+ // The remote signal may never arrive: so let's erase the action from the list ourselves
+ m_actionsInProgress.removeOne(action);
+
+ return errorReply;
+ }
+
+ return ActionReply::deserialize(reply.arguments().first().toByteArray());
+}
+
+Action::AuthStatus DBusHelperProxy::authorizeAction(const QString& action, const QString& helperID)
+{
+ if (!m_actionsInProgress.isEmpty()) {
+ return Action::Error;
+ }
+
+ QDBusConnection::systemBus().interface()->startService(helperID);
+
+ QDBusMessage message;
+ message = QDBusMessage::createMethodCall(helperID, QLatin1String("/"), QLatin1String("org.kde.auth"), QLatin1String("authorizeAction"));
+
+ QList<QVariant> args;
+ args << action << BackendsManager::authBackend()->callerID();
+ message.setArguments(args);
+
+ m_actionsInProgress.push_back(action);
+
+ QEventLoop e;
+ QDBusPendingCall pendingCall = QDBusConnection::systemBus().asyncCall(message);
+ QDBusPendingCallWatcher watcher(pendingCall, this);
+ connect(&watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), &e, SLOT(quit()));
+ e.exec();
+
+ m_actionsInProgress.removeOne(action);
+
+ QDBusMessage reply = pendingCall.reply();
+
+ if (reply.type() == QDBusMessage::ErrorMessage || reply.arguments().size() != 1) {
+ return Action::Error;
+ }
+
+ return static_cast<Action::AuthStatus>(reply.arguments().first().toUInt());
+}
+
+bool DBusHelperProxy::initHelper(const QString &name)
+{
+ new AuthAdaptor(this);
+
+ if (!QDBusConnection::systemBus().registerService(name)) {
+ return false;
+ }
+
+ if (!QDBusConnection::systemBus().registerObject(QLatin1String("/"), this)) {
+ return false;
+ }
+
+ m_name = name;
+
+ return true;
+}
+
+void DBusHelperProxy::setHelperResponder(QObject *o)
+{
+ responder = o;
+}
+
+void DBusHelperProxy::remoteSignalReceived(int t, const QString &action, QByteArray blob)
+{
+ SignalType type = (SignalType)t;
+ QDataStream stream(&blob, QIODevice::ReadOnly);
+
+ if (type == ActionStarted) {
+ emit actionStarted(action);
+ } else if (type == ActionPerformed) {
+ ActionReply reply = ActionReply::deserialize(blob);
+
+ m_actionsInProgress.removeOne(action);
+ emit actionPerformed(action, reply);
+ } else if (type == DebugMessage) {
+ int level;
+ QString message;
+
+ stream >> level >> message;
+
+ debugMessageReceived(level, message);
+ } else if (type == ProgressStepIndicator) {
+ int step;
+ stream >> step;
+
+ emit progressStep(action, step);
+ } else if (type == ProgressStepData) {
+ QVariantMap data;
+ stream >> data;
+
+ emit progressStep(action, data);
+ }
+}
+
+void DBusHelperProxy::stopAction(const QString &action)
+{
+ Q_UNUSED(action)
+#ifdef __GNUC__
+#warning FIXME: The stop request should be action-specific rather than global
+#endif
+ m_stopRequest = true;
+}
+
+bool DBusHelperProxy::hasToStopAction()
+{
+ QEventLoop loop;
+ loop.processEvents(QEventLoop::AllEvents);
+
+ return m_stopRequest;
+}
+
+void DBusHelperProxy::performActions(QByteArray blob, const QByteArray &callerID)
+{
+ QDataStream stream(&blob, QIODevice::ReadOnly);
+ QList< QPair< QString, QVariantMap > > actions;
+
+ stream >> actions;
+
+ QList< QPair< QString, QVariantMap > >::const_iterator i = actions.constBegin();
+ while (i != actions.constEnd()) {
+ QByteArray blob;
+ QDataStream stream(&blob, QIODevice::WriteOnly);
+
+ stream << i->second;
+
+ performAction(i->first, callerID, blob);
+
+ i++;
+ }
+}
+
+QByteArray DBusHelperProxy::performAction(const QString &action, const QByteArray &callerID, QByteArray arguments)
+{
+ if (!responder) {
+ return ActionReply::NoResponderReply.serialized();
+ }
+
+ if (!m_currentAction.isEmpty()) {
+ return ActionReply::HelperBusyReply.serialized();
+ }
+
+ QVariantMap args;
+ QDataStream s(&arguments, QIODevice::ReadOnly);
+ s >> args;
+
+ m_currentAction = action;
+ emit remoteSignal(ActionStarted, action, QByteArray());
+ QEventLoop e;
+ e.processEvents(QEventLoop::AllEvents);
+
+ ActionReply retVal;
+
+ QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
+ timer->stop();
+
+ if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) {
+ QString slotname = action;
+ if (slotname.startsWith(m_name + QLatin1Char('.'))) {
+ slotname = slotname.right(slotname.length() - m_name.length() - 1);
+ }
+
+ slotname.replace(QLatin1Char('.'), QLatin1Char('_'));
+
+ bool success = QMetaObject::invokeMethod(responder, slotname.toAscii(), Qt::DirectConnection,
+ Q_RETURN_ARG(ActionReply, retVal), Q_ARG(QVariantMap, args));
+
+ if (!success) {
+ retVal = ActionReply::NoSuchActionReply;
+ }
+
+ } else {
+ retVal = ActionReply::AuthorizationDeniedReply;
+ }
+
+ timer->start();
+
+ emit remoteSignal(ActionPerformed, action, retVal.serialized());
+ e.processEvents(QEventLoop::AllEvents);
+ m_currentAction.clear();
+ m_stopRequest = false;
+
+ return retVal.serialized();
+}
+
+
+uint DBusHelperProxy::authorizeAction(const QString& action, const QByteArray& callerID)
+{
+ if (!m_currentAction.isEmpty()) {
+ return static_cast<uint>(Action::Error);
+ }
+
+ m_currentAction = action;
+
+ uint retVal;
+
+ QTimer *timer = responder->property("__KAuth_Helper_Shutdown_Timer").value<QTimer*>();
+ timer->stop();
+
+ if (BackendsManager::authBackend()->isCallerAuthorized(action, callerID)) {
+ retVal = static_cast<uint>(Action::Authorized);
+ } else {
+ retVal = static_cast<uint>(Action::Denied);
+ }
+
+ timer->start();
+ m_currentAction.clear();
+
+ return retVal;
+}
+
+
+void DBusHelperProxy::sendDebugMessage(int level, const char *msg)
+{
+ QByteArray blob;
+ QDataStream stream(&blob, QIODevice::WriteOnly);
+
+ stream << level << QString::fromLocal8Bit(msg);
+
+ emit remoteSignal(DebugMessage, m_currentAction, blob);
+}
+
+void DBusHelperProxy::sendProgressStep(int step)
+{
+ QByteArray blob;
+ QDataStream stream(&blob, QIODevice::WriteOnly);
+
+ stream << step;
+
+ emit remoteSignal(ProgressStepIndicator, m_currentAction, blob);
+}
+
+void DBusHelperProxy::sendProgressStep(const QVariantMap &data)
+{
+ QByteArray blob;
+ QDataStream stream(&blob, QIODevice::WriteOnly);
+
+ stream << data;
+
+ emit remoteSignal(ProgressStepData, m_currentAction, blob);
+}
+
+void debugMessageReceived(int t, const QString &message)
+{
+ QtMsgType type = (QtMsgType)t;
+ switch (type) {
+ case QtDebugMsg:
+ qDebug("Debug message from helper: %s", message.toAscii().data());
+ break;
+ case QtWarningMsg:
+ qWarning("Warning from helper: %s", message.toAscii().data());
+ break;
+ case QtCriticalMsg:
+ qCritical("Critical warning from helper: %s", message.toAscii().data());
+ break;
+ case QtFatalMsg:
+ qFatal("Fatal error from helper: %s", message.toAscii().data());
+ break;
+ }
+}
+
+} // namespace Auth
+
+Q_EXPORT_PLUGIN2(kauth_helper_backend, KAuth::DBusHelperProxy)
diff --git a/kdecore/auth/backends/dbus/DBusHelperProxy.h b/kdecore/auth/backends/dbus/DBusHelperProxy.h
new file mode 100644
index 0000000..455cf51
--- /dev/null
+++ b/kdecore/auth/backends/dbus/DBusHelperProxy.h
@@ -0,0 +1,80 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 DBUS_HELPER_PROXY_H
+#define DBUS_HELPER_PROXY_H
+
+#include <QVariant>
+#include "HelperProxy.h"
+#include "kauthactionreply.h"
+
+namespace KAuth
+{
+
+class DBusHelperProxy : public HelperProxy
+{
+ Q_OBJECT
+ Q_INTERFACES(KAuth::HelperProxy)
+
+ QObject *responder;
+ QString m_name;
+ QString m_currentAction;
+ bool m_stopRequest;
+ QList<QString> m_actionsInProgress;
+
+ enum SignalType {
+ ActionStarted, // The blob argument is empty
+ ActionPerformed, // The blob argument contains the ActionReply
+ DebugMessage, // The blob argument contains the debug level and the message (in this order)
+ ProgressStepIndicator, // The blob argument contains the step indicator
+ ProgressStepData // The blob argument contains the QVariantMap
+ };
+
+public:
+ DBusHelperProxy() : responder(0), m_stopRequest(false) {}
+
+ virtual bool executeActions(const QList<QPair<QString, QVariantMap> > &list, const QString &helperID);
+ virtual ActionReply executeAction(const QString &action, const QString &helperID, const QVariantMap &arguments);
+ virtual Action::AuthStatus authorizeAction(const QString& action, const QString& helperID);
+ virtual void stopAction(const QString &action, const QString &helperID);
+
+ virtual bool initHelper(const QString &name);
+ virtual void setHelperResponder(QObject *o);
+ virtual bool hasToStopAction();
+ virtual void sendDebugMessage(int level, const char *msg);
+ virtual void sendProgressStep(int step);
+ virtual void sendProgressStep(const QVariantMap &data);
+
+public slots:
+ void stopAction(const QString &action);
+ void performActions(QByteArray blob, const QByteArray &callerID);
+ QByteArray performAction(const QString &action, const QByteArray &callerID, QByteArray arguments);
+ uint authorizeAction(const QString &action, const QByteArray &callerID);
+
+signals:
+ void remoteSignal(int type, const QString &action, const QByteArray &blob); // This signal is sent from the helper to the app
+
+private slots:
+ void remoteSignalReceived(int type, const QString &action, QByteArray blob);
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/backends/dbus/dbus_policy.stub b/kdecore/auth/backends/dbus/dbus_policy.stub
new file mode 100644
index 0000000..329a789
--- /dev/null
+++ b/kdecore/auth/backends/dbus/dbus_policy.stub
@@ -0,0 +1,11 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- Only user root can own the foo helper -->
+ <policy user="@HELPER_USER@">
+ <allow own="@HELPER_ID@"/>
+ </policy>
+
+</busconfig>
diff --git a/kdecore/auth/backends/dbus/dbus_service.stub b/kdecore/auth/backends/dbus/dbus_service.stub
new file mode 100644
index 0000000..e5f3c66
--- /dev/null
+++ b/kdecore/auth/backends/dbus/dbus_service.stub
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=@HELPER_ID@
+Exec=@LIBEXEC_INSTALL_DIR@/@HELPER_TARGET@
+User=@HELPER_USER@ \ No newline at end of file
diff --git a/kdecore/auth/backends/dbus/org.kde.auth.conf b/kdecore/auth/backends/dbus/org.kde.auth.conf
new file mode 100644
index 0000000..c1f2cad
--- /dev/null
+++ b/kdecore/auth/backends/dbus/org.kde.auth.conf
@@ -0,0 +1,13 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+<!-- Allow anyone to call into the service - we'll reject callers using PolicyKit -->
+ <policy context="default">
+ <allow send_interface="org.kde.auth"/>
+ <allow receive_sender="org.kde.auth"/>
+ <allow receive_interface="org.kde.auth"/>
+ </policy>
+
+</busconfig>
diff --git a/kdecore/auth/backends/dbus/org.kde.auth.xml b/kdecore/auth/backends/dbus/org.kde.auth.xml
new file mode 100644
index 0000000..575f6e5
--- /dev/null
+++ b/kdecore/auth/backends/dbus/org.kde.auth.xml
@@ -0,0 +1,30 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.kde.auth">
+ <method name="performAction" >
+ <arg name="action" type="s" direction="in" />
+ <arg name="callerID" type="ay" direction="in" />
+ <arg name="arguments" type="ay" direction="in" />
+ <arg name="r" type="ay" direction="out" />
+ </method>
+ <method name="authorizeAction" >
+ <arg name="action" type="s" direction="in" />
+ <arg name="callerID" type="ay" direction="in" />
+ <arg name="r" type="u" direction="out" />
+ </method>
+ <method name="performActions" >
+ <arg name="blob" type="ay" direction="in" />
+ <arg name="callerID" type="ay" direction="in" />
+ <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
+ </method>
+ <method name="stopAction" >
+ <arg name="action" type="s" direction="in" />
+ <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
+ </method>
+ <signal name="remoteSignal" >
+ <arg name="type" type="i" />
+ <arg name="action" type="s" />
+ <arg name="blob" type="ay" />
+ </signal>
+ </interface>
+</node> \ No newline at end of file
diff --git a/kdecore/auth/backends/fake/FakeBackend.cpp b/kdecore/auth/backends/fake/FakeBackend.cpp
new file mode 100644
index 0000000..6b18216
--- /dev/null
+++ b/kdecore/auth/backends/fake/FakeBackend.cpp
@@ -0,0 +1,60 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "FakeBackend.h"
+
+namespace KAuth
+{
+
+FakeBackend::FakeBackend()
+ : AuthBackend()
+{
+ setCapabilities(NoCapability);
+}
+
+Action::AuthStatus FakeBackend::authorizeAction(const QString &action)
+{
+ Q_UNUSED(action)
+ return Action::Denied;
+}
+
+void FakeBackend::setupAction(const QString &action)
+{
+ Q_UNUSED(action)
+}
+
+Action::AuthStatus FakeBackend::actionStatus(const QString &action)
+{
+ Q_UNUSED(action)
+ return Action::Denied;
+}
+
+QByteArray FakeBackend::callerID() const
+{
+ return QByteArray();
+}
+
+bool FakeBackend::isCallerAuthorized(const QString &action, QByteArray callerID)
+{
+ Q_UNUSED(action)
+ Q_UNUSED(callerID)
+ return false;
+}
+
+} // namespace Auth
diff --git a/kdecore/auth/backends/fake/FakeBackend.h b/kdecore/auth/backends/fake/FakeBackend.h
new file mode 100644
index 0000000..c475efa
--- /dev/null
+++ b/kdecore/auth/backends/fake/FakeBackend.h
@@ -0,0 +1,47 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 FAKE_BACKEND_H
+#define FAKE_BACKEND_H
+
+#include "AuthBackend.h"
+#include <QHash>
+
+class QByteArray;
+
+namespace KAuth
+{
+
+class FakeBackend : public AuthBackend
+{
+ Q_OBJECT
+ Q_INTERFACES(KAuth::AuthBackend)
+
+public:
+ FakeBackend();
+ virtual void setupAction(const QString&);
+ virtual Action::AuthStatus authorizeAction(const QString&);
+ virtual Action::AuthStatus actionStatus(const QString&);
+ virtual QByteArray callerID() const;
+ virtual bool isCallerAuthorized(const QString &action, QByteArray callerID);
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/backends/fake/kauth-policy-gen-polkit.cpp b/kdecore/auth/backends/fake/kauth-policy-gen-polkit.cpp
new file mode 100644
index 0000000..7e3b493
--- /dev/null
+++ b/kdecore/auth/backends/fake/kauth-policy-gen-polkit.cpp
@@ -0,0 +1,77 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 <auth/policy-gen/policy-gen.h>
+
+#include <cstdio>
+#include <QDebug>
+#include <QTextStream>
+
+const char header[] = ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<!DOCTYPE policyconfig PUBLIC\n"
+ "\"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd\">\n"
+ "<policyconfig>\n";
+
+const char policy_tag[] = ""
+ " <defaults>\n"
+ " <allow_inactive>no</allow_inactive>\n"
+ " <allow_active>%1</allow_active>\n"
+ " </defaults>\n";
+
+const char dent[] = " ";
+
+void output(QList<Action> actions, QHash<QString, QString> domain)
+{
+ Q_UNUSED(domain)
+
+ QTextStream out(stdout);
+ out.setCodec("UTF-8");
+
+ out << header;
+
+ foreach(const Action &action, actions) {
+ out << dent << "<action id=\"" << action.name << "\" >\n";
+
+ foreach(const QString& lang, action.descriptions.keys()) {
+ out << dent << dent << "<description";
+ if (lang != "en")
+ out << " xml:lang=\"" << lang << '"';
+ out << '>' << action.messages.value(lang) << "</description>\n";
+ }
+
+ foreach(const QString& lang, action.messages.keys()) {
+ out << dent << dent << "<message";
+ if (lang != "en")
+ out << " xml:lang=\"" << lang << '"';
+ out << '>' << action.descriptions.value(lang) << "</message>\n";
+ }
+
+ QString policy = action.policy;
+ if (!action.persistence.isEmpty())
+ policy += "_keep_" + action.persistence;
+
+ out << QString(policy_tag).arg(policy);
+
+ out << dent << "</action>\n";
+ }
+
+ out << "</policyconfig>\n";
+}
diff --git a/kdecore/auth/backends/fakehelper/FakeHelperProxy.cpp b/kdecore/auth/backends/fakehelper/FakeHelperProxy.cpp
new file mode 100644
index 0000000..595f6d6
--- /dev/null
+++ b/kdecore/auth/backends/fakehelper/FakeHelperProxy.cpp
@@ -0,0 +1,97 @@
+/*
+* Copyright (C) 2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "FakeHelperProxy.h"
+
+namespace KAuth {
+
+FakeHelperProxy::FakeHelperProxy()
+ : HelperProxy()
+{
+
+}
+
+FakeHelperProxy::~FakeHelperProxy()
+{
+
+}
+
+void FakeHelperProxy::sendProgressStep(const QVariantMap& step)
+{
+ Q_UNUSED(step)
+}
+
+void FakeHelperProxy::sendProgressStep(int step)
+{
+ Q_UNUSED(step)
+}
+
+void FakeHelperProxy::sendDebugMessage(int level, const char* msg)
+{
+ Q_UNUSED(level)
+ Q_UNUSED(msg)
+}
+
+bool FakeHelperProxy::hasToStopAction()
+{
+ return false;
+}
+
+void FakeHelperProxy::setHelperResponder(QObject* o)
+{
+ Q_UNUSED(o)
+}
+
+bool FakeHelperProxy::initHelper(const QString& name)
+{
+ Q_UNUSED(name)
+ return false;
+}
+
+void FakeHelperProxy::stopAction(const QString& action, const QString& helperID)
+{
+ Q_UNUSED(action)
+ Q_UNUSED(helperID)
+}
+
+KAuth::ActionReply FakeHelperProxy::executeAction(const QString& action, const QString& helperID, const QVariantMap& arguments)
+{
+ Q_UNUSED(action)
+ Q_UNUSED(helperID)
+ Q_UNUSED(arguments)
+ return KAuth::ActionReply::NoSuchActionReply;
+}
+
+bool FakeHelperProxy::executeActions(const QList< QPair< QString, QVariantMap > >& list, const QString& helperID)
+{
+ Q_UNUSED(list)
+ Q_UNUSED(helperID)
+ return false;
+}
+
+Action::AuthStatus FakeHelperProxy::authorizeAction(const QString& action, const QString& helperID)
+{
+ Q_UNUSED(action)
+ Q_UNUSED(helperID)
+ return Action::Denied;
+}
+
+}
+
+#include "FakeHelperProxy.moc"
diff --git a/kdecore/auth/backends/fakehelper/FakeHelperProxy.h b/kdecore/auth/backends/fakehelper/FakeHelperProxy.h
new file mode 100644
index 0000000..b3d5896
--- /dev/null
+++ b/kdecore/auth/backends/fakehelper/FakeHelperProxy.h
@@ -0,0 +1,50 @@
+/*
+* Copyright (C) 2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 FAKEHELPERPROXY_H
+#define FAKEHELPERPROXY_H
+
+#include "HelperProxy.h"
+
+namespace KAuth {
+
+class FakeHelperProxy : public HelperProxy
+{
+ Q_OBJECT
+ Q_INTERFACES(KAuth::HelperProxy)
+
+ public:
+ FakeHelperProxy();
+ virtual ~FakeHelperProxy();
+
+ virtual void sendProgressStep(const QVariantMap& step);
+ virtual void sendProgressStep(int step);
+ virtual void sendDebugMessage(int level, const char* msg);
+ virtual bool hasToStopAction();
+ virtual void setHelperResponder(QObject* o);
+ virtual bool initHelper(const QString& name);
+ virtual void stopAction(const QString& action, const QString& helperID);
+ virtual ActionReply executeAction(const QString& action, const QString& helperID, const QVariantMap& arguments);
+ virtual bool executeActions(const QList< QPair< QString, QVariantMap > >& list, const QString& helperID);
+ virtual Action::AuthStatus authorizeAction(const QString& action, const QString& helperID);
+};
+
+}
+
+#endif // FAKEHELPERPROXY_H
diff --git a/kdecore/auth/backends/mac/AuthServicesBackend.cpp b/kdecore/auth/backends/mac/AuthServicesBackend.cpp
new file mode 100644
index 0000000..56ef114
--- /dev/null
+++ b/kdecore/auth/backends/mac/AuthServicesBackend.cpp
@@ -0,0 +1,137 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "AuthServicesBackend.h"
+#include <Security/Security.h>
+
+#include <QtCore/qplugin.h>
+
+namespace KAuth
+{
+
+static AuthorizationRef s_authRef = NULL;
+
+AuthorizationRef authRef();
+
+AuthorizationRef authRef()
+{
+ if (!s_authRef) {
+ AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &s_authRef);
+ }
+
+ return s_authRef;
+}
+
+AuthServicesBackend::AuthServicesBackend()
+ : AuthBackend()
+{
+ setCapabilities(AuthorizeFromHelperCapability | CheckActionExistenceCapability);
+}
+
+void AuthServicesBackend::setupAction(const QString&)
+{
+ // Nothing to do here...
+}
+
+// On OS X, the suggestion is to make the helper grant the actual privilege. The app does instead a
+// "pre-authorization", that's equivalent to look at isCallerAuthorized() in policykit.
+Action::AuthStatus AuthServicesBackend::authorizeAction(const QString &action)
+{
+ return actionStatus(action);
+}
+
+Action::AuthStatus AuthServicesBackend::actionStatus(const QString &action)
+{
+ AuthorizationItem item;
+ item.name = action.toUtf8();
+ item.valueLength = 0;
+ item.value = NULL;
+ item.flags = 0;
+
+ AuthorizationRights rights;
+ rights.count = 1;
+ rights.items = &item;
+
+ OSStatus result = AuthorizationCopyRights(authRef(),
+ &rights,
+ kAuthorizationEmptyEnvironment,
+ kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize,
+ NULL);
+
+ switch (result) {
+ case errAuthorizationSuccess:
+ return Action::Authorized;
+ case errAuthorizationInteractionNotAllowed:
+ return Action::AuthRequired;
+ default:
+ return Action::Denied;
+ }
+}
+
+QByteArray AuthServicesBackend::callerID() const
+{
+ AuthorizationExternalForm ext;
+ AuthorizationMakeExternalForm(authRef(), &ext);
+
+ QByteArray id((const char *)&ext, sizeof(ext));
+
+ return id;
+}
+
+bool AuthServicesBackend::isCallerAuthorized(const QString &action, QByteArray callerID)
+{
+ AuthorizationExternalForm ext;
+ memcpy(&ext, callerID.data(), sizeof(ext));
+
+ AuthorizationRef auth;
+
+ if (AuthorizationCreateFromExternalForm(&ext, &auth) != noErr)
+ return false;
+
+ AuthorizationItem item;
+ item.name = action.toUtf8();
+ item.valueLength = 0;
+ item.value = NULL;
+ item.flags = 0;
+
+ AuthorizationRights rights;
+ rights.count = 1;
+ rights.items = &item;
+
+ OSStatus result = AuthorizationCopyRights(auth,
+ &rights,
+ kAuthorizationEmptyEnvironment,
+ kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed,
+ NULL);
+
+ AuthorizationFree(auth, kAuthorizationFlagDefaults);
+
+ return result == errAuthorizationSuccess;
+}
+
+bool AuthServicesBackend::actionExists(const QString& action)
+{
+ OSStatus exists = AuthorizationRightGet(action.toUtf8(), NULL);
+
+ return exists == errAuthorizationSuccess;
+}
+
+}; // namespace KAuth
+
+Q_EXPORT_PLUGIN2(kauth_backend, KAuth::AuthServicesBackend)
diff --git a/kdecore/auth/backends/mac/AuthServicesBackend.h b/kdecore/auth/backends/mac/AuthServicesBackend.h
new file mode 100644
index 0000000..ad30296
--- /dev/null
+++ b/kdecore/auth/backends/mac/AuthServicesBackend.h
@@ -0,0 +1,46 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 AUTHSERVICES_BACKEND_H
+#define AUTHSERVICES_BACKEND_H
+
+#include "AuthBackend.h"
+
+namespace KAuth
+{
+
+class AuthServicesBackend : public AuthBackend
+{
+ Q_OBJECT
+ Q_INTERFACES(KAuth::AuthBackend)
+
+public:
+ AuthServicesBackend();
+ virtual void setupAction(const QString&);
+ virtual Action::AuthStatus authorizeAction(const QString&);
+ virtual Action::AuthStatus actionStatus(const QString&);
+ virtual QByteArray callerID() const;
+ virtual bool isCallerAuthorized(const QString &action, QByteArray callerID);
+ virtual bool actionExists(const QString& action);
+};
+
+} // namespace KAuth
+
+#endif
+
diff --git a/kdecore/auth/backends/mac/kauth-policy-gen-mac.cpp b/kdecore/auth/backends/mac/kauth-policy-gen-mac.cpp
new file mode 100644
index 0000000..9ab8cc6
--- /dev/null
+++ b/kdecore/auth/backends/mac/kauth-policy-gen-mac.cpp
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 <auth/policy-gen/policy-gen.h>
+
+#include <iostream>
+#include <Security/Security.h>
+
+using namespace std;
+
+void output(QList<Action> actions, QHash<QString, QString> domain)
+{
+ AuthorizationRef auth;
+ AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &auth);
+
+ OSStatus err;
+
+ foreach(const Action &action, actions) {
+
+ err = AuthorizationRightGet(action.name.toAscii(), NULL);
+
+ if (err == errAuthorizationDenied) {
+
+ QString rule;
+
+ if (action.policy == QLatin1String("yes"))
+ rule = QString::fromLatin1(kAuthorizationRuleClassAllow);
+ else if (action.policy == QLatin1String("no"))
+ rule = QString::fromLatin1(kAuthorizationRuleClassDeny);
+ else if (action.policy == QLatin1String("auth_self"))
+ rule = QString::fromLatin1(kAuthorizationRuleAuthenticateAsSessionUser);
+ else if (action.policy == QLatin1String("auth_admin"))
+ rule = QString::fromLatin1(kAuthorizationRuleAuthenticateAsAdmin);
+
+ CFStringRef cfRule = CFStringCreateWithCString(NULL, rule.toAscii(), kCFStringEncodingASCII);
+ CFStringRef cfPrompt = CFStringCreateWithCString(NULL, action.descriptions.value(QLatin1String("en")).toAscii(), kCFStringEncodingASCII);
+
+ err = AuthorizationRightSet(auth, action.name.toAscii(), cfRule, cfPrompt, NULL, NULL);
+ if (err != noErr) {
+ cerr << "You don't have the right to edit the security database (try to run cmake with sudo): " << err << endl;
+ exit(1);
+ }
+ }
+ }
+}
diff --git a/kdecore/auth/backends/policykit/PolicyKitBackend.cpp b/kdecore/auth/backends/policykit/PolicyKitBackend.cpp
new file mode 100644
index 0000000..3be97f2
--- /dev/null
+++ b/kdecore/auth/backends/policykit/PolicyKitBackend.cpp
@@ -0,0 +1,104 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "PolicyKitBackend.h"
+
+#include <QtCore/qplugin.h>
+#include <syslog.h>
+#include <polkit-qt/context.h>
+#include <polkit-qt/auth.h>
+
+namespace KAuth
+{
+
+PolicyKitBackend::PolicyKitBackend()
+ : AuthBackend()
+{
+ setCapabilities(AuthorizeFromClientCapability);
+}
+
+Action::AuthStatus PolicyKitBackend::authorizeAction(const QString &action)
+{
+ switch (PolkitQt::Auth::computeAndObtainAuth(action)) {
+ case PolkitQt::Auth::Yes:
+ return Action::Authorized;
+ default:
+ return Action::Denied;
+ }
+}
+
+void PolicyKitBackend::setupAction(const QString &action)
+{
+ connect(PolkitQt::Context::instance(), SIGNAL(configChanged()),
+ this, SLOT(checkForResultChanged()));
+ connect(PolkitQt::Context::instance(), SIGNAL(consoleKitDBChanged()),
+ this, SLOT(checkForResultChanged()));
+
+ m_cachedResults[action] = actionStatus(action);
+}
+
+Action::AuthStatus PolicyKitBackend::actionStatus(const QString &action)
+{
+ PolkitQt::Auth::Result r = PolkitQt::Auth::isCallerAuthorized(action, QCoreApplication::applicationPid(),
+ false);
+ switch (r) {
+ case PolkitQt::Auth::Yes:
+ return Action::Authorized;
+ case PolkitQt::Auth::No:
+ case PolkitQt::Auth::Unknown:
+ return Action::Denied;
+ default:
+ return Action::AuthRequired;
+ }
+}
+
+QByteArray PolicyKitBackend::callerID() const
+{
+ QByteArray a;
+ QDataStream s(&a, QIODevice::WriteOnly);
+ s << QCoreApplication::applicationPid();
+
+ return a;
+}
+
+bool PolicyKitBackend::isCallerAuthorized(const QString &action, QByteArray callerID)
+{
+ QDataStream s(&callerID, QIODevice::ReadOnly);
+ qint64 pid;
+
+ s >> pid;
+
+ return (PolkitQt::Auth::isCallerAuthorized(action, pid, false) == PolkitQt::Auth::Yes);
+}
+
+void PolicyKitBackend::checkForResultChanged()
+{
+ QHash<QString, Action::AuthStatus>::iterator i;
+ for (i = m_cachedResults.begin(); i != m_cachedResults.end(); ++i) {
+ if (i.value() != actionStatus(i.key())) {
+ i.value() = actionStatus(i.key());
+ emit actionStatusChanged(i.key(), i.value());
+ }
+ }
+}
+
+} // namespace Auth
+
+Q_EXPORT_PLUGIN2(kauth_backend, KAuth::PolicyKitBackend)
diff --git a/kdecore/auth/backends/policykit/PolicyKitBackend.h b/kdecore/auth/backends/policykit/PolicyKitBackend.h
new file mode 100644
index 0000000..7154e93
--- /dev/null
+++ b/kdecore/auth/backends/policykit/PolicyKitBackend.h
@@ -0,0 +1,54 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 POLICYKIT_BACKEND_H
+#define POLICYKIT_BACKEND_H
+
+#include "AuthBackend.h"
+#include <QHash>
+
+class QByteArray;
+
+namespace KAuth
+{
+
+class PolicyKitBackend : public AuthBackend
+{
+ Q_OBJECT
+ Q_INTERFACES(KAuth::AuthBackend)
+
+public:
+ PolicyKitBackend();
+ virtual void setupAction(const QString&);
+ virtual Action::AuthStatus authorizeAction(const QString&);
+ virtual Action::AuthStatus actionStatus(const QString&);
+ virtual QByteArray callerID() const;
+ virtual bool isCallerAuthorized(const QString &action, QByteArray callerID);
+
+private Q_SLOTS:
+ void checkForResultChanged();
+
+private:
+ QHash<QString, Action::AuthStatus> m_cachedResults;
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/backends/policykit/kauth-policy-gen-polkit.cpp b/kdecore/auth/backends/policykit/kauth-policy-gen-polkit.cpp
new file mode 100644
index 0000000..e522534
--- /dev/null
+++ b/kdecore/auth/backends/policykit/kauth-policy-gen-polkit.cpp
@@ -0,0 +1,119 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 <auth/policy-gen/policy-gen.h>
+
+#include <cstdio>
+#include <QDebug>
+#include <QTextStream>
+
+const char header[] = ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<!DOCTYPE policyconfig PUBLIC\n"
+ "\"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd\">\n"
+ "<policyconfig>\n";
+
+const char policy_tag[] = ""
+ " <defaults>\n"
+ " <allow_inactive>%1</allow_inactive>\n"
+ " <allow_active>%2</allow_active>\n"
+ " </defaults>\n";
+
+const char dent[] = " ";
+
+void output(QList<Action> actions, QHash<QString, QString> domain)
+{
+ QTextStream out(stdout);
+ out.setCodec("UTF-8");
+
+ out << header;
+
+ // Blacklisted characters + replacements
+ QHash< QChar, QString > blacklist;
+ blacklist.insert(QChar::fromLatin1('&'), QString::fromLatin1("&amp;"));
+
+ if (domain.contains(QLatin1String("vendor"))) {
+ QHash< QChar, QString >::const_iterator blI;
+ QString vendor = domain[QLatin1String("vendor")];
+ for (blI = blacklist.constBegin(); blI != blacklist.constEnd(); ++blI) {
+ vendor.replace(blI.key(), blI.value());
+ }
+ out << "<vendor>" << vendor << "</vendor>\n";
+ }
+ if (domain.contains(QLatin1String("vendorurl"))) {
+ out << "<vendor_url>" << domain[QLatin1String("vendorurl")] << "</vendor_url>\n";
+ }
+ if (domain.contains(QLatin1String("icon"))) {
+ out << "<icon_name>" << domain[QLatin1String("icon")] << "</icon_name>\n";
+ }
+
+ foreach (const Action &action, actions) {
+ out << dent << "<action id=\"" << action.name << "\" >\n";
+
+ for (QHash< QString, QString >::const_iterator i = action.messages.constBegin(); i != action.messages.constEnd(); ++i) {
+ out << dent << dent << "<description";
+ if (i.key() != QLatin1String("en")) {
+ out << " xml:lang=\"" << i.key() << '"';
+ }
+
+ QHash< QChar, QString >::const_iterator blI;
+ QString description = i.value();
+ for (blI = blacklist.constBegin(); blI != blacklist.constEnd(); ++blI) {
+ description.replace(blI.key(), blI.value());
+ }
+
+ out << '>' << description << "</description>\n";
+ }
+
+ for (QHash< QString, QString>::const_iterator i = action.descriptions.constBegin();
+ i != action.descriptions.constEnd();
+ ++i) {
+ out << dent << dent << "<message";
+ if (i.key() != QLatin1String("en")) {
+ out << " xml:lang=\"" << i.key() << '"';
+ }
+
+ QHash< QChar, QString >::const_iterator blI;
+ QString message = i.value();
+ for (blI = blacklist.constBegin(); blI != blacklist.constEnd(); ++blI) {
+ message.replace(blI.key(), blI.value());
+ }
+
+ out << '>' << message << "</message>\n";
+ }
+
+ QString policy = action.policy;
+ QString policyInactive = action.policyInactive.isEmpty() ? QLatin1String("no") : action.policyInactive;
+ if (!action.persistence.isEmpty() && policy != QLatin1String("yes") && policy != QLatin1String("no")) {
+ policy += QLatin1String("_keep_") + action.persistence;
+ }
+ if (!action.persistence.isEmpty() && policyInactive != QLatin1String("yes") &&
+ policyInactive != QLatin1String("no")) {
+ policyInactive += QLatin1String("_keep_") + action.persistence;
+ }
+
+ out << QString(QLatin1String(policy_tag)).arg(policyInactive).arg(policy);
+
+ out << dent << "</action>\n";
+ }
+
+ out << "</policyconfig>\n";
+}
diff --git a/kdecore/auth/backends/polkit-1/Polkit1Backend.cpp b/kdecore/auth/backends/polkit-1/Polkit1Backend.cpp
new file mode 100644
index 0000000..cd7f6f3
--- /dev/null
+++ b/kdecore/auth/backends/polkit-1/Polkit1Backend.cpp
@@ -0,0 +1,229 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Radek Novacek <rnovacek@redhat.com>
+* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "Polkit1Backend.h"
+
+#include <QtCore/qplugin.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTimer>
+
+#include <QtGui/QApplication>
+#include <QtGui/QWidget>
+
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusConnectionInterface>
+
+#include <kdebug.h>
+
+#include <PolkitQt1/Authority>
+#include <PolkitQt1/Subject>
+
+namespace KAuth
+{
+
+PolkitResultEventLoop::PolkitResultEventLoop(QObject* parent)
+ : QEventLoop(parent)
+{
+}
+
+PolkitResultEventLoop::~PolkitResultEventLoop()
+{
+}
+
+void PolkitResultEventLoop::requestQuit(const PolkitQt1::Authority::Result& result)
+{
+ m_result = result;
+ quit();
+}
+
+PolkitQt1::Authority::Result PolkitResultEventLoop::result() const
+{
+ return m_result;
+}
+
+Polkit1Backend::Polkit1Backend()
+ : AuthBackend()
+ , m_flyingActions(false)
+{
+ setCapabilities(AuthorizeFromHelperCapability | CheckActionExistenceCapability | PreAuthActionCapability);
+
+ // Setup useful signals
+ connect(PolkitQt1::Authority::instance(), SIGNAL(configChanged()),
+ this, SLOT(checkForResultChanged()));
+ connect(PolkitQt1::Authority::instance(), SIGNAL(consoleKitDBChanged()),
+ this, SLOT(checkForResultChanged()));
+ connect(PolkitQt1::Authority::instance(), SIGNAL(enumerateActionsFinished(PolkitQt1::ActionDescription::List)),
+ this, SLOT(updateCachedActions(PolkitQt1::ActionDescription::List)));
+
+ // Cache existing action IDs as soon as possible
+ m_flyingActions = true;
+ PolkitQt1::Authority::instance()->enumerateActions();
+}
+
+Polkit1Backend::~Polkit1Backend()
+{
+
+}
+
+void Polkit1Backend::preAuthAction(const QString& action, QWidget* parent)
+{
+ kDebug();
+ // If a parent was not specified, skip this
+ if (!parent) {
+ kDebug() << "Parent widget does not exist, skipping";
+ return;
+ }
+
+ // Are we running our KDE auth agent?
+ if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.Polkit1AuthAgent"))) {
+ // Check if we actually are entitled to use GUI capabilities
+ if (qApp == 0 || QApplication::type() == QApplication::Tty) {
+ kDebug() << "Not streaming parent as we are on a TTY application";
+ }
+
+ // Retrieve the dialog root window Id
+ qulonglong wId = parent->effectiveWinId();
+
+ // Send it over the bus to our agent
+ QDBusMessage methodCall =
+ QDBusMessage::createMethodCall(QLatin1String("org.kde.Polkit1AuthAgent"), QLatin1String("/org/kde/Polkit1AuthAgent"), QLatin1String("org.kde.Polkit1AuthAgent"),
+ QLatin1String("setWIdForAction"));
+
+ methodCall << action;
+ methodCall << wId;
+
+ QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(methodCall);
+ call.waitForFinished();
+
+ if (call.isError()) {
+ kWarning() << "ERROR while streaming the parent!!" << call.error();
+ }
+ } else {
+ kDebug() << "KDE polkit agent appears too old or not registered on the bus";
+ }
+}
+
+void Polkit1Backend::updateCachedActions(const PolkitQt1::ActionDescription::List& actions)
+{
+ m_knownActions.clear();
+ foreach (const PolkitQt1::ActionDescription& action, actions) {
+ m_knownActions << action.actionId();
+ }
+ m_flyingActions = false;
+}
+
+Action::AuthStatus Polkit1Backend::authorizeAction(const QString &action)
+{
+ Q_UNUSED(action)
+ // Always return Yes here, we'll authorize inside isCallerAuthorized
+ return Action::Authorized;
+}
+
+void Polkit1Backend::setupAction(const QString &action)
+{
+ m_cachedResults[action] = actionStatus(action);
+}
+
+Action::AuthStatus Polkit1Backend::actionStatus(const QString &action)
+{
+ PolkitQt1::UnixProcessSubject subject(QCoreApplication::applicationPid());
+ PolkitQt1::Authority::Result r = PolkitQt1::Authority::instance()->checkAuthorizationSync(action, subject,
+ PolkitQt1::Authority::None);
+ switch (r) {
+ case PolkitQt1::Authority::Yes:
+ return Action::Authorized;
+ case PolkitQt1::Authority::No:
+ case PolkitQt1::Authority::Unknown:
+ return Action::Denied;
+ default:
+ return Action::AuthRequired;
+ }
+}
+
+QByteArray Polkit1Backend::callerID() const
+{
+ QByteArray a;
+ QDataStream s(&a, QIODevice::WriteOnly);
+ s << QCoreApplication::applicationPid();
+
+ return a;
+}
+
+bool Polkit1Backend::isCallerAuthorized(const QString &action, QByteArray callerID)
+{
+ QDataStream s(&callerID, QIODevice::ReadOnly);
+ qint64 pid;
+
+ s >> pid;
+
+ PolkitQt1::UnixProcessSubject subject(pid);
+ PolkitQt1::Authority *authority = PolkitQt1::Authority::instance();
+
+ PolkitResultEventLoop e;
+ connect(authority, SIGNAL(checkAuthorizationFinished(PolkitQt1::Authority::Result)),
+ &e, SLOT(requestQuit(PolkitQt1::Authority::Result)));
+ authority->checkAuthorization(action, subject, PolkitQt1::Authority::AllowUserInteraction);
+ e.exec();
+
+ switch (e.result()) {
+ case PolkitQt1::Authority::Yes:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+void Polkit1Backend::checkForResultChanged()
+{
+ foreach(const QString &action, m_cachedResults.keys()) {
+ if (m_cachedResults[action] != actionStatus(action)) {
+ m_cachedResults[action] = actionStatus(action);
+ emit actionStatusChanged(action, m_cachedResults[action]);
+ }
+ }
+
+ // Force updating known actions
+ PolkitQt1::Authority::instance()->enumerateActions();
+ m_flyingActions = true;
+}
+
+bool Polkit1Backend::actionExists(const QString& action)
+{
+ // Any flying actions?
+ if (m_flyingActions) {
+ int tries = 0;
+ while (m_flyingActions && tries < 10) {
+ // Wait max 2 seconds
+ QEventLoop e;
+ QTimer::singleShot(200, &e, SLOT(quit()));
+ e.exec();
+ ++tries;
+ }
+ }
+
+ return m_knownActions.contains(action);
+}
+
+} // namespace Auth
+
+Q_EXPORT_PLUGIN2(kauth_backend, KAuth::Polkit1Backend)
diff --git a/kdecore/auth/backends/polkit-1/Polkit1Backend.h b/kdecore/auth/backends/polkit-1/Polkit1Backend.h
new file mode 100644
index 0000000..18ed1a2
--- /dev/null
+++ b/kdecore/auth/backends/polkit-1/Polkit1Backend.h
@@ -0,0 +1,82 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Radek Novacek <rnovacek@redhat.com>
+* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 POLKIT1BACKEND_H
+#define POLKIT1BACKEND_H
+
+#include "AuthBackend.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QEventLoop>
+#include <QtCore/QStringList>
+
+#include <PolkitQt1/Authority>
+
+class QByteArray;
+
+namespace KAuth
+{
+
+class Polkit1Backend : public AuthBackend
+{
+ Q_OBJECT
+ Q_INTERFACES(KAuth::AuthBackend)
+
+public:
+ Polkit1Backend();
+ virtual ~Polkit1Backend();
+ virtual void setupAction(const QString&);
+ virtual void preAuthAction(const QString& action, QWidget* parent);
+ virtual Action::AuthStatus authorizeAction(const QString&);
+ virtual Action::AuthStatus actionStatus(const QString&);
+ virtual QByteArray callerID() const;
+ virtual bool isCallerAuthorized(const QString &action, QByteArray callerID);
+ virtual bool actionExists(const QString& action);
+
+private Q_SLOTS:
+ void checkForResultChanged();
+ void updateCachedActions(const PolkitQt1::ActionDescription::List &actions);
+
+private:
+ QHash<QString, Action::AuthStatus> m_cachedResults;
+ QStringList m_knownActions;
+ bool m_flyingActions;
+};
+
+class PolkitResultEventLoop : public QEventLoop
+{
+ Q_OBJECT
+public:
+ PolkitResultEventLoop(QObject* parent = 0);
+ virtual ~PolkitResultEventLoop();
+
+ PolkitQt1::Authority::Result result() const;
+
+public Q_SLOTS:
+ void requestQuit(const PolkitQt1::Authority::Result &result);
+
+private:
+ PolkitQt1::Authority::Result m_result;
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/backends/polkit-1/kauth-policy-gen-polkit1.cpp b/kdecore/auth/backends/polkit-1/kauth-policy-gen-polkit1.cpp
new file mode 100644
index 0000000..3b2f575
--- /dev/null
+++ b/kdecore/auth/backends/polkit-1/kauth-policy-gen-polkit1.cpp
@@ -0,0 +1,122 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 <auth/policy-gen/policy-gen.h>
+
+#include <cstdio>
+#include <QDebug>
+#include <QTextStream>
+
+const char header[] = ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<!DOCTYPE policyconfig PUBLIC\n"
+ "\"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd\">\n"
+ "<policyconfig>\n";
+
+const char policy_tag[] = ""
+ " <defaults>\n"
+ " <allow_inactive>%1</allow_inactive>\n"
+ " <allow_active>%2</allow_active>\n"
+ " </defaults>\n";
+
+const char dent[] = " ";
+
+void output(QList<Action> actions, QHash<QString, QString> domain)
+{
+ QTextStream out(stdout);
+ out.setCodec("UTF-8");
+
+ out << header;
+
+ // Blacklisted characters + replacements
+ QHash< QChar, QString > blacklist;
+ blacklist.insert(QLatin1Char('&'), QLatin1String("&amp;"));
+
+ if (domain.contains(QLatin1String("vendor"))) {
+ QHash< QChar, QString >::const_iterator blI;
+ QString vendor = domain[QLatin1String("vendor")];
+ for (blI = blacklist.constBegin(); blI != blacklist.constEnd(); ++blI) {
+ vendor.replace(blI.key(), blI.value());
+ }
+ out << "<vendor>" << vendor << "</vendor>\n";
+ }
+ if (domain.contains(QLatin1String("vendorurl"))) {
+ out << "<vendor_url>" << domain[QLatin1String("vendorurl")] << "</vendor_url>\n";
+ }
+ if (domain.contains(QLatin1String("icon"))) {
+ out << "<icon_name>" << domain[QLatin1String("icon")] << "</icon_name>\n";
+ }
+
+ foreach (const Action &action, actions) {
+ out << dent << "<action id=\"" << action.name << "\" >\n";
+
+ // Not a typo, messages and descriptions are actually inverted
+ for (QHash< QString, QString >::const_iterator i = action.messages.constBegin(); i != action.messages.constEnd(); ++i) {
+ out << dent << dent << "<description";
+ if (i.key() != QLatin1String("en")) {
+ out << " xml:lang=\"" << i.key() << '"';
+ }
+
+ QHash< QChar, QString >::const_iterator blI;
+ QString description = i.value();
+ for (blI = blacklist.constBegin(); blI != blacklist.constEnd(); ++blI) {
+ description.replace(blI.key(), blI.value());
+ }
+
+ out << '>' << description << "</description>\n";
+ }
+
+ QHash< QString, QString >::const_iterator i;
+ for (QHash< QString, QString >::const_iterator i = action.descriptions.constBegin();
+ i != action.descriptions.constEnd();
+ ++i) {
+ out << dent << dent << "<message";
+ if (i.key() != QLatin1String("en")) {
+ out << " xml:lang=\"" << i.key() << '"';
+ }
+
+ QHash< QChar, QString >::const_iterator blI;
+ QString message = i.value();
+ for (blI = blacklist.constBegin(); blI != blacklist.constEnd(); ++blI) {
+ message.replace(blI.key(), blI.value());
+ }
+
+ out << '>' << message << "</message>\n";
+ }
+
+ QString policy = action.policy;
+ QString policyInactive = action.policyInactive.isEmpty() ? QLatin1String("no") : action.policyInactive;
+ if (!action.persistence.isEmpty() && policy != QLatin1String("yes") && policy !=
+ QLatin1String("no")) {
+ policy += QLatin1String("_keep");
+ }
+ if (!action.persistence.isEmpty() && policyInactive != QLatin1String("yes") && policyInactive !=
+ QLatin1String("no")) {
+ policyInactive += QLatin1String("_keep");
+ }
+
+ out << QString(QLatin1String(policy_tag)).arg(policyInactive).arg(policy);
+
+ out << dent << "</action>\n";
+ }
+
+ out << "</policyconfig>\n";
+}
diff --git a/kdecore/auth/kauth.h b/kdecore/auth/kauth.h
new file mode 100644
index 0000000..5b69d3f
--- /dev/null
+++ b/kdecore/auth/kauth.h
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 KAUTH_H
+#define KAUTH_H
+
+#include "kauthaction.h"
+#include "kauthactionreply.h"
+#include "kauthactionwatcher.h"
+#include "kauthhelpersupport.h"
+
+#endif
diff --git a/kdecore/auth/kauthaction.cpp b/kdecore/auth/kauthaction.cpp
new file mode 100644
index 0000000..181547f
--- /dev/null
+++ b/kdecore/auth/kauthaction.cpp
@@ -0,0 +1,387 @@
+/*
+* Copyright (C) 2009 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009-2010 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "kauthaction.h"
+
+#include <QRegExp>
+#include <QWidget>
+
+#include "BackendsManager.h"
+#include "kauthactionwatcher.h"
+
+namespace KAuth
+{
+
+class Action::Private
+{
+public:
+ Private() : valid(false), async(false), parent(0) {}
+
+ QString name;
+ QString details;
+ QString helperId;
+ QVariantMap args;
+ bool valid;
+ bool async;
+ QWidget *parent;
+};
+
+// Constructors
+Action::Action()
+ : d(new Private())
+{
+}
+
+Action::Action(const Action &action)
+ : d(new Private())
+{
+ *this = action;
+}
+
+Action::Action(const QString &name)
+ : d(new Private())
+{
+ setName(name);
+ BackendsManager::authBackend()->setupAction(d->name);
+}
+
+Action::Action(const QString &name, const QString &details)
+ : d(new Private())
+{
+ setName(name);
+ setDetails(details);
+ BackendsManager::authBackend()->setupAction(d->name);
+}
+
+Action::~Action()
+{
+ delete d;
+}
+
+// Operators
+Action &Action::operator=(const Action & action)
+{
+ setName(action.d->name);
+ d->args = action.d->args;
+
+ return *this;
+}
+
+bool Action::operator==(const Action &action) const
+{
+ return d->name == action.d->name;
+}
+
+bool Action::operator!=(const Action &action) const
+{
+ return d->name != action.d->name;
+}
+
+// Accessors
+QString Action::name() const
+{
+ return d->name;
+}
+
+void Action::setName(const QString &name)
+{
+ d->name = name;
+
+ // Does the backend support checking for known actions?
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::CheckActionExistenceCapability) {
+ // In this case, just ask the backend
+ d->valid = BackendsManager::authBackend()->actionExists(name);
+ } else {
+ // Otherwise, check through a regexp
+ QRegExp exp(QLatin1String("[0-z]+(\\.[0-z]+)*"));
+ d->valid = exp.exactMatch(name);
+ }
+}
+
+QString Action::details() const
+{
+ return d->details;
+}
+
+void Action::setDetails(const QString &details)
+{
+ d->details = details;
+}
+
+bool Action::isValid() const
+{
+ return d->valid;
+}
+
+void Action::setArguments(const QVariantMap &arguments)
+{
+ d->args = arguments;
+}
+
+void Action::addArgument(const QString &key, const QVariant &value)
+{
+ d->args.insert(key, value);
+}
+
+QVariantMap Action::arguments() const
+{
+ return d->args;
+}
+
+ActionWatcher *Action::watcher()
+{
+ return ActionWatcher::watcher(d->name);
+}
+
+QString Action::helperID() const
+{
+ return d->helperId;
+}
+
+// TODO: Check for helper id's syntax
+void Action::setHelperID(const QString &id)
+{
+ d->helperId = id;
+}
+
+void Action::setParentWidget(QWidget* parent)
+{
+ d->parent = parent;
+}
+
+QWidget* Action::parentWidget() const
+{
+ return d->parent;
+}
+
+
+// Authorizaton methods
+Action::AuthStatus Action::authorize() const
+{
+ if (!isValid()) {
+ return Action::Invalid;
+ }
+
+ // If there is any pre auth action, let's perform it
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
+ BackendsManager::authBackend()->preAuthAction(d->name, d->parent);
+ }
+
+ // Let's check capabilities
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) {
+ // That's easy then
+ return BackendsManager::authBackend()->authorizeAction(d->name);
+ } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) {
+ // We need to check if we have an helper in this case
+ if (hasHelper()) {
+ // Ok, we need to use "helper authorization".
+ return BackendsManager::helperProxy()->authorizeAction(d->name, d->helperId);
+ } else {
+ // Ok, in this case we have to fake and just pretend we are an helper
+ if (BackendsManager::authBackend()->isCallerAuthorized(d->name, BackendsManager::authBackend()->callerID())) {
+ return Authorized;
+ } else {
+ return Denied;
+ }
+ }
+ } else {
+ // This should never, never happen
+ return Invalid;
+ }
+}
+
+
+Action::AuthStatus Action::earlyAuthorize() const
+{
+ // Check the status first
+ AuthStatus s = status();
+ if (s == AuthRequired) {
+ // Let's check what to do
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) {
+ // In this case we can actually try an authorization
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
+ BackendsManager::authBackend()->preAuthAction(d->name, d->parent);
+ }
+
+ return BackendsManager::authBackend()->authorizeAction(d->name);
+ } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) {
+ // In this case, just throw out Authorized, as the auth will take place later
+ return Authorized;
+ } else {
+ // This should never, never happen
+ return Invalid;
+ }
+ } else {
+ // It's fine, return the status
+ return s;
+ }
+}
+
+
+Action::AuthStatus Action::status() const
+{
+ if (!isValid()) {
+ return Action::Invalid;
+ }
+
+ return BackendsManager::authBackend()->actionStatus(d->name);
+}
+
+// Execution methods
+bool Action::executeActions(const QList<Action> &actions, QList<Action> *deniedActions, const QString &helperId)
+{
+ return executeActions(actions, deniedActions, helperId, 0);
+}
+
+bool Action::executeActions(const QList< Action >& actions, QList< Action >* deniedActions, const QString& helperId, QWidget* parent)
+{
+ QList<QPair<QString, QVariantMap> > list;
+
+ foreach(const Action &a, actions) {
+ // Save us an additional step
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) {
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
+ BackendsManager::authBackend()->preAuthAction(a.name(), parent);
+ }
+
+ AuthStatus s = BackendsManager::authBackend()->authorizeAction(a.name());
+
+ if (s == Authorized) {
+ list.push_back(QPair<QString, QVariantMap>(a.name(), a.arguments()));
+ } else if ((s == Denied || s == Invalid) && deniedActions) {
+ *deniedActions << a;
+ }
+ } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) {
+ list.push_back(QPair<QString, QVariantMap>(a.name(), a.arguments()));
+ } else {
+ // There's something totally wrong here
+ return false;
+ }
+ }
+
+ if (list.isEmpty()) {
+ return false;
+ }
+
+ return BackendsManager::helperProxy()->executeActions(list, helperId);
+}
+
+bool Action::executesAsync() const
+{
+ return d->async;
+}
+
+void Action::setExecutesAsync(bool async)
+{
+ d->async = async;
+}
+
+ActionReply Action::execute() const
+{
+ if (!isValid())
+ return ActionReply::InvalidActionReply;
+
+ return execute(helperID());
+}
+
+ActionReply Action::execute(const QString &helperID) const
+{
+ // Is the action valid?
+ if (!isValid()) {
+ return ActionReply::InvalidActionReply;
+ }
+
+ // What to do?
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) {
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
+ BackendsManager::authBackend()->preAuthAction(d->name, d->parent);
+ }
+ // Authorize from here
+ AuthStatus s = BackendsManager::authBackend()->authorizeAction(d->name);
+
+ // Abort if authorization fails
+ switch (s) {
+ case Denied:
+ return ActionReply::AuthorizationDeniedReply;
+ case Invalid:
+ return ActionReply::InvalidActionReply;
+ case UserCancelled:
+ return ActionReply::UserCancelledReply;
+ default:
+ break;
+ }
+ } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) {
+ // In this case we care only if the action is not async and does not have an helper
+ if (!d->async && !hasHelper()) {
+ // Authorize!
+ switch (authorize()) {
+ case Denied:
+ return ActionReply::AuthorizationDeniedReply;
+ case Invalid:
+ return ActionReply::InvalidActionReply;
+ case UserCancelled:
+ return ActionReply::UserCancelledReply;
+ default:
+ break;
+ }
+ }
+ } else {
+ // What?
+ return ActionReply::InvalidActionReply;
+ }
+
+ if (d->async) {
+ if (hasHelper()) {
+ // It makes no sense
+ return ActionReply::InvalidActionReply;
+ }
+
+ return executeActions(QList<Action>() << *this, NULL, helperID) ?
+ ActionReply::SuccessReply : ActionReply::AuthorizationDeniedReply;
+ } else {
+ if (hasHelper()) {
+ // Perform the pre auth here
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
+ BackendsManager::authBackend()->preAuthAction(d->name, d->parent);
+ }
+
+ return BackendsManager::helperProxy()->executeAction(d->name, helperID, d->args);
+ } else {
+ return ActionReply::SuccessReply;
+ }
+ }
+}
+
+void Action::stop()
+{
+ stop(helperID());
+}
+
+void Action::stop(const QString &helperID)
+{
+ BackendsManager::helperProxy()->stopAction(d->name, helperID);
+}
+
+bool Action::hasHelper() const
+{
+ return !d->helperId.isEmpty();
+}
+
+} // namespace Auth
diff --git a/kdecore/auth/kauthaction.h b/kdecore/auth/kauthaction.h
new file mode 100644
index 0000000..123883b
--- /dev/null
+++ b/kdecore/auth/kauthaction.h
@@ -0,0 +1,506 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 ACTION_H
+#define ACTION_H
+
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include <QtCore/QHash>
+
+#include <kdecore_export.h>
+
+#include "kauthactionreply.h"
+
+namespace KAuth
+{
+
+class ActionWatcher;
+
+/**
+ * @brief Class to access, authorize and execute actions.
+ *
+ * This is the main class of the kauth API. It provides the interface to
+ * manipulate actions. Every action is identified by its name. Every instance
+ * of the Action class with the same name refers to the same action.
+ *
+ * Once you have an action object you can tell the helper to execute it
+ * (asking the user to authenticate if needed) with one of the execute*() methods.
+ * The simplest thing to do is to execute a single action synchronously
+ * blocking for the reply, using the execute() method.
+ *
+ * For asynchronous calls, use the executeAsync() method. It sends the request
+ * to the helper and returns immediately. You can optionally provide an object
+ * and a slot. This will be connected to the actionPerformed() signal of the
+ * action's ActionWatcher object.
+ * By calling the watcher() method, you obtain an object that emits some useful
+ * signals that you can receive while the action is in progress. Those signals
+ * are emitted also with the synchronous calls.
+ * To execute a bunch of actions with a single call, you can use the executeActions()
+ * static method. This is not the same as calling executeAsync() for each action,
+ * because the actions are execute with a single request to the helper.
+ * To use any of the execute*() methods you have to set the default helper's ID using
+ * the setHelperID() static method. Alternatively, you can specify the helperID using
+ * the overloaded version of the methods that takes it as a parameter.
+ *
+ * Each action object contains a QVariantMap object that is passed directly to the
+ * helper when the action is executed. You can access this map using the arguments()
+ * method. You can insert into it any kind of custom data you need to pass to the helper.
+ *
+ * @since 4.4
+ */
+class KDECORE_EXPORT Action
+{
+ class Private;
+ Private * const d;
+
+public:
+ /**
+ * The three values returned by authorization methods
+ */
+ enum AuthStatus {
+ Denied, ///< The authorization has been denied by the authorization backend
+ Error, ///< An error occurred
+ Invalid, ///< An invalid action cannot be authorized
+ Authorized, ///< The authorization has been granted by the authorization backend
+ AuthRequired, ///< The user could obtain the authorization after authentication
+ UserCancelled ///< The user pressed Cancel the authentication dialog. Currently used only on the mac
+ };
+
+ /**
+ * @brief Default constructor
+ *
+ * This constructor sets the name to the empty string.
+ * Such an action is invalid and cannot be authorized nor executed, so
+ * you need to call setName() before you can use the object.
+ */
+ Action();
+
+ /** Copy constructor */
+ Action(const Action &action);
+
+ /**
+ * This creates a new action object with this name
+ * @param name The name of the new action
+ */
+ Action(const QString &name);
+
+ /**
+ * This creates a new action object with this name and details
+ * @param name The name of the new action
+ * @param details The details of the action
+ *
+ * @see setDetails
+ */
+ Action(const QString &name, const QString &details);
+
+ /// Virtual destructor
+ ~Action();
+
+ /// Assignment operator
+ Action &operator=(const Action &action);
+
+ /**
+ * @brief Comparison operator
+ *
+ * This comparison operator compares the <b>names</b> of two
+ * actions and returns whether they are the same. It does not
+ * care about the arguments stored in the actions. However,
+ * if two actions are invalid they'll match as equal, even
+ * if the invalid names are different.
+ *
+ * @returns true if the two actions are the same or both invalid
+ */
+ bool operator==(const Action &action) const;
+
+ /**
+ * @brief Negated comparison operator
+ *
+ * Returns the negation of operator==
+ *
+ * @returns true if the two actions are different and not both invalid
+ */
+ bool operator!=(const Action &action) const;
+
+ /**
+ * @brief Gets the action's name.
+ *
+ * This is the unique attribute that identifies
+ * an action object. Two action objects with the same
+ * name always refer to the same action.
+ *
+ * @return The action name
+ */
+ QString name() const;
+
+ /**
+ * @brief Sets the action's name.
+ *
+ * It's not common to change the action name
+ * after its creation. Usually you set the name
+ * with the constructor (and you have to, because
+ * there's no default constructor)
+ */
+ void setName(const QString &name);
+
+ /**
+ * @brief Sets the action's details
+ *
+ * You can use this function to provide the user more details
+ * (if the backend supports it) on the action being authorized in
+ * the authorization dialog
+ */
+ void setDetails(const QString &details);
+
+ /**
+ * @brief Gets the action's details
+ *
+ * The details that will be shown in the authorization dialog, if the
+ * backend supports it.
+ *
+ * @return The action's details
+ */
+ QString details() const;
+
+ /**
+ * @brief Returns if the object represents a valid action
+ *
+ * Action names have to respect a simple syntax.
+ * They have to be all in lowercase characters, separated
+ * by dots. Dots can't appear at the beginning and at the end of
+ * the name.
+ *
+ * In other words, the action name has to match this perl-like
+ * regular expression:
+ * @verbatim
+ * /^[a-z]+(\.[a-z]+)*$/
+ * @endverbatim
+ *
+ * This method returns false if the action name doesn't match the
+ * valid syntax.
+ *
+ * If the backend supports it, this method also checks if the action is
+ * valid and recognized by the backend itself.
+ *
+ * Invalid actions cannot be authorized nor executed.
+ * The empty string is not a valid action name, so the default
+ * constructor returns an invalid action.
+ */
+ bool isValid() const;
+
+ /**
+ * @brief Gets the default helper ID used for actions execution
+ *
+ * The helper ID is the string that uniquely identifies the helper in
+ * the system. It is the string passed to the KDE4_AUTH_HELPER() macro
+ * in the helper source. Because one could have different helpers,
+ * you need to specify an helper ID for each execution, or set a default
+ * ID by calling setHelperID(). This method returns the current default
+ * value.
+ *
+ * @return The default helper ID.
+ */
+ QString helperID() const;
+
+ /**
+ * @brief Sets the default helper ID used for actions execution
+ *
+ * This method sets the helper ID which contains the body of this action.
+ * If the string is non-empty, the corresponding helper will be fired and
+ * the action executed inside the helper. Otherwise, the action will be just
+ * authorized.
+ *
+ * @note To unset a previously set helper, just pass an empty string
+ *
+ * @param id The default helper ID.
+ *
+ * @see hasHelper
+ * @see helperID
+ */
+ void setHelperID(const QString &id);
+
+ /**
+ * @brief Checks if the action has an helper
+ *
+ * This function can be used to check if an helper will be called upon the
+ * execution of an action. Such an helper can be set through setHelperID. If
+ * this function returns false, upon execution the action will be just authorized.
+ *
+ * @since 4.5
+ *
+ * @return Whether the action has an helper or not
+ *
+ * @see setHelperID
+ */
+ bool hasHelper() const;
+
+ /**
+ * @brief Gets the ActionWatcher object for this action
+ *
+ * ActionWatcher objects are used to get notifications about the action
+ * execution status. Every action watcher is tied to an action and
+ * every action has a watcher. This means that if you call this method
+ * on two different Action objects with the same name, you'll get the
+ * same watcher object.
+ *
+ * @return The action watcher for this action
+ */
+ ActionWatcher *watcher();
+
+ /**
+ * @brief Sets the map object used to pass arguments to the helper.
+ *
+ * This method sets the variant map that the application
+ * can use to pass arbitrary data to the helper when executing the action.
+ *
+ * @param arguments The new arguments map
+ */
+ void setArguments(const QVariantMap &arguments);
+
+ /**
+ * @brief Returns map object used to pass arguments to the helper.
+ *
+ * This method returns the variant map that the application
+ * can use to pass arbitrary data to the helper when executing the action.
+ *
+ * @return The arguments map that will be passed to the helper.
+ */
+ QVariantMap arguments() const;
+
+ /**
+ * @brief Convenience method to add an argument.
+ *
+ * This method adds the pair @c key/value to the QVariantMap used to
+ * send custom data to the helper.
+ *
+ * Use this method if you don't want to create a new QVariantMap only to
+ * add a new entry.
+ *
+ * @param key The new entry's key
+ * @param value The value of the new entry
+ */
+ void addArgument(const QString &key, const QVariant &value);
+
+ /**
+ * @brief Acquires authorization for an action without excuting it.
+ *
+ * @note Please use this method if you really know what you are doing. If you are
+ * implementing a GUI, you probably should look into earlyAuthorize instead.
+ *
+ * @note Please remember that calling this method is not required for a successful action
+ * execution: it is safe and advised to call execute() only, without a previous call
+ * to authorize or earlyAuthorize.
+ *
+ * This method acquires the authorization rights for the action, asking
+ * the user to authenticate if needed. It tries very hard to resolve a possible
+ * challenge (AuthRequired); for this reason, it is meant only for advanced usages.
+ * If you are unsure, always use earlyAuthorize or execute the action directly.
+ *
+ * @return The result of the authorization process
+ *
+ * @see earlyAuthorize
+ */
+ AuthStatus authorize() const;
+
+ /**
+ * @brief Tries to resolve authorization status in the best possible way without executing the action
+ *
+ * This method checks for the status of the action, and tries to acquire authorization
+ * (if needed) if the backend being used supports client-side authorization.
+ *
+ * This means this method is not reliable - its purpose is to provide user interfaces with
+ * an efficient means to acquire authorization as early as possible, without interrupting
+ * the user's workflow. If the backend's authentication phase happens in the helper and the
+ * action requires authentication, \c Authorized will be returned.
+ *
+ * The main difference with authorize is that this method does not try to acquire authorization
+ * if the backend's authentication phase happens in the helper: using authorize in such a case
+ * might lead to ask the user its password twice, as the helper might time out, or in the case
+ * of a one shot authorization, the scope of the authorization would end with the authorization
+ * check itself. For this reason, you should @b always use this method instead of authorize, which
+ * is meant only for very advanced usages.
+ *
+ * This method is always safe to be called and used before an execution, even if not needed.
+ *
+ * @since 4.5
+ *
+ * @return The result of the early authorization process, with the caveats described above.
+ */
+ AuthStatus earlyAuthorize() const;
+
+ /**
+ * @brief Gets information about the authorization status of an action
+ *
+ * This methods query the authorization backend to know if the user can try
+ * to acquire the authorization for this action. If the result is Action::AuthRequired,
+ * the user can try to acquire the authorization by authenticating.
+ *
+ * It should not be needed to call this method directly, because the execution methods
+ * already take care of all the authorization stuff.
+ *
+ * @return @c Action::Denied if the user doesn't have the authorization to execute the action,
+ * @c Action::Authorized if the action can be executed,
+ * @c Action::AuthRequired if the user could acquire the authorization after authentication,
+ * @c Action::UserCancelled if the user cancels the authentication dialog. Not currently supported by the Polkit backend
+ */
+ AuthStatus status() const;
+
+ /**
+ * @brief Synchronously executes the action
+ *
+ * This is the simpler of all the action execution methods. It sends an execution request to the
+ * caller, and returns the reply directly to the caller. The ActionReply object will contain the
+ * custom data coming from the helper.
+ *
+ * The method blocks the execution, and will
+ * return only when the action has been completed (or failed). Take note, however, that with the D-Bus
+ * helper proxy (currently the only one implemented on all the supported platforms), the request is
+ * sent using the QDBus::BlockWithGui flag.
+ *
+ * This means the method will enter a local eventloop to wait
+ * for the reply. This allows the application GUI to stay responsive, but you have to be prepared to
+ * receive other events in the meantime.
+ *
+ * All the signals from the ActionWatcher class are emitted also with this method (although they're more
+ * useful with the asynchronous calls)
+ *
+ * The method checks for authorization before to execute the action. If the user is not authorized, the
+ * return value will be ActionReply::AuthorizationDeniedReply.
+ * If the user cancels the authentication, the return value should be ActionReply::UserCancelledReply.
+ * Due to policykit limitations, this currently only with the Mac OS X backend.
+ *
+ * If the helper is busy executing another action (or action group) the reply will be ActionReply::HelperBusyReply
+ *
+ * If the request cannot be sent for bus errors, the method returns ActionReply::DBusErrorReply.
+ *
+ * @return The reply from the helper, or an error reply if something's wrong.
+ */
+ ActionReply execute() const;
+
+ /**
+ * @brief Synchronously executes the action with a specific helperID
+ *
+ * This method does the exact same thing as execute(), but it takes a specific helperID, useful
+ * if you don't want to use the default one without changing it with setHelperID()
+ *
+ * @param helperID The helper ID to use for the execution of this action
+ * @return The reply from the helper, or an error if something's wrong.
+ */
+ ActionReply execute(const QString &helperID) const;
+
+ void setExecutesAsync(bool async);
+ bool executesAsync() const;
+
+ /**
+ * @brief Asynchronously executes a group of actions with a single request
+ *
+ * This method executes each action in the list. It checks for authorization of each action, and put the
+ * denied actions, if any, in the list pointed by the deniedActions parameter, if not NULL.
+ *
+ * Please note that with the D-Bus helper proxy (currently the only one implemented), the execution of a group
+ * of actions is very different from executing in sequence each action using, for example, executeAsync().
+ * Currently, the helper can execute only one request at the time. For this reason, if you have to call
+ * different actions in sequence, you can't call executeAsync() like this:
+ * @code
+ * action1.executeAsync();
+ * action2.executeAsync();
+ * @endcode
+ * because the second call will almost certainly return ActionReply::HelperBusy. You would have to execute the second
+ * action in the slot connected to the first action's actionPerformed() signal. This is not so good. This method
+ * allows the application to send a request with a list of actions. With this method, the code above becomes:
+ * @code
+ * QList<Action> list;
+ * list << action1 << action2;
+ * Action::executeActions(list);
+ * @endcode
+ * The return value will be false if communication errors occur. It will also be false if <b>all</b> the actions
+ * in the list are denied.
+ *
+ * @param actions The list of actions to execute
+ * @param deniedActions A pointer to a list to fill with the denied actions. Pass NULL if you don't need them.
+ * @param helperId The helper ID to execute the actions on.
+ */
+ static bool executeActions(const QList<Action> &actions, QList<Action> *deniedActions, const QString &helperId);
+
+ /**
+ * Convenience overload. This overload lets you specify, in addition, a QWidget which will be used as the
+ * authentication dialog's parent.
+ *
+ * @since 4.6
+ *
+ * @see executeActions
+ * @see setParentWidget
+ */
+ static bool executeActions(const QList<Action> &actions, QList<Action> *deniedActions, const QString &helperId,
+ QWidget *parent);
+
+ /**
+ * @brief Ask the helper to stop executing an action
+ *
+ * This method sends a request to the helper asking to stop the execution of an action. It is only
+ * useful for long-running actions, because short and fast actions won't obbey to this request most of the times.
+ * Calling this method will make the HelperSupport::isStopped() method to return true the next time it's called.
+ *
+ * It's the helper's responsibility to regularly call it and exit if requested
+ * The actionPerformed() signal is emitted normally because, actually, the helper exists regularly. The return data
+ * in this case is application-dependent.
+ */
+ void stop();
+
+ /**
+ * @brief Ask the helper to stop executing an action, using a specific helper ID
+ *
+ * This method works exactly as the stop() method, but it lets you specify an helper ID different from the
+ * default one.
+ *
+ * To stop an action you need to send the stop request to the helper that is executing that action. This of course means you have to
+ * use the same helperID used for the execution call (either passed as a parameter or set as default with setHelperID() )
+ */
+ void stop(const QString &helperID);
+
+ /**
+ * @brief Sets a parent widget for the authentication dialog
+ *
+ * This function is used for explicitly setting a parent window for an eventual authentication dialog required when
+ * authorization is triggered. Some backends, in fact, (like polkit-1) need to have a parent explicitly set for displaying
+ * the dialog correctly.
+ *
+ * @note If you are using KAuth through one of KDE's GUI components (KPushButton, KCModule...) you do not need and should not
+ * call this function, as it is already done by the component itself.
+ *
+ * @since 4.6
+ *
+ * @param parent A QWidget which will be used as the dialog's parent
+ */
+ void setParentWidget(QWidget *parent);
+
+ /**
+ * @brief Returns the parent widget for the authentication dialog for this action
+ *
+ * @since 4.6
+ *
+ * @returns A QWidget which will is being used as the dialog's parent
+ */
+ QWidget *parentWidget() const;
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/kauthactionreply.cpp b/kdecore/auth/kauthactionreply.cpp
new file mode 100644
index 0000000..53b0e39
--- /dev/null
+++ b/kdecore/auth/kauthactionreply.cpp
@@ -0,0 +1,190 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "kauthactionreply.h"
+
+#include <QDebug>
+
+namespace KAuth
+{
+
+class ActionReply::Private
+{
+public:
+ QVariantMap data; // User-defined data for success and helper error replies, empty for kauth errors
+ int errorCode;
+ QString errorDescription;
+ ActionReply::Type type;
+};
+
+// Predefined replies
+const ActionReply ActionReply::SuccessReply = ActionReply();
+const ActionReply ActionReply::HelperErrorReply = ActionReply(ActionReply::HelperError);
+const ActionReply ActionReply::NoResponderReply = ActionReply(ActionReply::NoResponder);
+const ActionReply ActionReply::NoSuchActionReply = ActionReply(ActionReply::NoSuchAction);
+const ActionReply ActionReply::InvalidActionReply = ActionReply(ActionReply::InvalidAction);
+const ActionReply ActionReply::AuthorizationDeniedReply = ActionReply(ActionReply::AuthorizationDenied);
+const ActionReply ActionReply::UserCancelledReply = ActionReply(ActionReply::UserCancelled);
+const ActionReply ActionReply::HelperBusyReply = ActionReply(ActionReply::HelperBusy);
+const ActionReply ActionReply::DBusErrorReply = ActionReply(ActionReply::DBusError);
+
+// Constructors
+ActionReply::ActionReply(const ActionReply &reply)
+ : d(new Private())
+{
+ *this = reply;
+}
+
+ActionReply::ActionReply()
+ : d(new Private())
+{
+ d->errorCode = 0;
+ d->type = Success;
+}
+
+ActionReply::ActionReply(ActionReply::Type type)
+ : d(new Private())
+{
+ d->errorCode = 0;
+ d->type = type;
+}
+
+ActionReply::ActionReply(int error)
+ : d(new Private())
+{
+ d->errorCode = error;
+ d->type = KAuthError;
+}
+
+ActionReply::~ActionReply()
+{
+ delete d;
+}
+
+void ActionReply::setData(const QVariantMap &data)
+{
+ d->data = data;
+}
+
+void ActionReply::addData(const QString &key, const QVariant &value)
+{
+ d->data.insert(key, value);
+}
+
+QVariantMap ActionReply::data() const
+{
+ return d->data;
+}
+
+ActionReply::Type ActionReply::type() const
+{
+ return d->type;
+}
+
+bool ActionReply::succeeded() const
+{
+ return d->type == Success;
+}
+
+bool ActionReply::failed() const
+{
+ return d->type != Success;
+}
+
+int ActionReply::errorCode() const
+{
+ return d->errorCode;
+}
+
+void ActionReply::setErrorCode(int errorCode)
+{
+ d->errorCode = errorCode;
+ if (d->type != HelperError) {
+ d->type = KAuthError;
+ }
+}
+
+QString ActionReply::errorDescription() const
+{
+ return d->errorDescription;
+}
+
+void ActionReply::setErrorDescription(const QString &error)
+{
+ d->errorDescription = error;
+}
+
+QByteArray ActionReply::serialized() const
+{
+ QByteArray data;
+ QDataStream s(&data, QIODevice::WriteOnly);
+
+ s << *this;
+
+ return data;
+}
+
+ActionReply ActionReply::deserialize(const QByteArray &data)
+{
+ ActionReply reply;
+ QByteArray a(data);
+ QDataStream s(&a, QIODevice::ReadOnly);
+
+ s >> reply;
+
+ return reply;
+}
+
+// Operators
+ActionReply &ActionReply::operator=(const ActionReply & reply)
+{
+ d->data = reply.d->data;
+ d->errorCode = reply.d->errorCode;
+ d->errorDescription = reply.d->errorDescription;
+ d->type = reply.d->type;
+
+ return *this;
+}
+
+bool ActionReply::operator==(const ActionReply &reply) const
+{
+ return (d->type == reply.d->type && d->errorCode == reply.d->errorCode);
+}
+
+bool ActionReply::operator!=(const ActionReply &reply) const
+{
+ return (d->type != reply.d->type || d->errorCode != reply.d->errorCode);
+}
+
+QDataStream &operator<<(QDataStream &d, const ActionReply &reply)
+{
+ return d << reply.d->data << reply.d->errorCode << (quint32)reply.d->type << reply.d->errorDescription;
+}
+
+QDataStream &operator>>(QDataStream &stream, ActionReply &reply)
+{
+ quint32 i;
+ stream >> reply.d->data >> reply.d->errorCode >> i >> reply.d->errorDescription;
+ reply.d->type = (ActionReply::Type) i;
+
+ return stream;
+}
+
+} // namespace Auth
diff --git a/kdecore/auth/kauthactionreply.h b/kdecore/auth/kauthactionreply.h
new file mode 100644
index 0000000..3584785
--- /dev/null
+++ b/kdecore/auth/kauthactionreply.h
@@ -0,0 +1,608 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 ACTION_REPLY_H
+#define ACTION_REPLY_H
+
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include <QtCore/QMap>
+#include <QtCore/QDataStream>
+
+#include <kdecore_export.h>
+/**
+ @namespace KAuth
+
+ @section kauth_intro Introduction
+ The KDE Authorization API allows developers to write desktop applications that run high-privileged tasks in an easy, secure and cross-platform way. Previously, if an application had to do administrative tasks,
+ it had to be run as root, using mechanisms such as sudo or graphical equivalents, or by setting the executable's setuid bit. This approach has some drawbacks. For example, the whole application code,
+ including GUI handling and network communication, had to be done as root. More code that runs as root means more possible security holes.
+
+ The solution is the caller/helper pattern. With this pattern, the privileged code is isolated in a small helper tool that runs as root. This tool includes only the few lines of code that actually
+ need to be run with privileges, not the whole application logic. All the other parts of the application are run as a normal user, and the helper tool is called when needed, using a secure mechanism that
+ ensures that the user is authorized to do so. This pattern is not very easy to implement, because the developer has to deal with a lot of details about how to authorize the user, how to call the helper
+ with the right privileges, how to exchange data with the helper, etc.. This is where the new KDE Authorization API becomes useful. Thanks to this new library, every developer can implement the
+ caller/helper pattern to write application that require high privileges, with a few lines of code in an easy, secure and cross-platform way.
+
+ Not only: the library can also be used to lock down some actions in your application without using a helper but just checking for authorization and verifying if the user is allowed to perform it.
+
+ The KDE Authorization library uses different backends depending on the system where it's built. As far as the user authorization is concerned, it currently uses PolicyKit on linux and Authorization Services
+ on Mac OSX, and a Windows backend will eventually be written, too. At the communication layer, the library uses D-Bus on every supported platform.
+
+
+ @section kauth_concepts Concepts
+ There are a few concepts to understand when using the library. Much of those are carried from underlying APIs such as PolicyKit, so if you know something about them there shouldn't be problems.
+
+ An <i>action</i> is a single task that needs to be done by the application. You refer to an action using an action identifier, which is a string in reverse domain name syntax (to avoid duplicates). For
+ example, if the date/time control center module needs to change the date, it would need an action like "org.kde.datatime.change". If your application has to perform more than one privileged task, you
+ should configure more than one action. This allows system administrators to fine tune the policies that allow users to perform your actions.
+
+ The <i>authorization</i> is the process that is executed to decide if a user can perform an action or not. In order to execute the helper as root, the user has to be authorized. For example, on linux,
+ che policykit backend will look at the policykit policy database to see what requirements the user has to meet in order to execute the action you requested. The policy set for that action could allow
+ or deny that user, or could say the user has to authenticate in order to gain the authorization.
+
+ The <i>authentication</i> is the process that allows the system to know that the person is in front of the console is who he says to be. If an action can be allowed or not depending on the user's identity,
+ it has to be proved by entering a password or any other identification data the system requires.
+
+ A typical session with the authorization API is like this:
+ - The user want to perform some privileged task
+ - The application asks the system if the user is authorized.
+ - The system asks the user to authenticate, if needed, and reply the application.
+ - The application uses some system-provided mechanism to execute the helper's code as the root user. Previously, you had to set the setuid bit to do this, but we have something cool called
+ "dbus activation" that doesn't require the setuid bit and is much more flexible.
+ - The helper code, immediately after starting, checks if the caller is authorized to do what it asks. If not the helper immediately exits!
+ - If the caller is authorized, the helper executes the task and exits.
+ - The application receives data back from the helper.
+
+ All these steps are managed by the library. Following sections will focus on how to write the helper to implement your actions and how to call the helper from the application.
+
+ @section kauth_helper Writing the helper tool
+
+ The first thing you need to do before writing anything is to decide what actions you need to implement. Every action needs to be identified by a string in the reverse domain name syntax. This helps to
+ avoid duplicates. An example of action id is "org.kde.datetime.change" or "org.kde.ksysguard.killprocess". Action names can only contain lowercase letters and dots (not as the first or last char).
+ You also need an identifier for your helper. An application using the KDE auth api can implement and use more than one helper, implementing different actions. An helper is uniquely identified in the
+ system context with a string. It, again, is in reverse domain name syntax to avoid duplicates. A common approach is to call the helper like the common prefix of your action names.
+ For example, the Date/Time kcm module could use a helper called "org.kde.datetime", to perform actions like "org.kde.datetime.changedate" and "org.kde.datetime.changetime". This naming convention
+ simplifies the implementation of the helper.
+
+ From the code point of view, the helper is implemented as a QObject subclass. Every action is implemented by a public slot. In the example/ directory in the source code tree you find a complete example.
+ Let's look at that.
+ The helper.h file declares the class that implements the helper. It looks like:
+
+ @code
+ #include <kauth.h>
+
+ using namespace KAuth;
+
+ class MyHelper : public QObject
+ {
+ Q_OBJECT
+
+ public slots:
+ ActionReply read(const QVariantMap& args);
+ ActionReply write(const QVariantMap& args);
+ ActionReply longaction(const QVariantMap& args);
+ };
+ @endcode
+
+ The slot names are the last part of the action name, without the helper's ID if it's a prefix, with all the dots replaced by underscores. In this case, the helper ID is "org.kde.auth.example", so those
+ three slots implement the actions "org.kde.auth.example.read", "org.kde.auth.example.write" and "org.kde.auth.example.longaction". The helper ID doesn't have to appear at the beginning of the action
+ name, but it's good practice. If you want to extend MyHelper to implement also a different action like "org.kde.datetime.changetime", since the helper ID doesn't match you'll have to implement a
+ slot called org_kde_datetime_changetime().
+
+ The slot's signature is fixed: the return type is ActionReply, a class that allows you to return results, error codes and custom data to the application when your action has finished to run.
+ Please note that due to QMetaObject being picky about namespaces, you NEED to declare the return type as ActionReply and not KAuth::ActionReply. So the using declaration is compulsory
+ The QVariantMap object that comes as argument contains custom data coming from the application.
+
+ Let's look at the read action implementation. Its purpose is to read files:
+
+ @code
+ ActionReply MyHelper::read(QVariantMap args)
+ {
+ ActionReply reply;
+ QString filename = args["filename"].toString();
+ QFile file(filename);
+ if (!file.open(QIODevice::ReadOnly)) {
+ reply = ActionReply::HelperErrorReply;
+ reply.setErrorCode(file.error());
+
+ return reply;
+ }
+
+ QTextStream stream(&file);
+ QString contents;
+ stream >> contents;
+ reply.data()["contents"] = contents;
+
+ return reply;
+ }
+ @endcode
+
+ First, the code creates a default reply object. The default constructor creates a reply that reports success. Then it gets the filename parameter from the argument QVariantMap, that has previously been
+ set by the application, before calling the helper. If it fails to open the file, it creates an ActionReply object that notifies that some error has happened in the helper, then set the error code to
+ that returned by QFile and returns. If there is no error, it reads the file. The contents are put into the reply.data() object, which is another QVariantMap. It will be sent back to the application
+ with the reply.
+
+ Because this class will be compiled into a standalone executable, we need a main() function and some code to initialize everything: you don't have to write it. Instead, you use the
+ KDE4_AUTH_HELPER_MAIN() macro that will take care of everything. It's used like this:
+
+ @code
+ KDE4_AUTH_HELPER_MAIN("org.kde.auth.example", MyHelper)
+ @endcode
+
+ The first parameter is the string containing the helper identifier. Please note that you need to use this same string in the application's code to tell the library which helper to call, so please
+ stay away from typos, because we don't have any way to detect them. The second parameter is the name of the helper's class.
+ Your helper, if complex, can be composed of a lot of source files, but the important thing is to include this macro in one at least one of them.
+
+ To build the helper, KDE macros provide a function named kde4_install_auth_helper_files(). Use it in your cmake file like this:
+
+ @code
+ kde4_add_executable(<helper_target> your sources...)
+ target_link_libraries(<helper_target> your libraries...)
+ install(TARGETS <helper_target> DESTINATION ${LIBEXEC_INSTALL_DIR})
+
+ kde4_install_auth_helper_files(<helper_target> <helper_id> <user>)
+ @endcode
+
+ The first argument is the cmake target name for the helper executable, which you have to build and install separately. Make sure to INSTALL THE HELPER IN ${LIBEXEC_INSTALL_DIR},
+ otherwise kde4_install_auth_helper_files will not work. The second argument is the
+ helper id. Please be sure to don't misspell it, and to not quote it. The user parameter is the user that the helper has to be run as. It usually is root, but some actions could require less strict
+ permissions, so you should use the right user where possible (for example the user apache if you have to mess with apache settings). Note that the target created by this macro already links to
+ libkauth and QtCore
+
+ @section kauth_actions Action registration
+ To be able to authorize the actions, they have to be added to the policy database. To do this in a cross-platform way, we provide a cmake macro. It looks like:
+ @code
+ kde4_install_auth_actions(<helper_id> <actions definition file>)
+ @endcode
+
+ The action definition file describes which actions are implemented by your code and which default security options they should have. It is a common text file in ini format, with one section for
+ each action and some parameters. The definition for the read action is:
+
+ @verbatim
+ [org.kde.auth.example.read]
+ Name=Read action
+ Description=Read action description
+ Policy=auth_admin
+ Persistence=session
+ @endverbatim
+
+ The name parameter is a text describing the action for <i>who reads the file</i>. The description parameter is the message shown to the user in the authentication dialog. It should be a finite phrase.
+ The policy attribute specify the default rule that the user must satisfy to be authorized. Possible values are:
+ - yes: the action should be always allowed
+ - no: the action should be always denied
+ - auth_self: the user should authenticate as itself
+ - auth_admin: the user should authenticate as an administrator user
+
+ The persistence attribute is optional. It says how long an authorization should be retained for that action. The values could be:
+ - session: the authorization persists until the user logs-out
+ - always: the authorization will persist indefinitely
+
+ @section kauth_app Calling the helper from the application
+
+ Once the helper is ready, we need to call it from the main application. In the example's mainwindow.cpp you can see how this is done. To create a reference to an action, an object of type Action has to
+ be created. Every Action object refers to an action by its action id. Two objects with the same action id will act on the same action.
+ With an Action object, you can authorize and execute the action. To execute an action you have a couple of choices:
+ - A synchronous call, using the Action::execute() method, will start the helper, execute the action and return the reply.
+ - An asynchronous call, by setting Action::setExecutesAsync(true) and calling ::execute(), will start the helper and return immediately.
+
+ The asynchronous call is the most flexible alternative, but you need a way to obtain the reply. This is done by connecting to a signal, but the Action class is not a QObject subclass. Instead, you connect
+ to signals exposed by the ActionWatcher class. For every action id you use, there is one ActionWatcher object. You can retrieve it using the Action::watcher() method. If you execute an action using
+ Action::executeAsync(), you can connect to the actionPerformed(ActionReply) signal to be notified when the action has been completed (or failed). As a parameter, you'll get a reply object containing
+ all the data you need. As a convenience, you can also pass an object and a slot to the executeAsync() method to directly connect them to the signal, if you don't want to mess with watchers.
+
+ The piece of code that calls the action of the previous example is located in example/mainwindow.cpp in the on_readAction_triggered() slot. It looks like this:
+ @code
+ QVariantMap args;
+ args["filename"] = filename;
+ Action readAction = "org.kde.auth.example.read";
+ readAction.setHelperID("org.kde.auth.example");
+ readAction.setArguments(args);
+
+ ActionReply reply = readAction.execute();
+ if (reply.failed())
+ QMessageBox::information(this, "Error", QString("KAuth returned an error code: %1").arg(reply.errorCode()));
+ else
+ contents = reply.data()["contents"].toString();
+ @endcode
+
+ First of all, it creates the action object specifying the action id. Then it loads the filename (we want to read a forbidden file) into the arguments() QVariantMap, which will be directly passed to the
+ helper in the read() slot's parameter. This example code uses a synchronous call to execute the action and retrieve the reply. If the reply succeeded, the reply data is retrieved from the returned QVariantMap
+ object. Please note that, although the execute() method will return only when the action is completed, the GUI will remain responsive because an internal event loop is entered. This means you should be
+ prepared to receive other events in the meanwhile. Also, notice that you have to explicitly set the helper ID to the action: this is done for added safety, to prevent the caller from accidentally invoking
+ a helper, and also because KAuth actions may be used without a helper attached (the default). In this case, action.execute() will return ActionSuccess if the authentication went well. This is quite useful
+ if you want your user to authenticate before doing something, which however needs no privileged permissions implementation-wise.
+
+
+ @section kauth_async Asynchronous calls, data reporting, and action termination
+
+ For a more advanced example, we look at the action "org.kde.auth.example.longaction" in the example helper. This is an action that takes a long time to execute, so we need some features:
+ - The helper needs to regularly send data to the application, to inform about the execution status.
+ - The application needs to be able to stop the action execution if the user stops it or close the application.
+ The example code follows:
+ @code
+ ActionReply MyHelper::longaction(QVariantMap args)
+ {
+ for (int i = 1; i <= 100; i++) {
+ if (HelperSupport::isStopped())
+ break;
+ HelperSupport::progressStep(i);
+ usleep(250000);
+ }
+ return ActionReply::SuccessReply;
+ }
+ @endcode
+
+ In this example, the action is only waiting a "long" time using a loop, but we can see some interesting line. The progress status is sent to the application using the HelperSupport::progressStep() method.
+ When this method is called, the ActionWatcher associated with this action will emit the progressStep() signal, reporting back the data to the application. There are two overloads of these methods and
+ corresponding signals. The one used here takes an integer. Its meaning is application dependent, so you can use it as a sort of percentage. The other overload takes a QVariantMap object that is directly
+ passed to the app. In this way, you can report to the application all the custom data you want.
+
+ In this example code, the loop exits when the HelperSupport::isStopped() returns true. This happens when the application calls the stop() method on the correponding action object. The stop() method, this
+ way, asks the helper to stop the action execution. It's up to the helper to obbey to this request, and if it does so, it should return from the slot, _not_ exit.
+
+ The code that calls the action in the application connects a slot to the actionPerformed() signal and then call executeAsync(). The progressStep() signal is directly connected to a QProgressBar, and
+ the Stop button in the UI is connected to a slot that calls the Action::stop() method.
+
+ @code
+ void MainWindow::on_longAction_triggered()
+ {
+ Action longAction = "org.kde.auth.example.longaction";
+ connect(longAction.watcher(), SIGNAL(progressStep(int)),
+ progressBar, SLOT(setValue(int)));
+ connect(longAction.watcher(), SIGNAL(actionPerformed(ActionReply)),
+ this, SLOT(longActionPerformed(ActionReply)));
+
+ longAction.setExecutesAsync(true);
+ if (longAction.execute() != Action::Authorized)
+ this->statusBar()->showMessage("Could not execute the long action");
+
+ //...
+ }
+
+ void MainWindow::stopLongAction()
+ {
+ Action("org.kde.auth.example.longaction").stop();
+ }
+
+ void MainWindow::longActionPerformed(ActionReply reply)
+ {
+ //...
+
+ if (reply.succeeded())
+ this->statusBar()->showMessage("Action succeeded", 10000);
+ else
+ this->statusBar()->showMessage(QString("Could not execute the long action: %1").arg(reply.errorCode()), 10000);
+ }
+ @endcode
+
+ Please pay attention that when you call an action, the helper will be busy executing that action. Therefore, you can't call two execute() methods in sequence like that:
+
+ @code
+ action1.execute();
+ action2.execute();
+ @endcode
+
+ If you do, you'll get a HelperBusy reply from the second action.
+ A solution would be to launch the second action from the slot connected to the first's actionPerformed signal, but this would be very ugly. Read further to know how to solve this problem.
+
+ @section kauth_other Other features
+
+ To allow to easily execute several actions in sequence, you can execute them in a group. This means using the Action::executeActions() static method, which takes a list of actions and asks the helper
+ to execute them with a single request. The helper will execute the actions in the specified order. All the signals will be emitted from the watchers associated with each action.
+
+ Sometimes the application needs to know when a particular action has started to execute. For this purpose, you can connect to the actionStarted() signal. It is emitted immediately before the helper's
+ slot is called. This isn't very useful if you call execute(), but if you use executeActions() it lets you know when individual actions in the group are started.
+
+ It doesn't happen very frequently that you code something that doesn't require some debugging, and you'll need some tool, even a basic one, to debug your helper code as well. For this reason, the
+ KDE Authorization library provides a message handler for the Qt debugging system. This means that every call to qDebug() & co. will be reported to the application, and printed using the same qt debugging
+ system, with the same debug level.
+ If, in the helper code, you write something like:
+ @code
+ qDebug() << "I'm in the helper";
+ @endcode
+ You'll see something like this in the <i>application</i>'s output:
+
+ @verbatim
+ Debug message from the helper: I'm in the helper
+ @endverbatim
+
+ Remember that the debug level is preserved, so if you use qFatal() you won't only abort the helper (which isn't suggested anyway), but also the application.
+
+
+
+ */
+namespace KAuth
+{
+
+/**
+* @brief Class that encapsulates a reply coming from the helper after executing an action
+*
+* An instance of ActionReply is returned every time you execute an action with the Action
+* class. You get the reply directly from the Action::execute() method or indirectly as
+* a parameter of the ActionWatcher::actionPerformed() signal.
+*
+* ActionReply objects can contain both data from a successful action or an error indicator.
+* In case of success, the errorCode() is ActionReply::NoError (zero) and the type() is
+* ActionReply::Success. The data() method returns a QVariantMap object that may contain
+* custom data sent back by the helper.
+*
+* In case of errors coming from the library, the type() is ActionReply::KAuthError. In this
+* case, errorCode() will always be one of the predefined errors from the ActionReply::Error enum.
+* An error reply of KAuthError type always contains an empty data() object. For some kind of errors
+* you could get a human-readable description with errorDescription().
+*
+* If, instead, the helper itself has to report some errors occurred during the action execution,
+* the type() will be (and has to be) ActionReply::HelperError. In this case the data() object can
+* contain custom data from the helper, and the errorCode() and errorDescription() values are
+* application-dependent.
+*
+* In the helper, to create an action reply object you have two choices: using the constructor, or
+* the predefined replies. For example, to create a successful reply you can use the default constructor
+* but to create a helper error reply, instead of writing <i>ActionReply(ActionReply::HelperError)</i>
+* you could use the more convenient <i>ActionReply::HelperErrorReply</i> constant.
+*
+* You should not use the predefined error replies to create and return new errors. Replies with the
+* KAuthError type are intended to be returned by the library only. However, you can use them for
+* comparisons.
+*
+* To quickly check for success or failure of an action, you can use succeeded() or failed().
+*
+* @since 4.4
+*/
+class KDECORE_EXPORT ActionReply
+{
+ class Private;
+ Private * const d;
+
+public:
+ /**
+ * Enumeration of the different kinds of replies.
+ */
+ enum Type {
+ KAuthError, ///< An error reply generated by the library itself.
+ HelperError, ///< An error reply generated by the helper.
+ Success ///< The action has been completed successfully
+ };
+
+ static const ActionReply SuccessReply; ///< An empty successful reply. Same as using the default constructor
+ static const ActionReply HelperErrorReply; ///< An empty reply with type() == HelperError.
+
+ static const ActionReply NoResponderReply; ///< errorCode() == NoResponder
+ static const ActionReply NoSuchActionReply; ///< errorCode() == NoSuchAction
+ static const ActionReply InvalidActionReply; ///< errorCode() == InvalidAction
+ static const ActionReply AuthorizationDeniedReply; ///< errorCode() == AuthorizationDenied
+ static const ActionReply UserCancelledReply; ///< errorCode() == UserCancelled
+ static const ActionReply HelperBusyReply; ///< errorCode() == HelperBusy
+ static const ActionReply DBusErrorReply; ///< errorCode() == DBusError
+
+ /**
+ * The enumeration of the possible values of errorCode() when type() is ActionReply::KAuthError
+ */
+ enum Error {
+ NoError = 0, ///< No error.
+ NoResponder, ///< The helper responder object hasn't been set. This shouldn't happen if you use the KDE4_AUTH_HELPER macro in the helper source
+ NoSuchAction, ///< The action you tried to execute doesn't exist.
+ InvalidAction, ///< You tried to execute an invalid action object
+ AuthorizationDenied, ///< You don't have the authorization to execute the action
+ UserCancelled, ///< Action execution has been cancelled by the user
+ HelperBusy, ///< The helper is busy executing another action (or group of actions). Try later
+ DBusError ///< An error from D-Bus occurred
+ };
+
+ /// Default constructor. Sets type() to Success and errorCode() to zero.
+ ActionReply();
+
+ /**
+ * @brief Constructor to directly set the type.
+ *
+ * This constructor directly sets the reply type. You shouldn't need to
+ * directly call this constructor, because you can use the more convenient
+ * predefined replies constants. You also shouldn't create a reply with
+ * the KAuthError type because it's reserved for errors coming from the
+ * library.
+ *
+ * @param type The type of the new reply
+ */
+ ActionReply(Type type);
+
+ /**
+ * @brief Constructor that creates a KAuthError reply with a specified error code.
+ * Do not use outside the library.
+ *
+ * This constructor is for internal use only, since it creates a reply
+ * with KAuthError type, which is reserved for errors coming from the library.
+ *
+ * @param errorCode The error code of the new reply
+ */
+ ActionReply(int errorCode);
+
+ /// Copy constructor
+ ActionReply(const ActionReply &reply);
+
+ /// Virtual destructor
+ virtual ~ActionReply();
+
+ /**
+ * @brief Sets the custom data to send back to the application
+ *
+ * In the helper's code you can use this function to set an QVariantMap
+ * with custom data that will be sent back to the application.
+ *
+ * @param data The new QVariantMap object.
+ */
+ void setData(const QVariantMap &data);
+
+ /**
+ * @brief Returns the custom data coming from the helper.
+ *
+ * This method is used to get the object that contains the custom
+ * data coming from the helper. In the helper's code, you can set it
+ * using setData() or the convenience method addData().
+ *
+ * @return The data coming from (or that will be sent by) the helper
+ */
+ QVariantMap data() const;
+
+ /**
+ * @brief Convenience method to add some data to the reply.
+ *
+ * This method adds the pair @c key/value to the QVariantMap used to
+ * report back custom data to the application.
+ *
+ * Use this method if you don't want to create a new QVariantMap only to
+ * add a new entry.
+ *
+ * @param key The new entry's key
+ * @param value The value of the new entry
+ */
+ void addData(const QString &key, const QVariant &value);
+
+ /// Returns the reply's type
+ Type type() const;
+
+ /**
+ * @brief Sets the reply type
+ *
+ * Every time you create an action reply, you implicitly set a type.
+ * Default constructed replies or ActionReply::SuccessReply have
+ * type() == Success.
+ * ActionReply::HelperErrorReply has type() == HelperError.
+ * Predefined error replies have type() == KAuthError.
+ *
+ * This means you rarely need to change the type after the creation,
+ * but if you need to, don't set it to KAuthError, because it's reserved
+ * for errors coming from the library.
+ *
+ * @param type The new reply type
+ */
+ void setType(Type type);
+
+ /// Returns true if type() == Success
+ bool succeeded() const;
+
+ /// Returns true if type() != Success
+ bool failed() const;
+
+ /**
+ * @brief Returns the error code of an error reply
+ *
+ * The error code returned is one of the values in the ActionReply::Error
+ * enumeration if type() == KAuthError, or is totally application-dependent if
+ * type() == HelperError. It also should be zero for successful replies.
+ *
+ * @return The reply error code
+ */
+ int errorCode() const;
+
+ /**
+ * @brief Sets the error code of an error reply
+ *
+ * If you're setting the error code in the helper because
+ * you need to return an error to the application, please make sure
+ * you already have set the type to HelperError, either by calling
+ * setType() or by creating the reply in the right way.
+ *
+ * If the type is Success when you call this method, it will become KAuthError
+ *
+ * @param errorCode The new reply error code
+ */
+ void setErrorCode(int errorCode);
+
+ /**
+ * @brief Gets a human-readble description of the error, if available
+ *
+ * Currently, replies of type KAuthError rarely report an error description.
+ * This situation could change in the future.
+ *
+ * By now, you can use this method for custom errors of type HelperError.
+ *
+ * @return The error human-readable description
+ */
+ QString errorDescription() const;
+
+ /**
+ * @brief Sets a human-readble description of the error
+ *
+ * Call this method from the helper if you want to send back a description for
+ * a custom error. Note that this method doesn't affect the errorCode in any way
+ *
+ * @param error The new error description
+ */
+ void setErrorDescription(const QString &error);
+
+ /**
+ * @brief Serialize the reply into a QByteArray.
+ *
+ * This is a convenience method used internally to sent the reply to a remote peer.
+ * To recreate the reply, use deserialize()
+ *
+ * @return A QByteArray representation of this reply
+ */
+ QByteArray serialized() const;
+
+ /**
+ * @brief Deserialize a reply from a QByteArray
+ *
+ * This method returns a reply from a QByteArray obtained from
+ * the serialized() method.
+ *
+ * @param data A QByteArray obtained with serialized()
+ */
+ static ActionReply deserialize(const QByteArray &data);
+
+ /// Assignment operator
+ ActionReply &operator=(const ActionReply &reply);
+
+ /**
+ * @brief Comparison operator
+ *
+ * This operator checks if the type and the error code of two replies are the same.
+ * It <b>doesn't</b> compare the data or the error descriptions, so be careful.
+ *
+ * The suggested use it to compare a reply agains one of the predefined error replies:
+ * @code
+ * if(reply == ActionReply::HelperBusyReply) {
+ * // Do something...
+ * }
+ * @endcode
+ *
+ * Note that you can do it also by compare errorCode() with the relative enumeration value.
+ */
+ bool operator==(const ActionReply &reply) const;
+
+ /**
+ * @brief Negated comparison operator
+ *
+ * See the operator==() for an important notice.
+ */
+ bool operator!=(const ActionReply &reply) const;
+
+ /// Output streaming operator for QDataStream
+ friend QDataStream &operator<<(QDataStream &, const ActionReply &);
+
+ /// Input streaming operator for QDataStream
+ friend QDataStream &operator>>(QDataStream &, ActionReply &);
+
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/kauthactionwatcher.cpp b/kdecore/auth/kauthactionwatcher.cpp
new file mode 100644
index 0000000..d2c920f
--- /dev/null
+++ b/kdecore/auth/kauthactionwatcher.cpp
@@ -0,0 +1,118 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "kauthactionwatcher.h"
+#include "BackendsManager.h"
+
+#include <QHash>
+
+namespace KAuth
+{
+
+class ActionWatcher::Private
+{
+public:
+ Private(ActionWatcher *parent) : q(parent) {}
+
+ ActionWatcher *q;
+ QString action;
+
+ void actionStartedSlot(const QString &action);
+ void actionPerformedSlot(const QString &action, const ActionReply &reply);
+ void progressStepSlot(const QString &action, int i);
+ void progressStepSlot(const QString &action, const QVariantMap &data);
+ void statusChangedSlot(const QString &action, Action::AuthStatus status);
+};
+
+static QHash<QString, ActionWatcher *> s_watchers;
+
+ActionWatcher::ActionWatcher(const QString &action)
+ : QObject(0)
+ , d(new Private(this))
+{
+ d->action = action;
+
+ HelperProxy *helper = BackendsManager::helperProxy();
+
+ connect(helper, SIGNAL(actionStarted(QString)), this, SLOT(actionStartedSlot(QString)));
+ connect(helper, SIGNAL(actionPerformed(QString,ActionReply)), this, SLOT(actionPerformedSlot(QString,ActionReply)));
+ connect(helper, SIGNAL(progressStep(QString,int)), this, SLOT(progressStepSlot(QString,int)));
+ connect(helper, SIGNAL(progressStep(QString,QVariantMap)), this, SLOT(progressStepSlot(QString,QVariantMap)));
+ connect(BackendsManager::authBackend(), SIGNAL(actionStatusChanged(QString,Action::AuthStatus)),
+ this, SLOT(statusChangedSlot(QString,Action::AuthStatus)));
+}
+
+ActionWatcher::~ActionWatcher()
+{
+ delete d;
+}
+
+ActionWatcher *ActionWatcher::watcher(const QString &action)
+{
+ if (!s_watchers.contains(action)) {
+ s_watchers[action] = new ActionWatcher(action);
+ }
+
+ return s_watchers[action];
+}
+
+QString ActionWatcher::action() const
+{
+ return d->action;
+}
+
+void ActionWatcher::Private::actionStartedSlot(const QString &taction)
+{
+ if (taction == action) {
+ emit q->actionStarted();
+ }
+}
+
+void ActionWatcher::Private::actionPerformedSlot(const QString &taction, const ActionReply &reply)
+{
+ if (taction == action) {
+ emit q->actionPerformed(reply);
+ }
+}
+
+void ActionWatcher::Private::progressStepSlot(const QString &taction, int i)
+{
+ if (taction == action) {
+ emit q->progressStep(i);
+ }
+}
+
+void ActionWatcher::Private::progressStepSlot(const QString &taction, const QVariantMap &data)
+{
+ if (taction == action) {
+ emit q->progressStep(data);
+ }
+}
+
+void ActionWatcher::Private::statusChangedSlot(const QString &taction, Action::AuthStatus status)
+{
+ if (taction == action) {
+ emit q->statusChanged(status);
+ }
+}
+
+} // namespace Auth
+
+#include "kauthactionwatcher.moc"
diff --git a/kdecore/auth/kauthactionwatcher.h b/kdecore/auth/kauthactionwatcher.h
new file mode 100644
index 0000000..c204fa1
--- /dev/null
+++ b/kdecore/auth/kauthactionwatcher.h
@@ -0,0 +1,154 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 ACTION_WATCHER_H
+#define ACTION_WATCHER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+#include <kdecore_export.h>
+
+#include "kauthactionreply.h"
+#include "kauthaction.h"
+
+namespace KAuth
+{
+
+/**
+ * @brief Class used to receive notifications about the status of an action execution.
+ *
+ * The ActionWatcher class provides some signals useful to track the execution of an action.
+ * The Action class is designed to be very ligthweight, so it's not the case to make it
+ * a QObject subclass. This means the action object can't expose signals. This is the reason
+ * why every action (not every Action object) used by the app has an associated ActionWatcher.
+ *
+ * You don't create watchers directly. Instead, you should get one from the Action::watcher() method,
+ * if you have an action object, or with the ActionWatcher::watcher() static method, which takes the
+ * action name string.
+ *
+ * See the documentation of single signals for more details about them.
+ *
+ * @since 4.4
+ */
+class KDECORE_EXPORT ActionWatcher : public QObject
+{
+ Q_OBJECT
+
+ class Private;
+ Private * const d;
+
+ ActionWatcher();
+ ActionWatcher(const QString &action);
+
+ Q_PRIVATE_SLOT(d, void actionStartedSlot(const QString &action))
+ Q_PRIVATE_SLOT(d, void actionPerformedSlot(const QString &action, const ActionReply &reply))
+ Q_PRIVATE_SLOT(d, void progressStepSlot(const QString &action, int i))
+ Q_PRIVATE_SLOT(d, void progressStepSlot(const QString &action, const QVariantMap &data))
+ Q_PRIVATE_SLOT(d, void statusChangedSlot(const QString &action, Action::AuthStatus status))
+
+public:
+ /**
+ * @brief Factory method to get watchers
+ *
+ * This method allows you to obtain (and create if needed) an
+ * action watcher from the action string identifier.
+ * It's more common to obtain a watcher using Action::watcher(),
+ * which actually calls this method.
+ *
+ * Every signal of this class
+ * is emitted whichever method you used to execute the action.
+ * This means you could connect to the signal actionPerformed()
+ * even if you're using the execute() method (which already returns the reply)
+ * and you'll get the same reply.
+ *
+ * @param action The action string identifier for the creation of the watcher
+ * @return The action watcher associated with the given action
+ */
+ static ActionWatcher *watcher(const QString &action);
+
+ /// Virtual destructor
+ virtual ~ActionWatcher();
+
+ /// Returns the action name associated with this watcher
+ QString action() const;
+
+Q_SIGNALS:
+ /**
+ * @brief Signal emitted when an action starts the execution
+ *
+ * This signal is emitted whe In case of
+ * execute() and executeAsync(), the signal is emitted about
+ * immediately, because the request is very fast.
+ *
+ * If you execute a group of actions using Action::executeActions(),
+ * this signal is emitted when the single action is actually about
+ * to be executed, not when the whole group starts executing.
+ * This means you can use this signal to start some kind of timeout
+ * to handle helper crashes, if you feel the need.
+ */
+ void actionStarted();
+
+ /**
+ * @brief Signal emitted when an action completed the execution
+ *
+ * This signal provides the only way to obtain the reply from the helper
+ * in case of asynchronous calls. The reply object is the same returned
+ * by the helper, or an error reply from the library if something went
+ * wrong.
+ *
+ * @param reply The reply coming from the helper
+ */
+ void actionPerformed(const ActionReply &reply);
+
+ /**
+ * @brief Signal emitted by the helper to notify the action's progress
+ *
+ * This signal is emitted every time the helper's code calls the
+ * HelperSupport::progressStep(int) method. This is useful to let the
+ * helper notify the execution status of a long action.
+ * The meaning of the integer passed here is totally application-dependent.
+ * If you need to be more expressive, you can use the other signal that
+ * pass a QVariantMap.
+ *
+ * @param progress The progress indicator from the helper
+ */
+ void progressStep(int progress);
+
+ /**
+ * @brief Signal emitted by the helper to notify the action's progress
+ *
+ * This signal is emitted every time the helper's code calls the
+ * HelperSupport::progressStep(QVariantMap) method. This is useful to let the
+ * helper notify the execution status of a long action, also providing
+ * some data, for example if you want to achieve some sort of progressive loading.
+ * The meaning of the data passed here is totally application-dependent.
+ * If you only need to pass some percentage, you can use the other signal that
+ * pass an int.
+ *
+ * @param data The progress data from the helper
+ */
+ void progressStep(const QVariantMap &data);
+
+ void statusChanged(int status);
+};
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/kauthhelpersupport.cpp b/kdecore/auth/kauthhelpersupport.cpp
new file mode 100644
index 0000000..41b673b
--- /dev/null
+++ b/kdecore/auth/kauthhelpersupport.cpp
@@ -0,0 +1,112 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "kauthhelpersupport.h"
+
+#include <cstdlib>
+#include <syslog.h>
+
+#include <QCoreApplication>
+#include <QTimer>
+
+#include "BackendsManager.h"
+
+Q_DECLARE_METATYPE(QTimer*)
+
+namespace KAuth
+{
+
+namespace HelperSupport
+{
+void helperDebugHandler(QtMsgType type, const char *msg);
+}
+
+static bool remote_dbg = false;
+
+int HelperSupport::helperMain(int argc, char **argv, const char *id, QObject *responder)
+{
+ openlog(id, 0, LOG_USER);
+ qInstallMsgHandler(&HelperSupport::helperDebugHandler);
+
+ if (!BackendsManager::helperProxy()->initHelper(QString::fromLatin1(id))) {
+ syslog(LOG_DEBUG, "Helper initialization failed");
+ return -1;
+ }
+
+ //closelog();
+ remote_dbg = true;
+
+ BackendsManager::helperProxy()->setHelperResponder(responder);
+
+ QCoreApplication app(argc, argv);
+ // Attach the timer
+ QTimer *timer = new QTimer(0);
+ responder->setProperty("__KAuth_Helper_Shutdown_Timer", QVariant::fromValue(timer));
+ timer->setInterval(10000);
+ timer->start();
+ QObject::connect(timer, SIGNAL(timeout()), &app, SLOT(quit()));
+ app.exec(); //krazy:exclude=crashy
+
+ return 0;
+}
+
+void HelperSupport::helperDebugHandler(QtMsgType type, const char *msg)
+{
+ if (!remote_dbg) {
+ int level = LOG_DEBUG;
+ switch (type) {
+ case QtDebugMsg:
+ level = LOG_DEBUG;
+ break;
+ case QtWarningMsg:
+ level = LOG_WARNING;
+ break;
+ case QtCriticalMsg:
+ case QtFatalMsg:
+ level = LOG_ERR;
+ break;
+ }
+ syslog(level, "%s", msg);
+ } else {
+ BackendsManager::helperProxy()->sendDebugMessage(type, msg);
+ }
+
+ // Anyway I should follow the rule:
+ if (type == QtFatalMsg) {
+ exit(-1);
+ }
+}
+
+void HelperSupport::progressStep(int step)
+{
+ BackendsManager::helperProxy()->sendProgressStep(step);
+}
+
+void HelperSupport::progressStep(const QVariantMap &data)
+{
+ BackendsManager::helperProxy()->sendProgressStep(data);
+}
+
+bool HelperSupport::isStopped()
+{
+ return BackendsManager::helperProxy()->hasToStopAction();
+}
+
+} // namespace Auth
diff --git a/kdecore/auth/kauthhelpersupport.h b/kdecore/auth/kauthhelpersupport.h
new file mode 100644
index 0000000..6697e7d
--- /dev/null
+++ b/kdecore/auth/kauthhelpersupport.h
@@ -0,0 +1,106 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 HELPER_SUPPORT_H
+#define HELPER_SUPPORT_H
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+
+#include <kdecore_export.h>
+
+#define KDE4_AUTH_HELPER_MAIN(ID, HelperClass) \
+ int main(int argc, char **argv) { return KAuth::HelperSupport::helperMain(argc, argv, ID, new HelperClass()); }
+
+namespace KAuth
+{
+
+/**
+ * @brief Support class with some KDECORE_EXPORT methods useful to the helper's code
+ *
+ * This class provides the API to write the helper tool that executes your actions.
+ * You don't create instances of HelperSupport. Instead, you use its KDECORE_EXPORT methods.
+ *
+ * This them you can notify the application of progress in your action's execution
+ * and you can check if the application asked you to terminate it.
+ *
+ * @since 4.4
+ */
+namespace HelperSupport
+{
+/**
+ * @brief Send a progressStep signal to the caller application
+ *
+ * You can use this method to notify progress information about the
+ * action execution. When you call this method, the ActionWatcher
+ * object associated with the current action will emit the progressStep(int)
+ * signal. The meaning of the integer passed here is totally application dependent,
+ * but you'll want to use it as a sort of percentage.
+ * If you need to be more expressive, use the other overload which takes a QVariantMap
+ *
+ * @param step The progress indicator
+ */
+KDECORE_EXPORT void progressStep(int step);
+
+/**
+* @brief Send a progressStep signal to the caller application
+*
+* You can use this method to notify progress information about the
+* action execution. When you call this method, the ActionWatcher
+* object associated with the current action will emit the progressStep(QVariantMap)
+* signal. The meaning of the data passed here is totally application dependent.
+* If you only need a simple percentage value, use the other overload which takes an int.
+*
+* @param data The progress data
+*/
+KDECORE_EXPORT void progressStep(const QVariantMap &data);
+
+/**
+ * @brief Check if the caller asked the helper to stop the execution
+ *
+ * This method will return true if the helper has been asked to stop the
+ * execution of the current action. If this happens, your helper should
+ * return (NOT exit). The meaning of the data you return in this case is
+ * application-dependent.
+ * It's good practice to check it regularly if you have a long-running action
+ *
+ * @return true if the helper has been asked to stop, false otherwise
+ */
+KDECORE_EXPORT bool isStopped();
+
+
+/**
+ * @brief Method that implements the main function of the helper tool. Do not call directly
+ *
+ * This method is called in the proper way by the code generated by the KDE4_AUTH_HELPER_MAIN(),
+ * which creates a main() function for the helper tool.
+ * macro. You shouldn't call this method directly.
+ *
+ * @param argc The argc parameter from the main() function.
+ * @param argv The argv parameter from the main() function.
+ * @param id The helper ID as passed to the macro
+ * @param responder The responder object for the helper. The macro passes a default-constructed,
+ * heap-allocated object of the class specified as the last macro parameter
+ */
+KDECORE_EXPORT int helperMain(int argc, char **argv, const char *id, QObject *responder);
+} // namespace HelperSupport
+
+} // namespace Auth
+
+#endif
diff --git a/kdecore/auth/policy-gen/policy-gen.cpp b/kdecore/auth/policy-gen/policy-gen.cpp
new file mode 100644
index 0000000..165f240
--- /dev/null
+++ b/kdecore/auth/policy-gen/policy-gen.cpp
@@ -0,0 +1,155 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 "policy-gen.h"
+#include <QFile>
+
+#include <QCoreApplication>
+#include <QSettings>
+#include <QRegExp>
+#include <QStringList>
+#include <QDebug>
+
+using namespace std;
+
+QList<Action> parse(QSettings &ini);
+QHash<QString, QString> parseDomain(QSettings &ini);
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ if (argc < 2) {
+ qCritical("Too few arguments");
+ return 1;
+ }
+
+ QSettings ini(QFile::decodeName(argv[1]), QSettings::IniFormat);
+ ini.setIniCodec("UTF-8");
+ if (ini.status()) {
+ qCritical("Error loading file: %s", argv[1]);
+ return 1;
+ }
+
+ output(parse(ini), parseDomain(ini));
+}
+
+QList<Action> parse(QSettings &ini)
+{
+ QList<Action> actions;
+ QRegExp actionExp(QLatin1String("[0-9a-z]+(\\.[0-9a-z]+)*"));
+ QRegExp descriptionExp(QLatin1String("description(?:\\[(\\w+)\\])?"));
+ QRegExp nameExp(QLatin1String("name(?:\\[(\\w+)\\])?"));
+ QRegExp policyExp(QLatin1String("yes|no|auth_self|auth_admin"));
+
+ descriptionExp.setCaseSensitivity(Qt::CaseInsensitive);
+ nameExp.setCaseSensitivity(Qt::CaseInsensitive);
+
+ foreach(const QString &name, ini.childGroups()) {
+ Action action;
+
+ if (name == QLatin1String("Domain")) {
+ continue;
+ }
+
+ if (!actionExp.exactMatch(name)) {
+ qCritical("Wrong action syntax: %s\n", name.toAscii().data());
+ exit(1);
+ }
+
+ action.name = name;
+ ini.beginGroup(name);
+
+ foreach(const QString &key, ini.childKeys()) {
+ if (descriptionExp.exactMatch(key)) {
+ QString lang = descriptionExp.capturedTexts().at(1);
+
+ if (lang.isEmpty())
+ lang = QString::fromLatin1("en");
+
+ action.descriptions.insert(lang, ini.value(key).toString());
+
+ } else if (nameExp.exactMatch(key)) {
+ QString lang = nameExp.capturedTexts().at(1);
+
+ if (lang.isEmpty())
+ lang = QString::fromLatin1("en");
+
+ action.messages.insert(lang, ini.value(key).toString());
+
+ } else if (key.toLower() == QLatin1String("policy")) {
+ QString policy = ini.value(key).toString();
+ if (!policyExp.exactMatch(policy)) {
+ qCritical("Wrong policy: %s", policy.toAscii().data());
+ exit(1);
+ }
+ action.policy = policy;
+
+ } else if (key.toLower() == QLatin1String("policyinactive")) {
+ QString policyInactive = ini.value(key).toString();
+ if (!policyExp.exactMatch(policyInactive)) {
+ qCritical("Wrong policy: %s", policyInactive.toAscii().data());
+ exit(1);
+ }
+ action.policyInactive = policyInactive;
+
+ } else if (key.toLower() == QLatin1String("persistence")) {
+ QString persistence = ini.value(key).toString();
+ if (persistence != QLatin1String("session") && persistence != QLatin1String("always")) {
+ qCritical("Wrong persistence: %s", persistence.toAscii().data());
+ exit(1);
+ }
+ action.persistence = persistence;
+ }
+ }
+
+ if (action.policy.isEmpty() || action.messages.isEmpty() || action.descriptions.isEmpty()) {
+ qCritical("Missing option in action: %s", name.toAscii().data());
+ exit(1);
+ }
+ ini.endGroup();
+
+ actions.append(action);
+ }
+
+ return actions;
+}
+
+
+QHash<QString, QString> parseDomain(QSettings& ini)
+{
+ QHash<QString, QString> rethash;
+
+ if (ini.childGroups().contains(QString::fromLatin1("Domain"))) {
+ if (ini.contains(QString::fromLatin1("Domain/Name"))) {
+ rethash[QString::fromLatin1("vendor")] = ini.value(QString::fromLatin1("Domain/Name")).toString();
+ }
+ if (ini.contains(QString::fromLatin1("Domain/URL"))) {
+ rethash[QString::fromLatin1("vendorurl")] = ini.value(QString::fromLatin1("Domain/URL")).toString();
+ }
+ if (ini.contains(QString::fromLatin1("Domain/Icon"))) {
+ rethash[QString::fromLatin1("icon")] = ini.value(QString::fromLatin1("Domain/Icon")).toString();
+ }
+ }
+
+ return rethash;
+}
+
+
diff --git a/kdecore/auth/policy-gen/policy-gen.h b/kdecore/auth/policy-gen/policy-gen.h
new file mode 100644
index 0000000..5feec28
--- /dev/null
+++ b/kdecore/auth/policy-gen/policy-gen.h
@@ -0,0 +1,42 @@
+/*
+* Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com>
+* Copyright (C) 2009 Dario Freddi <drf@kde.org>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 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 Lesser General Public 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 _POLICY_GEN_H_
+#define _POLICY_GEN_H_
+
+#include <QString>
+#include <QMap>
+#include <QHash>
+
+struct Action {
+ QString name;
+
+ QHash<QString, QString> descriptions;
+ QHash<QString, QString> messages;
+
+ QString policy;
+ QString policyInactive;
+ QString persistence;
+};
+
+extern void output(QList<Action> actions, QHash<QString, QString> domain);
+
+
+#endif
diff --git a/kdecore/compression/ConfigureChecks.cmake b/kdecore/compression/ConfigureChecks.cmake
new file mode 100644
index 0000000..8edd173
--- /dev/null
+++ b/kdecore/compression/ConfigureChecks.cmake
@@ -0,0 +1,12 @@
+macro_optional_find_package(BZip2)
+macro_log_feature(BZIP2_FOUND "BZip2" "Support for BZip2 compressed files and data streams" "http://www.bzip.org" FALSE "" "STRONGLY RECOMMENDED")
+
+macro_optional_find_package(LibLZMA)
+macro_log_feature(LIBLZMA_FOUND "LZMA/XZ" "Support for xz compressed files and data streams" "http://tukaani.org/xz/" FALSE "" "")
+
+macro_bool_to_01(BZIP2_FOUND HAVE_BZIP2_SUPPORT)
+if(BZIP2_FOUND AND BZIP2_NEED_PREFIX)
+ set(NEED_BZ2_PREFIX 1)
+endif(BZIP2_FOUND AND BZIP2_NEED_PREFIX)
+
+macro_bool_to_01(LIBLZMA_FOUND HAVE_XZ_SUPPORT)
diff --git a/kdecore/compression/config-compression.h.cmake b/kdecore/compression/config-compression.h.cmake
new file mode 100644
index 0000000..dce2ec1
--- /dev/null
+++ b/kdecore/compression/config-compression.h.cmake
@@ -0,0 +1,8 @@
+#cmakedefine01 HAVE_BZIP2_SUPPORT
+
+/* Set to 1 if the libbz2 functions need the BZ2_ prefix */
+#cmakedefine01 NEED_BZ2_PREFIX
+
+/* Set to 1 if you have xz */
+#cmakedefine01 HAVE_XZ_SUPPORT
+
diff --git a/kdecore/compression/karchive_export.h b/kdecore/compression/karchive_export.h
new file mode 100644
index 0000000..621c269
--- /dev/null
+++ b/kdecore/compression/karchive_export.h
@@ -0,0 +1,55 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KARCHIVE_EXPORT_H
+#define KARCHIVE_EXPORT_H
+
+#ifdef COMPILE_KARCHIVE_STANDALONE
+
+/* needed for KDE_EXPORT and KDE_IMPORT macros */
+#include <kdemacros.h>
+
+#ifndef KARCHIVE_EXPORT
+# if defined(KDELIBS_STATIC_LIBS)
+ /* No export/import for static libraries */
+# define KARCHIVE_EXPORT
+# elif defined(MAKE_KARCHIVE_LIB)
+ /* We are building this library */
+# define KARCHIVE_EXPORT KDE_EXPORT
+# else
+ /* We are using this library */
+# define KARCHIVE_EXPORT KDE_IMPORT
+# endif
+#endif
+
+#else
+
+/* KDE4 compatibility */
+
+#include <kdecore_export.h>
+#define KARCHIVE_EXPORT KDECORE_EXPORT
+
+#endif
+
+# ifndef KARCHIVE_EXPORT_DEPRECATED
+# define KARCHIVE_EXPORT_DEPRECATED KDE_DEPRECATED KARCHIVE_EXPORT
+# endif
+
+
+#endif
diff --git a/kdecore/compression/kbzip2filter.cpp b/kdecore/compression/kbzip2filter.cpp
new file mode 100644
index 0000000..0f55334
--- /dev/null
+++ b/kdecore/compression/kbzip2filter.cpp
@@ -0,0 +1,195 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000-2005 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kbzip2filter.h"
+
+#include <config-compression.h>
+
+#if HAVE_BZIP2_SUPPORT
+
+// we don't need that
+#define BZ_NO_STDIO
+extern "C" {
+ #include <bzlib.h>
+}
+
+#if NEED_BZ2_PREFIX
+ #define bzDecompressInit(x,y,z) BZ2_bzDecompressInit(x,y,z)
+ #define bzDecompressEnd(x) BZ2_bzDecompressEnd(x)
+ #define bzCompressEnd(x) BZ2_bzCompressEnd(x)
+ #define bzDecompress(x) BZ2_bzDecompress(x)
+ #define bzCompress(x,y) BZ2_bzCompress(x, y)
+ #define bzCompressInit(x,y,z,a) BZ2_bzCompressInit(x, y, z, a);
+#endif
+
+#include <QDebug>
+
+#include <qiodevice.h>
+
+
+
+// For docu on this, see /usr/doc/bzip2-0.9.5d/bzip2-0.9.5d/manual_3.html
+
+class KBzip2Filter::Private
+{
+public:
+ Private()
+ : isInitialized(false)
+ {
+ memset(&zStream, 0, sizeof(zStream));
+ mode = 0;
+ }
+
+ bz_stream zStream;
+ int mode;
+ bool isInitialized;
+};
+
+KBzip2Filter::KBzip2Filter()
+ :d(new Private)
+{
+}
+
+
+KBzip2Filter::~KBzip2Filter()
+{
+ delete d;
+}
+
+void KBzip2Filter::init( int mode )
+{
+ if (d->isInitialized) {
+ terminate();
+ }
+
+ d->zStream.next_in = 0;
+ d->zStream.avail_in = 0;
+ if ( mode == QIODevice::ReadOnly )
+ {
+ (void)bzDecompressInit(&d->zStream, 0, 0);
+ //qDebug() << "bzDecompressInit returned " << result;
+ // TODO: test result and return false on error
+ } else if ( mode == QIODevice::WriteOnly ) {
+ (void)bzCompressInit(&d->zStream, 5, 0, 0);
+ //qDebug() << "bzDecompressInit returned " << result;
+ // TODO: test result and return false on error
+ } else {
+ qWarning() << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+ // TODO return false
+ }
+ d->mode = mode;
+ d->isInitialized = true;
+}
+
+int KBzip2Filter::mode() const
+{
+ return d->mode;
+}
+
+void KBzip2Filter::terminate()
+{
+ if (d->mode == QIODevice::ReadOnly) {
+ int result = bzDecompressEnd(&d->zStream);
+ // TODO: test result and return false on error
+ //qDebug() << "bzDecompressEnd returned " << result;
+ } else if (d->mode == QIODevice::WriteOnly) {
+ int result = bzCompressEnd(&d->zStream);
+ // TODO: test result and return false on error
+ //qDebug() << "bzCompressEnd returned " << result;
+ } else {
+ qWarning() << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+ // TODO return false
+ }
+ d->isInitialized = false;
+}
+
+
+void KBzip2Filter::reset()
+{
+ // bzip2 doesn't seem to have a reset call...
+ terminate();
+ init( d->mode );
+}
+
+void KBzip2Filter::setOutBuffer( char * data, uint maxlen )
+{
+ d->zStream.avail_out = maxlen;
+ d->zStream.next_out = data;
+}
+
+void KBzip2Filter::setInBuffer( const char *data, unsigned int size )
+{
+ d->zStream.avail_in = size;
+ d->zStream.next_in = const_cast<char *>(data);
+}
+
+int KBzip2Filter::inBufferAvailable() const
+{
+ return d->zStream.avail_in;
+}
+
+int KBzip2Filter::outBufferAvailable() const
+{
+ return d->zStream.avail_out;
+}
+
+KBzip2Filter::Result KBzip2Filter::uncompress()
+{
+ //qDebug() << "Calling bzDecompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+ int result = bzDecompress(&d->zStream);
+ if ( result != BZ_OK )
+ {
+ qDebug() << "bzDecompress returned" << result;
+ qDebug() << "KBzip2Filter::uncompress" << ( result == BZ_STREAM_END ? KFilterBase::End : KFilterBase::Error );
+ }
+
+ switch (result) {
+ case BZ_OK:
+ return KFilterBase::Ok;
+ case BZ_STREAM_END:
+ return KFilterBase::End;
+ default:
+ return KFilterBase::Error;
+ }
+}
+
+KBzip2Filter::Result KBzip2Filter::compress( bool finish )
+{
+ //qDebug() << "Calling bzCompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+ int result = bzCompress(&d->zStream, finish ? BZ_FINISH : BZ_RUN );
+
+ switch (result) {
+ case BZ_OK:
+ case BZ_FLUSH_OK:
+ case BZ_RUN_OK:
+ case BZ_FINISH_OK:
+ return KFilterBase::Ok;
+ break;
+ case BZ_STREAM_END:
+ //qDebug() << " bzCompress returned " << result;
+ return KFilterBase::End;
+ break;
+ default:
+ //qDebug() << " bzCompress returned " << result;
+ return KFilterBase::Error;
+ break;
+ }
+}
+
+#endif /* HAVE_BZIP2_SUPPORT */
diff --git a/kdecore/compression/kbzip2filter.h b/kdecore/compression/kbzip2filter.h
new file mode 100644
index 0000000..dd5b202
--- /dev/null
+++ b/kdecore/compression/kbzip2filter.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kbzip2filter__h
+#define __kbzip2filter__h
+
+#include <config-compression.h>
+
+#if HAVE_BZIP2_SUPPORT
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KFilterDev
+ * @internal
+ */
+class KBzip2Filter : public KFilterBase
+{
+public:
+ KBzip2Filter();
+ virtual ~KBzip2Filter();
+
+ virtual void init( int );
+ virtual int mode() const;
+ virtual void terminate();
+ virtual void reset();
+ virtual bool readHeader() { return true; } // bzip2 handles it by itself ! Cool !
+ virtual bool writeHeader( const QByteArray & ) { return true; }
+ virtual void setOutBuffer( char * data, uint maxlen );
+ virtual void setInBuffer( const char * data, uint size );
+ virtual int inBufferAvailable() const;
+ virtual int outBufferAvailable() const;
+ virtual Result uncompress();
+ virtual Result compress( bool finish );
+private:
+ class Private;
+ Private* const d;
+};
+
+#endif
+
+#endif
diff --git a/kdecore/compression/kfilterbase.cpp b/kdecore/compression/kfilterbase.cpp
new file mode 100644
index 0000000..0e3a536
--- /dev/null
+++ b/kdecore/compression/kfilterbase.cpp
@@ -0,0 +1,168 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000-2005 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kfilterbase.h"
+#include <config-compression.h>
+
+#include <QDebug>
+#include <QtCore/QIODevice>
+#include <kmimetype.h>
+#include "kgzipfilter.h"
+#if HAVE_BZIP2_SUPPORT
+#include "kbzip2filter.h"
+#endif
+#if HAVE_XZ_SUPPORT
+#include "kxzfilter.h"
+#endif
+
+class KFilterBase::Private
+{
+public:
+ Private()
+ : m_flags(WithHeaders) {}
+ FilterFlags m_flags;
+};
+
+KFilterBase::KFilterBase()
+ : m_dev( 0L ), m_bAutoDel( false ), d(new Private)
+{
+}
+
+KFilterBase::~KFilterBase()
+{
+ if ( m_bAutoDel )
+ delete m_dev;
+ delete d;
+}
+
+void KFilterBase::setDevice( QIODevice * dev, bool autodelete )
+{
+ m_dev = dev;
+ m_bAutoDel = autodelete;
+}
+
+QIODevice * KFilterBase::device()
+{
+ return m_dev;
+}
+
+bool KFilterBase::inBufferEmpty() const
+{
+ return inBufferAvailable() == 0;
+}
+
+bool KFilterBase::outBufferFull() const
+{
+ return outBufferAvailable() == 0;
+}
+
+KFilterBase * KFilterBase::findFilterByFileName( const QString & fileName )
+{
+ if ( fileName.endsWith( QLatin1String(".gz"), Qt::CaseInsensitive ) )
+ {
+ return new KGzipFilter;
+ }
+#if HAVE_BZIP2_SUPPORT
+ if ( fileName.endsWith( QLatin1String(".bz2"), Qt::CaseInsensitive ) )
+ {
+ return new KBzip2Filter;
+ }
+#endif
+#if HAVE_XZ_SUPPORT
+ if ( fileName.endsWith( QLatin1String(".lzma"), Qt::CaseInsensitive ) || fileName.endsWith( QLatin1String(".xz"), Qt::CaseInsensitive ) )
+ {
+ return new KXzFilter;
+ }
+#endif
+ else
+ {
+ // not a warning, since this is called often with other mimetypes (see #88574)...
+ // maybe we can avoid that though?
+ //qDebug() << "KFilterBase::findFilterByFileName : no filter found for " << fileName;
+ }
+
+ return 0;
+}
+
+KFilterBase * KFilterBase::findFilterByMimeType( const QString & mimeType )
+{
+ if (mimeType == QLatin1String("application/x-gzip")) {
+ return new KGzipFilter;
+ }
+#if HAVE_BZIP2_SUPPORT
+ if (mimeType == QLatin1String("application/x-bzip")
+ || mimeType == QLatin1String("application/x-bzip2") // old name, kept for compatibility
+ ) {
+ return new KBzip2Filter;
+ }
+#endif
+#if HAVE_XZ_SUPPORT
+ if ( mimeType == QLatin1String( "application/x-lzma" ) // legacy name, still used
+ || mimeType == QLatin1String( "application/x-xz" ) // current naming
+ ) {
+ return new KXzFilter;
+ }
+#endif
+ const KMimeType::Ptr mime = KMimeType::mimeType(mimeType);
+ if (mime) {
+ if (mime->is(QString::fromLatin1("application/x-gzip"))) {
+ return new KGzipFilter;
+ }
+#if HAVE_BZIP2_SUPPORT
+ if (mime->is(QString::fromLatin1("application/x-bzip"))) {
+ return new KBzip2Filter;
+ }
+#endif
+#if HAVE_XZ_SUPPORT
+ if (mime->is(QString::fromLatin1("application/x-lzma"))) {
+ return new KXzFilter;
+ }
+
+ if (mime->is(QString::fromLatin1("application/x-xz"))) {
+ return new KXzFilter;
+ }
+#endif
+ }
+
+ // not a warning, since this is called often with other mimetypes (see #88574)...
+ // maybe we can avoid that though?
+ //qDebug() << "no filter found for" << mimeType;
+ return 0;
+}
+
+void KFilterBase::terminate()
+{
+}
+
+void KFilterBase::reset()
+{
+}
+
+void KFilterBase::setFilterFlags(FilterFlags flags)
+{
+ d->m_flags = flags;
+}
+
+KFilterBase::FilterFlags KFilterBase::filterFlags() const
+{
+ return d->m_flags;
+}
+
+void KFilterBase::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
diff --git a/kdecore/compression/kfilterbase.h b/kdecore/compression/kfilterbase.h
new file mode 100644
index 0000000..7163528
--- /dev/null
+++ b/kdecore/compression/kfilterbase.h
@@ -0,0 +1,133 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kfilterbase__h
+#define __kfilterbase__h
+
+#include <karchive_export.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+class QIODevice;
+
+/**
+ * This is the base class for compression filters
+ * such as gzip and bzip2. It's pretty much internal.
+ * Don't use directly, use KFilterDev instead.
+ * @internal
+ */
+class KARCHIVE_EXPORT KFilterBase
+{
+public:
+ KFilterBase();
+ virtual ~KFilterBase();
+
+ /**
+ * Sets the device on which the filter will work
+ * @param dev the device on which the filter will work
+ * @param autodelete if true, @p dev is deleted when the filter is deleted
+ */
+ void setDevice( QIODevice * dev, bool autodelete = false );
+ // Note that this isn't in the constructor, because of KLibFactory::create,
+ // but it should be called before using the filterbase !
+
+ /**
+ * Returns the device on which the filter will work.
+ * @returns the device on which the filter will work
+ */
+ QIODevice * device();
+ /** \internal */
+ virtual void init( int mode ) = 0; // KDE5 TODO: return a bool
+ /** \internal */
+ virtual int mode() const = 0;
+ /** \internal */
+ virtual void terminate();
+ /** \internal */
+ virtual void reset();
+ /** \internal */
+ virtual bool readHeader() = 0;
+ /** \internal */
+ virtual bool writeHeader( const QByteArray & filename ) = 0;
+ /** \internal */
+ virtual void setOutBuffer( char * data, uint maxlen ) = 0;
+ /** \internal */
+ virtual void setInBuffer( const char * data, uint size ) = 0;
+ /** \internal */
+ virtual bool inBufferEmpty() const;
+ /** \internal */
+ virtual int inBufferAvailable() const = 0;
+ /** \internal */
+ virtual bool outBufferFull() const;
+ /** \internal */
+ virtual int outBufferAvailable() const = 0;
+
+ /** \internal */
+ enum Result { Ok, End, Error };
+ /** \internal */
+ virtual Result uncompress() = 0;
+ /** \internal */
+ virtual Result compress( bool finish ) = 0;
+
+ /**
+ * \internal
+ * \since 4.3
+ */
+ enum FilterFlags {
+ NoHeaders = 0,
+ WithHeaders = 1
+ };
+ /**
+ * \internal
+ * \since 4.3
+ */
+ void setFilterFlags(FilterFlags flags);
+ FilterFlags filterFlags() const;
+
+ /**
+ * Call this to create the appropriate filter for the file
+ * named @p fileName.
+ * @param fileName the name of the file to filter
+ * @return the filter for the @p fileName, or 0 if not found
+ */
+ static KFilterBase * findFilterByFileName( const QString & fileName );
+
+ /**
+ * Call this to create the appropriate filter for the mimetype
+ * @p mimeType. For instance application/x-gzip.
+ * @param mimeType the mime type of the file to filter
+ * @return the filter for the @p mimeType, or 0 if not found
+ */
+ static KFilterBase * findFilterByMimeType( const QString & mimeType );
+
+protected: // TODO KDE5: move to d pointer
+ QIODevice * m_dev;
+ bool m_bAutoDel;
+protected:
+ /** Virtual hook, used to add new "virtual" functions while maintaining
+ binary compatibility. Unused in this class.
+ */
+ virtual void virtual_hook( int id, void* data );
+private:
+ Q_DISABLE_COPY( KFilterBase )
+ class Private;
+ Private * const d;
+};
+
+#endif
diff --git a/kdecore/compression/kfilterdev.cpp b/kdecore/compression/kfilterdev.cpp
new file mode 100644
index 0000000..6f83213
--- /dev/null
+++ b/kdecore/compression/kfilterdev.cpp
@@ -0,0 +1,366 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000, 2006 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kfilterdev.h"
+#include "kfilterbase.h"
+#include <QDebug>
+#include <stdio.h> // for EOF
+#include <stdlib.h>
+#include <assert.h>
+#include <QtCore/QFile>
+
+#define BUFFER_SIZE 8*1024
+
+class KFilterDev::Private
+{
+public:
+ Private() : bNeedHeader(true), bSkipHeaders(false),
+ autoDeleteFilterBase(false), bOpenedUnderlyingDevice(false),
+ bIgnoreData(false){}
+ bool bNeedHeader;
+ bool bSkipHeaders;
+ bool autoDeleteFilterBase;
+ bool bOpenedUnderlyingDevice;
+ bool bIgnoreData;
+ QByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing
+ QByteArray origFileName;
+ KFilterBase::Result result;
+ KFilterBase *filter;
+};
+
+KFilterDev::KFilterDev( KFilterBase * _filter, bool autoDeleteFilterBase )
+ : d(new Private)
+{
+ assert(_filter);
+ d->filter = _filter;
+ d->autoDeleteFilterBase = autoDeleteFilterBase;
+}
+
+KFilterDev::~KFilterDev()
+{
+ if ( isOpen() )
+ close();
+ if ( d->autoDeleteFilterBase )
+ delete d->filter;
+ delete d;
+}
+
+//static
+QIODevice * KFilterDev::deviceForFile( const QString & fileName, const QString & mimetype,
+ bool forceFilter )
+{
+ QFile * f = new QFile( fileName );
+ KFilterBase * base = mimetype.isEmpty() ? KFilterBase::findFilterByFileName( fileName )
+ : KFilterBase::findFilterByMimeType( mimetype );
+ if ( base )
+ {
+ base->setDevice(f, true);
+ return new KFilterDev(base, true);
+ }
+ if(!forceFilter)
+ return f;
+ else
+ {
+ delete f;
+ return 0L;
+ }
+}
+
+QIODevice * KFilterDev::device( QIODevice* inDevice, const QString & mimetype, bool autoDeleteInDevice )
+{
+ if (inDevice==0)
+ return 0;
+ KFilterBase * base = KFilterBase::findFilterByMimeType(mimetype);
+ if ( base )
+ {
+ base->setDevice(inDevice, autoDeleteInDevice);
+ return new KFilterDev(base, true /* auto-delete "base" */);
+ }
+ return 0;
+}
+
+bool KFilterDev::open( QIODevice::OpenMode mode )
+{
+ if (isOpen()) {
+ qWarning() << "KFilterDev::open: device is already open";
+ return true; // QFile returns false, but well, the device -is- open...
+ }
+ //kDebug(7005) << mode;
+ if ( mode == QIODevice::ReadOnly )
+ {
+ d->buffer.resize(0);
+ }
+ else
+ {
+ d->buffer.resize( BUFFER_SIZE );
+ d->filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
+ }
+ d->bNeedHeader = !d->bSkipHeaders;
+ d->filter->setFilterFlags(d->bSkipHeaders ? KFilterBase::NoHeaders : KFilterBase::WithHeaders);
+ d->filter->init( mode );
+ d->bOpenedUnderlyingDevice = !d->filter->device()->isOpen();
+ bool ret = d->bOpenedUnderlyingDevice ? d->filter->device()->open( mode ) : true;
+ d->result = KFilterBase::Ok;
+
+ if ( !ret )
+ qWarning() << "KFilterDev::open: Couldn't open underlying device";
+ else
+ setOpenMode( mode );
+
+ return ret;
+}
+
+void KFilterDev::close()
+{
+ if ( !isOpen() )
+ return;
+ if ( d->filter->mode() == QIODevice::WriteOnly )
+ write( 0L, 0 ); // finish writing
+ //kDebug(7005) << "Calling terminate().";
+
+ d->filter->terminate();
+ if ( d->bOpenedUnderlyingDevice )
+ d->filter->device()->close();
+ setOpenMode( QIODevice::NotOpen );
+}
+
+bool KFilterDev::seek( qint64 pos )
+{
+ qint64 ioIndex = this->pos(); // current position
+ if ( ioIndex == pos )
+ return true;
+
+ //kDebug(7005) << "seek(" << pos << ") called";
+
+ Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
+
+ if ( pos == 0 )
+ {
+ // We can forget about the cached data
+ d->bNeedHeader = !d->bSkipHeaders;
+ d->result = KFilterBase::Ok;
+ d->filter->setInBuffer(0L,0);
+ d->filter->reset();
+ QIODevice::seek(pos);
+ return d->filter->device()->reset();
+ }
+
+ if ( ioIndex > pos ) // we can start from here
+ pos = pos - ioIndex;
+ else
+ {
+ // we have to start from 0 ! Ugly and slow, but better than the previous
+ // solution (KTarGz was allocating everything into memory)
+ if (!seek(0)) // recursive
+ return false;
+ }
+
+ //kDebug(7005) << "reading " << pos << " dummy bytes";
+ QByteArray dummy( qMin( pos, (qint64)3*BUFFER_SIZE ), 0 );
+ d->bIgnoreData = true;
+ bool result = ( read( dummy.data(), pos ) == pos );
+ d->bIgnoreData = false;
+ QIODevice::seek(pos);
+ return result;
+}
+
+bool KFilterDev::atEnd() const
+{
+ return (d->result == KFilterBase::End)
+ && QIODevice::atEnd() // take QIODevice's internal buffer into account
+ && d->filter->device()->atEnd();
+}
+
+qint64 KFilterDev::readData( char *data, qint64 maxlen )
+{
+ Q_ASSERT ( d->filter->mode() == QIODevice::ReadOnly );
+ //kDebug(7005) << "maxlen=" << maxlen;
+ KFilterBase* filter = d->filter;
+
+ uint dataReceived = 0;
+
+ // We came to the end of the stream
+ if ( d->result == KFilterBase::End )
+ return dataReceived;
+
+ // If we had an error, return -1.
+ if ( d->result != KFilterBase::Ok )
+ return -1;
+
+
+ qint64 outBufferSize;
+ if ( d->bIgnoreData )
+ {
+ outBufferSize = qMin( maxlen, (qint64)3*BUFFER_SIZE );
+ }
+ else
+ {
+ outBufferSize = maxlen;
+ }
+ outBufferSize -= dataReceived;
+ qint64 availOut = outBufferSize;
+ filter->setOutBuffer( data, outBufferSize );
+
+ while ( dataReceived < maxlen )
+ {
+ if (filter->inBufferEmpty())
+ {
+ // Not sure about the best size to set there.
+ // For sure, it should be bigger than the header size (see comment in readHeader)
+ d->buffer.resize( BUFFER_SIZE );
+ // Request data from underlying device
+ int size = filter->device()->read( d->buffer.data(),
+ d->buffer.size() );
+ //kDebug(7005) << "got" << size << "bytes from device";
+ if (size) {
+ filter->setInBuffer( d->buffer.data(), size );
+ } else {
+ // Not enough data available in underlying device for now
+ break;
+ }
+ }
+ if (d->bNeedHeader)
+ {
+ (void) filter->readHeader();
+ d->bNeedHeader = false;
+ }
+
+ d->result = filter->uncompress();
+
+ if (d->result == KFilterBase::Error)
+ {
+ qWarning() << "KFilterDev: Error when uncompressing data";
+ break;
+ }
+
+ // We got that much data since the last time we went here
+ uint outReceived = availOut - filter->outBufferAvailable();
+ //kDebug(7005) << "avail_out = " << filter->outBufferAvailable() << " result=" << d->result << " outReceived=" << outReceived;
+ if( availOut < (uint)filter->outBufferAvailable() )
+ qWarning() << " last availOut " << availOut << " smaller than new avail_out=" << filter->outBufferAvailable() << " !";
+
+ dataReceived += outReceived;
+ if ( !d->bIgnoreData ) // Move on in the output buffer
+ {
+ data += outReceived;
+ availOut = maxlen - dataReceived;
+ }
+ else if ( maxlen - dataReceived < outBufferSize )
+ {
+ availOut = maxlen - dataReceived;
+ }
+ if (d->result == KFilterBase::End)
+ {
+ //kDebug(7005) << "got END. dataReceived=" << dataReceived;
+ break; // Finished.
+ }
+ filter->setOutBuffer( data, availOut );
+ }
+
+ return dataReceived;
+}
+
+qint64 KFilterDev::writeData( const char *data /*0 to finish*/, qint64 len )
+{
+ KFilterBase* filter = d->filter;
+ Q_ASSERT ( filter->mode() == QIODevice::WriteOnly );
+ // If we had an error, return 0.
+ if ( d->result != KFilterBase::Ok )
+ return 0;
+
+ bool finish = (data == 0L);
+ if (!finish)
+ {
+ filter->setInBuffer( data, len );
+ if (d->bNeedHeader)
+ {
+ (void)filter->writeHeader( d->origFileName );
+ d->bNeedHeader = false;
+ }
+ }
+
+ uint dataWritten = 0;
+ uint availIn = len;
+ while ( dataWritten < len || finish )
+ {
+
+ d->result = filter->compress( finish );
+
+ if (d->result == KFilterBase::Error)
+ {
+ qWarning() << "KFilterDev: Error when compressing data";
+ // What to do ?
+ break;
+ }
+
+ // Wrote everything ?
+ if (filter->inBufferEmpty() || (d->result == KFilterBase::End))
+ {
+ // We got that much data since the last time we went here
+ uint wrote = availIn - filter->inBufferAvailable();
+
+ //kDebug(7005) << " Wrote everything for now. avail_in=" << filter->inBufferAvailable() << "result=" << d->result << "wrote=" << wrote;
+
+ // Move on in the input buffer
+ data += wrote;
+ dataWritten += wrote;
+
+ availIn = len - dataWritten;
+ //kDebug(7005) << " availIn=" << availIn << "dataWritten=" << dataWritten << "pos=" << pos();
+ if ( availIn > 0 )
+ filter->setInBuffer( data, availIn );
+ }
+
+ if (filter->outBufferFull() || (d->result == KFilterBase::End) || finish)
+ {
+ //kDebug(7005) << " writing to underlying. avail_out=" << filter->outBufferAvailable();
+ int towrite = d->buffer.size() - filter->outBufferAvailable();
+ if ( towrite > 0 )
+ {
+ // Write compressed data to underlying device
+ int size = filter->device()->write( d->buffer.data(), towrite );
+ if ( size != towrite ) {
+ qWarning() << "KFilterDev::write. Could only write " << size << " out of " << towrite << " bytes";
+ return 0; // indicate an error (happens on disk full)
+ }
+ //else
+ //kDebug(7005) << " wrote " << size << " bytes";
+ }
+ if (d->result == KFilterBase::End)
+ {
+ //kDebug(7005) << " END";
+ Q_ASSERT(finish); // hopefully we don't get end before finishing
+ break;
+ }
+ d->buffer.resize(BUFFER_SIZE);
+ filter->setOutBuffer( d->buffer.data(), d->buffer.size() );
+ }
+ }
+
+ return dataWritten;
+}
+
+void KFilterDev::setOrigFileName( const QByteArray & fileName )
+{
+ d->origFileName = fileName;
+}
+
+void KFilterDev::setSkipHeaders()
+{
+ d->bSkipHeaders = true;
+}
diff --git a/kdecore/compression/kfilterdev.h b/kdecore/compression/kfilterdev.h
new file mode 100644
index 0000000..c6050d9
--- /dev/null
+++ b/kdecore/compression/kfilterdev.h
@@ -0,0 +1,153 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef __kfilterdev_h
+#define __kfilterdev_h
+
+#include <karchive_export.h>
+#include <QtCore/QIODevice>
+#include <QtCore/QString>
+
+class QFile;
+class KFilterBase;
+
+/**
+ * A class for reading and writing compressed data onto a device
+ * (e.g. file, but other usages are possible, like a buffer or a socket).
+ *
+ * To simply read/write compressed files, see deviceForFile.
+ *
+ * @author David Faure <faure@kde.org>
+ */
+class KARCHIVE_EXPORT KFilterDev : public QIODevice
+{
+public:
+ /**
+ * Destructs the KFilterDev.
+ * Calls close() if the filter device is still open.
+ */
+ virtual ~KFilterDev();
+
+ /**
+ * Open for reading or writing.
+ * If the KFilterBase's device is not opened, it will be opened.
+ */
+ virtual bool open( QIODevice::OpenMode mode );
+ /**
+ * Close after reading or writing.
+ * If the KFilterBase's device was opened by open(), it will be closed.
+ */
+ virtual void close();
+
+ /**
+ * For writing gzip compressed files only:
+ * set the name of the original file, to be used in the gzip header.
+ * @param fileName the name of the original file
+ */
+ void setOrigFileName( const QByteArray & fileName );
+
+ /**
+ * Call this let this device skip the gzip headers when reading/writing.
+ * This way KFilterDev (with gzip filter) can be used as a direct wrapper
+ * around zlib - this is used by KZip.
+ */
+ void setSkipHeaders();
+
+ /**
+ * That one can be quite slow, when going back. Use with care.
+ */
+ virtual bool seek( qint64 );
+
+ virtual bool atEnd() const;
+
+ /// Reimplemented to return true. KFilterDev is a sequential QIODevice.
+ /// Well, not really, since it supports seeking and KZip uses that.
+ //virtual bool isSequential() const { return true; }
+
+public:
+
+
+ // KDE4 TODO: turn those static methods into constructors
+
+ /**
+ * Creates an i/o device that is able to read from @p fileName,
+ * whether it's compressed or not. Available compression filters
+ * (gzip/bzip2 etc.) will automatically be used.
+ *
+ * The compression filter to be used is determined from the @p fileName
+ * if @p mimetype is empty. Pass "application/x-gzip" or "application/x-bzip"
+ * to force the corresponding decompression filter, if available.
+ *
+ * Warning: application/x-bzip may not be available.
+ * In that case a QFile opened on the compressed data will be returned !
+ * Use KFilterBase::findFilterByMimeType and code similar to what
+ * deviceForFile is doing, to better control what's happening.
+ *
+ * The returned QIODevice has to be deleted after using.
+ *
+ * @param fileName the name of the file to filter
+ * @param mimetype the mime type of the file to filter, or QString() if unknown
+ * @param forceFilter if true, the function will either find a compression filter, or return 0.
+ * If false, it will always return a QIODevice. If no
+ * filter is available it will return a simple QFile.
+ * This can be useful if the file is usable without a filter.
+ * @return if a filter has been found, the QIODevice for the filter. If the
+ * filter does not exist, the return value depends on @p forceFilter.
+ * The returned QIODevice has to be deleted after using.
+ */
+ static QIODevice * deviceForFile( const QString & fileName, const QString & mimetype = QString(),
+ bool forceFilter = false );
+
+ /**
+ * Creates an i/o device that is able to read from the QIODevice @p inDevice,
+ * whether the data is compressed or not. Available compression filters
+ * (gzip/bzip2 etc.) will automatically be used.
+ *
+ * The compression filter to be used is determined @p mimetype .
+ * Pass "application/x-gzip" or "application/x-bzip"
+ * to use the corresponding decompression filter.
+ *
+ * Warning: application/x-bzip may not be available.
+ * In that case 0 will be returned !
+ *
+ * The returned QIODevice has to be deleted after using.
+ * @param inDevice input device. Won't be deleted if @p autoDeleteInDevice = false
+ * @param mimetype the mime type for the filter
+ * @param autoDeleteInDevice if true, @p inDevice will be deleted automatically
+ * @return a KFilterDev that filters the original stream. Must be deleted after using
+ */
+ static QIODevice * device( QIODevice* inDevice, const QString & mimetype, bool autoDeleteInDevice = true );
+
+protected:
+ virtual qint64 readData( char *data, qint64 maxlen );
+ virtual qint64 writeData( const char *data, qint64 len );
+
+private:
+ /**
+ * Constructs a KFilterDev for a given filter (e.g. gzip, bzip2 etc.).
+ * @param filter the KFilterBase to use
+ * @param autoDeleteFilterBase when true this object will become the
+ * owner of @p filter.
+ */
+ explicit KFilterDev( KFilterBase * filter, bool autoDeleteFilterBase = false );
+private:
+ class Private;
+ Private* const d;
+};
+
+
+#endif
diff --git a/kdecore/compression/kgzipfilter.cpp b/kdecore/compression/kgzipfilter.cpp
new file mode 100644
index 0000000..f58fda1
--- /dev/null
+++ b/kdecore/compression/kgzipfilter.cpp
@@ -0,0 +1,385 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000-2005 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kgzipfilter.h"
+
+#include <time.h>
+#include <zlib.h>
+#include <QDebug>
+#include <QtCore/QIODevice>
+
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+// #define DEBUG_GZIP
+
+class KGzipFilter::Private
+{
+public:
+ Private()
+ : headerWritten(false), footerWritten(false), compressed(false), mode(0), crc(0), isInitialized(false)
+ {
+ zStream.zalloc = (alloc_func)0;
+ zStream.zfree = (free_func)0;
+ zStream.opaque = (voidpf)0;
+ }
+
+ z_stream zStream;
+ bool headerWritten;
+ bool footerWritten;
+ bool compressed;
+ int mode;
+ ulong crc;
+ bool isInitialized;
+};
+
+KGzipFilter::KGzipFilter()
+ : d(new Private)
+{
+}
+
+
+KGzipFilter::~KGzipFilter()
+{
+ delete d;
+}
+
+void KGzipFilter::init(int mode)
+{
+ init(mode, filterFlags() == WithHeaders ? GZipHeader : RawDeflate);
+}
+
+void KGzipFilter::init(int mode, Flag flag)
+{
+ if (d->isInitialized) {
+ terminate();
+ }
+ d->zStream.next_in = Z_NULL;
+ d->zStream.avail_in = 0;
+ if ( mode == QIODevice::ReadOnly )
+ {
+ const int windowBits = (flag == RawDeflate)
+ ? -MAX_WBITS /*no zlib header*/
+ : (flag == GZipHeader) ?
+ MAX_WBITS + 32 /* auto-detect and eat gzip header */
+ : MAX_WBITS /*zlib header*/;
+ const int result = inflateInit2(&d->zStream, windowBits);
+ if ( result != Z_OK ) {
+ qDebug() << "inflateInit2 returned " << result;
+ // TODO return false
+ }
+ } else if ( mode == QIODevice::WriteOnly )
+ {
+ int result = deflateInit2(&d->zStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); // same here
+ if ( result != Z_OK ) {
+ qDebug() << "deflateInit returned " << result;
+ // TODO return false
+ }
+ } else {
+ qWarning() << "KGzipFilter: Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+ }
+ d->mode = mode;
+ d->compressed = true;
+ d->headerWritten = false;
+ d->footerWritten = false;
+ d->isInitialized = true;
+}
+
+int KGzipFilter::mode() const
+{
+ return d->mode;
+}
+
+void KGzipFilter::terminate()
+{
+ if ( d->mode == QIODevice::ReadOnly )
+ {
+ int result = inflateEnd(&d->zStream);
+ if ( result != Z_OK ) {
+ qDebug() << "inflateEnd returned " << result;
+ // TODO return false
+ }
+ } else if ( d->mode == QIODevice::WriteOnly )
+ {
+ int result = deflateEnd(&d->zStream);
+ if ( result != Z_OK ) {
+ qDebug() << "deflateEnd returned " << result;
+ // TODO return false
+ }
+ }
+ d->isInitialized = false;
+}
+
+
+void KGzipFilter::reset()
+{
+ if ( d->mode == QIODevice::ReadOnly )
+ {
+ int result = inflateReset(&d->zStream);
+ if ( result != Z_OK ) {
+ qDebug() << "inflateReset returned " << result;
+ // TODO return false
+ }
+ } else if ( d->mode == QIODevice::WriteOnly ) {
+ int result = deflateReset(&d->zStream);
+ if ( result != Z_OK ) {
+ qDebug() << "deflateReset returned " << result;
+ // TODO return false
+ }
+ d->headerWritten = false;
+ d->footerWritten = false;
+ }
+}
+
+bool KGzipFilter::readHeader()
+{
+ // We now rely on zlib to read the full header (see the MAX_WBITS + 32 in init).
+ // We just use this method to check if the data is actually compressed.
+
+#ifdef DEBUG_GZIP
+ qDebug() << "avail=" << d->zStream.avail_in;
+#endif
+ // Assume not compressed until we see a gzip header
+ d->compressed = false;
+ Bytef *p = d->zStream.next_in;
+ int i = d->zStream.avail_in;
+ if ((i -= 10) < 0) return false; // Need at least 10 bytes
+#ifdef DEBUG_GZIP
+ qDebug() << "first byte is " << QString::number(*p,16);
+#endif
+ if (*p++ != 0x1f) return false; // GZip magic
+#ifdef DEBUG_GZIP
+ qDebug() << "second byte is " << QString::number(*p,16);
+#endif
+ if (*p++ != 0x8b) return false;
+
+#if 0
+ int method = *p++;
+ int flags = *p++;
+ if ((method != Z_DEFLATED) || (flags & RESERVED) != 0) return false;
+ p += 6;
+ if ((flags & EXTRA_FIELD) != 0) // skip extra field
+ {
+ if ((i -= 2) < 0) return false; // Need at least 2 bytes
+ int len = *p++;
+ len += (*p++) << 8;
+ if ((i -= len) < 0) return false; // Need at least len bytes
+ p += len;
+ }
+ if ((flags & ORIG_NAME) != 0) // skip original file name
+ {
+#ifdef DEBUG_GZIP
+ qDebug() << "ORIG_NAME=" << (char*)p;
+#endif
+ while( (i > 0) && (*p))
+ {
+ i--; p++;
+ }
+ if (--i <= 0) return false;
+ p++;
+ }
+ if ((flags & COMMENT) != 0) // skip comment
+ {
+ while( (i > 0) && (*p))
+ {
+ i--; p++;
+ }
+ if (--i <= 0) return false;
+ p++;
+ }
+ if ((flags & HEAD_CRC) != 0) // skip the header crc
+ {
+ if ((i-=2) < 0) return false;
+ p += 2;
+ }
+
+ d->zStream.avail_in = i;
+ d->zStream.next_in = p;
+#endif
+
+ d->compressed = true;
+#ifdef DEBUG_GZIP
+ qDebug() << "header OK";
+#endif
+ return true;
+}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+ *p++ = (uchar) ((w) & 0xff); \
+ *p++ = (uchar) ((ushort)(w) >> 8);
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) \
+ put_short((n) & 0xffff); \
+ put_short(((ulong)(n)) >> 16);
+
+bool KGzipFilter::writeHeader( const QByteArray & fileName )
+{
+ Bytef *p = d->zStream.next_out;
+ int i = d->zStream.avail_out;
+ *p++ = 0x1f;
+ *p++ = 0x8b;
+ *p++ = Z_DEFLATED;
+ *p++ = ORIG_NAME;
+ put_long( time( 0L ) ); // Modification time (in unix format)
+ *p++ = 0; // Extra flags (2=max compress, 4=fastest compress)
+ *p++ = 3; // Unix
+
+ uint len = fileName.length();
+ for ( uint j = 0 ; j < len ; ++j )
+ *p++ = fileName[j];
+ *p++ = 0;
+ int headerSize = p - d->zStream.next_out;
+ i -= headerSize;
+ Q_ASSERT(i>0);
+ d->crc = crc32(0L, Z_NULL, 0);
+ d->zStream.next_out = p;
+ d->zStream.avail_out = i;
+ d->headerWritten = true;
+ return true;
+}
+
+void KGzipFilter::writeFooter()
+{
+ Q_ASSERT( d->headerWritten );
+ Q_ASSERT(!d->footerWritten);
+ Bytef *p = d->zStream.next_out;
+ int i = d->zStream.avail_out;
+ //qDebug() << "avail_out=" << i << "writing CRC=" << QString::number(d->crc, 16) << "at p=" << p;
+ put_long( d->crc );
+ //qDebug() << "writing totalin=" << d->zStream.total_in << "at p=" << p;
+ put_long( d->zStream.total_in );
+ i -= p - d->zStream.next_out;
+ d->zStream.next_out = p;
+ d->zStream.avail_out = i;
+ d->footerWritten = true;
+}
+
+void KGzipFilter::setOutBuffer( char * data, uint maxlen )
+{
+ d->zStream.avail_out = maxlen;
+ d->zStream.next_out = (Bytef *) data;
+}
+void KGzipFilter::setInBuffer( const char * data, uint size )
+{
+#ifdef DEBUG_GZIP
+ qDebug() << "avail_in=" << size;
+#endif
+ d->zStream.avail_in = size;
+ d->zStream.next_in = (Bytef*) data;
+}
+int KGzipFilter::inBufferAvailable() const
+{
+ return d->zStream.avail_in;
+}
+int KGzipFilter::outBufferAvailable() const
+{
+ return d->zStream.avail_out;
+}
+
+KGzipFilter::Result KGzipFilter::uncompress_noop()
+{
+ // I'm not sure we really need support for that (uncompressed streams),
+ // but why not, it can't hurt to have it. One case I can think of is someone
+ // naming a tar file "blah.tar.gz" :-)
+ if ( d->zStream.avail_in > 0 )
+ {
+ int n = (d->zStream.avail_in < d->zStream.avail_out) ? d->zStream.avail_in : d->zStream.avail_out;
+ memcpy( d->zStream.next_out, d->zStream.next_in, n );
+ d->zStream.avail_out -= n;
+ d->zStream.next_in += n;
+ d->zStream.avail_in -= n;
+ return KFilterBase::Ok;
+ } else
+ return KFilterBase::End;
+}
+
+KGzipFilter::Result KGzipFilter::uncompress()
+{
+#ifndef NDEBUG
+ if (d->mode == 0) {
+ qWarning() << "mode==0; KGzipFilter::init was not called!";
+ return KFilterBase::Error;
+ } else if (d->mode == QIODevice::WriteOnly) {
+ qWarning() << "uncompress called but the filter was opened for writing!";
+ return KFilterBase::Error;
+ }
+ Q_ASSERT ( d->mode == QIODevice::ReadOnly );
+#endif
+
+ if ( d->compressed )
+ {
+#ifdef DEBUG_GZIP
+ qDebug() << "Calling inflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+ qDebug() << " next_in=" << d->zStream.next_in;
+#endif
+ int result = inflate(&d->zStream, Z_SYNC_FLUSH);
+#ifdef DEBUG_GZIP
+ qDebug() << " -> inflate returned " << result;
+ qDebug() << " now avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+ qDebug() << " next_in=" << d->zStream.next_in;
+#else
+ if ( result != Z_OK && result != Z_STREAM_END )
+ qDebug() << "Warning: inflate() returned " << result;
+#endif
+ return ( result == Z_OK ? KFilterBase::Ok : ( result == Z_STREAM_END ? KFilterBase::End : KFilterBase::Error ) );
+ } else
+ return uncompress_noop();
+}
+
+KGzipFilter::Result KGzipFilter::compress( bool finish )
+{
+ Q_ASSERT ( d->compressed );
+ Q_ASSERT ( d->mode == QIODevice::WriteOnly );
+
+ Bytef* p = d->zStream.next_in;
+ ulong len = d->zStream.avail_in;
+#ifdef DEBUG_GZIP
+ qDebug() << " calling deflate with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+#endif
+ const int result = deflate(&d->zStream, finish ? Z_FINISH : Z_NO_FLUSH);
+ if ( result != Z_OK && result != Z_STREAM_END ) {
+ qDebug() << " deflate returned " << result;
+ }
+ if ( d->headerWritten )
+ {
+ //qDebug() << "Computing CRC for the next " << len - d->zStream.avail_in << " bytes";
+ d->crc = crc32(d->crc, p, len - d->zStream.avail_in);
+ }
+ KGzipFilter::Result callerResult = result == Z_OK ? KFilterBase::Ok : (Z_STREAM_END ? KFilterBase::End : KFilterBase::Error);
+
+ if (result == Z_STREAM_END && d->headerWritten && !d->footerWritten) {
+ if (d->zStream.avail_out >= 8 /*footer size*/) {
+ //qDebug() << "finished, write footer";
+ writeFooter();
+ } else {
+ // No room to write the footer (#157706/#188415), we'll have to do it on the next pass.
+ //qDebug() << "finished, but no room for footer yet";
+ callerResult = KFilterBase::Ok;
+ }
+ }
+ return callerResult;
+}
diff --git a/kdecore/compression/kgzipfilter.h b/kdecore/compression/kgzipfilter.h
new file mode 100644
index 0000000..38b0a23
--- /dev/null
+++ b/kdecore/compression/kgzipfilter.h
@@ -0,0 +1,73 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000, 2009 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __kgzipfilter__h
+#define __kgzipfilter__h
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KFilterDev
+ *
+ * This header is not installed.
+ *
+ * @internal
+ */
+class KARCHIVE_EXPORT KGzipFilter : public KFilterBase
+{
+public:
+ KGzipFilter();
+ virtual ~KGzipFilter();
+
+
+ virtual void init(int mode);
+
+ // The top of zlib.h explains it: there are three cases.
+ // - Raw deflate, no header (e.g. inside a ZIP file)
+ // - Thin zlib header (1) (which is normally what HTTP calls "deflate" (2))
+ // - Gzip header, implemented here by readHeader
+ //
+ // (1) as written out by compress()/compress2()
+ // (2) see http://www.zlib.net/zlib_faq.html#faq39
+ enum Flag {
+ RawDeflate = 0, // raw deflate data
+ ZlibHeader = 1, // zlib headers (HTTP deflate)
+ GZipHeader = 2
+ };
+ void init(int mode, Flag flag); // for direct users of KGzipFilter
+ virtual int mode() const;
+ virtual void terminate();
+ virtual void reset();
+ virtual bool readHeader(); // this is about the GZIP header
+ virtual bool writeHeader( const QByteArray & fileName );
+ void writeFooter();
+ virtual void setOutBuffer( char * data, uint maxlen );
+ virtual void setInBuffer( const char * data, uint size );
+ virtual int inBufferAvailable() const;
+ virtual int outBufferAvailable() const;
+ virtual Result uncompress();
+ virtual Result compress( bool finish );
+
+private:
+ Result uncompress_noop();
+ class Private;
+ Private* const d;
+};
+
+#endif
diff --git a/kdecore/compression/kxzfilter.cpp b/kdecore/compression/kxzfilter.cpp
new file mode 100644
index 0000000..0f323fd
--- /dev/null
+++ b/kdecore/compression/kxzfilter.cpp
@@ -0,0 +1,174 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2007-2008 Per Øyvind Karlsen <peroyvind@mandriva.org>
+
+ Based on kbzip2filter:
+ Copyright (C) 2000-2005 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kxzfilter.h"
+
+#include <config-compression.h>
+
+#if HAVE_XZ_SUPPORT
+extern "C" {
+ #include <lzma.h>
+}
+
+#include <QDebug>
+
+#include <qiodevice.h>
+
+
+class KXzFilter::Private
+{
+public:
+ Private()
+ : isInitialized(false)
+ {
+ memset(&zStream, 0, sizeof(zStream));
+ mode = 0;
+ }
+
+ lzma_stream zStream;
+ int mode;
+ bool isInitialized;
+};
+
+KXzFilter::KXzFilter()
+ :d(new Private)
+{
+}
+
+
+KXzFilter::~KXzFilter()
+{
+ delete d;
+}
+
+void KXzFilter::init( int mode )
+{
+ if (d->isInitialized) {
+ terminate();
+ }
+
+ lzma_ret result;
+ d->zStream.next_in = 0;
+ d->zStream.avail_in = 0;
+ if ( mode == QIODevice::ReadOnly )
+ {
+ /* We set the memlimit for decompression to 100MiB which should be
+ * more than enough to be sufficient for level 9 which requires 65 MiB.
+ */
+ result = lzma_auto_decoder(&d->zStream, 100<<20, 0);
+ //kDebug(7131) << "lzma_auto_decoder returned " << result;
+ } else if ( mode == QIODevice::WriteOnly ) {
+ result = lzma_easy_encoder(&d->zStream, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC32);
+ //kDebug(7131) << "lzma_easy_encoder returned " << result;
+ } else
+ qWarning() << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+ d->mode = mode;
+ d->isInitialized = true;
+}
+
+int KXzFilter::mode() const
+{
+ return d->mode;
+}
+
+void KXzFilter::terminate()
+{
+ if (d->mode == QIODevice::ReadOnly || d->mode == QIODevice::WriteOnly) {
+ lzma_end(&d->zStream);
+ } else {
+ qWarning() << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
+ }
+ d->isInitialized = false;
+}
+
+
+void KXzFilter::reset()
+{
+ //kDebug(7131) << "KXzFilter::reset";
+ // liblzma doesn't have a reset call...
+ terminate();
+ init( d->mode );
+}
+
+void KXzFilter::setOutBuffer( char * data, uint maxlen )
+{
+ d->zStream.avail_out = maxlen;
+ d->zStream.next_out = (uint8_t *)data;
+}
+
+void KXzFilter::setInBuffer( const char *data, unsigned int size )
+{
+ d->zStream.avail_in = size;
+ d->zStream.next_in = (uint8_t *)const_cast<char *>(data);
+}
+
+int KXzFilter::inBufferAvailable() const
+{
+ return d->zStream.avail_in;
+}
+
+int KXzFilter::outBufferAvailable() const
+{
+ return d->zStream.avail_out;
+}
+
+KXzFilter::Result KXzFilter::uncompress()
+{
+ //kDebug(7131) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out =" << outBufferAvailable();
+ lzma_ret result = lzma_code(&d->zStream, LZMA_RUN);
+ if ( result != LZMA_OK )
+ {
+ qDebug() << "lzma_code returned " << result;
+ qDebug() << "KXzFilter::uncompress " << ( result == LZMA_STREAM_END ? KFilterBase::End : KFilterBase::Error );
+ }
+
+ switch (result) {
+ case LZMA_OK:
+ return KFilterBase::Ok;
+ case LZMA_STREAM_END:
+ return KFilterBase::End;
+ default:
+ return KFilterBase::Error;
+ }
+}
+
+KXzFilter::Result KXzFilter::compress( bool finish )
+{
+ //kDebug(7131) << "Calling lzma_code with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
+ lzma_ret result = lzma_code(&d->zStream, finish ? LZMA_FINISH : LZMA_RUN );
+
+ switch (result) {
+ case LZMA_OK:
+ return KFilterBase::Ok;
+ break;
+ case LZMA_STREAM_END:
+ qDebug() << " lzma_code returned " << result;
+ return KFilterBase::End;
+ break;
+ default:
+ qDebug() << " lzma_code returned " << result;
+ return KFilterBase::Error;
+ break;
+ }
+}
+
+#endif /* HAVE_XZ_SUPPORT */
diff --git a/kdecore/compression/kxzfilter.h b/kdecore/compression/kxzfilter.h
new file mode 100644
index 0000000..91cd84d
--- /dev/null
+++ b/kdecore/compression/kxzfilter.h
@@ -0,0 +1,61 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2007-2008 Per Øyvind Karlsen <peroyvind@mandriva.org>
+
+ Based on kbzip2filter:
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KXZFILTER_H
+#define KXZFILTER_H
+
+#include <config-compression.h>
+
+#if HAVE_XZ_SUPPORT
+
+#include "kfilterbase.h"
+
+/**
+ * Internal class used by KFilterDev
+ * @internal
+ */
+class KXzFilter : public KFilterBase
+{
+public:
+ KXzFilter();
+ virtual ~KXzFilter();
+
+ virtual void init( int );
+ virtual int mode() const;
+ virtual void terminate();
+ virtual void reset();
+ virtual bool readHeader() { return true; } // lzma handles it by itself ! Cool !
+ virtual bool writeHeader( const QByteArray & ) { return true; }
+ virtual void setOutBuffer( char * data, uint maxlen );
+ virtual void setInBuffer( const char * data, uint size );
+ virtual int inBufferAvailable() const;
+ virtual int outBufferAvailable() const;
+ virtual Result uncompress();
+ virtual Result compress( bool finish );
+private:
+ class Private;
+ Private* const d;
+};
+
+#endif
+
+#endif // KXZFILTER_H
diff --git a/kdecore/config-kstandarddirs.h.cmake b/kdecore/config-kstandarddirs.h.cmake
new file mode 100644
index 0000000..a0b52d7
--- /dev/null
+++ b/kdecore/config-kstandarddirs.h.cmake
@@ -0,0 +1,2 @@
+#define KDE_DEFAULT_HOME "${KDE_DEFAULT_HOME}"
+
diff --git a/kdecore/config/DESIGN b/kdecore/config/DESIGN
new file mode 100644
index 0000000..3cccc1c
--- /dev/null
+++ b/kdecore/config/DESIGN
@@ -0,0 +1,106 @@
+If you add a major new feature, suggest using it in
+http://techbase.kde.org/Development/Tutorials/KConfig
+
+kconfigdata.h contains definitions of the data formats used by kconfig.
+
+Configuration entries are stored as "KEntry". They are indexed with "KEntryKey".
+The primary store is a "KEntryMap" which is defined as a QMap from "KEntryKey"
+to "KEntry"
+
+KEntry's are stored in order in the KEntryMap. The most significant sort
+criteria is mGroup. This means that all entries who belong in the same group,
+are grouped in the QMap as well.
+
+The start of a group is indicated with a KEntryKey with an empty mKey and a
+dummy KEntry. This allows us to search for the start of the group and then to
+iterate until we end up in another group. That way we will find all entries
+of a certain group.
+
+Entries that are localised with the _current_ locale are stored with bLocal
+set to true. Entries that are localised with another locale are either not
+stored at all (default), or with the localization as part of the key and bRaw
+set to true (when reading a file in order to merge it).
+
+Entries that are being read from a location other than the location to
+which is written back are marked as "default" and will be added both as
+normal entry as well as an entry with the key marked as default.
+
+When the configuration is synced to disk, the current on-disk state is re-read
+into a temporary map, updated with dirty (modified) entries from the
+current config object's entry map and then written back.
+
+
+Note that there is a subtle difference between revertToDefault() and deleteEntry().
+revertToDefault() will change the entry to the default value set by the system
+administrator (Via e.g. $KDEDIR/share/config) or, if no such default was set,
+non-existant.
+deleteEntry() will make the entry non-existant. If if the system administrator
+has specified a default value, the local entry is marked with [$d].
+
+Entries are marked "immutable" if the key is followed by [$i]. This means
+that a user can not override these entries.
+
+
+------------------------------------------------------------------------------
+
+KConfig XT
+==========
+
+My buzzword picker offered KConfig XT ("eXtended Technology") and KConfig NG
+("Next Generation"). Since the planned changes are ment to be evolutionary
+rather than revolutionary, KConfig NG was dropped.
+
+Goals
+=====
+
+* Have the default value for config entries defined in 1 place. Currently it is
+not uncommon to have them defined in three places:
+ 1) In the application that reads the setting in order to use it
+ 2) In the settings dialog when reading the setting
+ 3) In the settings dialog when selecting "Use defaults".
+
+* Provide type-information about config entries to facilate "KConfEdit" like
+tools. Ideally type-information also includes range-information; this is even
+mandatory if enums become an explicit type.
+
+* Facilitate the documentation of config entries.
+
+KCoreConfigSkeleton
+ |
+ v
+ KConfigSkeleton /--< myapp.kcfg
+ | /
+ |*---------------<
+ |kconfig_compiler \
+ | \--< myconfig.kcfgc
+ v
+ MyConfig <-----KConfigDialogManager----> MyConfigWidget *---< myconfigwidget.ui
+ uic
+
+KCoreConfigSkeleton/ base class for deriving classes that store application
+KConfigSkeleton: specific options providing type-safety and single-point
+ defaults.
+
+MyConfig: An application specific class that offers configuration options
+ to the applications via variables or accessor functions and that
+ handles type-safety and defaults. MyConfig is just an example
+ name, the application developer choses the actual name.
+
+myapp.kcfg: File describing the configuration options used by a specific
+ application. myapp.kcfg is just an example name, the application
+ developer choses the actual name.
+
+myconfig.kcfgc: Implementation specific code generation instructions
+ for the MyConfig class. myconfig.kcfgc is
+ just an example name, the application developer
+ choses the actual name.
+
+KConfigDialogManager: Class that links widgets in a dialog up with their
+ corresponding confguration options in a configuration
+ object derived from KConfigSkeleton.
+
+MyConfigWidget: Dialog generated from a .ui description file. Widget names
+ in the dialog that start with "kcfg_" refer to configuration
+ options.
+
+See http://techbase.kde.org/Development/Tutorials/Using_KConfig_XT
diff --git a/kdecore/config/TODO b/kdecore/config/TODO
new file mode 100644
index 0000000..158a78a
--- /dev/null
+++ b/kdecore/config/TODO
@@ -0,0 +1,216 @@
+bugs
+====
+
+- make expandString stuff consistent
+- KConfigGroup::revertToDefault
+ - does not match apidoc re. reverting to kdeglobals 1)
+ - should use entryMap.revertEntry()
+ - map has no bRevert flag that could be set along with bDirty, so it
+ is impossible to get rid of a once set key
+- KConfigGroup::exists() should return true only if the group contains
+ any non-deleted entries (?)
+- immutable groups with no entries are not written out and thus lose
+ their immutability.
+- "C" & "en_US" should be detected early and converted to a null string
+ (but also save the original string, so locale() semantics don't change
+ at that point).
+
+1)
+> > > > > > > I think the apidoc is wrong, it probably shouldn't have the extra
+> > > > > > > paragraph about opening kdeglobals explicitely
+> > > > > > >
+> > > > > > not necessarily. you are assuming a certain model: that kdeglobals
+> > > > > > blends into the config and is on the same level as the master file.
+> > > > > > however, that's not the case - kdeglobals is also a defaults file
+> > > > > > for the master file - which also happens to be writeable. in that, it
+> > > > > > already is an instance of the "master diversion" idea i want to
+> > > > > > generalize.
+> > > > >
+> > > > > no, I'm assuming that any entry read from kdeglobals if reverted will
+> > > > > revert back to the value from kdeglobals, since the default should
+> > > > > have bGlobal set.
+> > > > >
+> > > > yes. and now imagine that you want to revert the entries in kdeglobals
+> > > > to the system wide kdeglobals. this is what this comment is about.
+> > >
+> > > this is what happens, look at KConfig::parseGlobalFiles(). all the
+> > > files are parsed with ParseDefaults *except* the local one.
+> > >
+> > that is right, but makes no sense argumentation-wise.
+> > suppose we have default-foorc, kdeglobals and local-foorc; we opened the
+> > latter explicitly. now i revert key bar. it can only revert from
+> > local-foorc to kdeglobals or from kdeglobals to default-foorc.
+> >
+> no, you will revert from local-foorc to either default-foorc or
+> kdeglobals depending on whether bGlobal is set on the default.
+> $KDEHOME/share/config/kdeglobals can revert from any of
+> $KDEDIRS/share/config/[system.]kdeglobals
+>
+ok - but in either case the key in the master file is reverted.
+to revert the values in kdeglobals itself, you have to open kdeglobals
+as the master file. that's all that the comment says.
+
+
+wishes
+======
+
+- use lazy loading
+ - load as soon as the first KConfigGroup is instanciated
+ - lazy parsing of values is interesting, too - see kconfig_take2 branch
+- add $\\VAR and $\\(cmd) escapes to list-quote expanded string
+- possibly:
+ - preserve unchanged parts of the config literally. problem: comments
+ might become stale. so if a comment is already there, add an additional
+ comment that indicates that the value was changed (include old value?).
+ - api to actively add comments to files, groups and keys
+ - option to start these comments with ## as a sign that they should not
+ trigger the above change indicator logic.
+ - guaranteeing that write order of new keys is preserved
+ - detect commented out entries and put actual entries with the same key
+ right behind them
+- possibly: selective multi-level master diversion
+ - this is to support roaming profiles that have machine/user/etc. specific
+ settings
+ - files, groups and keys can have [$m] and [$s] markers; these cascade
+ within each file only. the least significant object (farthest away from
+ the master) with an effective $m mode becomes the master (i.e., is
+ written to and not read past).
+ default is $m for the master file and $s for the default files.
+ - the CascadeConfig flag being unset doesn't make things exactly simpler
+ - can kdeglobals be handled by this?
+ - does this really make sense? promoting an object to profile wide status
+ is a conscious decision - which probably needs to be repeated every time
+ the value changes.
+
+internals
+=========
+
+- clear up bDeleted vs. isNull in entrymap
+- make entrymap truly hierarchical
+ - an entry map contains its flags, a map of keys and a map of submaps.
+ it does NOT contain its name and has no parent pointer.
+ - when creating a kconfiggroup, ask parent for the respective submap
+ and link it if it is present. if it is not, create one at write op,
+ link it and tell parent to add it to its entry map. both query and
+ creation are recursive, obviously.
+ a kconfiggroup DOES contain its name and has a parent pointer.
+ - 3)
+- 4)
+
+3)
+> We wouldn't have to worry about the KEntryGroup being removed out from
+> under us, because the only way that should happen is if the config
+> object is destroyed or reparsed, and in those cases you shouldn't be
+> using a KConfigGroup from prior to that.
+>
+i don't think "this is stupid and will not happen" works; [...]
+given that cascaded parsing includes writing to existing maps, i think
+the simplest approach is clearing the existing structure from keymaps
+and resetting the attributes, but leaving the subgroup maps populated,
+thus keeping any group refs valid.
+the question is about the type of reference held to the entry map.
+originally i had thought of pointers. a map would be linked only if it
+really existed, otherwise the pointer would be null (thus indicating
+reads to return the default immediately and writes to ask the parent to
+create a submap). however, keeping that consistent with deletions would
+be a nightmare, and with the rescan changing the groups underneath
+impossible without each map having a list of referring configgroups.
+therefore it might make more sense to always create a corresponding tree
+of empty maps when a configroup for a non-existing group is instanciated
+- these groups won't be written out (they have no entries and cannot be
+immutable) and access to non-existing groups (esp. without an subsequent
+write that would actually create it) is rare, so the performance and
+memory overhead of this "eager" approach is likely to be negligible. as
+a middle way one could use a pointer and lazily populate it on first
+access whithout putting semantics into the pointer being already set,
+but i don't think the added complexity will pay off.
+
+4)
+> > > > hmm, wait. maybe it would be better if the map did not do actual
+> > > > permission checking. the frontent is peppered with asserts already
+> > >
+> > > that's the group doing permission checking, if this group is immutable
+> > > then the entry can't be changed. plus, now that KEntryKey doesn't know
+> > > what group it belongs to KEntryMap can't check if the group is
+> > > immutable.
+> > >
+> > > > (need to consider how to handle release builds). in the backend, the
+> > > > ugly immutableGroups hack would be unnecessary.
+> > >
+> > > no, immutableGroups would still be necessary unless i remove all
+> > > checking from KGroupEntry and KEntryMap. but, then checks for
+> > > immutable would have to be used everywhere that an entry might be
+> > > changed.
+> > >
+> > yes - and the frontend already handles it and the backend *should*
+> > handle it (issue warnings for trying to overwrite $i settings).
+>
+> i don't know, i think most handling of the immutability of a group
+> can/should be handled by the KGroupEntry itself. this way we can keep
+> all the data about a group in one place and let KGroupEntry keep
+> itself in a consistent/valid state.
+>
+dunno, either. the use cases are:
+- backend: writing immutable objects is fine, as long as the
+ immutability does not come from a pre-existing default.
+ given that there will be multiple backends, it sounds like
+ centralizing the check and warning reporting might make sense. otoh,
+ such a low-level function might not have enough context to make a
+ useful message.
+- frontend: obviously, writing immutable objects is not permitted. this
+ is already checked everywhere through asserts. in non-debug builds
+ these asserts have no effect, but if a write gets that far it means
+ that the app already permitted changing the option in the first place
+ due to failure to check for immutability. i don't see much point in
+ preventing the illegitimate change from being saved, as it can be
+ repeated anyway (i'm not really convinced of security through
+ exhaustion/boredom of the attacker :).
+i'm not sure whether that means that the two use cases need separate
+mutators or whether the mutator should not apply any immutability
+semantics at all.
+
+
+overwriting semantics
+=====================
+
+generally:
+- localized entries cannot exist without an unlocalized "primary" entry,
+ so writing a localized key when no corresponding unlocalized key
+ exists should print a warning and copy the value to the unlocalized
+ key.
+- a primary entry in the user config overshadows not only the immediate
+ default, but also any localizations of the default. applies also to a
+ [$d] marker, obviously.
+ a localized entry in the user config overshadows only that
+ localization from the default.
+
+write ops:
+> > - writing an entry with the localization flag changes really only that
+> > key.
+> > trying to change the globality of the key prints a warning and does
+> > nothing.
+- key exists in local config => overwritten
+- key does not exist => created
+yes, that's the trivial case.
+
+> > - writing an entry without the localization flag deletes all
+> > localizations.
+> > in this case, changing the globality of the key poses no problem.
+- the key itself is handled trivially
+- if localizations exist in the local config, they are actively purged
+- localizations in the default config don't matter, as they will be
+ overshadowed by the unlocalized key in the local config
+
+> > - deleting an entry also deletes all localizations.
+- if default exists, write [$d] entry
+- if no default exists, delete entry
+- if localizations exist in the local config, they are actively purged
+- localizations in the default config don't matter, as they will be
+ overshadowed by the unlocalized key in the local config (as
+ localizations cannot exist without a primary key, a deletion marker
+ key will be present).
+
+> > - reverting a key to default also restores all localizations.
+- any local entries are actively purged
+
+
diff --git a/kdecore/config/bufferfragment_p.h b/kdecore/config/bufferfragment_p.h
new file mode 100644
index 0000000..5a753ad
--- /dev/null
+++ b/kdecore/config/bufferfragment_p.h
@@ -0,0 +1,181 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2008 Jakub Stachowski <qbast@go2.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef BUFFERFRAGMENT_H
+#define BUFFERFRAGMENT_H
+
+#define bf_isspace(str) ((str == ' ') || (str == '\t') || (str == '\r'))
+
+// This class provides wrapper around fragment of existing buffer (array of bytes).
+// If underlying buffer gets deleted, all BufferFragment objects referencing it become invalid.
+// Use toByteArray() to make deep copy of the buffer fragment.
+//
+// API is designed to subset of QByteArray methods with some changes:
+// - trim() is like QByteArray.trimmed(), but it modifies current object
+// - truncateLeft() provides way to cut off beginning of the buffer
+// - split() works more like strtok_r than QByteArray.split()
+// - truncateLeft() and mid() require position argument to be valid
+
+class KConfigIniBackend::BufferFragment
+{
+
+public:
+
+ BufferFragment() : d(0), len(0)
+ {
+ }
+
+ BufferFragment(char* buf, int size) : d(buf), len(size)
+ {
+ }
+
+ int length() const
+ {
+ return len;
+ }
+
+ char at(unsigned int i) const
+ {
+ Q_ASSERT(i < len);
+ return d[i];
+ }
+
+ void clear()
+ {
+ len = 0;
+ }
+
+ const char* constData() const
+ {
+ return d;
+ }
+
+ char* data() const
+ {
+ return d;
+ }
+
+ void trim()
+ {
+ while (bf_isspace(*d) && len > 0) {
+ d++;
+ len--;
+ }
+ while (len > 0 && bf_isspace(d[len - 1]))
+ len--;
+ }
+
+ // similar to strtok_r . On first call variable pointed by start should be set to 0.
+ // Each call will update *start to new starting position.
+ BufferFragment split(char c, unsigned int* start)
+ {
+ while (*start < len) {
+ int end = indexOf(c, *start);
+ if (end == -1) end = len;
+ BufferFragment line(d + (*start), end - (*start));
+ *start = end + 1;
+ return line;
+ }
+ return BufferFragment();
+ }
+
+ bool isEmpty() const
+ {
+ return (len == 0);
+ }
+
+ BufferFragment left(unsigned int size) const
+ {
+ return BufferFragment(d, qMin(size,len));
+ }
+
+ void truncateLeft(unsigned int size)
+ {
+ Q_ASSERT(size <= len);
+ d += size;
+ len -= size;
+ }
+
+ void truncate(unsigned int pos)
+ {
+ if (pos < len) len = pos;
+ }
+
+ bool isNull() const
+ {
+ return (d == 0);
+ }
+
+ BufferFragment mid(unsigned int pos, int length=-1) const
+ {
+ Q_ASSERT(pos < len);
+ int size = length;
+ if (length == -1 || (pos + length) > len)
+ size = len - pos;
+ return BufferFragment(d + pos, size);
+ }
+
+ bool operator==(const QByteArray& other) const
+ {
+ return (other.size() == (int)len && memcmp(d,other.constData(),len) == 0);
+ }
+
+ bool operator!=(const QByteArray& other) const
+ {
+ return (other.size() != (int)len || memcmp(d,other.constData(),len) != 0);
+ }
+
+ int indexOf(char c, unsigned int from = 0) const
+ {
+ const char* cursor = d + from - 1;
+ const char* end = d + len;
+ while ( ++cursor < end)
+ if (*cursor ==c )
+ return cursor - d;
+ return -1;
+ }
+
+ int lastIndexOf(char c) const
+ {
+ int from = len - 1;
+ while (from >= 0)
+ if (d[from] == c)
+ return from;
+ else
+ from--;
+ return -1;
+ }
+
+ QByteArray toByteArray() const {
+ return QByteArray(d,len);
+ }
+
+ // this is faster than toByteArray, but returned QByteArray becomes invalid
+ // when buffer for this BufferFragment disappears
+ QByteArray toVolatileByteArray() const {
+ return QByteArray::fromRawData(d, len);
+ }
+
+private:
+ char* d;
+ unsigned int len;
+};
+
+#endif
diff --git a/kdecore/config/conversion_check.h b/kdecore/config/conversion_check.h
new file mode 100644
index 0000000..53a4658
--- /dev/null
+++ b/kdecore/config/conversion_check.h
@@ -0,0 +1,120 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006 Thomas Braxton <brax108@cox.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef CONVERSION_CHECK_H
+#define CONVERSION_CHECK_H
+
+#include <QtCore/QString>
+#include <QtGui/QColor>
+#include <QtGui/QFont>
+#include <QtCore/QDate>
+#include <QtCore/QPoint>
+#include <QtCore/QSize>
+#include <QtCore/QRect>
+#include <kurl.h>
+#include <QtCore/QVariant>
+
+namespace ConversionCheck {
+
+// used to distinguish between supported/unsupported types
+struct supported { };
+struct unsupported { };
+
+// traits type class to define support for constraints
+template <typename T>
+struct QVconvertible
+{
+ typedef unsupported toQString;
+ typedef unsupported toQVariant;
+};
+
+// constraint classes
+template <typename T>
+struct type_toQString
+{
+ void constraint() { supported x = y; Q_UNUSED(x); }
+ typename QVconvertible<T>::toQString y;
+};
+
+template <typename T>
+struct type_toQVariant
+{
+ void constraint() { supported x = y; Q_UNUSED(x); }
+ typename QVconvertible<T>::toQVariant y;
+};
+
+
+// check if T is convertible to QString thru QVariant
+// if not supported can't be used in QList<T> functions
+template <typename T>
+inline void to_QString()
+{
+ void (type_toQString<T>::*x)() = &type_toQString<T>::constraint;
+ Q_UNUSED(x);
+}
+
+// check if T is convertible to QVariant & supported in readEntry/writeEntry
+template <typename T>
+inline void to_QVariant()
+{
+ void (type_toQVariant<T>::*x)() = &type_toQVariant<T>::constraint;
+ Q_UNUSED(x);
+}
+
+// define for all types handled in readEntry/writeEntry
+// string_support - is supported by QVariant(type).toString(),
+// can be used in QList<T> functions
+// variant_support - has a QVariant constructor
+#define QVConversions(type, string_support, variant_support) \
+template <> struct QVconvertible<type> {\
+ typedef string_support toQString;\
+ typedef variant_support toQVariant;\
+}
+
+// The only types needed here are the types handled in readEntry/writeEntry
+// the default QVconvertible will take care of the rest.
+QVConversions(bool, supported, supported);
+QVConversions(int, supported, supported);
+QVConversions(unsigned int, supported, supported);
+QVConversions(long long, supported, supported);
+QVConversions(unsigned long long, supported, supported);
+QVConversions(float, supported, supported);
+QVConversions(double, supported, supported);
+QVConversions(QString, supported, supported);
+QVConversions(QColor, unsupported, supported);
+QVConversions(QFont, supported, supported);
+QVConversions(QDateTime, unsupported, supported);
+QVConversions(QDate, unsupported, supported);
+QVConversions(QSize, unsupported, supported);
+QVConversions(QRect, unsupported, supported);
+QVConversions(QPoint, unsupported, supported);
+QVConversions(QSizeF, unsupported, supported);
+QVConversions(QRectF, unsupported, supported);
+QVConversions(QPointF, unsupported, supported);
+QVConversions(QByteArray, supported, supported);
+QVConversions(QStringList, unsupported, supported);
+QVConversions(QVariantList, unsupported, supported);
+QVConversions(KUrl, supported, supported);
+QVConversions(KUrl::List, unsupported, supported);
+}
+
+#endif
+
diff --git a/kdecore/config/kconfig.cpp b/kdecore/config/kconfig.cpp
new file mode 100644
index 0000000..fcf0ce9
--- /dev/null
+++ b/kdecore/config/kconfig.cpp
@@ -0,0 +1,888 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kconfig.h"
+#include "kconfig_p.h"
+
+#include <cstdlib>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "kconfigbackend.h"
+#include "kconfiggroup.h"
+#include <kde_file.h>
+#include <kstringhandler.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kurl.h>
+#include <kcomponentdata.h>
+#include <ktoolinvocation.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include <qbytearray.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qcolor.h>
+#include <QtCore/QProcess>
+#include <QtCore/QPointer>
+#include <QtCore/QSet>
+#include <QtCore/QStack>
+
+bool KConfigPrivate::mappingsRegistered=false;
+
+KConfigPrivate::KConfigPrivate(const KComponentData &componentData_, KConfig::OpenFlags flags,
+ const char* resource)
+ : openFlags(flags), resourceType(resource), mBackend(0),
+ bDynamicBackend(true), bDirty(false), bReadDefaults(false),
+ bFileImmutable(false), bForceGlobal(false), bSuppressGlobal(false),
+ componentData(componentData_), configState(KConfigBase::NoAccess)
+{
+ sGlobalFileName = componentData.dirs()->saveLocation("config", QString(), false) + QLatin1String("kdeglobals");
+
+ static int use_etc_kderc = -1;
+ if (use_etc_kderc < 0)
+ use_etc_kderc = getenv("KDE_SKIP_KDERC") != 0 ? 0 : 1; // for unit tests
+ if (use_etc_kderc) {
+
+ etc_kderc =
+#ifdef Q_WS_WIN
+ QFile::decodeName( qgetenv("WINDIR") + "/kde4rc" );
+#else
+ QLatin1String("/etc/kde4rc");
+#endif
+ if (!KStandardDirs::checkAccess(etc_kderc, R_OK)) {
+ etc_kderc.clear();
+ }
+ }
+
+// if (!mappingsRegistered) {
+// KEntryMap tmp;
+// if (!etc_kderc.isEmpty()) {
+// KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, etc_kderc, QLatin1String("INI"));
+// backend->parseConfig( "en_US", tmp, KConfigBackend::ParseDefaults);
+// }
+// const QString kde4rc(QDir::home().filePath(".kde4rc"));
+// if (KStandardDirs::checkAccess(kde4rc, R_OK)) {
+// KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, kde4rc, QLatin1String("INI"));
+// backend->parseConfig( "en_US", tmp, KConfigBackend::ParseOptions());
+// }
+// KConfigBackend::registerMappings(tmp);
+// mappingsRegistered = true;
+// }
+
+ setLocale(KGlobal::hasLocale() ? KGlobal::locale()->language() : KLocale::defaultLanguage());
+}
+
+
+bool KConfigPrivate::lockLocal()
+{
+ if (mBackend) {
+ return mBackend->lock(componentData);
+ }
+ // anonymous object - pretend we locked it
+ return true;
+}
+
+void KConfigPrivate::copyGroup(const QByteArray& source, const QByteArray& destination,
+ KConfigGroup *otherGroup, KConfigBase::WriteConfigFlags flags) const
+{
+ KEntryMap& otherMap = otherGroup->config()->d_ptr->entryMap;
+ const int len = source.length();
+ const bool sameName = (destination == source);
+
+ // we keep this bool outside the foreach loop so that if
+ // the group is empty, we don't end up marking the other config
+ // as dirty erroneously
+ bool dirtied = false;
+
+ for (KEntryMap::ConstIterator entryMapIt( entryMap.constBegin() ); entryMapIt != entryMap.constEnd(); ++entryMapIt) {
+ const QByteArray& group = entryMapIt.key().mGroup;
+
+ if (!group.startsWith(source)) // nothing to do
+ continue;
+
+ // don't copy groups that start with the same prefix, but are not sub-groups
+ if (group.length() > len && group[len] != '\x1d')
+ continue;
+
+ KEntryKey newKey = entryMapIt.key();
+
+ if (flags & KConfigBase::Localized) {
+ newKey.bLocal = true;
+ }
+
+ if (!sameName)
+ newKey.mGroup.replace(0, len, destination);
+
+ KEntry entry = entryMap[ entryMapIt.key() ];
+ dirtied = entry.bDirty = flags & KConfigBase::Persistent;
+
+ if (flags & KConfigBase::Global) {
+ entry.bGlobal = true;
+ }
+
+ otherMap[newKey] = entry;
+ }
+
+ if (dirtied) {
+ otherGroup->config()->d_ptr->bDirty = true;
+ }
+}
+
+QString KConfigPrivate::expandString(const QString& value)
+{
+ QString aValue = value;
+
+ // check for environment variables and make necessary translations
+ int nDollarPos = aValue.indexOf( QLatin1Char('$') );
+ while( nDollarPos != -1 && nDollarPos+1 < aValue.length()) {
+ // there is at least one $
+ if( aValue[nDollarPos+1] == QLatin1Char('(') ) {
+ int nEndPos = nDollarPos+1;
+ // the next character is not $
+ while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!=QLatin1Char(')')) )
+ nEndPos++;
+ nEndPos++;
+ QString cmd = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
+
+ QString result;
+ QByteArray oldpath = qgetenv( "PATH" );
+ QByteArray newpath;
+ if (KGlobal::hasMainComponent()) {
+ newpath = QFile::encodeName(KGlobal::dirs()->resourceDirs("exe").join(QChar::fromLatin1(KPATH_SEPARATOR)));
+ if (!newpath.isEmpty() && !oldpath.isEmpty())
+ newpath += KPATH_SEPARATOR;
+ }
+ newpath += oldpath;
+ setenv( "PATH", newpath, 1/*overwrite*/ );
+// FIXME: wince does not have pipes
+#ifndef _WIN32_WCE
+ FILE *fs = popen(QFile::encodeName(cmd).data(), "r");
+ if (fs) {
+ QTextStream ts(fs, QIODevice::ReadOnly);
+ result = ts.readAll().trimmed();
+ pclose(fs);
+ }
+#endif
+ setenv( "PATH", oldpath, 1/*overwrite*/ );
+ aValue.replace( nDollarPos, nEndPos-nDollarPos, result );
+ nDollarPos += result.length();
+ } else if( aValue[nDollarPos+1] != QLatin1Char('$') ) {
+ int nEndPos = nDollarPos+1;
+ // the next character is not $
+ QString aVarName;
+ if ( aValue[nEndPos] == QLatin1Char('{') ) {
+ while ( (nEndPos <= aValue.length()) && (aValue[nEndPos] != QLatin1Char('}')) )
+ nEndPos++;
+ nEndPos++;
+ aVarName = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 );
+ } else {
+ while ( nEndPos <= aValue.length() &&
+ (aValue[nEndPos].isNumber() ||
+ aValue[nEndPos].isLetter() ||
+ aValue[nEndPos] == QLatin1Char('_') ) )
+ nEndPos++;
+ aVarName = aValue.mid( nDollarPos+1, nEndPos-nDollarPos-1 );
+ }
+ QString env;
+ if (!aVarName.isEmpty()) {
+#ifdef Q_OS_WIN
+ if (aVarName == QLatin1String("HOME"))
+ env = QDir::homePath();
+ else
+#endif
+ {
+ QByteArray pEnv = qgetenv( aVarName.toAscii() );
+ if( !pEnv.isEmpty() )
+ // !!! Sergey A. Sukiyazov <corwin@micom.don.ru> !!!
+ // An environment variable may contain values in 8bit
+ // locale specified encoding or UTF8 encoding
+ env = KStringHandler::from8Bit( pEnv );
+ }
+ aValue.replace(nDollarPos, nEndPos-nDollarPos, env);
+ nDollarPos += env.length();
+ } else
+ aValue.remove( nDollarPos, nEndPos-nDollarPos );
+ } else {
+ // remove one of the dollar signs
+ aValue.remove( nDollarPos, 1 );
+ nDollarPos++;
+ }
+ nDollarPos = aValue.indexOf( QLatin1Char('$'), nDollarPos );
+ }
+
+ return aValue;
+}
+
+
+KConfig::KConfig( const QString& file, OpenFlags mode,
+ const char* resourceType)
+ : d_ptr(new KConfigPrivate(KGlobal::mainComponent(), mode, resourceType))
+{
+ d_ptr->changeFileName(file, resourceType); // set the local file name
+
+ // read initial information off disk
+ reparseConfiguration();
+}
+
+KConfig::KConfig( const KComponentData& componentData, const QString& file, OpenFlags mode,
+ const char* resourceType)
+ : d_ptr(new KConfigPrivate(componentData, mode, resourceType))
+{
+ d_ptr->changeFileName(file, resourceType); // set the local file name
+
+ // read initial information off disk
+ reparseConfiguration();
+}
+
+KConfig::KConfig(const QString& file, const QString& backend, const char* resourceType)
+ : d_ptr(new KConfigPrivate(KGlobal::mainComponent(), SimpleConfig, resourceType))
+{
+ d_ptr->mBackend = KConfigBackend::create(d_ptr->componentData, file, backend);
+ d_ptr->bDynamicBackend = false;
+ d_ptr->changeFileName(file, ""); // set the local file name
+
+ // read initial information off disk
+ reparseConfiguration();
+}
+
+KConfig::KConfig(KConfigPrivate &d)
+ : d_ptr(&d)
+{
+}
+
+KConfig::~KConfig()
+{
+ Q_D(KConfig);
+ if (d->bDirty && d->mBackend.isUnique())
+ sync();
+ delete d;
+}
+
+const KComponentData& KConfig::componentData() const
+{
+ Q_D(const KConfig);
+ return d->componentData;
+}
+
+QStringList KConfig::groupList() const
+{
+ Q_D(const KConfig);
+ QSet<QString> groups;
+
+ for (KEntryMap::ConstIterator entryMapIt( d->entryMap.constBegin() ); entryMapIt != d->entryMap.constEnd(); ++entryMapIt) {
+ const KEntryKey& key = entryMapIt.key();
+ const QByteArray group = key.mGroup;
+ if (key.mKey.isNull() && !group.isEmpty() && group != "<default>" && group != "$Version") {
+ const QString groupname = QString::fromUtf8(group);
+ groups << groupname.left(groupname.indexOf(QLatin1Char('\x1d')));
+ }
+ }
+
+ return groups.toList();
+}
+
+QStringList KConfigPrivate::groupList(const QByteArray& group) const
+{
+ QByteArray theGroup = group + '\x1d';
+ QSet<QString> groups;
+
+ for (KEntryMap::ConstIterator entryMapIt( entryMap.constBegin() ); entryMapIt != entryMap.constEnd(); ++entryMapIt) {
+ const KEntryKey& key = entryMapIt.key();
+ if (key.mKey.isNull() && key.mGroup.startsWith(theGroup)) {
+ const QString groupname = QString::fromUtf8(key.mGroup.mid(theGroup.length()));
+ groups << groupname.left(groupname.indexOf(QLatin1Char('\x1d')));
+ }
+ }
+
+ return groups.toList();
+}
+
+// List all sub groups, including subsubgroups
+QSet<QByteArray> KConfigPrivate::allSubGroups(const QByteArray& parentGroup) const
+{
+ QSet<QByteArray> groups;
+ QByteArray theGroup = parentGroup + '\x1d';
+ groups << parentGroup;
+
+ for (KEntryMap::const_iterator entryMapIt = entryMap.begin(); entryMapIt != entryMap.end(); ++entryMapIt) {
+ const KEntryKey& key = entryMapIt.key();
+ if (key.mKey.isNull() && key.mGroup.startsWith(theGroup)) {
+ groups << key.mGroup;
+ }
+ }
+ return groups;
+}
+
+bool KConfigPrivate::hasNonDeletedEntries(const QByteArray& group) const
+{
+ const QSet<QByteArray> allGroups = allSubGroups(group);
+
+ Q_FOREACH(const QByteArray& aGroup, allGroups) {
+ // Could be optimized, let's use the slow way for now
+ // Check for any non-deleted entry
+ if (!keyListImpl(aGroup).isEmpty())
+ return true;
+ }
+ return false;
+}
+
+
+QStringList KConfigPrivate::keyListImpl(const QByteArray& theGroup) const
+{
+ QStringList keys;
+
+ const KEntryMapConstIterator theEnd = entryMap.constEnd();
+ KEntryMapConstIterator it = entryMap.findEntry(theGroup);
+ if (it != theEnd) {
+ ++it; // advance past the special group entry marker
+
+ QSet<QString> tmp;
+ for (; it != theEnd && it.key().mGroup == theGroup; ++it) {
+ const KEntryKey& key = it.key();
+ if (key.mGroup == theGroup && !key.mKey.isNull() && !it->bDeleted)
+ tmp << QString::fromUtf8(key.mKey);
+ }
+ keys = tmp.toList();
+ }
+
+ return keys;
+}
+
+QStringList KConfig::keyList(const QString& aGroup) const
+{
+ Q_D(const KConfig);
+ const QByteArray theGroup(aGroup.isEmpty() ? "<default>" : aGroup.toUtf8());
+ return d->keyListImpl(theGroup);
+}
+
+QMap<QString,QString> KConfig::entryMap(const QString& aGroup) const
+{
+ Q_D(const KConfig);
+ QMap<QString, QString> theMap;
+ const QByteArray theGroup(aGroup.isEmpty() ? "<default>" : aGroup.toUtf8());
+
+ const KEntryMapConstIterator theEnd = d->entryMap.constEnd();
+ KEntryMapConstIterator it = d->entryMap.findEntry(theGroup, 0, 0);
+ if (it != theEnd) {
+ ++it; // advance past the special group entry marker
+
+ for (; it != theEnd && it.key().mGroup == theGroup; ++it) {
+ // leave the default values and deleted entries out
+ if (!it->bDeleted && !it.key().bDefault) {
+ const QString key = QString::fromUtf8(it.key().mKey.constData());
+ // the localized entry should come first, so don't overwrite it
+ // with the non-localized entry
+ if (!theMap.contains(key)) {
+ if (it->bExpand) {
+ theMap.insert(key,KConfigPrivate::expandString(QString::fromUtf8(it->mValue.constData())));
+ } else {
+ theMap.insert(key,QString::fromUtf8(it->mValue.constData()));
+ }
+ }
+ }
+ }
+ }
+
+ return theMap;
+}
+
+// TODO KDE5: return a bool value
+void KConfig::sync()
+{
+ Q_D(KConfig);
+
+ if (isImmutable() || name().isEmpty()) {
+ // can't write to an immutable or anonymous file.
+ return;
+ }
+
+ if (d->bDirty && d->mBackend) {
+ const QByteArray utf8Locale(locale().toUtf8());
+
+ // Create the containing dir, maybe it wasn't there
+ d->mBackend->createEnclosing();
+
+ // lock the local file
+ if (d->configState == ReadWrite && !d->lockLocal()) {
+ qWarning() << "couldn't lock local file";
+ return;
+ }
+
+ // Rewrite global/local config only if there is a dirty entry in it.
+ bool writeGlobals = false;
+ bool writeLocals = false;
+ foreach (const KEntry& e, d->entryMap) {
+ if (e.bDirty) {
+ if (e.bGlobal) {
+ writeGlobals = true;
+ } else {
+ writeLocals = true;
+ }
+
+ if (writeGlobals && writeLocals) {
+ break;
+ }
+ }
+ }
+
+ d->bDirty = false; // will revert to true if a config write fails
+
+ if (d->wantGlobals() && writeGlobals) {
+ KSharedPtr<KConfigBackend> tmp = KConfigBackend::create(componentData(), d->sGlobalFileName);
+ if (d->configState == ReadWrite && !tmp->lock(componentData())) {
+ qWarning() << "couldn't lock global file";
+ return;
+ }
+ if (!tmp->writeConfig(utf8Locale, d->entryMap, KConfigBackend::WriteGlobal, d->componentData)) {
+ d->bDirty = true;
+ // TODO KDE5: return false? (to tell the app that writing wasn't possible, e.g.
+ // config file is immutable or disk full)
+ }
+ if (tmp->isLocked()) {
+ tmp->unlock();
+ }
+ }
+
+ if (writeLocals) {
+ if (!d->mBackend->writeConfig(utf8Locale, d->entryMap, KConfigBackend::WriteOptions(), d->componentData)) {
+ d->bDirty = true;
+ // TODO KDE5: return false? (to tell the app that writing wasn't possible, e.g.
+ // config file is immutable or disk full)
+ }
+ }
+ if (d->mBackend->isLocked()) {
+ d->mBackend->unlock();
+ }
+ }
+}
+
+void KConfig::markAsClean()
+{
+ Q_D(KConfig);
+ d->bDirty = false;
+
+ // clear any dirty flags that entries might have set
+ const KEntryMapIterator theEnd = d->entryMap.end();
+ for (KEntryMapIterator it = d->entryMap.begin(); it != theEnd; ++it)
+ it->bDirty = false;
+}
+
+void KConfig::checkUpdate(const QString &id, const QString &updateFile)
+{
+ const KConfigGroup cg(this, "$Version");
+ const QString cfg_id = updateFile+QLatin1Char(':')+id;
+ const QStringList ids = cg.readEntry("update_info", QStringList());
+ if (!ids.contains(cfg_id)) {
+ KToolInvocation::kdeinitExecWait(QString::fromLatin1("kconf_update"), QStringList() << QString::fromLatin1("--check") << updateFile);
+ reparseConfiguration();
+ }
+}
+
+KConfig* KConfig::copyTo(const QString &file, KConfig *config) const
+{
+ Q_D(const KConfig);
+ if (!config)
+ config = new KConfig(componentData(), QString(), SimpleConfig);
+ config->d_func()->changeFileName(file, d->resourceType);
+ config->d_func()->entryMap = d->entryMap;
+ config->d_func()->bFileImmutable = false;
+
+ const KEntryMapIterator theEnd = config->d_func()->entryMap.end();
+ for (KEntryMapIterator it = config->d_func()->entryMap.begin(); it != theEnd; ++it)
+ it->bDirty = true;
+ config->d_ptr->bDirty = true;
+
+ return config;
+}
+
+QString KConfig::name() const
+{
+ Q_D(const KConfig);
+ return d->fileName;
+}
+
+void KConfigPrivate::changeFileName(const QString& name, const char* type)
+{
+ fileName = name;
+
+ QString file;
+ if (name.isEmpty()) {
+ if (wantDefaults()) { // accessing default app-specific config "appnamerc"
+ const QString appName = componentData.aboutData()->appName();
+ if (!appName.isEmpty()) {
+ fileName = appName + QLatin1String("rc");
+ if (type && *type)
+ resourceType = type; // only change it if it's not empty
+ file = KStandardDirs::locateLocal(resourceType, fileName, false, componentData);
+ }
+ } else if (wantGlobals()) { // accessing "kdeglobals" - XXX used anywhere?
+ resourceType = "config";
+ fileName = QLatin1String("kdeglobals");
+ file = sGlobalFileName;
+ } // else anonymous config.
+ // KDE5: remove these magic overloads
+ } else if (QDir::isAbsolutePath(fileName)) {
+ fileName = KStandardDirs::realFilePath(fileName);
+ file = fileName;
+ } else {
+ if (type && *type)
+ resourceType = type; // only change it if it's not empty
+ file = KStandardDirs::locateLocal(resourceType, fileName, false, componentData);
+ }
+
+ if (file.isEmpty()) {
+ openFlags = KConfig::SimpleConfig;
+ return;
+ }
+
+ bSuppressGlobal = (file == sGlobalFileName);
+
+ if (bDynamicBackend || !mBackend) // allow dynamic changing of backend
+ mBackend = KConfigBackend::create(componentData, file);
+ else
+ mBackend->setFilePath(file);
+
+ configState = mBackend->accessMode();
+}
+
+void KConfig::reparseConfiguration()
+{
+ Q_D(KConfig);
+ if (d->fileName.isEmpty()) {
+ return;
+ }
+
+ // Don't lose pending changes
+ if (!d->isReadOnly() && d->bDirty)
+ sync();
+
+ d->entryMap.clear();
+
+ d->bFileImmutable = false;
+
+ // Parse all desired files from the least to the most specific.
+ if (d->wantGlobals())
+ d->parseGlobalFiles();
+
+ d->parseConfigFiles();
+}
+
+
+QStringList KConfigPrivate::getGlobalFiles() const
+{
+ const KStandardDirs *const dirs = componentData.dirs();
+ QStringList globalFiles;
+ foreach (const QString& dir1, dirs->findAllResources("config", QLatin1String("kdeglobals")))
+ globalFiles.push_front(dir1);
+ foreach (const QString& dir2, dirs->findAllResources("config", QLatin1String("system.kdeglobals")))
+ globalFiles.push_front(dir2);
+ if (!etc_kderc.isEmpty())
+ globalFiles.push_front(etc_kderc);
+ return globalFiles;
+}
+
+void KConfigPrivate::parseGlobalFiles()
+{
+ const QStringList globalFiles = getGlobalFiles();
+// qDebug() << "parsing global files" << globalFiles;
+
+ // TODO: can we cache the values in etc_kderc / other global files
+ // on a per-application basis?
+ const QByteArray utf8Locale = locale.toUtf8();
+ foreach(const QString& file, globalFiles) {
+ KConfigBackend::ParseOptions parseOpts = KConfigBackend::ParseGlobal|KConfigBackend::ParseExpansions;
+ if (file != sGlobalFileName)
+ parseOpts |= KConfigBackend::ParseDefaults;
+
+ KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, file);
+ if ( backend->parseConfig( utf8Locale, entryMap, parseOpts) == KConfigBackend::ParseImmutable)
+ break;
+ }
+}
+
+void KConfigPrivate::parseConfigFiles()
+{
+ // can only read the file if there is a backend and a file name
+ if (mBackend && !fileName.isEmpty()) {
+
+ bFileImmutable = false;
+
+ QList<QString> files;
+ if (wantDefaults()) {
+ if (bSuppressGlobal) {
+ files = getGlobalFiles();
+ } else {
+ foreach (const QString& f, componentData.dirs()->findAllResources(
+ resourceType, fileName))
+ files.prepend(f);
+ }
+ } else {
+ files << mBackend->filePath();
+ }
+ if (!isSimple())
+ files = extraFiles.toList() + files;
+
+// qDebug() << "parsing local files" << files;
+
+ const QByteArray utf8Locale = locale.toUtf8();
+ foreach(const QString& file, files) {
+ if (file == mBackend->filePath()) {
+ switch (mBackend->parseConfig(utf8Locale, entryMap, KConfigBackend::ParseExpansions)) {
+ case KConfigBackend::ParseOk:
+ break;
+ case KConfigBackend::ParseImmutable:
+ bFileImmutable = true;
+ break;
+ case KConfigBackend::ParseOpenError:
+ configState = KConfigBase::NoAccess;
+ break;
+ }
+ } else {
+ KSharedPtr<KConfigBackend> backend = KConfigBackend::create(componentData, file);
+ bFileImmutable = (backend->parseConfig(utf8Locale, entryMap,
+ KConfigBackend::ParseDefaults|KConfigBackend::ParseExpansions)
+ == KConfigBackend::ParseImmutable);
+ }
+
+ if (bFileImmutable)
+ break;
+ }
+ if (componentData.dirs()->isRestrictedResource(resourceType, fileName))
+ bFileImmutable = true;
+ }
+}
+
+KConfig::AccessMode KConfig::accessMode() const
+{
+ Q_D(const KConfig);
+ return d->configState;
+}
+
+void KConfig::addConfigSources(const QStringList& files)
+{
+ Q_D(KConfig);
+ foreach(const QString& file, files) {
+ d->extraFiles.push(file);
+ }
+
+ if (!files.isEmpty()) {
+ reparseConfiguration();
+ }
+}
+
+QString KConfig::locale() const
+{
+ Q_D(const KConfig);
+ return d->locale;
+}
+
+bool KConfigPrivate::setLocale(const QString& aLocale)
+{
+ if (aLocale != locale) {
+ locale = aLocale;
+ return true;
+ }
+ return false;
+}
+
+bool KConfig::setLocale(const QString& locale)
+{
+ Q_D(KConfig);
+ if (d->setLocale(locale)) {
+ reparseConfiguration();
+ return true;
+ }
+ return false;
+}
+
+void KConfig::setReadDefaults(bool b)
+{
+ Q_D(KConfig);
+ d->bReadDefaults = b;
+}
+
+bool KConfig::readDefaults() const
+{
+ Q_D(const KConfig);
+ return d->bReadDefaults;
+}
+
+bool KConfig::isImmutable() const
+{
+ Q_D(const KConfig);
+ return d->bFileImmutable;
+}
+
+bool KConfig::isGroupImmutableImpl(const QByteArray& aGroup) const
+{
+ Q_D(const KConfig);
+ return isImmutable() || d->entryMap.getEntryOption(aGroup, 0, 0, KEntryMap::EntryImmutable);
+}
+
+#ifndef KDE_NO_DEPRECATED
+void KConfig::setForceGlobal(bool b)
+{
+ Q_D(KConfig);
+ d->bForceGlobal = b;
+}
+#endif
+
+#ifndef KDE_NO_DEPRECATED
+bool KConfig::forceGlobal() const
+{
+ Q_D(const KConfig);
+ return d->bForceGlobal;
+}
+#endif
+
+KConfigGroup KConfig::groupImpl(const QByteArray &group)
+{
+ return KConfigGroup(this, group.constData());
+}
+
+const KConfigGroup KConfig::groupImpl(const QByteArray &group) const
+{
+ return KConfigGroup(this, group.constData());
+}
+
+KEntryMap::EntryOptions convertToOptions(KConfig::WriteConfigFlags flags)
+{
+ KEntryMap::EntryOptions options=0;
+
+ if (flags&KConfig::Persistent)
+ options |= KEntryMap::EntryDirty;
+ if (flags&KConfig::Global)
+ options |= KEntryMap::EntryGlobal;
+ if (flags&KConfig::Localized)
+ options |= KEntryMap::EntryLocalized;
+ return options;
+}
+
+void KConfig::deleteGroupImpl(const QByteArray &aGroup, WriteConfigFlags flags)
+{
+ Q_D(KConfig);
+ KEntryMap::EntryOptions options = convertToOptions(flags)|KEntryMap::EntryDeleted;
+
+ const QSet<QByteArray> groups = d->allSubGroups(aGroup);
+ foreach (const QByteArray& group, groups) {
+ const QStringList keys = d->keyListImpl(group);
+ foreach (const QString& _key, keys) {
+ const QByteArray &key = _key.toUtf8();
+ if (d->canWriteEntry(group, key.constData())) {
+ d->entryMap.setEntry(group, key, QByteArray(), options);
+ d->bDirty = true;
+ }
+ }
+ }
+}
+
+bool KConfig::isConfigWritable(bool warnUser)
+{
+ Q_D(KConfig);
+ bool allWritable = (d->mBackend.isNull()? false: d->mBackend->isWritable());
+
+ if (warnUser && !allWritable) {
+ QString errorMsg;
+ if (!d->mBackend.isNull()) // TODO how can be it be null? Set errorMsg appropriately
+ errorMsg = d->mBackend->nonWritableErrorMessage();
+
+ // Note: We don't ask the user if we should not ask this question again because we can't save the answer.
+ errorMsg += i18n("Please contact your system administrator.");
+ QString cmdToExec = KStandardDirs::findExe(QString::fromLatin1("kdialog"));
+ if (!cmdToExec.isEmpty() && componentData().isValid())
+ {
+ QProcess::execute(cmdToExec, QStringList()
+ << QString::fromLatin1("--title") << componentData().componentName()
+ << QString::fromLatin1("--msgbox") << errorMsg);
+ }
+ }
+
+ d->configState = allWritable ? ReadWrite : ReadOnly; // update the read/write status
+
+ return allWritable;
+}
+
+bool KConfig::hasGroupImpl(const QByteArray& aGroup) const
+{
+ Q_D(const KConfig);
+
+ // No need to look for the actual group entry anymore, or for subgroups:
+ // a group exists if it contains any non-deleted entry.
+
+ return d->hasNonDeletedEntries(aGroup);
+}
+
+bool KConfigPrivate::canWriteEntry(const QByteArray& group, const char* key, bool isDefault) const
+{
+ if (bFileImmutable ||
+ entryMap.getEntryOption(group, key, KEntryMap::SearchLocalized, KEntryMap::EntryImmutable))
+ return isDefault;
+ return true;
+}
+
+void KConfigPrivate::putData( const QByteArray& group, const char* key,
+ const QByteArray& value, KConfigBase::WriteConfigFlags flags, bool expand)
+{
+ KEntryMap::EntryOptions options = convertToOptions(flags);
+
+ if (bForceGlobal)
+ options |= KEntryMap::EntryGlobal;
+ if (expand)
+ options |= KEntryMap::EntryExpansion;
+
+ if (value.isNull()) // deleting entry
+ options |= KEntryMap::EntryDeleted;
+
+ bool dirtied = entryMap.setEntry(group, key, value, options);
+ if (dirtied && (flags & KConfigBase::Persistent))
+ bDirty = true;
+}
+
+QByteArray KConfigPrivate::lookupData(const QByteArray& group, const char* key,
+ KEntryMap::SearchFlags flags) const
+{
+ if (bReadDefaults)
+ flags |= KEntryMap::SearchDefaults;
+ const KEntryMapConstIterator it = entryMap.findEntry(group, key, flags);
+ if (it == entryMap.constEnd())
+ return QByteArray();
+ return it->mValue;
+}
+
+QString KConfigPrivate::lookupData(const QByteArray& group, const char* key,
+ KEntryMap::SearchFlags flags, bool *expand) const
+{
+ if (bReadDefaults)
+ flags |= KEntryMap::SearchDefaults;
+ return entryMap.getEntry(group, key, QString(), flags, expand);
+}
+
+void KConfig::virtual_hook(int /*id*/, void* /*data*/)
+{
+ /* nothing */
+}
+
diff --git a/kdecore/config/kconfig.h b/kdecore/config/kconfig.h
new file mode 100644
index 0000000..51381ca
--- /dev/null
+++ b/kdecore/config/kconfig.h
@@ -0,0 +1,412 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIG_H
+#define KCONFIG_H
+
+#include "kconfigbase.h"
+
+#include <kdecore_export.h>
+
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+
+class KConfigGroup;
+class KComponentData;
+class KEntryMap;
+class KConfigPrivate;
+
+/**
+ * \class KConfig kconfig.h <KConfig>
+ *
+ * \brief The central class of the KDE configuration data system.
+ *
+ * Quickstart:
+ *
+ * Get the default application config object via KGlobal::config().
+ *
+ * Load a specific configuration file:
+ * \code
+ * KConfig config( "/etc/kderc", KConfig::SimpleConfig );
+ * \endcode
+ *
+ * Load the configuration of a specific component (taking into account
+ * possible custom directories in KStandardDirs):
+ * \code
+ * KConfig config( componentData(), "pluginrc" );
+ * \endcode
+ *
+ * In general it is recommended to use KSharedConfig instead of
+ * creating multiple instances of KConfig to avoid the overhead of
+ * separate objects or concerns about synchronizing writes to disk
+ * even if the configuration object is updated from multiple code paths.
+ * KSharedConfig provides a set of open methods as counterparts for the
+ * KConfig constructors.
+ *
+ * \sa KSharedConfig, KConfigGroup, <a href="http://techbase.kde.org/index.php?title=Development/Tutorials/KConfig">the techbase HOWTO on KConfig</a>.
+ */
+class KDECORE_EXPORT KConfig : public KConfigBase
+{
+public:
+ /**
+ * Determines how the system-wide and user's global settings will affect
+ * the reading of the configuration.
+ *
+ * If CascadeConfig is selected, system-wide configuration sources are used
+ * to provide defaults for the settings accessed through this object, or
+ * possibly to override those settings in certain cases.
+ *
+ * IncludeGlobals does the same, but with the global settings sources.
+ *
+ * Note that the main configuration source overrides the cascaded sources,
+ * which override those provided to addConfigSources(), which override the
+ * global sources. The exception is that if a key or group is marked as
+ * being immutable, it will not be overridden.
+ *
+ * Note that all values other than IncludeGlobals and CascadeConfig are
+ * convenience definitions for the basic mode.
+ * Do @em not combine them with anything.
+ */
+ enum OpenFlag {
+ IncludeGlobals = 0x01, ///< Blend kdeglobals into the config object.
+ CascadeConfig = 0x02, ///< Cascade to system-wide config files.
+
+ SimpleConfig = 0x00, ///< Just a single config file.
+ NoCascade = IncludeGlobals, ///< Include user's globals, but omit system settings.
+ NoGlobals = CascadeConfig, ///< Cascade to system settings, but omit user's globals.
+ FullConfig = IncludeGlobals|CascadeConfig ///< Fully-fledged config, including globals and cascading to system settings
+ };
+ Q_DECLARE_FLAGS(OpenFlags, OpenFlag)
+
+ /**
+ * Creates a KConfig object to manipulate a configuration file for the
+ * current application.
+ *
+ * If an absolute path is specified for @p file, that file will be used
+ * as the store for the configuration settings. If a non-absolute path
+ * is provided, the file will be looked for in the standard directory
+ * specified by resourceType. If no path is provided, a default
+ * configuration file will be used based on the name of the main
+ * application component.
+ *
+ * @p mode determines whether the user or global settings will be allowed
+ * to influence the values returned by this object. See OpenFlags for
+ * more details.
+ *
+ * @note You probably want to use KSharedConfig::openConfig instead.
+ *
+ * @param file the name of the file. If an empty string is passed in
+ * and SimpleConfig is passed in for the OpenFlags, then an in-memory
+ * KConfig object is created which will not write out to file nor which
+ * requires any file in the filesystem at all.
+ * @param mode how global settings should affect the configuration
+ * options exposed by this KConfig object
+ * @param resourceType The standard directory to look for the configuration
+ * file in (see KStandardDirs)
+ *
+ * @sa KSharedConfig::openConfig(const QString&, OpenFlags, const char*)
+ */
+ explicit KConfig(const QString& file = QString(), OpenFlags mode = FullConfig,
+ const char* resourceType = "config");
+
+ /**
+ * Creates a KConfig object to manipulate the configuration for a specific
+ * component.
+ *
+ * If an absolute path is specified for @p file, that file will be used
+ * as the store for the configuration settings. If a non-absolute path
+ * is provided, the file will be looked for in the standard directory
+ * specified by resourceType. If no path is provided, a default
+ * configuration file will be used based on the component's name.
+ *
+ * @p mode determines whether the user or global settings will be allowed
+ * to influence the values returned by this object. See KConfig::OpenFlags for
+ * more details.
+ *
+ * @note You probably want to use KSharedConfig::openConfig instead.
+ *
+ * @param componentData the component that you wish to load a configuration
+ * file for
+ * @param file overrides the configuration file name if not empty; if it is empty
+ * and SimpleConfig is passed in for the OpenFlags, then an in-memory
+ * KConfig object is created which will not write out to file nor which
+ * requires any file in the filesystem at all.
+ * @param mode how global settings should affect the configuration
+ * options exposed by this KConfig object.
+ * See OpenFlags
+ * @param resourceType The standard directory to look for the configuration
+ * file in
+ *
+ * @sa KSharedConfig::openConfig(const KComponentData&, const QString&, OpenFlags, const char*)
+ */
+ explicit KConfig(const KComponentData& componentData, const QString& file = QString(),
+ OpenFlags mode = FullConfig, const char* resourceType = "config");
+
+ /**
+ * @internal
+ *
+ * Creates a KConfig object using the specified backend. If the backend can not
+ * be found or loaded, then the standard configuration parser is used as a fallback.
+ *
+ * @param file the file to be parsed
+ * @param backend the backend to load
+ * @param resourceType where to look for the file if an absolute path is not provided
+ *
+ * @since 4.1
+ */
+ KConfig(const QString& file, const QString& backend, const char* resourceType = "config");
+
+ virtual ~KConfig();
+
+ /**
+ * Returns the component data this configuration is for.
+ */
+ const KComponentData &componentData() const; // krazy:exclude=constref
+
+ /**
+ * Returns the filename used to store the configuration.
+ */
+ QString name() const;
+
+ /// @reimp
+ void sync();
+
+ /// @reimp
+ void markAsClean();
+
+ /// @{ configuration object state
+ /// @reimp
+ AccessMode accessMode() const;
+
+ /**
+ * Whether the configuration can be written to.
+ *
+ * If @p warnUser is true and the configuration cannot be
+ * written to (ie: this method returns @c false), a warning
+ * message box will be shown to the user telling them to
+ * contact their system administrator to get the problem fixed.
+ *
+ * The most likely cause for this method returning @c false
+ * is that the user does not have write permission for the
+ * configuration file.
+ *
+ * @param warnUser whether to show a warning message to the user
+ * if the configuration cannot be written to
+ *
+ * @returns true if the configuration can be written to, false
+ * if the configuration cannot be written to
+ */
+ bool isConfigWritable(bool warnUser);
+ /// @}
+
+ /**
+ * Copies all entries from this config object to a new config
+ * object that will save itself to @p file.
+ *
+ * The configuration will not actually be saved to @p file
+ * until the returned object is destroyed, or sync() is called
+ * on it.
+ *
+ * Do not forget to delete the returned KConfig object if
+ * @p config was 0.
+ *
+ * @param file the new config object will save itself to
+ * @param config if not 0, copy to the given KConfig object rather
+ * than creating a new one
+ *
+ * @return @p config if it was set, otherwise a new KConfig object
+ */
+ KConfig* copyTo(const QString &file, KConfig *config = 0) const;
+
+ /**
+ * Ensures that the configuration file contains a certain update.
+ *
+ * If the configuration file does not contain the update @p id
+ * as contained in @p updateFile, kconf_update is run to update
+ * the configuration file.
+ *
+ * If you install config update files with critical fixes
+ * you may wish to use this method to verify that a critical
+ * update has indeed been performed to catch the case where
+ * a user restores an old config file from backup that has
+ * not been updated yet.
+ *
+ * @param id the update to check
+ * @param updateFile the file containing the update
+ */
+ void checkUpdate(const QString &id, const QString &updateFile);
+
+ /**
+ * Updates the state of this object to match the persistent storage.
+ */
+ void reparseConfiguration();
+
+ /// @{ extra config files
+ /**
+ * Adds the list of configuration sources to the merge stack.
+ *
+ * Currently only files are accepted as configuration sources.
+ *
+ * The first entry in @p sources is treated as the most general and will
+ * be overridden by the second entry. The settings in the final entry
+ * in @p sources will override all the other sources provided in the list.
+ *
+ * The settings in @p sources will also be overridden by the sources
+ * provided by any previous calls to addConfigSources().
+ *
+ * The settings in the global configuration sources will be overridden by
+ * the sources provided to this method (@see IncludeGlobals).
+ * All the sources provided to any call to this method will be overridden
+ * by any files that cascade from the source provided to the constructor
+ * (@see CascadeConfig), which will in turn be
+ * overridden by the source provided to the constructor (either explicitly
+ * or implicity via a KComponentData).
+ *
+ * Note that only the most specific file, ie: the file provided to the
+ * constructor, will be written to by this object.
+ *
+ * The state is automatically updated by this method, so there is no need to call
+ * reparseConfiguration().
+ *
+ * @param sources A list of extra config sources.
+ */
+ void addConfigSources(const QStringList &sources);
+
+ /// @}
+ /// @{ locales
+ /**
+ * Returns the current locale.
+ */
+ QString locale() const;
+ /**
+ * Sets the locale to @p aLocale.
+ *
+ * The global locale is used by default.
+ *
+ * @note If set to the empty string, @b no locale will be matched. This effectively disables
+ * reading translated entries.
+ *
+ * @return @c true if locale was changed, @c false if the call had no
+ * effect (eg: @p aLocale was already the current locale for this
+ * object)
+ */
+ bool setLocale(const QString& aLocale);
+ /// @}
+
+ /// @{ defaults
+ /**
+ * When set, all readEntry calls return the system-wide (default) values
+ * instead of the user's settings.
+ *
+ * This is off by default.
+ *
+ * @param b whether to read the system-wide defaults instead of the
+ * user's settings
+ */
+ void setReadDefaults(bool b);
+ /**
+ * @returns @c true if the system-wide defaults will be read instead of the
+ * user's settings
+ */
+ bool readDefaults() const;
+ /// @}
+
+ /// @{ immutability
+ /// @reimp
+ bool isImmutable() const;
+ /// @}
+
+ /// @{ global
+ /**
+ * @deprecated
+ *
+ * Forces all following write-operations to be performed on @c kdeglobals,
+ * independent of the @c Global flag in writeEntry().
+ *
+ * @param force true to force writing to kdeglobals
+ * @see forceGlobal
+ */
+#ifndef KDE_NO_DEPRECATED
+ KDE_DEPRECATED void setForceGlobal(bool force);
+#endif
+ /**
+ * @deprecated
+ *
+ * Returns whether all entries are being written to @c kdeglobals.
+ *
+ * @return @c true if all entries are being written to @c kdeglobals
+ * @see setForceGlobal
+ * @deprecated
+ */
+#ifndef KDE_NO_DEPRECATED
+ KDE_DEPRECATED bool forceGlobal() const;
+#endif
+ /// @}
+
+ /// @reimp
+ QStringList groupList() const;
+
+ /**
+ * Returns a map (tree) of entries in a particular group.
+ *
+ * The entries are all returned as strings.
+ *
+ * @param aGroup The group to get entries from.
+ *
+ * @return A map of entries in the group specified, indexed by key.
+ * The returned map may be empty if the group is empty, or not found.
+ * @see QMap
+ */
+ QMap<QString, QString> entryMap(const QString &aGroup=QString()) const;
+
+protected:
+ virtual bool hasGroupImpl(const QByteArray &group) const;
+ virtual KConfigGroup groupImpl( const QByteArray &b);
+ virtual const KConfigGroup groupImpl(const QByteArray &b) const;
+ virtual void deleteGroupImpl(const QByteArray &group, WriteConfigFlags flags = Normal);
+ virtual bool isGroupImmutableImpl(const QByteArray& aGroup) const;
+
+ friend class KConfigGroup;
+ friend class KConfigGroupPrivate;
+
+ /** Virtual hook, used to add new "virtual" functions while maintaining
+ * binary compatibility. Unused in this class.
+ */
+ virtual void virtual_hook( int id, void* data );
+
+ KConfigPrivate *const d_ptr;
+
+ KConfig(KConfigPrivate &d);
+
+private:
+ QStringList keyList(const QString& aGroup=QString()) const;
+
+ Q_DISABLE_COPY(KConfig)
+
+ Q_DECLARE_PRIVATE(KConfig)
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS( KConfig::OpenFlags )
+
+#endif // KCONFIG_H
diff --git a/kdecore/config/kconfig_p.h b/kdecore/config/kconfig_p.h
new file mode 100644
index 0000000..7751242
--- /dev/null
+++ b/kdecore/config/kconfig_p.h
@@ -0,0 +1,116 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIG_P_H
+#define KCONFIG_P_H
+
+#include "kconfigdata.h"
+#include <kglobal.h>
+#include "kconfigbackend.h"
+#include "kconfiggroup.h"
+#include "kcomponentdata.h"
+#include "kstandarddirs.h"
+#include "klocale.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QStack>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+
+#include <unistd.h>
+
+class KConfigPrivate
+{
+ friend class KConfig;
+public:
+ KConfig::OpenFlags openFlags;
+ const char* resourceType;
+
+ void changeFileName(const QString& fileName, const char* resourceType);
+
+ // functions for KConfigGroup
+ bool canWriteEntry(const QByteArray& group, const char* key, bool isDefault=false) const;
+ QString lookupData(const QByteArray& group, const char* key, KEntryMap::SearchFlags flags,
+ bool* expand) const;
+ QByteArray lookupData(const QByteArray& group, const char* key, KEntryMap::SearchFlags flags) const;
+
+ void putData(const QByteArray& group, const char* key, const QByteArray& value,
+ KConfigBase::WriteConfigFlags flags, bool expand=false);
+ QStringList groupList(const QByteArray& group) const;
+ // copies the entries from @p source to @p otherGroup changing all occurrences
+ // of @p source with @p destination
+ void copyGroup(const QByteArray& source, const QByteArray& destination,
+ KConfigGroup *otherGroup, KConfigBase::WriteConfigFlags flags) const;
+ QStringList keyListImpl(const QByteArray& theGroup) const;
+ QSet<QByteArray> allSubGroups(const QByteArray& parentGroup) const;
+ bool hasNonDeletedEntries(const QByteArray& group) const;
+
+ static QString expandString(const QString& value);
+
+protected:
+ KSharedPtr<KConfigBackend> mBackend;
+
+ KConfigPrivate(const KComponentData &componentData_, KConfig::OpenFlags flags,
+ const char* resource);
+
+ virtual ~KConfigPrivate()
+ {
+ }
+
+ bool bDynamicBackend:1; // do we own the backend?
+private:
+ bool bDirty:1;
+ bool bLocaleInitialized:1;
+ bool bReadDefaults:1;
+ bool bFileImmutable:1;
+ bool bForceGlobal:1;
+ bool bSuppressGlobal:1;
+
+ QString sGlobalFileName;
+ static bool mappingsRegistered;
+
+
+ KEntryMap entryMap;
+ QString backendType;
+ QStack<QString> extraFiles;
+
+ QString locale;
+ QString fileName;
+ QString etc_kderc;
+ KComponentData componentData;
+ KConfigBase::AccessMode configState;
+
+ bool wantGlobals() const { return openFlags&KConfig::IncludeGlobals && !bSuppressGlobal; }
+ bool wantDefaults() const { return openFlags&KConfig::CascadeConfig; }
+ bool isSimple() const { return openFlags == KConfig::SimpleConfig; }
+ bool isReadOnly() const { return configState == KConfig::ReadOnly; }
+
+ bool setLocale(const QString& aLocale);
+ QStringList getGlobalFiles() const;
+ void parseGlobalFiles();
+ void parseConfigFiles();
+ void initCustomized(KConfig*);
+ bool lockLocal();
+};
+
+#endif // KCONFIG_P_H
diff --git a/kdecore/config/kconfigbackend.cpp b/kdecore/config/kconfigbackend.cpp
new file mode 100644
index 0000000..cd10da7
--- /dev/null
+++ b/kdecore/config/kconfigbackend.cpp
@@ -0,0 +1,131 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006 Thomas Braxton <brax108@cox.net>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kconfigbackend.h"
+
+#include <QtCore/QDateTime>
+#include <QtCore/QStringList>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QHash>
+#include <QtCore/QDebug>
+
+#include "kglobal.h"
+//#include "klocale.h"
+#include "kpluginloader.h"
+#include "kservicetypetrader.h"
+//#include "kapplication.h"
+#include "kconfig.h"
+#include "kconfigini_p.h"
+#include "kconfigdata.h"
+#include "kdebug.h"
+#include "kstandarddirs.h"
+#include "kconfigbackend.moc"
+
+typedef KSharedPtr<KConfigBackend> BackendPtr;
+
+class KConfigBackend::Private
+{
+public:
+ qint64 size;
+ QDateTime lastModified;
+ QString localFileName;
+
+ static QString whatSystem(const QString& /*fileName*/)
+ {
+ return QLatin1String("INI");
+ }
+};
+
+
+void KConfigBackend::registerMappings(const KEntryMap& /*entryMap*/)
+{
+}
+
+BackendPtr KConfigBackend::create(const KComponentData& componentData, const QString& file,
+ const QString& sys)
+{
+ Q_UNUSED(componentData);
+ //qDebug() << "creating a backend for file" << file << "with system" << sys;
+ const QString system = (sys.isEmpty() ? Private::whatSystem(file) : sys);
+ KConfigBackend* backend = 0;
+
+ if (system.compare(QLatin1String("INI"), Qt::CaseInsensitive) != 0) {
+ const QString constraint = QString::fromLatin1("[X-KDE-PluginInfo-Name] ~~ '%1'").arg(system);
+ KService::List offers = KServiceTypeTrader::self()->query(QLatin1String("KConfigBackend"), constraint);
+
+ //qDebug() << "found" << offers.count() << "offers for KConfigBackend plugins with name" << system;
+ foreach (const KService::Ptr& offer, offers) {
+ backend = offer->createInstance<KConfigBackend>(0);
+ if (backend) {
+ //qDebug() << "successfully created a backend for" << system;
+ backend->setFilePath(file);
+ return BackendPtr(backend);
+ }
+ } // foreach offers
+ }
+
+ //qDebug() << "default creation of the Ini backend";
+ backend = new KConfigIniBackend;
+ backend->setFilePath(file);
+ return BackendPtr(backend);
+}
+
+KConfigBackend::KConfigBackend()
+ : d(new Private)
+{
+}
+
+KConfigBackend::~KConfigBackend()
+{
+ delete d;
+}
+
+QDateTime KConfigBackend::lastModified() const
+{
+ return d->lastModified;
+}
+
+void KConfigBackend::setLastModified(const QDateTime& dt)
+{
+ d->lastModified = dt;
+}
+
+qint64 KConfigBackend::size() const
+{
+ return d->size;
+}
+
+void KConfigBackend::setSize(qint64 sz)
+{
+ d->size = sz;
+}
+
+QString KConfigBackend::filePath() const
+{
+ return d->localFileName;
+}
+
+void KConfigBackend::setLocalFilePath(const QString& file)
+{
+ d->localFileName = file;
+}
diff --git a/kdecore/config/kconfigbackend.desktop b/kdecore/config/kconfigbackend.desktop
new file mode 100644
index 0000000..25ca2e8
--- /dev/null
+++ b/kdecore/config/kconfigbackend.desktop
@@ -0,0 +1,85 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KConfigBackend
+
+Comment=Storage backend for KConfig
+Comment[ar]=خلفية الحفظ لـ KConfig
+Comment[as]=KConfig ৰ বাবে ভঁৰালৰ বেকএন্ড
+Comment[ast]=Infraestructura d'atroxamientu pa KConfig
+Comment[be@latin]=Słužba schovišča dla systemy „KConfig”
+Comment[bg]=Storage backend for KConfig
+Comment[bn]=KConfig-এর স্টোরেজ ব্যাকেন্ড
+Comment[bn_IN]=KConfig-র জন্য ব্যবহৃত ব্যাক-এন্ড সংগ্রহস্থল
+Comment[bs]=Skladišna pozadina za K‑konfig
+Comment[ca]=Dorsal d'emmagatzematge per al KConfig
+Comment[ca@valencia]=Dorsal d'emmagatzematge per al KConfig
+Comment[cs]=Úložiště pro KConfig
+Comment[csb]=Zôpisownô zbiérnica dlô KConfig
+Comment[da]=Lagringsmotor til KConfig
+Comment[de]=Speicher-Unterstützung für KConfig
+Comment[el]=Σύστημα υποστήριξης αποθήκευσης για το KConfig
+Comment[en_GB]=Storage backend for KConfig
+Comment[es]=Motor de almacenamiento para KConfig
+Comment[et]=KConfigi salvestamise taustaprogramm
+Comment[eu]=KConfig-en biltegiratze euskarria
+Comment[fi]=Asetusvaraston taustaosa
+Comment[fr]=Méthode de stockage pour KConfig
+Comment[fy]=Opslach efterein foar KConfig
+Comment[ga]=Inneall stórais KConfig
+Comment[gl]=Infraestrutura de almacenaxe para KConfig
+Comment[gu]=KConfig માટે સંગ્રહ પાશ્ર્વભાગ
+Comment[he]=מנוע שמירה עבור KConfig
+Comment[hne]=के-कानफिग बर भंडार बैकएण्ड
+Comment[hr]=Skladišna pozadina za KConfig
+Comment[hsb]=składowanski backend za KConfig
+Comment[hu]=Tároló a KConfighoz
+Comment[ia]=Retro-administration de immagazinage (storage) pro Kconfig
+Comment[id]=Backend penyimpanan untuk KConfig
+Comment[is]=Geymslubakendi fyrir KConfig
+Comment[it]=Backend di archiviazione per KConfig
+Comment[ja]=KConfig のストレージバックエンド
+Comment[kk]=KConfig үшін сақтау тетігі
+Comment[km]=កម្មវិធី​ខាងក្រោយ​ការ​ផ្ទុក​សម្រាប់ KConfig
+Comment[kn]=ಕೆಕಾನ್ಫಿಗ್ ಗೆ ಸಂಗ್ರಹಣಾ ಹಿಂಬದಿ (ಬಾಕೆಂಡ್)
+Comment[ko]=KConfig의 저장소 백엔드
+Comment[ku]=Embara ser-dawî ji bo KVeavakirin
+Comment[lt]=KConfig saugojimo sąsaja
+Comment[lv]=KConfig glabāšanas aizmugure
+Comment[mai]=KConfig क' लेल भंडारक बैकेंड
+Comment[ml]=കെകോണ്‍ഫിഗിനുളള സ്റ്റോറേജ് ബാക്കെന്‍ഡ്
+Comment[mr]=KConfig करीता संचयन बॅकएन्ड
+Comment[ms]=Storan belakang untuk KConfig
+Comment[nb]=Bakgrunnslagring for KConfig
+Comment[nds]=Spieker-Hülpprogramm för KConfig
+Comment[nl]=Opslagbackend voor KConfig
+Comment[nn]=Lagringsmotor for KConfig
+Comment[or]=KConfig ପାଇଁ ଭଣ୍ଡାର ପଛ ପାଖ
+Comment[pa]=KConfig ਲਈ ਸਟੋਰੇਜ਼ ਬੈਕਐਂਡ
+Comment[pl]=Przechowywanie danych dla KConfig
+Comment[pt]=Armazenamento da infra-estrutura do KConfig
+Comment[pt_BR]=Infraestrutura de armazenamento para o KConfig
+Comment[ro]=Suport de stocare pentru KConfig
+Comment[ru]=Модуль хранения параметров KConfig
+Comment[se]=KConfig vurkenduogáš
+Comment[si]=KConfig සඳහා ගබඩා පසුඈදුම
+Comment[sk]=Úložisko pre KConfig
+Comment[sl]=Ozadje za shranjevanje v KConfigu
+Comment[sq]=Mbështetëse Ruajtëse për KConfig
+Comment[sr]=Складишна позадина за К‑конфиг
+Comment[sr@ijekavian]=Складишна позадина за К‑конфиг
+Comment[sr@ijekavianlatin]=Skladišna pozadina za KConfig
+Comment[sr@latin]=Skladišna pozadina za KConfig
+Comment[sv]=Lagringsgränssnitt för KConfig
+Comment[ta]=கேவடிவமைப்பிற்கான பின்னணி சேமிப்பகம்
+Comment[tg]=Пуштибонии захирагоҳ барои KConfig
+Comment[th]=โปรแกรมเบื้องหลังพื้นที่จัดเก็บข้อมูลสำหรับ KConfig
+Comment[tr]=KConfig için Depolama Arka Ucu
+Comment[tt]=KConfig өчен саклау бэкенды
+Comment[ug]=KConfig نىڭ ساقلاش ئارقا ئۇچى
+Comment[uk]=Засіб збереження для KConfig
+Comment[vi]=Hậu trường lưu trữ cho KConfig
+Comment[wa]=Bouye di fond di stocaedje po KConfig
+Comment[x-test]=xxStorage backend for KConfigxx
+Comment[zh_CN]=KConfig 存储后端
+Comment[zh_TW]=KConfig 儲存後端介面
+
diff --git a/kdecore/config/kconfigbackend.h b/kdecore/config/kconfigbackend.h
new file mode 100644
index 0000000..e5cb389
--- /dev/null
+++ b/kdecore/config/kconfigbackend.h
@@ -0,0 +1,223 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Portions copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGBACKEND_H
+#define KCONFIGBACKEND_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+#include <kdecore_export.h>
+#include <kconfigbase.h>
+#include <kdebug.h>
+#ifndef KDE_NO_DEPRECATED
+#include <kgenericfactory.h>
+#endif
+#include <klocale.h>
+#include <kpluginfactory.h>
+#include <kpluginloader.h>
+#include <ksharedptr.h>
+
+class KEntryMap;
+class KComponentData;
+class QFile;
+class QByteArray;
+class QDateTime;
+
+/**
+ * \class KConfigBackend kconfigbackend.h <KConfigBackend>
+ *
+ * Provides the implementation for accessing configuration sources.
+ *
+ * KDELibs only provides an INI backend, but this class can be used
+ * to create plugins that allow access to other file formats and
+ * configuration systems.
+ */
+class KDECORE_EXPORT KConfigBackend : public QObject, public KShared
+{
+ Q_OBJECT
+ Q_FLAGS(ParseOption)
+ Q_FLAGS(WriteOption)
+
+public:
+ /**
+ * Creates a new KConfig backend.
+ *
+ * If no @p system is given, or the given @p system is unknown, this method tries
+ * to determine the correct backend to use.
+ *
+ * @param componentData the owning component
+ * @param fileName the absolute file name of the configuration file
+ * @param system the configuration system to use
+ * @return a KConfigBackend object to be used with KConfig
+ */
+ static KSharedPtr<KConfigBackend> create(const KComponentData& componentData,
+ const QString& fileName = QString(),
+ const QString& system = QString());
+
+ /**
+ * Registers mappings from directories/files to configuration systems
+ *
+ * Allows you to tell KConfigBackend that create() should use a particular
+ * backend for a particular file or directory.
+ *
+ * @warning currently does nothing
+ *
+ * @param entryMap the KEntryMap to build the mappings from
+ */
+ static void registerMappings(const KEntryMap& entryMap);
+
+ /** Destroys the backend */
+ virtual ~KConfigBackend();
+
+ /** Allows the behaviour of parseConfig() to be tuned */
+ enum ParseOption {
+ ParseGlobal = 1, /// entries should be marked as @em global
+ ParseDefaults = 2, /// entries should be marked as @em default
+ ParseExpansions = 4 /// entries are allowed to be marked as @em expandable
+ };
+ /// @typedef typedef QFlags<ParseOption> ParseOptions
+ Q_DECLARE_FLAGS(ParseOptions, ParseOption)
+
+ /** Allows the behaviour of writeConfig() to be tuned */
+ enum WriteOption {
+ WriteGlobal = 1 /// only write entries marked as "global"
+ };
+ /// @typedef typedef QFlags<WriteOption> WriteOptions
+ Q_DECLARE_FLAGS(WriteOptions, WriteOption)
+
+ /** Return value from parseConfig() */
+ enum ParseInfo {
+ ParseOk, /// the configuration was opened read/write
+ ParseImmutable, /// the configuration is @em immutable
+ ParseOpenError /// the configuration could not be opened
+ };
+
+ /**
+ * Read persistent storage
+ *
+ * @param locale the locale to read entries for (if the backend supports localized entries)
+ * @param pWriteBackMap the KEntryMap where the entries are placed
+ * @param options @see ParseOptions
+ * @return @see ParseInfo
+ */
+ virtual ParseInfo parseConfig(const QByteArray& locale,
+ KEntryMap& pWriteBackMap,
+ ParseOptions options = ParseOptions()) = 0;
+
+ /**
+ * Write the @em dirty entries to permanent storage
+ *
+ * @param locale the locale to write entries for (if the backend supports localized entries)
+ * @param entryMap the KEntryMap containing the config object's entries.
+ * @param options @see WriteOptions
+ * @param data the component that requested the write
+ *
+ * @return @c true if the write was successful, @c false if writing the configuration failed
+ */
+ virtual bool writeConfig(const QByteArray& locale, KEntryMap& entryMap,
+ WriteOptions options, const KComponentData &data) = 0;
+
+ /**
+ * If isWritable() returns false, writeConfig() will always fail.
+ *
+ * @return @c true if the configuration is writable, @c false if it is immutable
+ */
+ virtual bool isWritable() const = 0;
+ /**
+ * When isWritable() returns @c false, return an error message to
+ * explain to the user why saving configuration will not work.
+ *
+ * The return value when isWritable() returns @c true is undefined.
+ *
+ * @returns a translated user-visible explanation for the configuration
+ * object not being writable
+ */
+ virtual QString nonWritableErrorMessage() const = 0;
+ /**
+ * @return the read/write status of the configuration object
+ *
+ * @see KConfigBase::AccessMode
+ */
+ virtual KConfigBase::AccessMode accessMode() const = 0;
+ /**
+ * Create the enclosing object of the configuration object
+ *
+ * For example, if the configuration object is a file, this should create
+ * the parent directory.
+ */
+ virtual void createEnclosing() = 0;
+
+ /**
+ * Set the file path.
+ *
+ * @note @p path @b MUST be @em absolute.
+ *
+ * @param path the absolute file path
+ */
+ virtual void setFilePath(const QString& path) = 0;
+
+ /**
+ * Lock the file
+ */
+ virtual bool lock(const KComponentData& componentData) = 0;
+ /**
+ * Release the lock on the file
+ */
+ virtual void unlock() = 0;
+ /**
+ * @return @c true if the file is locked, @c false if it is not locked
+ */
+ virtual bool isLocked() const = 0;
+
+ /**
+ * @return the date and time when the object was last modified
+ */
+ QDateTime lastModified() const;
+ /** @return the absolute path to the object */
+ QString filePath() const;
+ /** @return the size of the object */
+ qint64 size() const;
+
+protected:
+ KConfigBackend();
+ void setLastModified(const QDateTime& dt);
+ void setSize(qint64 sz);
+ void setLocalFilePath(const QString& file);
+
+private:
+ class Private;
+ Private *const d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigBackend::ParseOptions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigBackend::WriteOptions)
+
+/**
+ * Register a KConfig backend when it is contained in a loadable module
+ */
+#define K_EXPORT_KCONFIGBACKEND(libname, classname) \
+K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) \
+K_EXPORT_PLUGIN(factory("kconfigbackend_" #libname))
+
+
+#endif // KCONFIGBACKEND_H
diff --git a/kdecore/config/kconfigbase.cpp b/kdecore/config/kconfigbase.cpp
new file mode 100644
index 0000000..4be7ac2
--- /dev/null
+++ b/kdecore/config/kconfigbase.cpp
@@ -0,0 +1,112 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kconfigbase.h"
+
+#include "kconfiggroup.h"
+
+#include <QtCore/QString>
+
+bool KConfigBase::hasGroup(const QString &group) const
+{
+ return hasGroupImpl(group.toUtf8());
+}
+
+bool KConfigBase::hasGroup(const char *group) const
+{
+ return hasGroupImpl(QByteArray(group));
+}
+
+bool KConfigBase::hasGroup(const QByteArray &group) const
+{
+ return hasGroupImpl(group);
+}
+
+KConfigGroup KConfigBase::group( const QByteArray &b)
+{
+ return groupImpl(b);
+}
+
+KConfigGroup KConfigBase::group( const QString &str)
+{
+ return groupImpl(str.toUtf8());
+}
+
+KConfigGroup KConfigBase::group( const char *str)
+{
+ return groupImpl(QByteArray(str));
+}
+
+const KConfigGroup KConfigBase::group( const QByteArray &b ) const
+{
+ return groupImpl(b);
+}
+
+const KConfigGroup KConfigBase::group( const QString &s ) const
+{
+ return groupImpl(s.toUtf8());
+}
+
+const KConfigGroup KConfigBase::group( const char *s ) const
+{
+ return groupImpl(QByteArray(s));
+}
+
+void KConfigBase::deleteGroup(const QByteArray &group, WriteConfigFlags flags)
+{
+ deleteGroupImpl(group, flags);
+}
+
+void KConfigBase::deleteGroup(const QString &group, WriteConfigFlags flags)
+{
+ deleteGroupImpl(group.toUtf8(), flags);
+}
+
+void KConfigBase::deleteGroup(const char *group, WriteConfigFlags flags)
+{
+ deleteGroupImpl(QByteArray(group), flags);
+}
+
+bool KConfigBase::isGroupImmutable(const QByteArray& aGroup) const
+{
+ return isGroupImmutableImpl(aGroup);
+}
+
+bool KConfigBase::isGroupImmutable(const QString& aGroup) const
+{
+ return isGroupImmutableImpl(aGroup.toUtf8());
+}
+
+
+bool KConfigBase::isGroupImmutable(const char *aGroup) const
+{
+ return isGroupImmutableImpl(QByteArray(aGroup));
+}
+
+KConfigBase::~KConfigBase()
+{}
+
+KConfigBase::KConfigBase()
+{}
+
+void KConfigBase::virtual_hook(int , void *)
+{}
diff --git a/kdecore/config/kconfigbase.h b/kdecore/config/kconfigbase.h
new file mode 100644
index 0000000..716f20f
--- /dev/null
+++ b/kdecore/config/kconfigbase.h
@@ -0,0 +1,184 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGBASE_H
+#define KCONFIGBASE_H
+
+#include <kdecore_export.h>
+
+#include <QtCore/QtGlobal>
+
+class QStringList;
+class KConfigGroup;
+class KConfigBasePrivate;
+
+/**
+ * \class KConfigBase kconfigbase.h <KConfigBase>
+ */
+class KDECORE_EXPORT KConfigBase
+{
+public:
+ /**
+ * Flags to control write entry
+ */
+ enum WriteConfigFlag
+ {
+ Persistent = 0x01,
+ /**<
+ * Save this entry when saving the config object.
+ */
+ Global = 0x02,
+ /**<
+ * Save the entry to the global %KDE config file instead of the
+ * application specific config file.
+ */
+ Localized = 0x04,
+ /**<
+ * Add the locale tag to the key when writing it.
+ */
+ Normal=Persistent
+ /**<
+ * Save the entry to the application specific config file without
+ * a locale tag. This is the default.
+ */
+
+ };
+ Q_DECLARE_FLAGS(WriteConfigFlags, WriteConfigFlag)
+
+ /**
+ * Destructs the KConfigBase object.
+ */
+ virtual ~KConfigBase();
+
+ /**
+ * Returns a list of groups that are known about.
+ *
+ * @return The list of groups.
+ **/
+ virtual QStringList groupList() const = 0;
+
+ /**
+ * Returns true if the specified group is known about.
+ *
+ * @param group The group to search for.
+ * @return true if the group exists.
+ */
+ bool hasGroup(const QString &group) const;
+ bool hasGroup(const char *group) const;
+ bool hasGroup(const QByteArray &group) const;
+
+ /**
+ * Returns an object for the named subgroup.
+ *
+ * @param group the group to open. Pass a null string on to the KConfig
+ * object to obtain a handle on the root group.
+ * @return The list of groups.
+ **/
+ KConfigGroup group(const QByteArray &group);
+ KConfigGroup group(const QString &group);
+ KConfigGroup group(const char *group);
+
+ /**
+ * @overload
+ **/
+ const KConfigGroup group(const QByteArray &group) const;
+ const KConfigGroup group(const QString &group) const;
+ const KConfigGroup group(const char *group) const;
+
+ /**
+ * Delete @p aGroup. This marks @p aGroup as @em deleted in the config object. This effectively
+ * removes any cascaded values from config files earlier in the stack.
+ */
+ void deleteGroup(const QByteArray &group, WriteConfigFlags flags = Normal);
+ void deleteGroup(const QString &group, WriteConfigFlags flags = Normal);
+ void deleteGroup(const char *group, WriteConfigFlags flags = Normal);
+
+ /**
+ * Syncs the configuration object that this group belongs to.
+ * Unrelated concurrent changes to the same file are merged and thus
+ * not overwritten. Note however, that this object is @em not automatically
+ * updated with those changes.
+ */
+ virtual void sync() = 0;
+
+ /**
+ * Reset the dirty flags of all entries in the entry map, so the
+ * values will not be written to disk on a later call to sync().
+ */
+ virtual void markAsClean() = 0;
+
+ /**
+ * Possible return values for accessMode().
+ */
+ enum AccessMode { NoAccess, ReadOnly, ReadWrite };
+
+ /**
+ * Returns the access mode of the app-config object.
+ *
+ * Possible return values
+ * are NoAccess (the application-specific config file could not be
+ * opened neither read-write nor read-only), ReadOnly (the
+ * application-specific config file is opened read-only, but not
+ * read-write) and ReadWrite (the application-specific config
+ * file is opened read-write).
+ *
+ * @return the access mode of the app-config object
+ */
+ virtual AccessMode accessMode() const = 0;
+
+ /**
+ * Checks whether this configuration object can be modified.
+ * @return whether changes may be made to this configuration object.
+ */
+ virtual bool isImmutable() const = 0;
+
+ /**
+ * Can changes be made to the entries in @p aGroup?
+ *
+ * @param aGroup The group to check for immutability.
+ * @return @c false if the entries in @p aGroup can be modified.
+ */
+ bool isGroupImmutable(const QByteArray& aGroup) const;
+ bool isGroupImmutable(const QString& aGroup) const;
+ bool isGroupImmutable(const char *aGroup) const;
+
+protected:
+ KConfigBase();
+
+ virtual bool hasGroupImpl(const QByteArray &group) const = 0;
+ virtual KConfigGroup groupImpl( const QByteArray &b) = 0;
+ virtual const KConfigGroup groupImpl(const QByteArray &b) const = 0;
+ virtual void deleteGroupImpl(const QByteArray &group, WriteConfigFlags flags = Normal) = 0;
+ virtual bool isGroupImmutableImpl(const QByteArray& aGroup) const = 0;
+
+ /** Virtual hook, used to add new "virtual" functions while maintaining
+ * binary compatibility. Unused in this class.
+ */
+ virtual void virtual_hook( int id, void* data );
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigBase::WriteConfigFlags)
+
+
+
+#endif // KCONFIG_H
diff --git a/kdecore/config/kconfigbase_p.h b/kdecore/config/kconfigbase_p.h
new file mode 100644
index 0000000..c106626
--- /dev/null
+++ b/kdecore/config/kconfigbase_p.h
@@ -0,0 +1,30 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (C) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGBASE_P_H
+#define KCONFIGBASE_P_H
+
+#include <QtCore/QSharedData>
+
+class KConfigBasePrivate : public QSharedData
+{
+};
+#endif
diff --git a/kdecore/config/kconfigdata.h b/kdecore/config/kconfigdata.h
new file mode 100644
index 0000000..0dff4ad
--- /dev/null
+++ b/kdecore/config/kconfigdata.h
@@ -0,0 +1,473 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 1999-2000 Preston Brown <pbrown@kde.org>
+ Copyright (C) 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGDATA_H
+#define KCONFIGDATA_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QString>
+#include <QtCore/QMap>
+#include <QtCore/QDebug>
+
+/**
+ * map/dict/list config node entry.
+ * @internal
+ */
+struct KEntry
+{
+ /** Constructor. @internal */
+ KEntry()
+ : mValue(), bDirty(false),
+ bGlobal(false), bImmutable(false), bDeleted(false), bExpand(false) {}
+ /** @internal */
+ QByteArray mValue;
+ /**
+ * Must the entry be written back to disk?
+ */
+ bool bDirty :1;
+ /**
+ * Entry should be written to the global config file
+ */
+ bool bGlobal:1;
+ /**
+ * Entry can not be modified.
+ */
+ bool bImmutable:1;
+ /**
+ * Entry has been deleted.
+ */
+ bool bDeleted:1;
+ /**
+ * Whether to apply dollar expansion or not.
+ */
+ bool bExpand:1;
+};
+
+// These operators are used to check whether an entry which is about
+// to be written equals the previous value. As such, this intentionally
+// omits the dirty flag from the comparison.
+inline bool operator ==(const KEntry &k1, const KEntry &k2)
+{
+ return k1.bGlobal == k2.bGlobal && k1.bImmutable == k2.bImmutable
+ && k1.bDeleted == k2.bDeleted && k1.bExpand == k2.bExpand
+ && k1.mValue == k2.mValue;
+}
+
+inline bool operator !=(const KEntry &k1, const KEntry &k2)
+{
+ return !(k1 == k2);
+}
+
+/**
+ * key structure holding both the actual key and the group
+ * to which it belongs.
+ * @internal
+ */
+struct KEntryKey
+{
+ /** Constructor. @internal */
+ KEntryKey(const QByteArray& _group = QByteArray(),
+ const QByteArray& _key = QByteArray(), bool isLocalized=false, bool isDefault=false)
+ : mGroup(_group), mKey(_key), bLocal(isLocalized), bDefault(isDefault), bRaw(false)
+ { ; }
+ /**
+ * The "group" to which this EntryKey belongs
+ */
+ QByteArray mGroup;
+ /**
+ * The _actual_ key of the entry in question
+ */
+ QByteArray mKey;
+ /**
+ * Entry is localised or not
+ */
+ bool bLocal :1;
+ /**
+ * Entry indicates if this is a default value.
+ */
+ bool bDefault:1;
+ /** @internal
+ * Key is a raw unprocessed key.
+ * @warning this should only be set during merging, never for normal use.
+ */
+ bool bRaw:1;
+};
+
+/**
+ * Compares two KEntryKeys (needed for QMap). The order is localized, localized-default,
+ * non-localized, non-localized-default
+ * @internal
+ */
+inline bool operator <(const KEntryKey &k1, const KEntryKey &k2)
+{
+ int result = qstrcmp(k1.mGroup, k2.mGroup);
+ if (result != 0) {
+ return result < 0;
+ }
+
+ result = qstrcmp(k1.mKey, k2.mKey);
+ if (result != 0) {
+ return result < 0;
+ }
+
+ if (k1.bLocal != k2.bLocal)
+ return k1.bLocal;
+ return (!k1.bDefault && k2.bDefault);
+}
+
+/**
+ * \relates KEntry
+ * type specifying a map of entries (key,value pairs).
+ * The keys are actually a key in a particular config file group together
+ * with the group name.
+ * @internal
+ */
+class KEntryMap : public QMap<KEntryKey, KEntry>
+{
+ public:
+ enum SearchFlag {
+ SearchDefaults=1,
+ SearchLocalized=2
+ };
+ Q_DECLARE_FLAGS(SearchFlags, SearchFlag)
+
+ enum EntryOption {
+ EntryDirty=1,
+ EntryGlobal=2,
+ EntryImmutable=4,
+ EntryDeleted=8,
+ EntryExpansion=16,
+ EntryRawKey=32,
+ EntryDefault=(SearchDefaults<<16),
+ EntryLocalized=(SearchLocalized<<16)
+ };
+ Q_DECLARE_FLAGS(EntryOptions, EntryOption)
+
+ Iterator findExactEntry(const QByteArray& group, const QByteArray& key = QByteArray(),
+ SearchFlags flags = SearchFlags())
+ {
+ KEntryKey theKey(group, key, false, bool(flags&SearchDefaults));
+
+ // try the localized key first
+ if (flags&SearchLocalized) {
+ theKey.bLocal = true;
+ return find(theKey);
+ }
+ return find(theKey);
+ }
+
+ Iterator findEntry(const QByteArray& group, const QByteArray& key = QByteArray(),
+ SearchFlags flags = SearchFlags())
+ {
+ KEntryKey theKey(group, key, false, bool(flags&SearchDefaults));
+
+ // try the localized key first
+ if (flags&SearchLocalized) {
+ theKey.bLocal = true;
+
+ Iterator it = find(theKey);
+ if (it != end())
+ return it;
+
+ theKey.bLocal = false;
+ }
+ return find(theKey);
+ }
+
+ ConstIterator findEntry(const QByteArray& group, const QByteArray& key = QByteArray(),
+ SearchFlags flags = SearchFlags()) const
+ {
+ KEntryKey theKey(group, key, false, bool(flags&SearchDefaults));
+
+ // try the localized key first
+ if (flags&SearchLocalized) {
+ theKey.bLocal = true;
+
+ ConstIterator it = find(theKey);
+ if (it != constEnd())
+ return it;
+
+ theKey.bLocal = false;
+ }
+ return find(theKey);
+ }
+
+ /**
+ * Returns true if the entry gets dirtied or false in other case
+ */
+ bool setEntry(const QByteArray& group, const QByteArray& key,
+ const QByteArray& value, EntryOptions options)
+ {
+ KEntryKey k;
+ KEntry e;
+ bool newKey = false;
+
+ const Iterator it = findExactEntry(group, key, SearchFlags(options>>16));
+
+ if (key.isEmpty()) { // inserting a group marker
+ k.mGroup = group;
+ e.bImmutable = (options&EntryImmutable);
+ if (options&EntryDeleted) { qWarning("Internal KConfig error: cannot mark groups as deleted"); }
+ if(it == end()) {
+ insert(k, e);
+ return true;
+ } else if(it.value() == e) {
+ return false;
+ }
+
+ it.value() = e;
+ return true;
+ }
+
+
+ if (it != end()) {
+ if (it->bImmutable)
+ return false; // we cannot change this entry. Inherits group immutability.
+ k = it.key();
+ e = *it;
+ } else {
+ // make sure the group marker is in the map
+ KEntryMap const *that = this;
+ ConstIterator cit = that->findEntry(group);
+ if (cit == constEnd())
+ insert(KEntryKey(group), KEntry());
+ else if (cit->bImmutable)
+ return false; // this group is immutable, so we cannot change this entry.
+
+ k = KEntryKey(group, key);
+ newKey = true;
+ }
+
+ // set these here, since we may be changing the type of key from the one we found
+ k.bLocal = (options&EntryLocalized);
+ k.bDefault = (options&EntryDefault);
+ k.bRaw = (options&EntryRawKey);
+
+ //qDebug() << "changing [" << group << "," << key << "] =" << e.mValue;
+ e.mValue = value;
+ e.bDirty = e.bDirty || (options&EntryDirty);
+ e.bGlobal = (options&EntryGlobal); //we can't use || here, because changes to entries in
+ //kdeglobals would be written to kdeglobals instead
+ //of the local config file, regardless of the globals flag
+ e.bImmutable = e.bImmutable || (options&EntryImmutable);
+ if (value.isNull())
+ e.bDeleted = e.bDeleted || (options&EntryDeleted);
+ else
+ e.bDeleted = false; // setting a value to a previously deleted entry
+ e.bExpand = (options&EntryExpansion);
+
+ //qDebug() << "to [" << group << "," << key << "] =" << e.mValue << "newKey=" << newKey;
+ if(newKey)
+ {
+ insert(k, e);
+ if(k.bDefault)
+ {
+ k.bDefault = false;
+ insert(k, e);
+ }
+ // TODO check for presence of unlocalized key
+ return true;
+ } else {
+// KEntry e2 = it.value();
+ if(it.value() != e)
+ {
+ it.value() = e;
+ if(k.bDefault)
+ {
+ k.bDefault = false;
+ insert(k, e);
+ }
+ if (!(options & EntryLocalized)) {
+ KEntryKey theKey(group, key, true, false);
+ remove(theKey);
+ if (k.bDefault) {
+ theKey.bDefault = false;
+ remove(theKey);
+ }
+ }
+ return true;
+ } else {
+ if (!(options & EntryLocalized)) {
+ KEntryKey theKey(group, key, true, false);
+ bool ret = false;
+ Iterator cit = find(theKey);
+ if (cit != end()) {
+ erase(cit);
+ ret = true;
+ }
+ if (k.bDefault) {
+ theKey.bDefault = false;
+ Iterator cit = find(theKey);
+ if (cit != end()) {
+ erase(cit);
+ return true;
+ }
+ }
+ return ret;
+ }
+ // When we are writing a default, we know that the non-
+ // default is the same as the default, so we can simply
+ // use the same branch.
+ return false;
+ }
+ }
+ }
+
+ void setEntry(const QByteArray& group, const QByteArray& key,
+ const QString & value, EntryOptions options)
+ {
+ setEntry(group, key, value.toUtf8(), options);
+ }
+
+ QString getEntry(const QByteArray& group, const QByteArray& key,
+ const QString & defaultValue = QString(),
+ SearchFlags flags = SearchFlags(),
+ bool * expand=0) const
+ {
+ const ConstIterator it = findEntry(group, key, flags);
+ QString theValue = defaultValue;
+
+ if (it != constEnd() && !it->bDeleted) {
+ if (!it->mValue.isNull()) {
+ const QByteArray data=it->mValue;
+ theValue = QString::fromUtf8(data.constData(), data.length());
+ if (expand)
+ *expand = it->bExpand;
+ }
+ }
+
+ return theValue;
+ }
+
+
+
+ bool hasEntry(const QByteArray& group, const QByteArray& key = QByteArray(),
+ SearchFlags flags = SearchFlags()) const
+ {
+ const ConstIterator it = findEntry(group, key, flags);
+ if (it == constEnd())
+ return false;
+ if (it->bDeleted)
+ return false;
+ if (key.isNull()) { // looking for group marker
+ return it->mValue.isNull();
+ }
+ return true;
+ }
+
+ bool getEntryOption(const ConstIterator& it, EntryOption option) const
+ {
+ if (it != constEnd()) {
+ switch (option) {
+ case EntryDirty:
+ return it->bDirty;
+ case EntryLocalized:
+ return it.key().bLocal;
+ case EntryGlobal:
+ return it->bGlobal;
+ case EntryImmutable:
+ return it->bImmutable;
+ case EntryDeleted:
+ return it->bDeleted;
+ case EntryExpansion:
+ return it->bExpand;
+ default:
+ break; // fall through
+ }
+ }
+
+ return false;
+ }
+ bool getEntryOption(const QByteArray& group, const QByteArray& key,
+ SearchFlags flags, EntryOption option) const
+ {
+ return getEntryOption(findEntry(group, key, flags), option);
+ }
+
+ void setEntryOption(Iterator it, EntryOption option, bool bf)
+ {
+ if (it != end()) {
+ switch (option) {
+ case EntryDirty:
+ it->bDirty = bf;
+ break;
+ case EntryGlobal:
+ it->bGlobal = bf;
+ break;
+ case EntryImmutable:
+ it->bImmutable = bf;
+ break;
+ case EntryDeleted:
+ it->bDeleted = bf;
+ break;
+ case EntryExpansion:
+ it->bExpand = bf;
+ break;
+ default:
+ break; // fall through
+ }
+ }
+ }
+ void setEntryOption(const QByteArray& group, const QByteArray& key, SearchFlags flags,
+ EntryOption option, bool bf)
+ {
+ setEntryOption(findEntry(group, key, flags), option, bf);
+ }
+
+ void revertEntry(const QByteArray& group, const QByteArray& key, SearchFlags flags=SearchFlags())
+ {
+ Iterator entry = findEntry(group, key, flags);
+ if (entry != end()) {
+ //qDebug() << "reverting [" << group << "," << key << "] = " << entry->mValue;
+ const ConstIterator defaultEntry(entry+1);
+ if (defaultEntry != constEnd() && defaultEntry.key().bDefault) {
+ *entry = *defaultEntry;
+ entry->bDirty = true;
+ } else if (!entry->mValue.isNull()){
+ entry->mValue = QByteArray();
+ entry->bDirty = true;
+ entry->bDeleted = true;
+ }
+ //qDebug() << "to [" << group << "," << key << "] =" << entry->mValue;
+ }
+ }
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::SearchFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::EntryOptions)
+
+/**
+ * \relates KEntry
+ * type for iterating over keys in a KEntryMap in sorted order.
+ * @internal
+ */
+typedef QMap<KEntryKey, KEntry>::Iterator KEntryMapIterator;
+
+/**
+ * \relates KEntry
+ * type for iterating over keys in a KEntryMap in sorted order.
+ * It is const, thus you cannot change the entries in the iterator,
+ * only examine them.
+ * @internal
+ */
+typedef QMap<KEntryKey, KEntry>::ConstIterator KEntryMapConstIterator;
+
+#endif
diff --git a/kdecore/config/kconfiggroup.cpp b/kdecore/config/kconfiggroup.cpp
new file mode 100644
index 0000000..9e73eb7
--- /dev/null
+++ b/kdecore/config/kconfiggroup.cpp
@@ -0,0 +1,1251 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kconfiggroup.h"
+#include "kconfiggroup_p.h"
+
+#include "kconfig.h"
+#include "kconfig_p.h"
+#include "ksharedconfig.h"
+#include "kstringhandler.h"
+#include "kcomponentdata.h"
+#include "kconfigdata.h"
+#include <kdebug.h>
+
+#include <QtCore/QDate>
+#include <QtCore/QSharedData>
+#include <QtCore/QFile>
+#include <QtCore/QPoint>
+#include <QtCore/QRect>
+#include <QtCore/QString>
+#include <QtCore/QTextStream>
+#include <QtCore/QDir>
+
+#include <stdlib.h>
+
+class KConfigGroupPrivate : public QSharedData
+{
+ public:
+ KConfigGroupPrivate(KConfig* owner, bool isImmutable, bool isConst, const QByteArray &name)
+ : mOwner(owner), mName(name), bImmutable(isImmutable), bConst(isConst)
+ {
+ }
+
+ KConfigGroupPrivate(const KSharedConfigPtr &owner, const QByteArray& name)
+ : sOwner(owner), mOwner(sOwner.data()), mName(name),
+ bImmutable(name.isEmpty()? owner->isImmutable(): owner->isGroupImmutable(name)), bConst(false)
+ {
+ }
+
+ KConfigGroupPrivate(KConfigGroup* parent, bool isImmutable, bool isConst, const QByteArray& name)
+ : sOwner(parent->d->sOwner), mOwner(parent->d->mOwner), mName(name),
+ bImmutable(isImmutable), bConst(isConst)
+ {
+ if (!parent->d->mName.isEmpty())
+ mParent = parent->d;
+ }
+
+ KConfigGroupPrivate(const KConfigGroupPrivate* other, bool isImmutable, const QByteArray &name)
+ : sOwner(other->sOwner), mOwner(other->mOwner), mName(name),
+ bImmutable(isImmutable), bConst(other->bConst)
+ {
+ if (!other->mName.isEmpty())
+ mParent = const_cast<KConfigGroupPrivate *>(other);
+ }
+
+ KSharedConfig::Ptr sOwner;
+ KConfig *mOwner;
+ QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent;
+ QByteArray mName;
+
+ /* bitfield */
+ const bool bImmutable:1; // is this group immutable?
+ const bool bConst:1; // is this group read-only?
+
+ QByteArray fullName() const
+ {
+ if (!mParent) {
+ return name();
+ }
+ return mParent->fullName(mName);
+ }
+
+ QByteArray name() const
+ {
+ if (mName.isEmpty())
+ return "<default>";
+ return mName;
+ }
+
+ QByteArray fullName(const QByteArray& aGroup) const
+ {
+ if (mName.isEmpty())
+ return aGroup;
+ return fullName() + '\x1d' + aGroup;
+ }
+
+ static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master,
+ const QByteArray &name,
+ bool isImmutable,
+ bool isConst)
+ {
+ QExplicitlySharedDataPointer<KConfigGroupPrivate> data;
+ if (dynamic_cast<KConfigGroup*>(master))
+ data = new KConfigGroupPrivate(dynamic_cast<KConfigGroup*>(master), isImmutable, isConst, name);
+ else
+ data = new KConfigGroupPrivate(dynamic_cast<KConfig*>(master), isImmutable, isConst, name);
+ return data;
+ }
+
+ static QByteArray serializeList(const QList<QByteArray> &list);
+ static QStringList deserializeList(const QString &data);
+};
+
+QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list)
+{
+ QByteArray value = "";
+
+ if (!list.isEmpty()) {
+ QList<QByteArray>::ConstIterator it = list.constBegin();
+ const QList<QByteArray>::ConstIterator end = list.constEnd();
+
+ value = QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,");
+
+ while (++it != end) {
+ // In the loop, so it is not done when there is only one element.
+ // Doing it repeatedly is a pretty cheap operation.
+ value.reserve(4096);
+
+ value += ',';
+ value += QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,");
+ }
+
+ // To be able to distinguish an empty list from a list with one empty element.
+ if (value.isEmpty())
+ value = "\\0";
+ }
+
+ return value;
+}
+
+QStringList KConfigGroupPrivate::deserializeList(const QString &data)
+{
+ if (data.isEmpty())
+ return QStringList();
+ if (data == QLatin1String("\\0"))
+ return QStringList(QString());
+ QStringList value;
+ QString val;
+ val.reserve(data.size());
+ bool quoted = false;
+ for (int p = 0; p < data.length(); p++) {
+ if (quoted) {
+ val += data[p];
+ quoted = false;
+ } else if (data[p].unicode() == '\\') {
+ quoted = true;
+ } else if (data[p].unicode() == ',') {
+ val.squeeze(); // release any unused memory
+ value.append(val);
+ val.clear();
+ val.reserve(data.size() - p);
+ } else {
+ val += data[p];
+ }
+ }
+ value.append(val);
+ return value;
+}
+
+static QList<int> asIntList(const QByteArray& string)
+{
+ QList<int> list;
+ Q_FOREACH(const QByteArray& s, string.split(','))
+ list << s.toInt();
+ return list;
+}
+
+static QList<qreal> asRealList(const QByteArray& string)
+{
+ QList<qreal> list;
+ Q_FOREACH(const QByteArray& s, string.split(','))
+ list << s.toDouble();
+ return list;
+}
+
+static QString errString( const char * pKey, const QByteArray & value, const QVariant & aDefault ) {
+ return QString::fromLatin1("\"%1\" - conversion of \"%3\" to %2 failed")
+ .arg(QString::fromLatin1(pKey))
+ .arg(QString::fromLatin1(QVariant::typeToName(aDefault.type())))
+ .arg(QString::fromLatin1(value));
+}
+
+static QString formatError( int expected, int got ) {
+ return QString::fromLatin1(" (wrong format: expected %1 items, got %2)").arg( expected ).arg( got );
+}
+
+QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray& value, const QVariant& aDefault)
+{
+ // if a type handler is added here you must add a QVConversions definition
+ // to conversion_check.h, or ConversionCheck::to_QVariant will not allow
+ // readEntry<T> to convert to QVariant.
+ switch( aDefault.type() ) {
+ case QVariant::Invalid:
+ return QVariant();
+ case QVariant::String:
+ // this should return the raw string not the dollar expanded string.
+ // imho if processed string is wanted should call
+ // readEntry(key, QString) not readEntry(key, QVariant)
+ return QString::fromUtf8(value);
+ case QVariant::List:
+ case QVariant::StringList:
+ return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value));
+ case QVariant::ByteArray:
+ return value;
+ case QVariant::Bool: {
+ const QByteArray lower(value.toLower());
+ if (lower == "false" || lower == "no" || lower == "off" || lower == "0")
+ return false;
+ return true;
+ }
+ case QVariant::Double:
+ case QMetaType::Float:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::LongLong:
+ case QVariant::ULongLong: {
+ QVariant tmp = value;
+ if ( !tmp.convert(aDefault.type()) )
+ tmp = aDefault;
+ return tmp;
+ }
+ case QVariant::Point: {
+ const QList<int> list = asIntList(value);
+
+ if ( list.count() != 2 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 2, list.count() );
+ return aDefault;
+ }
+ return QPoint(list.at( 0 ), list.at( 1 ));
+ }
+ case QVariant::PointF: {
+ const QList<qreal> list = asRealList(value);
+
+ if ( list.count() != 2 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 2, list.count() );
+ return aDefault;
+ }
+ return QPointF(list.at( 0 ), list.at( 1 ));
+ }
+ case QVariant::Rect: {
+ const QList<int> list = asIntList(value);
+
+ if ( list.count() != 4 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 4, list.count() );
+ return aDefault;
+ }
+ const QRect rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 ));
+ if ( !rect.isValid() ) {
+ kError() << errString( pKey, value, aDefault );
+ return aDefault;
+ }
+ return rect;
+ }
+ case QVariant::RectF: {
+ const QList<qreal> list = asRealList(value);
+
+ if ( list.count() != 4 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 4, list.count() );
+ return aDefault;
+ }
+ const QRectF rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 ));
+ if ( !rect.isValid() ) {
+ kError() << errString( pKey, value, aDefault );
+ return aDefault;
+ }
+ return rect;
+ }
+ case QVariant::Size: {
+ const QList<int> list = asIntList(value);
+
+ if ( list.count() != 2 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 2, list.count() );
+ return aDefault;
+ }
+ const QSize size(list.at( 0 ), list.at( 1 ));
+ if ( !size.isValid() ) {
+ kError() << errString( pKey, value, aDefault );
+ return aDefault;
+ }
+ return size;
+ }
+ case QVariant::SizeF: {
+ const QList<qreal> list = asRealList(value);
+
+ if ( list.count() != 2 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 2, list.count() );
+ return aDefault;
+ }
+ const QSizeF size(list.at( 0 ), list.at( 1 ));
+ if ( !size.isValid() ) {
+ kError() << errString( pKey, value, aDefault );
+ return aDefault;
+ }
+ return size;
+ }
+ case QVariant::DateTime: {
+ const QList<int> list = asIntList(value);
+ if ( list.count() != 6 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 6, list.count() );
+ return aDefault;
+ }
+ const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) );
+ const QTime time( list.at( 3 ), list.at( 4 ), list.at( 5 ) );
+ const QDateTime dt( date, time );
+ if ( !dt.isValid() ) {
+ kError() << errString( pKey, value, aDefault );
+ return aDefault;
+ }
+ return dt;
+ }
+ case QVariant::Date: {
+ QList<int> list = asIntList(value);
+ if ( list.count() == 6 )
+ list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime
+ if ( list.count() != 3 ) {
+ kError() << errString( pKey, value, aDefault )
+ << formatError( 3, list.count() );
+ return aDefault;
+ }
+ const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) );
+ if ( !date.isValid() ) {
+ kError() << errString( pKey, value, aDefault );
+ return aDefault;
+ }
+ return date;
+ }
+ case QVariant::Color:
+ case QVariant::Font:
+ kWarning() << "KConfigGroup::readEntry was passed GUI type '"
+ << aDefault.typeName()
+ << "' but kdeui isn't linked! If it is linked to your program, "
+ "this is a platform bug. Please inform the KDE developers";
+ break;
+ case QVariant::Url:
+ return QUrl(QString::fromUtf8(value));
+
+ default:
+ if( aDefault.canConvert<KUrl>() ) {
+ const KUrl url(QString::fromUtf8(value));
+ return qVariantFromValue<KUrl>( url );
+ }
+ break;
+ }
+
+ kWarning() << "unhandled type " << aDefault.typeName();
+ return QVariant();
+}
+
+#ifdef Q_WS_WIN
+# include <QtCore/QDir>
+#endif
+
+static bool cleanHomeDirPath( QString &path, const QString &homeDir )
+{
+#ifdef Q_WS_WIN //safer
+ if (!QDir::convertSeparators(path).startsWith(QDir::convertSeparators(homeDir)))
+ return false;
+#else
+ if (!path.startsWith(homeDir))
+ return false;
+#endif
+
+ int len = homeDir.length();
+ // replace by "$HOME" if possible
+ if (len && (path.length() == len || path[len] == QLatin1Char('/'))) {
+ path.replace(0, len, QString::fromLatin1("$HOME"));
+ return true;
+ } else
+ return false;
+}
+
+static QString translatePath( QString path ) // krazy:exclude=passbyvalue
+{
+ if (path.isEmpty())
+ return path;
+
+ // only "our" $HOME should be interpreted
+ path.replace(QLatin1Char('$'), QLatin1String("$$"));
+
+ bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive);
+
+ // return original path, if it refers to another type of URL (e.g. http:/), or
+ // if the path is already relative to another directory
+ if ((!startsWithFile && QFileInfo(path).isRelative()) ||
+ (startsWithFile && QFileInfo(path.mid(5)).isRelative()))
+ return path;
+
+ if (startsWithFile)
+ path.remove(0,5); // strip leading "file:/" off the string
+
+ // keep only one single '/' at the beginning - needed for cleanHomeDirPath()
+ while (path[0] == QLatin1Char('/') && path[1] == QLatin1Char('/'))
+ path.remove(0,1);
+
+ // we can not use KGlobal::dirs()->relativeLocation("home", path) here,
+ // since it would not recognize paths without a trailing '/'.
+ // All of the 3 following functions to return the user's home directory
+ // can return different paths. We have to test all them.
+ const QString homeDir0 = QFile::decodeName(qgetenv("HOME"));
+ const QString homeDir1 = QDir::homePath();
+ const QString homeDir2 = QDir(homeDir1).canonicalPath();
+ if (cleanHomeDirPath(path, homeDir0) ||
+ cleanHomeDirPath(path, homeDir1) ||
+ cleanHomeDirPath(path, homeDir2) ) {
+ // kDebug() << "Path was replaced\n";
+ }
+
+ if (startsWithFile)
+ path.prepend(QString::fromLatin1("file://"));
+
+ return path;
+}
+
+
+KConfigGroup::KConfigGroup() : d(0)
+{
+}
+
+bool KConfigGroup::isValid() const
+{
+ return 0 != d.constData();
+}
+
+KConfigGroupGui _kde_internal_KConfigGroupGui;
+static inline bool readEntryGui(const QByteArray& data, const char* key, const QVariant &input,
+ QVariant &output)
+{
+ if (_kde_internal_KConfigGroupGui.readEntryGui)
+ return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output);
+ return false;
+}
+
+static inline bool writeEntryGui(KConfigGroup *cg, const char* key, const QVariant &input,
+ KConfigGroup::WriteConfigFlags flags)
+{
+ if (_kde_internal_KConfigGroupGui.writeEntryGui)
+ return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags);
+ return false;
+}
+
+KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group)
+ : d(KConfigGroupPrivate::create(master, _group.toUtf8(), master->isGroupImmutable(_group), false))
+{
+}
+
+KConfigGroup::KConfigGroup(KConfigBase *master, const char *_group)
+ : d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false))
+{
+}
+
+KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group)
+ : d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group.toUtf8(), master->isGroupImmutable(_group), true))
+{
+}
+
+KConfigGroup::KConfigGroup(const KConfigBase *master, const char * _group)
+ : d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group, master->isGroupImmutable(_group), true))
+{
+}
+
+KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group)
+ : d(new KConfigGroupPrivate(master, _group.toUtf8()))
+{
+}
+
+KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const char * _group)
+ : d(new KConfigGroupPrivate(master, _group))
+{
+}
+
+KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs)
+{
+ d = rhs.d;
+ return *this;
+}
+
+KConfigGroup::KConfigGroup(const KConfigGroup &rhs)
+ : KConfigBase(), d(rhs.d)
+{
+}
+
+KConfigGroup::~KConfigGroup()
+{
+ d = 0;
+}
+
+KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
+ Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
+
+ KConfigGroup newGroup;
+
+ newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup);
+
+ return newGroup;
+}
+
+const KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group");
+ Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group");
+
+ KConfigGroup newGroup;
+
+ newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup*>(this), isGroupImmutableImpl(aGroup),
+ true, aGroup);
+
+ return newGroup;
+}
+
+KConfigGroup KConfigGroup::parent() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group");
+
+ KConfigGroup parentGroup;
+
+ if (d->mParent) {
+ parentGroup.d = d->mParent;
+ } else {
+ parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, "");
+ // make sure we keep the refcount up on the KConfig object
+ parentGroup.d->sOwner = d->sOwner;
+ }
+
+ return parentGroup;
+}
+
+void KConfigGroup::deleteGroup(WriteConfigFlags flags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group");
+
+ config()->deleteGroup(d->fullName(), flags);
+}
+
+#ifndef KDE_NO_DEPRECATED
+void KConfigGroup::changeGroup( const QString &group )
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group");
+ d.detach();
+ d->mName = group.toUtf8();
+}
+#endif
+
+#ifndef KDE_NO_DEPRECATED
+void KConfigGroup::changeGroup( const char *group )
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group");
+ d.detach();
+ d->mName = group;
+}
+#endif
+
+QString KConfigGroup::name() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group");
+
+ return QString::fromUtf8(d->name());
+}
+
+bool KConfigGroup::exists() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group");
+
+ return config()->hasGroup( d->fullName() );
+}
+
+void KConfigGroup::sync()
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group");
+
+ if (!d->bConst)
+ config()->sync();
+}
+
+QMap<QString, QString> KConfigGroup::entryMap() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group");
+
+ return config()->entryMap(QString::fromUtf8(d->fullName()));
+}
+
+KConfig* KConfigGroup::config()
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
+
+ return d->mOwner;
+}
+
+const KConfig* KConfigGroup::config() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group");
+
+ return d->mOwner;
+}
+
+bool KConfigGroup::isEntryImmutable(const char* key) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group");
+
+ return (isImmutable() ||
+ !config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults()));
+}
+
+bool KConfigGroup::isEntryImmutable(const QString& key) const
+{
+ return isEntryImmutable(key.toUtf8().constData());
+}
+
+QString KConfigGroup::readEntryUntranslated(const QString& pKey, const QString& aDefault) const
+{
+ return readEntryUntranslated(pKey.toUtf8().constData(), aDefault);
+}
+
+QString KConfigGroup::readEntryUntranslated(const char *key, const QString& aDefault) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group");
+
+ QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), 0);
+ if (result.isNull())
+ return aDefault;
+ return result;
+}
+
+QString KConfigGroup::readEntry(const char *key, const char* aDefault) const
+{
+ return readEntry(key, QString::fromUtf8(aDefault));
+}
+
+QString KConfigGroup::readEntry(const QString &key, const char* aDefault) const
+{
+ return readEntry(key.toUtf8().constData(), aDefault);
+}
+
+QString KConfigGroup::readEntry(const char* key, const QString& aDefault) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
+
+ bool expand = false;
+
+ // read value from the entry map
+ QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized,
+ &expand);
+ if (aValue.isNull())
+ aValue = aDefault;
+
+ if (expand)
+ return KConfigPrivate::expandString(aValue);
+
+ return aValue;
+}
+
+QString KConfigGroup::readEntry(const QString &key, const QString& aDefault) const
+{
+ return readEntry(key.toUtf8().constData(), aDefault);
+}
+
+QStringList KConfigGroup::readEntry(const char* key, const QStringList& aDefault) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
+
+ const QString data = readEntry(key, QString());
+ if (data.isNull())
+ return aDefault;
+
+ return KConfigGroupPrivate::deserializeList(data);
+}
+
+QStringList KConfigGroup::readEntry( const QString& key, const QStringList& aDefault) const
+{
+ return readEntry( key.toUtf8().constData(), aDefault );
+}
+
+QVariant KConfigGroup::readEntry( const char* key, const QVariant &aDefault ) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
+
+ const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized);
+ if (data.isNull())
+ return aDefault;
+
+ QVariant value;
+ if (!readEntryGui( data, key, aDefault, value ))
+ return convertToQVariant(key, data, aDefault);
+
+ return value;
+}
+
+QVariant KConfigGroup::readEntry( const QString& key, const QVariant& aDefault) const
+{
+ return readEntry( key.toUtf8().constData(), aDefault );
+}
+
+QVariantList KConfigGroup::readEntry( const char* key, const QVariantList& aDefault) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group");
+
+ const QString data = readEntry(key, QString());
+ if (data.isNull())
+ return aDefault;
+
+ QVariantList value;
+ foreach(const QString& v, KConfigGroupPrivate::deserializeList(data))
+ value << v;
+
+ return value;
+}
+
+QVariantList KConfigGroup::readEntry( const QString& key, const QVariantList& aDefault) const
+{
+ return readEntry( key.toUtf8().constData(), aDefault );
+}
+
+QStringList KConfigGroup::readXdgListEntry(const QString& key, const QStringList& aDefault) const
+{
+ return readXdgListEntry(key.toUtf8().constData(), aDefault);
+}
+
+QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList& aDefault) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group");
+
+ const QString data = readEntry(key, QString());
+ if (data.isNull())
+ return aDefault;
+
+ QStringList value;
+ QString val;
+ val.reserve(data.size());
+ // XXX List serialization being a separate layer from low-level parsing is
+ // probably a bug. No affected entries are defined, though.
+ bool quoted = false;
+ for (int p = 0; p < data.length(); p++) {
+ if (quoted) {
+ val += data[p];
+ quoted = false;
+ } else if (data[p] == QLatin1Char('\\')) {
+ quoted = true;
+ } else if (data[p] == QLatin1Char(';')) {
+ value.append(val);
+ val.clear();
+ val.reserve(data.size() - p);
+ } else {
+ val += data[p];
+ }
+ }
+ if (!val.isEmpty()) {
+ kWarning() << "List entry" << key << "in" << config()->name() << "is not compliant with XDG standard (missing trailing semicolon).";
+ value.append(val);
+ }
+ return value;
+}
+
+QString KConfigGroup::readPathEntry(const QString& pKey, const QString & aDefault) const
+{
+ return readPathEntry(pKey.toUtf8().constData(), aDefault);
+}
+
+QString KConfigGroup::readPathEntry(const char *key, const QString & aDefault) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
+
+ bool expand = false;
+
+ QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized,
+ &expand);
+ if (aValue.isNull())
+ aValue = aDefault;
+
+ return KConfigPrivate::expandString(aValue);
+}
+
+QStringList KConfigGroup::readPathEntry(const QString& pKey, const QStringList& aDefault) const
+{
+ return readPathEntry(pKey.toUtf8().constData(), aDefault);
+}
+
+QStringList KConfigGroup::readPathEntry(const char *key, const QStringList& aDefault) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group");
+
+ const QString data = readPathEntry(key, QString());
+ if (data.isNull())
+ return aDefault;
+
+ return KConfigGroupPrivate::deserializeList(data);
+}
+
+void KConfigGroup::writeEntry( const char* key, const QString& value, WriteConfigFlags flags )
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
+
+ writeEntry(key, value.toUtf8(), flags);
+}
+
+void KConfigGroup::writeEntry( const QString& key, const QString& value, WriteConfigFlags flags )
+{
+ writeEntry(key.toUtf8().constData(), value, flags);
+}
+
+void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
+
+ writeEntry(key.toUtf8().constData(), QVariant(QString::fromLatin1(value)), pFlags);
+}
+
+void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags)
+{
+ writeEntry(key, QVariant(QString::fromLatin1(value)), pFlags);
+}
+
+void KConfigGroup::writeEntry( const char* key, const QByteArray& value,
+ WriteConfigFlags flags )
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
+
+ config()->d_func()->putData(d->fullName(), key, value.isNull()? QByteArray(""): value, flags);
+}
+
+void KConfigGroup::writeEntry(const QString& key, const QByteArray& value,
+ WriteConfigFlags pFlags)
+{
+ writeEntry(key.toUtf8().constData(), value, pFlags);
+}
+
+void KConfigGroup::writeEntry(const char* key, const QStringList &list, WriteConfigFlags flags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
+
+ QList<QByteArray> balist;
+
+ foreach(const QString &entry, list)
+ balist.append(entry.toUtf8());
+
+ writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags);
+}
+
+void KConfigGroup::writeEntry(const QString& key, const QStringList &list, WriteConfigFlags flags)
+{
+ writeEntry(key.toUtf8().constData(), list, flags);
+}
+
+void KConfigGroup::writeEntry( const char* key, const QVariantList& list, WriteConfigFlags flags )
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
+
+ QList<QByteArray> data;
+
+ foreach(const QVariant& v, list) {
+ if (v.type() == QVariant::ByteArray)
+ data << v.toByteArray();
+ else
+ data << v.toString().toUtf8();
+ }
+
+ writeEntry(key, KConfigGroupPrivate::serializeList(data), flags);
+}
+
+void KConfigGroup::writeEntry( const char* key, const QVariant &value,
+ WriteConfigFlags flags )
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group");
+
+ if ( writeEntryGui( this, key, value, flags ) )
+ return; // GUI type that was handled
+
+ QByteArray data;
+ // if a type handler is added here you must add a QVConversions definition
+ // to conversion_check.h, or ConversionCheck::to_QVariant will not allow
+ // writeEntry<T> to convert to QVariant.
+ switch( value.type() ) {
+ case QVariant::Invalid:
+ data = "";
+ break;
+ case QVariant::ByteArray:
+ data = value.toByteArray();
+ break;
+ case QVariant::String:
+ case QVariant::Int:
+ case QVariant::UInt:
+ case QVariant::Double:
+ case QMetaType::Float:
+ case QVariant::Bool:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ data = value.toString().toUtf8();
+ break;
+ case QVariant::List:
+ kError(!value.canConvert(QVariant::StringList))
+ << "not all types in \"" << key << "\" can convert to QString,"
+ " information will be lost";
+ case QVariant::StringList:
+ writeEntry( key, value.toList(), flags );
+ return;
+ case QVariant::Point: {
+ QVariantList list;
+ const QPoint rPoint = value.toPoint();
+ list.insert( 0, rPoint.x() );
+ list.insert( 1, rPoint.y() );
+
+ writeEntry( key, list, flags );
+ return;
+ }
+ case QVariant::PointF: {
+ QVariantList list;
+ const QPointF point = value.toPointF();
+ list.insert( 0, point.x() );
+ list.insert( 1, point.y() );
+
+ writeEntry( key, list, flags );
+ return;
+ }
+ case QVariant::Rect:{
+ QVariantList list;
+ const QRect rRect = value.toRect();
+ list.insert( 0, rRect.left() );
+ list.insert( 1, rRect.top() );
+ list.insert( 2, rRect.width() );
+ list.insert( 3, rRect.height() );
+
+ writeEntry( key, list, flags );
+ return;
+ }
+ case QVariant::RectF:{
+ QVariantList list;
+ const QRectF rRectF = value.toRectF();
+ list.insert(0, rRectF.left());
+ list.insert(1, rRectF.top());
+ list.insert(2, rRectF.width());
+ list.insert(3, rRectF.height());
+
+ writeEntry(key, list, flags);
+ return;
+ }
+ case QVariant::Size:{
+ QVariantList list;
+ const QSize rSize = value.toSize();
+ list.insert( 0, rSize.width() );
+ list.insert( 1, rSize.height() );
+
+ writeEntry( key, list, flags );
+ return;
+ }
+ case QVariant::SizeF:{
+ QVariantList list;
+ const QSizeF rSizeF = value.toSizeF();
+ list.insert(0, rSizeF.width());
+ list.insert(1, rSizeF.height());
+
+ writeEntry(key, list, flags);
+ return;
+ }
+ case QVariant::Date: {
+ QVariantList list;
+ const QDate date = value.toDate();
+
+ list.insert( 0, date.year() );
+ list.insert( 1, date.month() );
+ list.insert( 2, date.day() );
+
+ writeEntry( key, list, flags );
+ return;
+ }
+ case QVariant::DateTime: {
+ QVariantList list;
+ const QDateTime rDateTime = value.toDateTime();
+
+ const QTime time = rDateTime.time();
+ const QDate date = rDateTime.date();
+
+ list.insert( 0, date.year() );
+ list.insert( 1, date.month() );
+ list.insert( 2, date.day() );
+
+ list.insert( 3, time.hour() );
+ list.insert( 4, time.minute() );
+ list.insert( 5, time.second() );
+
+ writeEntry( key, list, flags );
+ return;
+ }
+
+ case QVariant::Color:
+ case QVariant::Font:
+ kWarning() << "KConfigGroup::writeEntry was passed GUI type '"
+ << value.typeName()
+ << "' but kdeui isn't linked! If it is linked to your program, this is a platform bug. "
+ "Please inform the KDE developers";
+ break;
+ case QVariant::Url:
+ data = KUrl(value.toUrl()).url().toUtf8();
+ break;
+ default:
+ if( value.canConvert<KUrl>() ) {
+ data = qvariant_cast<KUrl>(value).url().toUtf8();
+ break;
+ }
+ kWarning() << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name();
+ }
+
+ writeEntry(key, data, flags);
+}
+
+void KConfigGroup::writeEntry( const QString& key, const QVariant& value, WriteConfigFlags flags )
+{
+ writeEntry(key.toUtf8().constData(), value, flags);
+}
+
+void KConfigGroup::writeEntry(const QString& key, const QVariantList &list, WriteConfigFlags flags)
+{
+ writeEntry(key.toUtf8().constData(), list, flags);
+}
+
+void KConfigGroup::writeXdgListEntry(const QString& key, const QStringList &value, WriteConfigFlags pFlags)
+{
+ writeXdgListEntry(key.toUtf8().constData(), value, pFlags);
+}
+
+void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group");
+
+ QString value;
+ value.reserve(4096);
+
+ // XXX List serialization being a separate layer from low-level escaping is
+ // probably a bug. No affected entries are defined, though.
+ QStringList::ConstIterator it = list.constBegin();
+ const QStringList::ConstIterator end = list.constEnd();
+ for (; it != end; ++it) {
+ QString val(*it);
+ val.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char(';'), QLatin1String("\\;"));
+ value += val;
+ value += QLatin1Char(';');
+ }
+
+ writeEntry(key, value, flags);
+}
+
+void KConfigGroup::writePathEntry(const QString& pKey, const QString & path, WriteConfigFlags pFlags)
+{
+ writePathEntry(pKey.toUtf8().constData(), path, pFlags);
+}
+
+void KConfigGroup::writePathEntry(const char *pKey, const QString & path, WriteConfigFlags pFlags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
+
+ config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true);
+}
+
+void KConfigGroup::writePathEntry(const QString& pKey, const QStringList &value, WriteConfigFlags pFlags)
+{
+ writePathEntry(pKey.toUtf8().constData(), value, pFlags);
+}
+
+void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group");
+
+ QList<QByteArray> list;
+ foreach(const QString& path, value)
+ list << translatePath(path).toUtf8();
+
+ config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true);
+}
+
+void KConfigGroup::deleteEntry( const char *key, WriteConfigFlags flags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group");
+
+ config()->d_func()->putData(d->fullName(), key, QByteArray(), flags);
+}
+
+void KConfigGroup::deleteEntry( const QString& key, WriteConfigFlags flags)
+{
+ deleteEntry(key.toUtf8().constData(), flags);
+}
+
+void KConfigGroup::revertToDefault(const char *key)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group");
+
+ const QByteArray theDefault = config()->d_func()->lookupData(d->fullName(), key,
+ KEntryMap::SearchDefaults|KEntryMap::SearchLocalized);
+
+ config()->d_func()->putData(d->fullName(), key, theDefault, KConfig::Normal);
+}
+
+void KConfigGroup::revertToDefault(const QString &key)
+{
+ revertToDefault(key.toUtf8().constData());
+}
+
+bool KConfigGroup::hasDefault(const char *key) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group");
+
+ KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults|KEntryMap::SearchLocalized;
+
+ return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
+}
+
+bool KConfigGroup::hasDefault(const QString &key) const
+{
+ return hasDefault(key.toUtf8().constData());
+}
+
+bool KConfigGroup::hasKey(const char *key) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group");
+
+ KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized;
+ if ( config()->readDefaults() )
+ flags |= KEntryMap::SearchDefaults;
+
+ return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull();
+}
+
+bool KConfigGroup::hasKey(const QString &key) const
+{
+ return hasKey(key.toUtf8().constData());
+}
+
+bool KConfigGroup::isImmutable() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group");
+
+ return d->bImmutable;
+}
+
+QStringList KConfigGroup::groupList() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group");
+
+ return config()->d_func()->groupList(d->fullName());
+}
+
+QStringList KConfigGroup::keyList() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group");
+
+ return entryMap().keys();
+}
+
+void KConfigGroup::markAsClean()
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group");
+
+ config()->markAsClean();
+}
+
+KConfigGroup::AccessMode KConfigGroup::accessMode() const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group");
+
+ return config()->accessMode();
+}
+
+bool KConfigGroup::hasGroupImpl(const QByteArray & b) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group");
+
+ return config()->hasGroup(d->fullName(b));
+}
+
+void KConfigGroup::deleteGroupImpl(const QByteArray &b, WriteConfigFlags flags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst,"KConfigGroup::deleteGroupImpl", "deleting from a read-only group");
+
+ config()->deleteGroup(d->fullName(b), flags);
+}
+
+bool KConfigGroup::isGroupImmutableImpl(const QByteArray& b) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group");
+
+ if (!hasGroupImpl(b)) // group doesn't exist yet
+ return d->bImmutable; // child groups are immutable if the parent is immutable.
+
+ return config()->isGroupImmutable(d->fullName(b));
+}
+
+void KConfigGroup::copyTo(KConfigBase* other, WriteConfigFlags pFlags) const
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group");
+ Q_ASSERT(other != 0);
+
+ if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup*>(other)) {
+ config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags);
+ } else if (KConfig* otherConfig = dynamic_cast<KConfig*>(other)) {
+ KConfigGroup newGroup = otherConfig->group(d->fullName());
+ otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags);
+ } else {
+ Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase");
+ }
+}
+
+void KConfigGroup::reparent(KConfigBase* parent, WriteConfigFlags pFlags)
+{
+ Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group");
+ Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group");
+ Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group");
+ Q_ASSERT(parent != 0);
+
+ KConfigGroup oldGroup(*this);
+
+ d = KConfigGroupPrivate::create(parent, d->mName, false, false);
+ oldGroup.copyTo(this, pFlags);
+ oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync
+}
diff --git a/kdecore/config/kconfiggroup.h b/kdecore/config/kconfiggroup.h
new file mode 100644
index 0000000..8eddfd5
--- /dev/null
+++ b/kdecore/config/kconfiggroup.h
@@ -0,0 +1,769 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
+ Copyright (c) 1999 Preston Brown <pbrown@kde.org>
+ Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org>
+ Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCONFIGGROUP_H
+#define KCONFIGGROUP_H
+
+#include "kconfigbase.h"
+
+#include <kdecore_export.h>
+
+#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QVariant>
+#include <QtCore/QStringList>
+
+class KConfig;
+class KConfigGroupPrivate;
+class KSharedConfig;
+template <typename T> class KSharedPtr;
+typedef KSharedPtr<KSharedConfig> KSharedConfigPtr;
+
+/**
+ * \class KConfigGroup kconfiggroup.h <KConfigGroup>
+ *
+ * A class for one specific group in a KConfig object.
+ *
+ * If you want to access the top-level entries of a KConfig
+ * object, which are not associated with any group, use an
+ * empty group name.
+ *
+ * A KConfigGroup will be read-only if it is constructed from a
+ * const config object or from another read-only group.
+ */
+class KDECORE_EXPORT KConfigGroup : public KConfigBase
+{
+public:
+ /**
+ * Constructs an invalid group.
+ *
+ * \see isValid
+ */
+ KConfigGroup();
+
+ /**
+ * Construct a config group corresponding to @p group in @p master.
+ *
+ * This allows the creation of subgroups by passing another
+ * group as @p master.
+ *
+ * @p group is the group name encoded in UTF-8.
+ */
+ KConfigGroup(KConfigBase *master, const QString &group);
+ /** Overload for KConfigGroup(KConfigBase*,const QString&) */
+ KConfigGroup(KConfigBase *master, const char *group);
+
+ /**
+ * Construct a read-only config group.
+ *
+ * A read-only group will silently ignore any attempts to write to it.
+ *
+ * This allows the creation of subgroups by passing an existing group
+ * as @p master.
+ */
+ KConfigGroup(const KConfigBase *master, const QString &group);
+ /** Overload for KConfigGroup(const KConfigBase*,const QString&) */
+ KConfigGroup(const KConfigBase *master, const char *group);
+
+ /** Overload for KConfigGroup(const KConfigBase*,const QString&) */
+ KConfigGroup(const KSharedConfigPtr &master, const QString &group);
+ /** Overload for KConfigGroup(const KConfigBase*,const QString&) */
+ KConfigGroup(const KSharedConfigPtr &master, const char *group);
+
+ /**
+ * Creates a read-only copy of a read-only group.
+ */
+ KConfigGroup(const KConfigGroup &);
+ KConfigGroup &operator=(const KConfigGroup &);
+
+ ~KConfigGroup();
+
+ /**
+ * Whether the group is valid.
+ *
+ * A group is invalid if it was constructed without arguments.
+ *
+ * You should not call any functions on an invalid group.
+ *
+ * @return @c true if the group is valid, @c false if it is invalid.
+ */
+ bool isValid() const;
+
+ /**
+ * The name of this group.
+ *
+ * The root group is named "<default>".
+ */
+ QString name() const;
+
+ /**
+ * Check whether the containing KConfig object acutally contains a
+ * group with this name.
+ */
+ bool exists() const;
+
+ /**
+ * @reimp
+ *
+ * Syncs the parent config.
+ */
+ void sync();
+
+ /// @reimp
+ void markAsClean();
+
+ /// @reimp
+ AccessMode accessMode() const;
+
+ /**
+ * Return the config object that this group belongs to
+ */
+ KConfig* config();
+ /**
+ * Return the config object that this group belongs to
+ */
+ const KConfig* config() const;
+
+ /**
+ * Changes the group of the object
+ *
+ * @deprecated
+ * Create another KConfigGroup from the parent of this group instead.
+ */
+#ifndef KDE_NO_DEPRECATED
+ KDE_DEPRECATED void changeGroup(const QString &group);
+#endif
+ /**
+ * Overload for changeGroup(const QString&)
+ *
+ * @deprecated
+ * Create another KConfigGroup from the parent of this group instead.
+ */
+#ifndef KDE_NO_DEPRECATED
+ KDE_DEPRECATED void changeGroup(const char *group);
+#endif
+
+ /**
+ * Copies the entries in this group to another configuration object
+ *
+ * @note @p other can be either another group or a different file.
+ *
+ * @param other the configuration object to copy this group's entries to
+ * @param pFlags the flags to use when writing the entries to the
+ * other configuration object
+ *
+ * @since 4.1
+ */
+ void copyTo(KConfigBase *other, WriteConfigFlags pFlags = Normal) const;
+
+ /**
+ * Changes the configuration object that this group belongs to
+ *
+ * @note @p other can be another group, the top-level KConfig object or
+ * a different KConfig object entirely.
+ *
+ * If @p parent is already the parent of this group, this method will have
+ * no effect.
+ *
+ * @param parent the config object to place this group under
+ * @param pFlags the flags to use in determining which storage source to
+ * write the data to
+ *
+ * @since 4.1
+ */
+ void reparent(KConfigBase *parent, WriteConfigFlags pFlags = Normal);
+
+ /**
+ * Returns the group that this group belongs to
+ *
+ * @return the parent group, or an invalid group if this is a top-level
+ * group
+ *
+ * @since 4.1
+ */
+ KConfigGroup parent() const;
+
+ /**
+ * @reimp
+ */
+ QStringList groupList() const;
+
+ /**
+ * Returns a list of keys this group contains
+ */
+ QStringList keyList() const;
+
+ /**
+ * Delete all entries in the entire group
+ *
+ * @param pFlags flags passed to KConfig::deleteGroup
+ *
+ * @see deleteEntry()
+ */
+ void deleteGroup(WriteConfigFlags pFlags = Normal);
+ using KConfigBase::deleteGroup;
+
+ /**
+ * Reads the value of an entry specified by @p pKey in the current group
+ *
+ * This template method makes it possible to write
+ * QString foo = readEntry("...", QString("default"));
+ * and the same with all other types supported by QVariant.
+ *
+ * The return type of the method is simply the same as the type of the default value.
+ *
+ * @note readEntry("...", Qt::white) will not compile because Qt::white is an enum.
+ * You must turn it into readEntry("...", QColor(Qt::white)).
+ *
+ * @note Only the following QVariant types are allowed : String,
+ * StringList, List, Font, Point, Rect, Size, Color, Int, UInt, Bool,
+ * Double, LongLong, ULongLong, DateTime and Date.
+ *
+ * @param key The key to search for
+ * @param aDefault A default value returned if the key was not found
+ * @return The value for this key, or @p aDefault.
+ *
+ * @see writeEntry(), deleteEntry(), hasKey()
+ */
+ template <typename T>
+ inline T readEntry(const QString &key, const T &aDefault) const
+ { return readCheck(key.toUtf8().constData(), aDefault); }
+ /** Overload for readEntry(const QString&, const T&) const */
+ template <typename T>
+ inline T readEntry(const char *key, const T &aDefault) const
+ { return readCheck(key, aDefault); }
+
+ /**
+ * Reads the value of an entry specified by @p key in the current group
+ *
+ * @param key the key to search for